xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c (revision cd93bdd351ff6db57bb306f3135a27aff71919d0)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5605445d5Sdg199075  * Common Development and Distribution License (the "License").
6605445d5Sdg199075  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
220a0e9771SDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247d897698SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
28605445d5Sdg199075 #include <stddef.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/time.h>
357c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <sys/socket.h>
38605445d5Sdg199075 #include <sys/vlan.h>
397c478bd9Sstevel@tonic-gate #include <net/if.h>
407c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
417c478bd9Sstevel@tonic-gate #include <netinet/in.h>
427c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
437c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
447c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
457c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
46b127ac41SPhilip Kirk #include <inet/ip.h>
47b127ac41SPhilip Kirk #include <inet/ip6.h>
487c478bd9Sstevel@tonic-gate #include <netdb.h>
497c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
507c478bd9Sstevel@tonic-gate #include <setjmp.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <sys/pfmod.h>
537c478bd9Sstevel@tonic-gate #include "snoop.h"
54605445d5Sdg199075 #include "snoop_vlan.h"
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * This module generates code for the kernel packet filter.
587c478bd9Sstevel@tonic-gate  * The kernel packet filter is more efficient since it
597c478bd9Sstevel@tonic-gate  * operates without context switching or moving data into
607c478bd9Sstevel@tonic-gate  * the capture buffer.  On the other hand, it is limited
617c478bd9Sstevel@tonic-gate  * in its filtering ability i.e. can't cope with variable
627c478bd9Sstevel@tonic-gate  * length headers, can't compare the packet size, 1 and 4 octet
637c478bd9Sstevel@tonic-gate  * comparisons are awkward, code space is limited to ENMAXFILTERS
647c478bd9Sstevel@tonic-gate  * halfwords, etc.
657c478bd9Sstevel@tonic-gate  * The parser is the same for the user-level packet filter though
667c478bd9Sstevel@tonic-gate  * more limited in the variety of expressions it can generate
677c478bd9Sstevel@tonic-gate  * code for.  If the pf compiler finds an expression it can't
687c478bd9Sstevel@tonic-gate  * handle, it tries to set up a split filter in kernel and do the
697c478bd9Sstevel@tonic-gate  * remaining filtering in userland. If that also fails, it resorts
707c478bd9Sstevel@tonic-gate  * to userland filter. (See additional comment in pf_compile)
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate extern struct Pf_ext_packetfilt pf;
747c478bd9Sstevel@tonic-gate static ushort_t *pfp;
757c478bd9Sstevel@tonic-gate jmp_buf env;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	EQ(val)		(strcmp(token, val) == 0)
787c478bd9Sstevel@tonic-gate #define	IPV4_ONLY	0
797c478bd9Sstevel@tonic-gate #define	IPV6_ONLY	1
807c478bd9Sstevel@tonic-gate #define	IPV4_AND_IPV6	2
817c478bd9Sstevel@tonic-gate 
82b127ac41SPhilip Kirk typedef struct {
83b127ac41SPhilip Kirk 	int	transport_protocol;
84b127ac41SPhilip Kirk 	int	network_protocol;
857c478bd9Sstevel@tonic-gate 	/*
86b127ac41SPhilip Kirk 	 * offset is the offset in bytes from the beginning
87b127ac41SPhilip Kirk 	 * of the network protocol header to where the transport
88b127ac41SPhilip Kirk 	 * protocol type is.
897c478bd9Sstevel@tonic-gate 	 */
90b127ac41SPhilip Kirk 	int	offset;
91041bde0aSSebastien Roy } transport_table_t;
927c478bd9Sstevel@tonic-gate 
93b127ac41SPhilip Kirk typedef struct network_table {
94b127ac41SPhilip Kirk 	char *nmt_name;
95b127ac41SPhilip Kirk 	int nmt_val;
96b127ac41SPhilip Kirk } network_table_t;
97b127ac41SPhilip Kirk 
98b127ac41SPhilip Kirk static network_table_t ether_network_mapping_table[] = {
99b127ac41SPhilip Kirk 	{ "pup", ETHERTYPE_PUP },
100b127ac41SPhilip Kirk 	{ "ip", ETHERTYPE_IP },
101b127ac41SPhilip Kirk 	{ "arp", ETHERTYPE_ARP },
102573f0244SCody Peter Mello 	{ "rarp", ETHERTYPE_REVARP },
103b127ac41SPhilip Kirk 	{ "at", ETHERTYPE_AT },
104b127ac41SPhilip Kirk 	{ "aarp", ETHERTYPE_AARP },
105b127ac41SPhilip Kirk 	{ "vlan", ETHERTYPE_VLAN },
106b127ac41SPhilip Kirk 	{ "ip6", ETHERTYPE_IPV6 },
107b127ac41SPhilip Kirk 	{ "slow", ETHERTYPE_SLOW },
108b127ac41SPhilip Kirk 	{ "ppoed", ETHERTYPE_PPPOED },
109b127ac41SPhilip Kirk 	{ "ppoes", ETHERTYPE_PPPOES },
110b127ac41SPhilip Kirk 	{ "NULL", -1 }
111b127ac41SPhilip Kirk 
112b127ac41SPhilip Kirk };
113b127ac41SPhilip Kirk 
114b127ac41SPhilip Kirk static network_table_t ib_network_mapping_table[] = {
115b127ac41SPhilip Kirk 	{ "pup", ETHERTYPE_PUP },
116b127ac41SPhilip Kirk 	{ "ip", ETHERTYPE_IP },
117b127ac41SPhilip Kirk 	{ "arp", ETHERTYPE_ARP },
118573f0244SCody Peter Mello 	{ "rarp", ETHERTYPE_REVARP },
119b127ac41SPhilip Kirk 	{ "at", ETHERTYPE_AT },
120b127ac41SPhilip Kirk 	{ "aarp", ETHERTYPE_AARP },
121b127ac41SPhilip Kirk 	{ "vlan", ETHERTYPE_VLAN },
122b127ac41SPhilip Kirk 	{ "ip6", ETHERTYPE_IPV6 },
123b127ac41SPhilip Kirk 	{ "slow", ETHERTYPE_SLOW },
124b127ac41SPhilip Kirk 	{ "ppoed", ETHERTYPE_PPPOED },
125b127ac41SPhilip Kirk 	{ "ppoes", ETHERTYPE_PPPOES },
126b127ac41SPhilip Kirk 	{ "NULL", -1 }
127b127ac41SPhilip Kirk 
128b127ac41SPhilip Kirk };
129b127ac41SPhilip Kirk 
130b127ac41SPhilip Kirk static network_table_t ipnet_network_mapping_table[] = {
1310a0e9771SDarren Reed 	{ "ip", (DL_IPNETINFO_VERSION << 8 | AF_INET) },
1320a0e9771SDarren Reed 	{ "ip6", (DL_IPNETINFO_VERSION << 8 | AF_INET6) },
133b127ac41SPhilip Kirk 	{ "NULL", -1 }
134b127ac41SPhilip Kirk 
135b127ac41SPhilip Kirk };
136b127ac41SPhilip Kirk 
137041bde0aSSebastien Roy static transport_table_t ether_transport_mapping_table[] = {
138b127ac41SPhilip Kirk 	{IPPROTO_TCP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
139b127ac41SPhilip Kirk 	{IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
140b127ac41SPhilip Kirk 	{IPPROTO_UDP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
141b127ac41SPhilip Kirk 	{IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
142b127ac41SPhilip Kirk 	{IPPROTO_OSPF, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
143b127ac41SPhilip Kirk 	{IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
144b127ac41SPhilip Kirk 	{IPPROTO_SCTP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
145b127ac41SPhilip Kirk 	{IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
146b127ac41SPhilip Kirk 	{IPPROTO_ICMP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
147b127ac41SPhilip Kirk 	{IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
148b127ac41SPhilip Kirk 	{IPPROTO_ENCAP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
149b127ac41SPhilip Kirk 	{IPPROTO_ESP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
150b127ac41SPhilip Kirk 	{IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
151b127ac41SPhilip Kirk 	{IPPROTO_AH, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
152b127ac41SPhilip Kirk 	{IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
153b127ac41SPhilip Kirk 	{-1, 0, 0}	/* must be the final entry */
154b127ac41SPhilip Kirk };
155b127ac41SPhilip Kirk 
156041bde0aSSebastien Roy static transport_table_t ipnet_transport_mapping_table[] = {
1570a0e9771SDarren Reed 	{IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
158b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1590a0e9771SDarren Reed 	{IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
160b127ac41SPhilip Kirk 	    IPV6_TYPE_HEADER_OFFSET},
1610a0e9771SDarren Reed 	{IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
162b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1630a0e9771SDarren Reed 	{IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
164b127ac41SPhilip Kirk 	    IPV6_TYPE_HEADER_OFFSET},
1650a0e9771SDarren Reed 	{IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET),
166b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1670a0e9771SDarren Reed 	{IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
168b127ac41SPhilip Kirk 	    IPV6_TYPE_HEADER_OFFSET},
1690a0e9771SDarren Reed 	{IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
170b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1710a0e9771SDarren Reed 	{IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
172b127ac41SPhilip Kirk 	    IPV6_TYPE_HEADER_OFFSET},
1730a0e9771SDarren Reed 	{IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
174b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1750a0e9771SDarren Reed 	{IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
176b127ac41SPhilip Kirk 	    IPV6_TYPE_HEADER_OFFSET},
1770a0e9771SDarren Reed 	{IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
178b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1790a0e9771SDarren Reed 	{IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET),
180b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1810a0e9771SDarren Reed 	{IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
182b127ac41SPhilip Kirk 	    IPV6_TYPE_HEADER_OFFSET},
1830a0e9771SDarren Reed 	{IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET),
184b127ac41SPhilip Kirk 	    IPV4_TYPE_HEADER_OFFSET},
1850a0e9771SDarren Reed 	{IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | AF_INET6),
186b127ac41SPhilip Kirk 	    IPV6_TYPE_HEADER_OFFSET},
187b127ac41SPhilip Kirk 	{-1, 0, 0}	/* must be the final entry */
188b127ac41SPhilip Kirk };
189b127ac41SPhilip Kirk 
190041bde0aSSebastien Roy static transport_table_t ib_transport_mapping_table[] = {
191b127ac41SPhilip Kirk 	{IPPROTO_TCP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
192b127ac41SPhilip Kirk 	{IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
193b127ac41SPhilip Kirk 	{IPPROTO_UDP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
194b127ac41SPhilip Kirk 	{IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
195b127ac41SPhilip Kirk 	{IPPROTO_OSPF, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
196b127ac41SPhilip Kirk 	{IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
197b127ac41SPhilip Kirk 	{IPPROTO_SCTP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
198b127ac41SPhilip Kirk 	{IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
199b127ac41SPhilip Kirk 	{IPPROTO_ICMP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
200b127ac41SPhilip Kirk 	{IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
201b127ac41SPhilip Kirk 	{IPPROTO_ENCAP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
202b127ac41SPhilip Kirk 	{IPPROTO_ESP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
203b127ac41SPhilip Kirk 	{IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
204b127ac41SPhilip Kirk 	{IPPROTO_AH, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
205b127ac41SPhilip Kirk 	{IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
206b127ac41SPhilip Kirk 	{-1, 0, 0}	/* must be the final entry */
207b127ac41SPhilip Kirk };
208b127ac41SPhilip Kirk 
209b127ac41SPhilip Kirk typedef struct datalink {
210b127ac41SPhilip Kirk 	uint_t			dl_type;
211b127ac41SPhilip Kirk 	void			(*dl_match_fn)(uint_t datatype);
212041bde0aSSebastien Roy 	transport_table_t	*dl_trans_map_tbl;
213b127ac41SPhilip Kirk 	network_table_t		*dl_net_map_tbl;
214b127ac41SPhilip Kirk 	int			dl_link_header_len;
215b127ac41SPhilip Kirk 	int			dl_link_type_offset;
216b127ac41SPhilip Kirk 	int			dl_link_dest_offset;
217b127ac41SPhilip Kirk 	int			dl_link_src_offset;
218b127ac41SPhilip Kirk 	int			dl_link_addr_len;
219b127ac41SPhilip Kirk } datalink_t;
220b127ac41SPhilip Kirk 
221b127ac41SPhilip Kirk datalink_t	dl;
222b127ac41SPhilip Kirk 
223b127ac41SPhilip Kirk #define	IPV4_SRCADDR_OFFSET	(dl.dl_link_header_len + 12)
224b127ac41SPhilip Kirk #define	IPV4_DSTADDR_OFFSET	(dl.dl_link_header_len + 16)
225b127ac41SPhilip Kirk #define	IPV6_SRCADDR_OFFSET	(dl.dl_link_header_len + 8)
226b127ac41SPhilip Kirk #define	IPV6_DSTADDR_OFFSET	(dl.dl_link_header_len + 24)
227b127ac41SPhilip Kirk 
2280a0e9771SDarren Reed #define	IPNET_SRCZONE_OFFSET 16
2290a0e9771SDarren Reed #define	IPNET_DSTZONE_OFFSET 20
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate static int inBrace = 0, inBraceOR = 0;
2327c478bd9Sstevel@tonic-gate static int foundOR = 0;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate extern void next();
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate static void pf_expression();
237605445d5Sdg199075 static void pf_check_vlan_tag(uint_t offset);
238605445d5Sdg199075 static void pf_clear_offset_register();
239605445d5Sdg199075 static void pf_emit_load_offset(uint_t offset);
240605445d5Sdg199075 static void pf_match_ethertype(uint_t ethertype);
241b127ac41SPhilip Kirk static void pf_match_ipnettype(uint_t type);
242b127ac41SPhilip Kirk static void pf_match_ibtype(uint_t type);
243605445d5Sdg199075 static void pf_check_transport_protocol(uint_t transport_protocol);
244605445d5Sdg199075 static void pf_compare_value_mask_generic(int offset, uint_t len,
245605445d5Sdg199075     uint_t val, int mask, uint_t op);
246041bde0aSSebastien Roy static void pf_matchfn(const char *name);
247605445d5Sdg199075 
248605445d5Sdg199075 /*
249605445d5Sdg199075  * This pointer points to the function that last generated
250605445d5Sdg199075  * instructions to change the offset register.  It's used
251605445d5Sdg199075  * for comparisons to see if we need to issue more instructions
252605445d5Sdg199075  * to change the register.
253605445d5Sdg199075  *
254605445d5Sdg199075  * It's initialized to pf_clear_offset_register because the offset
255605445d5Sdg199075  * register in pfmod is initialized to zero, similar to the state
256605445d5Sdg199075  * it would be in after executing the instructions issued by
257605445d5Sdg199075  * pf_clear_offset_register.
258605445d5Sdg199075  */
259605445d5Sdg199075 static void *last_offset_operation = (void*)pf_clear_offset_register;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate static void
pf_emit(ushort_t x)262*cd93bdd3SToomas Soome pf_emit(ushort_t x)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1])
2657c478bd9Sstevel@tonic-gate 		longjmp(env, 1);
2667c478bd9Sstevel@tonic-gate 	*pfp++ = x;
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate static void
pf_codeprint(ushort_t * code,int len)270*cd93bdd3SToomas Soome pf_codeprint(ushort_t *code, int len)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	ushort_t *pc;
2737c478bd9Sstevel@tonic-gate 	ushort_t *plast = code + len;
2747c478bd9Sstevel@tonic-gate 	int op, action;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (len > 0) {
2777c478bd9Sstevel@tonic-gate 		printf("Kernel Filter:\n");
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	for (pc = code; pc < plast; pc++) {
2817c478bd9Sstevel@tonic-gate 		printf("\t%3d: ", pc - code);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		op = *pc & 0xfc00;	/* high 10 bits */
2847c478bd9Sstevel@tonic-gate 		action = *pc & 0x3ff;	/* low   6 bits */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 		switch (action) {
2877c478bd9Sstevel@tonic-gate 		case ENF_PUSHLIT:
2887c478bd9Sstevel@tonic-gate 			printf("PUSHLIT ");
2897c478bd9Sstevel@tonic-gate 			break;
2907c478bd9Sstevel@tonic-gate 		case ENF_PUSHZERO:
2917c478bd9Sstevel@tonic-gate 			printf("PUSHZERO ");
2927c478bd9Sstevel@tonic-gate 			break;
2937c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHONE
2947c478bd9Sstevel@tonic-gate 		case ENF_PUSHONE:
2957c478bd9Sstevel@tonic-gate 			printf("PUSHONE ");
2967c478bd9Sstevel@tonic-gate 			break;
2977c478bd9Sstevel@tonic-gate #endif
2987c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHFFFF
2997c478bd9Sstevel@tonic-gate 		case ENF_PUSHFFFF:
3007c478bd9Sstevel@tonic-gate 			printf("PUSHFFFF ");
3017c478bd9Sstevel@tonic-gate 			break;
3027c478bd9Sstevel@tonic-gate #endif
3037c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHFF00
3047c478bd9Sstevel@tonic-gate 		case ENF_PUSHFF00:
3057c478bd9Sstevel@tonic-gate 			printf("PUSHFF00 ");
3067c478bd9Sstevel@tonic-gate 			break;
3077c478bd9Sstevel@tonic-gate #endif
3087c478bd9Sstevel@tonic-gate #ifdef ENF_PUSH00FF
3097c478bd9Sstevel@tonic-gate 		case ENF_PUSH00FF:
3107c478bd9Sstevel@tonic-gate 			printf("PUSH00FF ");
3117c478bd9Sstevel@tonic-gate 			break;
3127c478bd9Sstevel@tonic-gate #endif
313605445d5Sdg199075 		case ENF_LOAD_OFFSET:
314605445d5Sdg199075 			printf("LOAD_OFFSET ");
315605445d5Sdg199075 			break;
316605445d5Sdg199075 		case ENF_BRTR:
317605445d5Sdg199075 			printf("BRTR ");
318605445d5Sdg199075 			break;
319605445d5Sdg199075 		case ENF_BRFL:
320605445d5Sdg199075 			printf("BRFL ");
321605445d5Sdg199075 			break;
322605445d5Sdg199075 		case ENF_POP:
323605445d5Sdg199075 			printf("POP ");
324605445d5Sdg199075 			break;
3257c478bd9Sstevel@tonic-gate 		}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		if (action >= ENF_PUSHWORD)
3287c478bd9Sstevel@tonic-gate 			printf("PUSHWORD %d ", action - ENF_PUSHWORD);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 		switch (op) {
3317c478bd9Sstevel@tonic-gate 		case ENF_EQ:
3327c478bd9Sstevel@tonic-gate 			printf("EQ ");
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		case ENF_LT:
3357c478bd9Sstevel@tonic-gate 			printf("LT ");
3367c478bd9Sstevel@tonic-gate 			break;
3377c478bd9Sstevel@tonic-gate 		case ENF_LE:
3387c478bd9Sstevel@tonic-gate 			printf("LE ");
3397c478bd9Sstevel@tonic-gate 			break;
3407c478bd9Sstevel@tonic-gate 		case ENF_GT:
3417c478bd9Sstevel@tonic-gate 			printf("GT ");
3427c478bd9Sstevel@tonic-gate 			break;
3437c478bd9Sstevel@tonic-gate 		case ENF_GE:
3447c478bd9Sstevel@tonic-gate 			printf("GE ");
3457c478bd9Sstevel@tonic-gate 			break;
3467c478bd9Sstevel@tonic-gate 		case ENF_AND:
3477c478bd9Sstevel@tonic-gate 			printf("AND ");
3487c478bd9Sstevel@tonic-gate 			break;
3497c478bd9Sstevel@tonic-gate 		case ENF_OR:
3507c478bd9Sstevel@tonic-gate 			printf("OR ");
3517c478bd9Sstevel@tonic-gate 			break;
3527c478bd9Sstevel@tonic-gate 		case ENF_XOR:
3537c478bd9Sstevel@tonic-gate 			printf("XOR ");
3547c478bd9Sstevel@tonic-gate 			break;
3557c478bd9Sstevel@tonic-gate 		case ENF_COR:
3567c478bd9Sstevel@tonic-gate 			printf("COR ");
3577c478bd9Sstevel@tonic-gate 			break;
3587c478bd9Sstevel@tonic-gate 		case ENF_CAND:
3597c478bd9Sstevel@tonic-gate 			printf("CAND ");
3607c478bd9Sstevel@tonic-gate 			break;
3617c478bd9Sstevel@tonic-gate 		case ENF_CNOR:
3627c478bd9Sstevel@tonic-gate 			printf("CNOR ");
3637c478bd9Sstevel@tonic-gate 			break;
3647c478bd9Sstevel@tonic-gate 		case ENF_CNAND:
3657c478bd9Sstevel@tonic-gate 			printf("CNAND ");
3667c478bd9Sstevel@tonic-gate 			break;
3677c478bd9Sstevel@tonic-gate 		case ENF_NEQ:
3687c478bd9Sstevel@tonic-gate 			printf("NEQ ");
3697c478bd9Sstevel@tonic-gate 			break;
3707c478bd9Sstevel@tonic-gate 		}
3717c478bd9Sstevel@tonic-gate 
372605445d5Sdg199075 		if (action == ENF_PUSHLIT ||
373605445d5Sdg199075 		    action == ENF_LOAD_OFFSET ||
374605445d5Sdg199075 		    action == ENF_BRTR ||
375605445d5Sdg199075 		    action == ENF_BRFL) {
3767c478bd9Sstevel@tonic-gate 			pc++;
3777c478bd9Sstevel@tonic-gate 			printf("\n\t%3d:   %d (0x%04x)", pc - code, *pc, *pc);
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		printf("\n");
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * Emit packet filter code to check a
3867c478bd9Sstevel@tonic-gate  * field in the packet for a particular value.
3877c478bd9Sstevel@tonic-gate  * Need different code for each field size.
3887c478bd9Sstevel@tonic-gate  * Since the pf can only compare 16 bit quantities
3897c478bd9Sstevel@tonic-gate  * we have to use masking to compare byte values.
3907c478bd9Sstevel@tonic-gate  * Long word (32 bit) quantities have to be done
3917c478bd9Sstevel@tonic-gate  * as two 16 bit comparisons.
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate static void
pf_compare_value(int offset,uint_t len,uint_t val)3947c478bd9Sstevel@tonic-gate pf_compare_value(int offset, uint_t len, uint_t val)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	/*
3977c478bd9Sstevel@tonic-gate 	 * If the property being filtered on is absent in the media
3987c478bd9Sstevel@tonic-gate 	 * packet, error out.
3997c478bd9Sstevel@tonic-gate 	 */
4007c478bd9Sstevel@tonic-gate 	if (offset == -1)
4017c478bd9Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	switch (len) {
4047c478bd9Sstevel@tonic-gate 	case 1:
4057c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
4067c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
4077c478bd9Sstevel@tonic-gate 		if (offset % 2)
4087c478bd9Sstevel@tonic-gate #else
4097c478bd9Sstevel@tonic-gate 		if (!(offset % 2))
4107c478bd9Sstevel@tonic-gate #endif
4117c478bd9Sstevel@tonic-gate 		{
4127c478bd9Sstevel@tonic-gate #ifdef ENF_PUSH00FF
4137c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSH00FF | ENF_AND);
4147c478bd9Sstevel@tonic-gate #else
4157c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
4167c478bd9Sstevel@tonic-gate 			pf_emit(0x00FF);
4177c478bd9Sstevel@tonic-gate #endif
4187c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_EQ);
4197c478bd9Sstevel@tonic-gate 			pf_emit(val);
4207c478bd9Sstevel@tonic-gate 		} else {
4217c478bd9Sstevel@tonic-gate #ifdef ENF_PUSHFF00
4227c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSHFF00 | ENF_AND);
4237c478bd9Sstevel@tonic-gate #else
4247c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
4257c478bd9Sstevel@tonic-gate 			pf_emit(0xFF00);
4267c478bd9Sstevel@tonic-gate #endif
4277c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_EQ);
4287c478bd9Sstevel@tonic-gate 			pf_emit(val << 8);
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		break;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	case 2:
4337c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
4347c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
4357c478bd9Sstevel@tonic-gate 		pf_emit((ushort_t)val);
4367c478bd9Sstevel@tonic-gate 		break;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	case 4:
4397c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
4407c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
4417c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
4427c478bd9Sstevel@tonic-gate 		pf_emit(val >> 16);
4437c478bd9Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN)
4447c478bd9Sstevel@tonic-gate 		pf_emit(val & 0xffff);
4457c478bd9Sstevel@tonic-gate #else
4467c478bd9Sstevel@tonic-gate #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined
4477c478bd9Sstevel@tonic-gate #endif
4487c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
4497c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
4507c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
4517c478bd9Sstevel@tonic-gate 		pf_emit(val & 0xffff);
4527c478bd9Sstevel@tonic-gate #else
4537c478bd9Sstevel@tonic-gate 		pf_emit(val >> 16);
4547c478bd9Sstevel@tonic-gate #endif
4557c478bd9Sstevel@tonic-gate 		pf_emit(ENF_AND);
4567c478bd9Sstevel@tonic-gate 		break;
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate /*
4617c478bd9Sstevel@tonic-gate  * same as pf_compare_value, but only for emiting code to
4627c478bd9Sstevel@tonic-gate  * compare ipv6 addresses.
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate static void
pf_compare_value_v6(int offset,uint_t len,struct in6_addr val)4657c478bd9Sstevel@tonic-gate pf_compare_value_v6(int offset, uint_t len, struct in6_addr val)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	int i;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i += 2) {
4707c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2 + i / 2);
4717c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_EQ);
4727c478bd9Sstevel@tonic-gate 		pf_emit(*(uint16_t *)&val.s6_addr[i]);
4737c478bd9Sstevel@tonic-gate 		if (i != 0)
4747c478bd9Sstevel@tonic-gate 			pf_emit(ENF_AND);
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * Same as above except mask the field value
481605445d5Sdg199075  * before doing the comparison.  The comparison checks
482605445d5Sdg199075  * to make sure the values are equal.
4837c478bd9Sstevel@tonic-gate  */
4847c478bd9Sstevel@tonic-gate static void
pf_compare_value_mask(int offset,uint_t len,uint_t val,int mask)4857c478bd9Sstevel@tonic-gate pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
4867c478bd9Sstevel@tonic-gate {
487605445d5Sdg199075 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ);
488605445d5Sdg199075 }
489605445d5Sdg199075 
490605445d5Sdg199075 /*
491605445d5Sdg199075  * Same as above except the values are compared to see if they are not
492605445d5Sdg199075  * equal.
493605445d5Sdg199075  */
494605445d5Sdg199075 static void
pf_compare_value_mask_neq(int offset,uint_t len,uint_t val,int mask)495605445d5Sdg199075 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask)
496605445d5Sdg199075 {
497605445d5Sdg199075 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ);
498605445d5Sdg199075 }
499605445d5Sdg199075 
500605445d5Sdg199075 /*
501605445d5Sdg199075  * Similar to pf_compare_value.
502605445d5Sdg199075  *
503605445d5Sdg199075  * This is the utility function that does the actual work to compare
504605445d5Sdg199075  * two values using a mask.  The comparison operation is passed into
505605445d5Sdg199075  * the function.
506605445d5Sdg199075  */
507605445d5Sdg199075 static void
pf_compare_value_mask_generic(int offset,uint_t len,uint_t val,int mask,uint_t op)508605445d5Sdg199075 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask,
509605445d5Sdg199075     uint_t op)
510605445d5Sdg199075 {
5117c478bd9Sstevel@tonic-gate 	/*
5127c478bd9Sstevel@tonic-gate 	 * If the property being filtered on is absent in the media
5137c478bd9Sstevel@tonic-gate 	 * packet, error out.
5147c478bd9Sstevel@tonic-gate 	 */
5157c478bd9Sstevel@tonic-gate 	if (offset == -1)
5167c478bd9Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	switch (len) {
5197c478bd9Sstevel@tonic-gate 	case 1:
5207c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
5217c478bd9Sstevel@tonic-gate #if defined(_BIG_ENDIAN)
5227c478bd9Sstevel@tonic-gate 		if (offset % 2)
5237c478bd9Sstevel@tonic-gate #else
5247c478bd9Sstevel@tonic-gate 		if (!offset % 2)
5257c478bd9Sstevel@tonic-gate #endif
5267c478bd9Sstevel@tonic-gate 		{
5277c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
5287c478bd9Sstevel@tonic-gate 			pf_emit(mask & 0x00ff);
529605445d5Sdg199075 			pf_emit(ENF_PUSHLIT | op);
5307c478bd9Sstevel@tonic-gate 			pf_emit(val);
5317c478bd9Sstevel@tonic-gate 		} else {
5327c478bd9Sstevel@tonic-gate 			pf_emit(ENF_PUSHLIT | ENF_AND);
5337c478bd9Sstevel@tonic-gate 			pf_emit((mask << 8) & 0xff00);
534605445d5Sdg199075 			pf_emit(ENF_PUSHLIT | op);
5357c478bd9Sstevel@tonic-gate 			pf_emit(val << 8);
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 		break;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	case 2:
5407c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
5417c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_AND);
5427c478bd9Sstevel@tonic-gate 		pf_emit(htons((ushort_t)mask));
543605445d5Sdg199075 		pf_emit(ENF_PUSHLIT | op);
5447c478bd9Sstevel@tonic-gate 		pf_emit(htons((ushort_t)val));
5457c478bd9Sstevel@tonic-gate 		break;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	case 4:
5487c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + offset / 2);
5497c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_AND);
5507c478bd9Sstevel@tonic-gate 		pf_emit(htons((ushort_t)((mask >> 16) & 0xffff)));
551605445d5Sdg199075 		pf_emit(ENF_PUSHLIT | op);
5527c478bd9Sstevel@tonic-gate 		pf_emit(htons((ushort_t)((val >> 16) & 0xffff)));
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
5557c478bd9Sstevel@tonic-gate 		pf_emit(ENF_PUSHLIT | ENF_AND);
5567c478bd9Sstevel@tonic-gate 		pf_emit(htons((ushort_t)(mask & 0xffff)));
557605445d5Sdg199075 		pf_emit(ENF_PUSHLIT | op);
5587c478bd9Sstevel@tonic-gate 		pf_emit(htons((ushort_t)(val & 0xffff)));
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		pf_emit(ENF_AND);
5617c478bd9Sstevel@tonic-gate 		break;
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate /*
5660a0e9771SDarren Reed  * Like pf_compare_value() but compare on a 32-bit zoneid value.
567b127ac41SPhilip Kirk  * The argument val passed in is in network byte order.
568b127ac41SPhilip Kirk  */
569b127ac41SPhilip Kirk static void
pf_compare_zoneid(int offset,uint32_t val)5700a0e9771SDarren Reed pf_compare_zoneid(int offset, uint32_t val)
571b127ac41SPhilip Kirk {
572b127ac41SPhilip Kirk 	int i;
573b127ac41SPhilip Kirk 
5740a0e9771SDarren Reed 	for (i = 0; i < sizeof (uint32_t) / 2; i ++) {
575b127ac41SPhilip Kirk 		pf_emit(ENF_PUSHWORD + offset / 2 + i);
576b127ac41SPhilip Kirk 		pf_emit(ENF_PUSHLIT | ENF_EQ);
577b127ac41SPhilip Kirk 		pf_emit(((uint16_t *)&val)[i]);
578b127ac41SPhilip Kirk 		if (i != 0)
579b127ac41SPhilip Kirk 			pf_emit(ENF_AND);
580b127ac41SPhilip Kirk 	}
581b127ac41SPhilip Kirk }
582b127ac41SPhilip Kirk 
583b127ac41SPhilip Kirk /*
5847c478bd9Sstevel@tonic-gate  * Generate pf code to match an IPv4 or IPv6 address.
5857c478bd9Sstevel@tonic-gate  */
5867c478bd9Sstevel@tonic-gate static void
pf_ipaddr_match(enum direction which,char * hostname,int inet_type)587*cd93bdd3SToomas Soome pf_ipaddr_match(enum direction which, char *hostname, int inet_type)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	bool_t found_host;
5907c478bd9Sstevel@tonic-gate 	uint_t *addr4ptr;
5917c478bd9Sstevel@tonic-gate 	uint_t addr4;
5927c478bd9Sstevel@tonic-gate 	struct in6_addr *addr6ptr;
5937c478bd9Sstevel@tonic-gate 	int h_addr_index;
5947c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
5957c478bd9Sstevel@tonic-gate 	int error_num = 0;
5967c478bd9Sstevel@tonic-gate 	boolean_t first = B_TRUE;
5977c478bd9Sstevel@tonic-gate 	int pass = 0;
598041bde0aSSebastien Roy 	int i;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	/*
6017c478bd9Sstevel@tonic-gate 	 * The addr4offset and addr6offset variables simplify the code which
6027c478bd9Sstevel@tonic-gate 	 * generates the address comparison filter.  With these two variables,
6037c478bd9Sstevel@tonic-gate 	 * duplicate code need not exist for the TO and FROM case.
6047c478bd9Sstevel@tonic-gate 	 * A value of -1 describes the ANY case (TO and FROM).
6057c478bd9Sstevel@tonic-gate 	 */
6067c478bd9Sstevel@tonic-gate 	int addr4offset;
6077c478bd9Sstevel@tonic-gate 	int addr6offset;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	found_host = 0;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	if (tokentype == ADDR_IP) {
6127c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
6137c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
6147c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
6157c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
6167c478bd9Sstevel@tonic-gate 				    hostname);
6177c478bd9Sstevel@tonic-gate 			} else {
6187c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
6197c478bd9Sstevel@tonic-gate 			}
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 		inet_type = IPV4_ONLY;
6227c478bd9Sstevel@tonic-gate 	} else if (tokentype == ADDR_IP6) {
6237c478bd9Sstevel@tonic-gate 		hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
6247c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
6257c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
6267c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
6277c478bd9Sstevel@tonic-gate 				    hostname);
6287c478bd9Sstevel@tonic-gate 			} else {
6297c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
6307c478bd9Sstevel@tonic-gate 			}
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 		inet_type = IPV6_ONLY;
6337c478bd9Sstevel@tonic-gate 	} else if (tokentype == ALPHA) {
6347c478bd9Sstevel@tonic-gate 		/* Some hostname i.e. tokentype is ALPHA */
6357c478bd9Sstevel@tonic-gate 		switch (inet_type) {
6367c478bd9Sstevel@tonic-gate 		case IPV4_ONLY:
6377c478bd9Sstevel@tonic-gate 			/* Only IPv4 address is needed */
6387c478bd9Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
6397c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
6407c478bd9Sstevel@tonic-gate 				found_host = 1;
6417c478bd9Sstevel@tonic-gate 			}
6427c478bd9Sstevel@tonic-gate 			break;
6437c478bd9Sstevel@tonic-gate 		case IPV6_ONLY:
6447c478bd9Sstevel@tonic-gate 			/* Only IPv6 address is needed */
6457c478bd9Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
6467c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
6477c478bd9Sstevel@tonic-gate 				found_host = 1;
6487c478bd9Sstevel@tonic-gate 			}
6497c478bd9Sstevel@tonic-gate 			break;
6507c478bd9Sstevel@tonic-gate 		case IPV4_AND_IPV6:
6517c478bd9Sstevel@tonic-gate 			/* Both IPv4 and IPv6 are needed */
6527c478bd9Sstevel@tonic-gate 			hp = getipnodebyname(hostname, AF_INET6,
6537c478bd9Sstevel@tonic-gate 			    AI_ALL | AI_V4MAPPED, &error_num);
6547c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
6557c478bd9Sstevel@tonic-gate 				found_host = 1;
6567c478bd9Sstevel@tonic-gate 			}
6577c478bd9Sstevel@tonic-gate 			break;
6587c478bd9Sstevel@tonic-gate 		default:
6597c478bd9Sstevel@tonic-gate 			found_host = 0;
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		if (!found_host) {
6637c478bd9Sstevel@tonic-gate 			if (error_num == TRY_AGAIN) {
6647c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s (try again later)",
6657c478bd9Sstevel@tonic-gate 				    hostname);
6667c478bd9Sstevel@tonic-gate 			} else {
6677c478bd9Sstevel@tonic-gate 				pr_err("could not resolve %s", hostname);
6687c478bd9Sstevel@tonic-gate 			}
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 	} else {
6717c478bd9Sstevel@tonic-gate 		pr_err("unknown token type: %s", hostname);
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 
6747d897698SMilan Jurik 	if (hp == NULL)
6757d897698SMilan Jurik 		return;
6767d897698SMilan Jurik 
6777c478bd9Sstevel@tonic-gate 	switch (which) {
6787c478bd9Sstevel@tonic-gate 	case TO:
6797c478bd9Sstevel@tonic-gate 		addr4offset = IPV4_DSTADDR_OFFSET;
6807c478bd9Sstevel@tonic-gate 		addr6offset = IPV6_DSTADDR_OFFSET;
6817c478bd9Sstevel@tonic-gate 		break;
6827c478bd9Sstevel@tonic-gate 	case FROM:
6837c478bd9Sstevel@tonic-gate 		addr4offset = IPV4_SRCADDR_OFFSET;
6847c478bd9Sstevel@tonic-gate 		addr6offset = IPV6_SRCADDR_OFFSET;
6857c478bd9Sstevel@tonic-gate 		break;
6867c478bd9Sstevel@tonic-gate 	case ANY:
6877c478bd9Sstevel@tonic-gate 		addr4offset = -1;
6887c478bd9Sstevel@tonic-gate 		addr6offset = -1;
6897c478bd9Sstevel@tonic-gate 		break;
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 
6927d897698SMilan Jurik 	if (hp->h_addrtype == AF_INET) {
693041bde0aSSebastien Roy 		pf_matchfn("ip");
694b127ac41SPhilip Kirk 		if (dl.dl_type == DL_ETHER)
695605445d5Sdg199075 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
6967c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
6977c478bd9Sstevel@tonic-gate 		addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
6987c478bd9Sstevel@tonic-gate 		while (addr4ptr != NULL) {
6997c478bd9Sstevel@tonic-gate 			if (addr4offset == -1) {
7007c478bd9Sstevel@tonic-gate 				pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
7017c478bd9Sstevel@tonic-gate 				    *addr4ptr);
7027c478bd9Sstevel@tonic-gate 				if (h_addr_index != 0)
7037c478bd9Sstevel@tonic-gate 					pf_emit(ENF_OR);
7047c478bd9Sstevel@tonic-gate 				pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
7057c478bd9Sstevel@tonic-gate 				    *addr4ptr);
7067c478bd9Sstevel@tonic-gate 				pf_emit(ENF_OR);
7077c478bd9Sstevel@tonic-gate 			} else {
7087c478bd9Sstevel@tonic-gate 				pf_compare_value(addr4offset, 4,
7097c478bd9Sstevel@tonic-gate 				    *addr4ptr);
7107c478bd9Sstevel@tonic-gate 				if (h_addr_index != 0)
7117c478bd9Sstevel@tonic-gate 					pf_emit(ENF_OR);
7127c478bd9Sstevel@tonic-gate 			}
7137c478bd9Sstevel@tonic-gate 			addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
7147c478bd9Sstevel@tonic-gate 		}
7157c478bd9Sstevel@tonic-gate 		pf_emit(ENF_AND);
7167c478bd9Sstevel@tonic-gate 	} else {
7177c478bd9Sstevel@tonic-gate 		/* first pass: IPv4 addresses */
7187c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
7197c478bd9Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
7207c478bd9Sstevel@tonic-gate 		first = B_TRUE;
7217c478bd9Sstevel@tonic-gate 		while (addr6ptr != NULL) {
7227c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
7237c478bd9Sstevel@tonic-gate 				if (first) {
724041bde0aSSebastien Roy 					pf_matchfn("ip");
725b127ac41SPhilip Kirk 					if (dl.dl_type == DL_ETHER) {
726605445d5Sdg199075 						pf_check_vlan_tag(
727605445d5Sdg199075 						    ENCAP_ETHERTYPE_OFF/2);
728b127ac41SPhilip Kirk 					}
7297c478bd9Sstevel@tonic-gate 					pass++;
7307c478bd9Sstevel@tonic-gate 				}
7317c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(addr6ptr,
7327c478bd9Sstevel@tonic-gate 				    (struct in_addr *)&addr4);
7337c478bd9Sstevel@tonic-gate 				if (addr4offset == -1) {
7347c478bd9Sstevel@tonic-gate 					pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
7357c478bd9Sstevel@tonic-gate 					    addr4);
7367c478bd9Sstevel@tonic-gate 					if (!first)
7377c478bd9Sstevel@tonic-gate 						pf_emit(ENF_OR);
7387c478bd9Sstevel@tonic-gate 					pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
7397c478bd9Sstevel@tonic-gate 					    addr4);
7407c478bd9Sstevel@tonic-gate 					pf_emit(ENF_OR);
7417c478bd9Sstevel@tonic-gate 				} else {
7427c478bd9Sstevel@tonic-gate 					pf_compare_value(addr4offset, 4,
7437c478bd9Sstevel@tonic-gate 					    addr4);
7447c478bd9Sstevel@tonic-gate 					if (!first)
7457c478bd9Sstevel@tonic-gate 						pf_emit(ENF_OR);
7467c478bd9Sstevel@tonic-gate 				}
7477c478bd9Sstevel@tonic-gate 				if (first)
7487c478bd9Sstevel@tonic-gate 					first = B_FALSE;
7497c478bd9Sstevel@tonic-gate 			}
7507c478bd9Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
7517c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[++h_addr_index];
7527c478bd9Sstevel@tonic-gate 		}
7537c478bd9Sstevel@tonic-gate 		if (!first) {
7547c478bd9Sstevel@tonic-gate 			pf_emit(ENF_AND);
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 		/* second pass: IPv6 addresses */
7577c478bd9Sstevel@tonic-gate 		h_addr_index = 0;
7587c478bd9Sstevel@tonic-gate 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
7597c478bd9Sstevel@tonic-gate 		first = B_TRUE;
7607c478bd9Sstevel@tonic-gate 		while (addr6ptr != NULL) {
7617c478bd9Sstevel@tonic-gate 			if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
7627c478bd9Sstevel@tonic-gate 				if (first) {
763041bde0aSSebastien Roy 					pf_matchfn("ip6");
764b127ac41SPhilip Kirk 					if (dl.dl_type == DL_ETHER) {
765605445d5Sdg199075 						pf_check_vlan_tag(
766605445d5Sdg199075 						    ENCAP_ETHERTYPE_OFF / 2);
767b127ac41SPhilip Kirk 					}
7687c478bd9Sstevel@tonic-gate 					pass++;
7697c478bd9Sstevel@tonic-gate 				}
7707c478bd9Sstevel@tonic-gate 				if (addr6offset == -1) {
7717c478bd9Sstevel@tonic-gate 					pf_compare_value_v6(IPV6_SRCADDR_OFFSET,
7727c478bd9Sstevel@tonic-gate 					    16, *addr6ptr);
7737c478bd9Sstevel@tonic-gate 					if (!first)
7747c478bd9Sstevel@tonic-gate 						pf_emit(ENF_OR);
7757c478bd9Sstevel@tonic-gate 					pf_compare_value_v6(IPV6_DSTADDR_OFFSET,
7767c478bd9Sstevel@tonic-gate 					    16, *addr6ptr);
7777c478bd9Sstevel@tonic-gate 					pf_emit(ENF_OR);
7787c478bd9Sstevel@tonic-gate 				} else {
7797c478bd9Sstevel@tonic-gate 					pf_compare_value_v6(addr6offset, 16,
7807c478bd9Sstevel@tonic-gate 					    *addr6ptr);
7817c478bd9Sstevel@tonic-gate 					if (!first)
7827c478bd9Sstevel@tonic-gate 						pf_emit(ENF_OR);
7837c478bd9Sstevel@tonic-gate 				}
7847c478bd9Sstevel@tonic-gate 				if (first)
7857c478bd9Sstevel@tonic-gate 					first = B_FALSE;
7867c478bd9Sstevel@tonic-gate 			}
7877c478bd9Sstevel@tonic-gate 			addr6ptr = (struct in6_addr *)
7887c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[++h_addr_index];
7897c478bd9Sstevel@tonic-gate 		}
7907c478bd9Sstevel@tonic-gate 		if (!first) {
7917c478bd9Sstevel@tonic-gate 			pf_emit(ENF_AND);
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 		if (pass == 2) {
7947c478bd9Sstevel@tonic-gate 			pf_emit(ENF_OR);
7957c478bd9Sstevel@tonic-gate 		}
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	freehostent(hp);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate static void
pf_compare_address(int offset,uint_t len,uchar_t * addr)8037c478bd9Sstevel@tonic-gate pf_compare_address(int offset, uint_t len, uchar_t *addr)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	uint32_t val;
8067c478bd9Sstevel@tonic-gate 	uint16_t sval;
8077c478bd9Sstevel@tonic-gate 	boolean_t didone = B_FALSE;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	/*
8107c478bd9Sstevel@tonic-gate 	 * If the property being filtered on is absent in the media
8117c478bd9Sstevel@tonic-gate 	 * packet, error out.
8127c478bd9Sstevel@tonic-gate 	 */
8137c478bd9Sstevel@tonic-gate 	if (offset == -1)
8147c478bd9Sstevel@tonic-gate 		pr_err("filter option unsupported on media");
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	while (len > 0) {
8177c478bd9Sstevel@tonic-gate 		if (len >= 4) {
8187c478bd9Sstevel@tonic-gate 			(void) memcpy(&val, addr, 4);
8197c478bd9Sstevel@tonic-gate 			pf_compare_value(offset, 4, val);
8207c478bd9Sstevel@tonic-gate 			addr += 4;
8217c478bd9Sstevel@tonic-gate 			offset += 4;
8227c478bd9Sstevel@tonic-gate 			len -= 4;
8237c478bd9Sstevel@tonic-gate 		} else if (len >= 2) {
8247c478bd9Sstevel@tonic-gate 			(void) memcpy(&sval, addr, 2);
8257c478bd9Sstevel@tonic-gate 			pf_compare_value(offset, 2, sval);
8267c478bd9Sstevel@tonic-gate 			addr += 2;
8277c478bd9Sstevel@tonic-gate 			offset += 2;
8287c478bd9Sstevel@tonic-gate 			len -= 2;
8297c478bd9Sstevel@tonic-gate 		} else {
8307c478bd9Sstevel@tonic-gate 			pf_compare_value(offset++, 1, *addr++);
8317c478bd9Sstevel@tonic-gate 			len--;
8327c478bd9Sstevel@tonic-gate 		}
8337c478bd9Sstevel@tonic-gate 		if (didone)
8347c478bd9Sstevel@tonic-gate 			pf_emit(ENF_AND);
8357c478bd9Sstevel@tonic-gate 		didone = B_TRUE;
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate /*
8407c478bd9Sstevel@tonic-gate  * Compare ethernet addresses.
8417c478bd9Sstevel@tonic-gate  */
8427c478bd9Sstevel@tonic-gate static void
pf_etheraddr_match(enum direction which,char * hostname)843*cd93bdd3SToomas Soome pf_etheraddr_match(enum direction which, char *hostname)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate 	struct ether_addr e, *ep = NULL;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	if (isxdigit(*hostname))
8487c478bd9Sstevel@tonic-gate 		ep = ether_aton(hostname);
8497c478bd9Sstevel@tonic-gate 	if (ep == NULL) {
8507c478bd9Sstevel@tonic-gate 		if (ether_hostton(hostname, &e))
8517c478bd9Sstevel@tonic-gate 			if (!arp_for_ether(hostname, &e))
8527c478bd9Sstevel@tonic-gate 				pr_err("cannot obtain ether addr for %s",
8537c478bd9Sstevel@tonic-gate 				    hostname);
8547c478bd9Sstevel@tonic-gate 		ep = &e;
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 
857605445d5Sdg199075 	pf_clear_offset_register();
858605445d5Sdg199075 
8597c478bd9Sstevel@tonic-gate 	switch (which) {
8607c478bd9Sstevel@tonic-gate 	case TO:
861b127ac41SPhilip Kirk 		pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
8627c478bd9Sstevel@tonic-gate 		    (uchar_t *)ep);
8637c478bd9Sstevel@tonic-gate 		break;
8647c478bd9Sstevel@tonic-gate 	case FROM:
865b127ac41SPhilip Kirk 		pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
8667c478bd9Sstevel@tonic-gate 		    (uchar_t *)ep);
8677c478bd9Sstevel@tonic-gate 		break;
8687c478bd9Sstevel@tonic-gate 	case ANY:
869b127ac41SPhilip Kirk 		pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
8707c478bd9Sstevel@tonic-gate 		    (uchar_t *)ep);
871b127ac41SPhilip Kirk 		pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
8727c478bd9Sstevel@tonic-gate 		    (uchar_t *)ep);
8737c478bd9Sstevel@tonic-gate 		pf_emit(ENF_OR);
8747c478bd9Sstevel@tonic-gate 		break;
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate  * Emit code to compare the network part of
8807c478bd9Sstevel@tonic-gate  * an IP address.
8817c478bd9Sstevel@tonic-gate  */
8827c478bd9Sstevel@tonic-gate static void
pf_netaddr_match(enum direction which,char * netname)883*cd93bdd3SToomas Soome pf_netaddr_match(enum direction which, char *netname)
8847c478bd9Sstevel@tonic-gate {
8857c478bd9Sstevel@tonic-gate 	uint_t addr;
8867c478bd9Sstevel@tonic-gate 	uint_t mask = 0xff000000;
8877c478bd9Sstevel@tonic-gate 	struct netent *np;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	if (isdigit(*netname)) {
8907c478bd9Sstevel@tonic-gate 		addr = inet_network(netname);
8917c478bd9Sstevel@tonic-gate 	} else {
8927c478bd9Sstevel@tonic-gate 		np = getnetbyname(netname);
8937c478bd9Sstevel@tonic-gate 		if (np == NULL)
8947c478bd9Sstevel@tonic-gate 			pr_err("net %s not known", netname);
8957c478bd9Sstevel@tonic-gate 		addr = np->n_net;
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	/*
8997c478bd9Sstevel@tonic-gate 	 * Left justify the address and figure
9007c478bd9Sstevel@tonic-gate 	 * out a mask based on the supplied address.
9017c478bd9Sstevel@tonic-gate 	 * Set the mask according to the number of zero
9027c478bd9Sstevel@tonic-gate 	 * low-order bytes.
9037c478bd9Sstevel@tonic-gate 	 * Note: this works only for whole octet masks.
9047c478bd9Sstevel@tonic-gate 	 */
9057c478bd9Sstevel@tonic-gate 	if (addr) {
9067c478bd9Sstevel@tonic-gate 		while ((addr & ~mask) != 0) {
9077c478bd9Sstevel@tonic-gate 			mask |= (mask >> 8);
9087c478bd9Sstevel@tonic-gate 		}
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 
911605445d5Sdg199075 	pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
912605445d5Sdg199075 
9137c478bd9Sstevel@tonic-gate 	switch (which) {
9147c478bd9Sstevel@tonic-gate 	case TO:
9157c478bd9Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
9167c478bd9Sstevel@tonic-gate 		break;
9177c478bd9Sstevel@tonic-gate 	case FROM:
9187c478bd9Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
9197c478bd9Sstevel@tonic-gate 		break;
9207c478bd9Sstevel@tonic-gate 	case ANY:
9217c478bd9Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
9227c478bd9Sstevel@tonic-gate 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
9237c478bd9Sstevel@tonic-gate 		pf_emit(ENF_OR);
9247c478bd9Sstevel@tonic-gate 		break;
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate 
928605445d5Sdg199075 /*
929b127ac41SPhilip Kirk  * Emit code to match on src or destination zoneid.
930b127ac41SPhilip Kirk  * The zoneid passed in is in network byte order.
931b127ac41SPhilip Kirk  */
932b127ac41SPhilip Kirk static void
pf_match_zone(enum direction which,uint32_t zoneid)9330a0e9771SDarren Reed pf_match_zone(enum direction which, uint32_t zoneid)
934b127ac41SPhilip Kirk {
935b127ac41SPhilip Kirk 	if (dl.dl_type != DL_IPNET)
936b127ac41SPhilip Kirk 		pr_err("zone filter option unsupported on media");
937b127ac41SPhilip Kirk 
938b127ac41SPhilip Kirk 	switch (which) {
939b127ac41SPhilip Kirk 	case TO:
940b127ac41SPhilip Kirk 		pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
941b127ac41SPhilip Kirk 		break;
942b127ac41SPhilip Kirk 	case FROM:
943b127ac41SPhilip Kirk 		pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
944b127ac41SPhilip Kirk 		break;
945b127ac41SPhilip Kirk 	case ANY:
946b127ac41SPhilip Kirk 		pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
947b127ac41SPhilip Kirk 		pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
948b127ac41SPhilip Kirk 		pf_emit(ENF_OR);
949b127ac41SPhilip Kirk 		break;
950b127ac41SPhilip Kirk 	}
951b127ac41SPhilip Kirk }
952b127ac41SPhilip Kirk 
953b127ac41SPhilip Kirk /*
954605445d5Sdg199075  * A helper function to keep the code to emit instructions
955605445d5Sdg199075  * to change the offset register in one place.
956605445d5Sdg199075  *
957605445d5Sdg199075  * INPUTS: offset - An value representing an offset in 16-bit
958605445d5Sdg199075  *                  words.
959605445d5Sdg199075  * OUTPUTS:  If there is enough room in the storage for the
960605445d5Sdg199075  *           packet filtering program, instructions to load
961605445d5Sdg199075  *           a constant to the offset register.  Otherwise,
962605445d5Sdg199075  *           nothing.
963605445d5Sdg199075  */
964605445d5Sdg199075 static void
pf_emit_load_offset(uint_t offset)965605445d5Sdg199075 pf_emit_load_offset(uint_t offset)
966605445d5Sdg199075 {
967605445d5Sdg199075 	pf_emit(ENF_LOAD_OFFSET | ENF_NOP);
968605445d5Sdg199075 	pf_emit(offset);
969605445d5Sdg199075 }
970605445d5Sdg199075 
971605445d5Sdg199075 /*
972605445d5Sdg199075  * Clear pfmod's offset register.
973605445d5Sdg199075  *
974605445d5Sdg199075  * INPUTS:  none
975605445d5Sdg199075  * OUTPUTS:  Instructions to clear the offset register if
976605445d5Sdg199075  *           there is enough space remaining in the packet
977605445d5Sdg199075  *           filtering program structure's storage, and
978605445d5Sdg199075  *           the last thing done to the offset register was
979605445d5Sdg199075  *           not clearing the offset register.  Otherwise,
980605445d5Sdg199075  *           nothing.
981605445d5Sdg199075  */
982605445d5Sdg199075 static void
pf_clear_offset_register()983605445d5Sdg199075 pf_clear_offset_register()
984605445d5Sdg199075 {
985605445d5Sdg199075 	if (last_offset_operation != (void*)pf_clear_offset_register) {
986605445d5Sdg199075 		pf_emit_load_offset(0);
987605445d5Sdg199075 		last_offset_operation = (void*)pf_clear_offset_register;
988605445d5Sdg199075 	}
989605445d5Sdg199075 }
990605445d5Sdg199075 
991605445d5Sdg199075 /*
992605445d5Sdg199075  * This function will issue opcodes to check if a packet
993605445d5Sdg199075  * is VLAN tagged, and if so, update the offset register
994605445d5Sdg199075  * with the appropriate offset.
995605445d5Sdg199075  *
996605445d5Sdg199075  * Note that if the packet is not VLAN tagged, then the offset
997605445d5Sdg199075  * register will be cleared.
998605445d5Sdg199075  *
999605445d5Sdg199075  * If the interface type is not an ethernet type, then this
1000605445d5Sdg199075  * function returns without doing anything.
1001605445d5Sdg199075  *
1002605445d5Sdg199075  * If the last attempt to change the offset register occured because
1003605445d5Sdg199075  * of a call to this function that was called with the same offset,
1004605445d5Sdg199075  * then we don't issue packet filtering instructions.
1005605445d5Sdg199075  *
1006605445d5Sdg199075  * INPUTS:  offset - an offset in 16 bit words.  The function
1007605445d5Sdg199075  *                   will set the offset register to this
1008605445d5Sdg199075  *                   value if the packet is VLAN tagged.
1009605445d5Sdg199075  * OUTPUTS:  If the conditions are met, packet filtering instructions.
1010605445d5Sdg199075  */
1011605445d5Sdg199075 static void
pf_check_vlan_tag(uint_t offset)1012605445d5Sdg199075 pf_check_vlan_tag(uint_t offset)
1013605445d5Sdg199075 {
1014605445d5Sdg199075 	static uint_t last_offset = 0;
1015605445d5Sdg199075 
1016605445d5Sdg199075 	if ((interface->mac_type == DL_ETHER ||
1017605445d5Sdg199075 	    interface->mac_type == DL_CSMACD) &&
1018605445d5Sdg199075 	    (last_offset_operation != (void*)pf_check_vlan_tag ||
1019605445d5Sdg199075 	    last_offset != offset)) {
1020605445d5Sdg199075 		/*
1021605445d5Sdg199075 		 * First thing is to clear the offset register.
1022605445d5Sdg199075 		 * We don't know what state it is in, and if it
1023605445d5Sdg199075 		 * is not zero, then we have no idea what we load
1024605445d5Sdg199075 		 * when we execute ENF_PUSHWORD.
1025605445d5Sdg199075 		 */
1026605445d5Sdg199075 		pf_clear_offset_register();
1027605445d5Sdg199075 
1028605445d5Sdg199075 		/*
1029605445d5Sdg199075 		 * Check the ethertype.
1030605445d5Sdg199075 		 */
1031b127ac41SPhilip Kirk 		pf_compare_value(dl.dl_link_type_offset, 2,
1032b127ac41SPhilip Kirk 		    htons(ETHERTYPE_VLAN));
1033605445d5Sdg199075 
1034605445d5Sdg199075 		/*
1035605445d5Sdg199075 		 * And if it's not VLAN, don't load offset to the offset
1036605445d5Sdg199075 		 * register.
1037605445d5Sdg199075 		 */
1038605445d5Sdg199075 		pf_emit(ENF_BRFL | ENF_NOP);
1039605445d5Sdg199075 		pf_emit(3);
1040605445d5Sdg199075 
1041605445d5Sdg199075 		/*
1042605445d5Sdg199075 		 * Otherwise, load offset to the offset register.
1043605445d5Sdg199075 		 */
1044605445d5Sdg199075 		pf_emit_load_offset(offset);
1045605445d5Sdg199075 
1046605445d5Sdg199075 		/*
1047605445d5Sdg199075 		 * Now get rid of the results of the comparison,
1048605445d5Sdg199075 		 * we don't want the results of the comparison to affect
1049605445d5Sdg199075 		 * other logic in the packet filtering program.
1050605445d5Sdg199075 		 */
1051605445d5Sdg199075 		pf_emit(ENF_POP | ENF_NOP);
1052605445d5Sdg199075 
1053605445d5Sdg199075 		/*
1054605445d5Sdg199075 		 * Set the last operation at the end, or any time
1055605445d5Sdg199075 		 * after the call to pf_clear_offset because
1056605445d5Sdg199075 		 * pf_clear_offset uses it.
1057605445d5Sdg199075 		 */
1058605445d5Sdg199075 		last_offset_operation = (void*)pf_check_vlan_tag;
1059605445d5Sdg199075 		last_offset = offset;
1060605445d5Sdg199075 	}
1061605445d5Sdg199075 }
1062605445d5Sdg199075 
1063605445d5Sdg199075 /*
1064605445d5Sdg199075  * Utility function used to emit packet filtering code
1065605445d5Sdg199075  * to match an ethertype.
1066605445d5Sdg199075  *
1067605445d5Sdg199075  * INPUTS:  ethertype - The ethertype we want to check for.
1068605445d5Sdg199075  *                      Don't call htons on the ethertype before
1069605445d5Sdg199075  *                      calling this function.
1070605445d5Sdg199075  * OUTPUTS:  If there is sufficient storage available, packet
1071605445d5Sdg199075  *           filtering code to check an ethertype.  Otherwise,
1072605445d5Sdg199075  *           nothing.
1073605445d5Sdg199075  */
1074605445d5Sdg199075 static void
pf_match_ethertype(uint_t ethertype)1075605445d5Sdg199075 pf_match_ethertype(uint_t ethertype)
1076605445d5Sdg199075 {
1077605445d5Sdg199075 	/*
1078605445d5Sdg199075 	 * If the user wants to filter on ethertype VLAN,
1079605445d5Sdg199075 	 * then clear the offset register so that the offset
1080605445d5Sdg199075 	 * for ENF_PUSHWORD points to the right place in the
1081605445d5Sdg199075 	 * packet.
1082605445d5Sdg199075 	 *
1083605445d5Sdg199075 	 * Otherwise, call pf_check_vlan_tag to set the offset
1084605445d5Sdg199075 	 * register such that the contents of the offset register
1085605445d5Sdg199075 	 * plus the argument for ENF_PUSHWORD point to the right
1086605445d5Sdg199075 	 * part of the packet, whether or not the packet is VLAN
1087605445d5Sdg199075 	 * tagged.  We call pf_check_vlan_tag with an offset of
1088605445d5Sdg199075 	 * two words because if the packet is VLAN tagged, we have
1089605445d5Sdg199075 	 * to move past the ethertype in the ethernet header, and
1090605445d5Sdg199075 	 * past the lower two octets of the VLAN header to get to
1091605445d5Sdg199075 	 * the ethertype in the VLAN header.
1092605445d5Sdg199075 	 */
1093605445d5Sdg199075 	if (ethertype == ETHERTYPE_VLAN)
1094605445d5Sdg199075 		pf_clear_offset_register();
1095605445d5Sdg199075 	else
1096605445d5Sdg199075 		pf_check_vlan_tag(2);
1097605445d5Sdg199075 
1098b127ac41SPhilip Kirk 	pf_compare_value(dl.dl_link_type_offset, 2, htons(ethertype));
1099605445d5Sdg199075 }
1100605445d5Sdg199075 
1101b127ac41SPhilip Kirk static void
pf_match_ipnettype(uint_t type)1102b127ac41SPhilip Kirk pf_match_ipnettype(uint_t type)
1103b127ac41SPhilip Kirk {
1104b127ac41SPhilip Kirk 	pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1105b127ac41SPhilip Kirk }
1106605445d5Sdg199075 
1107b127ac41SPhilip Kirk static void
pf_match_ibtype(uint_t type)1108b127ac41SPhilip Kirk pf_match_ibtype(uint_t type)
1109b127ac41SPhilip Kirk {
1110b127ac41SPhilip Kirk 	pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1111b127ac41SPhilip Kirk }
1112605445d5Sdg199075 
1113605445d5Sdg199075 /*
1114605445d5Sdg199075  * This function uses the table above to generate a
1115605445d5Sdg199075  * piece of a packet filtering program to check a transport
1116605445d5Sdg199075  * protocol type.
1117605445d5Sdg199075  *
1118605445d5Sdg199075  * INPUTS:  tranport_protocol - the transport protocol we're
1119605445d5Sdg199075  *                              interested in.
1120605445d5Sdg199075  * OUTPUTS:  If there is sufficient storage, then packet filtering
1121605445d5Sdg199075  *           code to check a transport protocol type.  Otherwise,
1122605445d5Sdg199075  *           nothing.
1123605445d5Sdg199075  */
1124605445d5Sdg199075 static void
pf_check_transport_protocol(uint_t transport_protocol)1125605445d5Sdg199075 pf_check_transport_protocol(uint_t transport_protocol)
1126605445d5Sdg199075 {
1127041bde0aSSebastien Roy 	int i;
1128605445d5Sdg199075 	uint_t number_of_matches = 0;
1129605445d5Sdg199075 
1130041bde0aSSebastien Roy 	for (i = 0; dl.dl_trans_map_tbl[i].transport_protocol != -1; i++) {
1131605445d5Sdg199075 		if (transport_protocol ==
1132041bde0aSSebastien Roy 		    (uint_t)dl.dl_trans_map_tbl[i].transport_protocol) {
1133605445d5Sdg199075 			number_of_matches++;
1134041bde0aSSebastien Roy 			dl.dl_match_fn(dl.dl_trans_map_tbl[i].network_protocol);
1135605445d5Sdg199075 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
1136041bde0aSSebastien Roy 			pf_compare_value(dl.dl_trans_map_tbl[i].offset +
1137b127ac41SPhilip Kirk 			    dl.dl_link_header_len, 1,
1138605445d5Sdg199075 			    transport_protocol);
1139605445d5Sdg199075 			pf_emit(ENF_AND);
1140605445d5Sdg199075 			if (number_of_matches > 1) {
1141605445d5Sdg199075 				/*
1142605445d5Sdg199075 				 * Since we have two or more matches, in
1143605445d5Sdg199075 				 * order to have a correct and complete
1144605445d5Sdg199075 				 * program we need to OR the result of
1145605445d5Sdg199075 				 * each block of comparisons together.
1146605445d5Sdg199075 				 */
1147605445d5Sdg199075 				pf_emit(ENF_OR);
1148605445d5Sdg199075 			}
1149605445d5Sdg199075 		}
1150605445d5Sdg199075 	}
1151605445d5Sdg199075 }
1152605445d5Sdg199075 
11537c478bd9Sstevel@tonic-gate static void
pf_matchfn(const char * proto)1154041bde0aSSebastien Roy pf_matchfn(const char *proto)
1155b127ac41SPhilip Kirk {
1156041bde0aSSebastien Roy 	int i;
1157041bde0aSSebastien Roy 
1158041bde0aSSebastien Roy 	for (i = 0; dl.dl_net_map_tbl[i].nmt_val != -1; i++) {
1159041bde0aSSebastien Roy 		if (strcmp(proto, dl.dl_net_map_tbl[i].nmt_name) == 0) {
1160041bde0aSSebastien Roy 			dl.dl_match_fn(dl.dl_net_map_tbl[i].nmt_val);
1161041bde0aSSebastien Roy 			break;
1162041bde0aSSebastien Roy 		}
1163b127ac41SPhilip Kirk 	}
1164b127ac41SPhilip Kirk }
1165b127ac41SPhilip Kirk 
1166b127ac41SPhilip Kirk static void
pf_primary()11677c478bd9Sstevel@tonic-gate pf_primary()
11687c478bd9Sstevel@tonic-gate {
11697c478bd9Sstevel@tonic-gate 	for (;;) {
11707c478bd9Sstevel@tonic-gate 		if (tokentype == FIELD)
11717c478bd9Sstevel@tonic-gate 			break;
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 		if (EQ("ip")) {
1174b127ac41SPhilip Kirk 			pf_matchfn("ip");
11757c478bd9Sstevel@tonic-gate 			opstack++;
11767c478bd9Sstevel@tonic-gate 			next();
11777c478bd9Sstevel@tonic-gate 			break;
11787c478bd9Sstevel@tonic-gate 		}
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 		if (EQ("ip6")) {
1181b127ac41SPhilip Kirk 			pf_matchfn("ip6");
11827c478bd9Sstevel@tonic-gate 			opstack++;
11837c478bd9Sstevel@tonic-gate 			next();
11847c478bd9Sstevel@tonic-gate 			break;
11857c478bd9Sstevel@tonic-gate 		}
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 		if (EQ("pppoe")) {
1188b127ac41SPhilip Kirk 			pf_matchfn("pppoe");
1189605445d5Sdg199075 			pf_match_ethertype(ETHERTYPE_PPPOES);
11907c478bd9Sstevel@tonic-gate 			pf_emit(ENF_OR);
11917c478bd9Sstevel@tonic-gate 			opstack++;
11927c478bd9Sstevel@tonic-gate 			next();
11937c478bd9Sstevel@tonic-gate 			break;
11947c478bd9Sstevel@tonic-gate 		}
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 		if (EQ("pppoed")) {
1197b127ac41SPhilip Kirk 			pf_matchfn("pppoed");
11987c478bd9Sstevel@tonic-gate 			opstack++;
11997c478bd9Sstevel@tonic-gate 			next();
12007c478bd9Sstevel@tonic-gate 			break;
12017c478bd9Sstevel@tonic-gate 		}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 		if (EQ("pppoes")) {
1204b127ac41SPhilip Kirk 			pf_matchfn("pppoes");
12057c478bd9Sstevel@tonic-gate 			opstack++;
12067c478bd9Sstevel@tonic-gate 			next();
12077c478bd9Sstevel@tonic-gate 			break;
12087c478bd9Sstevel@tonic-gate 		}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		if (EQ("arp")) {
1211b127ac41SPhilip Kirk 			pf_matchfn("arp");
1212605445d5Sdg199075 			opstack++;
1213605445d5Sdg199075 			next();
1214605445d5Sdg199075 			break;
1215605445d5Sdg199075 		}
1216605445d5Sdg199075 
1217605445d5Sdg199075 		if (EQ("vlan")) {
1218b127ac41SPhilip Kirk 			pf_matchfn("vlan");
1219605445d5Sdg199075 			pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2,
1220605445d5Sdg199075 			    0, VLAN_ID_MASK);
1221605445d5Sdg199075 			pf_emit(ENF_AND);
1222605445d5Sdg199075 			opstack++;
1223605445d5Sdg199075 			next();
1224605445d5Sdg199075 			break;
1225605445d5Sdg199075 		}
1226605445d5Sdg199075 
1227605445d5Sdg199075 		if (EQ("vlan-id")) {
1228605445d5Sdg199075 			next();
1229605445d5Sdg199075 			if (tokentype != NUMBER)
1230605445d5Sdg199075 				pr_err("VLAN ID expected");
1231b127ac41SPhilip Kirk 			pf_matchfn("vlan-id");
1232605445d5Sdg199075 			pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
1233605445d5Sdg199075 			    VLAN_ID_MASK);
1234605445d5Sdg199075 			pf_emit(ENF_AND);
12357c478bd9Sstevel@tonic-gate 			opstack++;
12367c478bd9Sstevel@tonic-gate 			next();
12377c478bd9Sstevel@tonic-gate 			break;
12387c478bd9Sstevel@tonic-gate 		}
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 		if (EQ("rarp")) {
1241b127ac41SPhilip Kirk 			pf_matchfn("rarp");
12427c478bd9Sstevel@tonic-gate 			opstack++;
12437c478bd9Sstevel@tonic-gate 			next();
12447c478bd9Sstevel@tonic-gate 			break;
12457c478bd9Sstevel@tonic-gate 		}
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 		if (EQ("tcp")) {
1248605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_TCP);
12497c478bd9Sstevel@tonic-gate 			opstack++;
12507c478bd9Sstevel@tonic-gate 			next();
12517c478bd9Sstevel@tonic-gate 			break;
12527c478bd9Sstevel@tonic-gate 		}
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 		if (EQ("udp")) {
1255605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_UDP);
12567c478bd9Sstevel@tonic-gate 			opstack++;
12577c478bd9Sstevel@tonic-gate 			next();
12587c478bd9Sstevel@tonic-gate 			break;
12597c478bd9Sstevel@tonic-gate 		}
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 		if (EQ("ospf")) {
1262605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_OSPF);
12637c478bd9Sstevel@tonic-gate 			opstack++;
12647c478bd9Sstevel@tonic-gate 			next();
12657c478bd9Sstevel@tonic-gate 			break;
12667c478bd9Sstevel@tonic-gate 		}
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 		if (EQ("sctp")) {
1270605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_SCTP);
12717c478bd9Sstevel@tonic-gate 			opstack++;
12727c478bd9Sstevel@tonic-gate 			next();
12737c478bd9Sstevel@tonic-gate 			break;
12747c478bd9Sstevel@tonic-gate 		}
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 		if (EQ("icmp")) {
1277605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_ICMP);
12787c478bd9Sstevel@tonic-gate 			opstack++;
12797c478bd9Sstevel@tonic-gate 			next();
12807c478bd9Sstevel@tonic-gate 			break;
12817c478bd9Sstevel@tonic-gate 		}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 		if (EQ("icmp6")) {
1284605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_ICMPV6);
12857c478bd9Sstevel@tonic-gate 			opstack++;
12867c478bd9Sstevel@tonic-gate 			next();
12877c478bd9Sstevel@tonic-gate 			break;
12887c478bd9Sstevel@tonic-gate 		}
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 		if (EQ("ip-in-ip")) {
1291605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_ENCAP);
12927c478bd9Sstevel@tonic-gate 			opstack++;
12937c478bd9Sstevel@tonic-gate 			next();
12947c478bd9Sstevel@tonic-gate 			break;
12957c478bd9Sstevel@tonic-gate 		}
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 		if (EQ("esp")) {
1298605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_ESP);
12997c478bd9Sstevel@tonic-gate 			opstack++;
13007c478bd9Sstevel@tonic-gate 			next();
13017c478bd9Sstevel@tonic-gate 			break;
13027c478bd9Sstevel@tonic-gate 		}
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 		if (EQ("ah")) {
1305605445d5Sdg199075 			pf_check_transport_protocol(IPPROTO_AH);
13067c478bd9Sstevel@tonic-gate 			opstack++;
13077c478bd9Sstevel@tonic-gate 			next();
13087c478bd9Sstevel@tonic-gate 			break;
13097c478bd9Sstevel@tonic-gate 		}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 		if (EQ("(")) {
13127c478bd9Sstevel@tonic-gate 			inBrace++;
13137c478bd9Sstevel@tonic-gate 			next();
13147c478bd9Sstevel@tonic-gate 			pf_expression();
13157c478bd9Sstevel@tonic-gate 			if (EQ(")")) {
13167c478bd9Sstevel@tonic-gate 				if (inBrace)
13177c478bd9Sstevel@tonic-gate 					inBraceOR--;
13187c478bd9Sstevel@tonic-gate 				inBrace--;
13197c478bd9Sstevel@tonic-gate 				next();
13207c478bd9Sstevel@tonic-gate 			}
13217c478bd9Sstevel@tonic-gate 			break;
13227c478bd9Sstevel@tonic-gate 		}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 		if (EQ("to") || EQ("dst")) {
13257c478bd9Sstevel@tonic-gate 			dir = TO;
13267c478bd9Sstevel@tonic-gate 			next();
13277c478bd9Sstevel@tonic-gate 			continue;
13287c478bd9Sstevel@tonic-gate 		}
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 		if (EQ("from") || EQ("src")) {
13317c478bd9Sstevel@tonic-gate 			dir = FROM;
13327c478bd9Sstevel@tonic-gate 			next();
13337c478bd9Sstevel@tonic-gate 			continue;
13347c478bd9Sstevel@tonic-gate 		}
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 		if (EQ("ether")) {
13377c478bd9Sstevel@tonic-gate 			eaddr = 1;
13387c478bd9Sstevel@tonic-gate 			next();
13397c478bd9Sstevel@tonic-gate 			continue;
13407c478bd9Sstevel@tonic-gate 		}
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 		if (EQ("inet")) {
13437c478bd9Sstevel@tonic-gate 			next();
13447c478bd9Sstevel@tonic-gate 			if (EQ("host"))
13457c478bd9Sstevel@tonic-gate 				next();
13467c478bd9Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP)
13477c478bd9Sstevel@tonic-gate 				pr_err("host/IPv4 addr expected after inet");
13487c478bd9Sstevel@tonic-gate 			pf_ipaddr_match(dir, token, IPV4_ONLY);
13497c478bd9Sstevel@tonic-gate 			opstack++;
13507c478bd9Sstevel@tonic-gate 			next();
13517c478bd9Sstevel@tonic-gate 			break;
13527c478bd9Sstevel@tonic-gate 		}
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 		if (EQ("inet6")) {
13557c478bd9Sstevel@tonic-gate 			next();
13567c478bd9Sstevel@tonic-gate 			if (EQ("host"))
13577c478bd9Sstevel@tonic-gate 				next();
13587c478bd9Sstevel@tonic-gate 			if (tokentype != ALPHA && tokentype != ADDR_IP6)
13597c478bd9Sstevel@tonic-gate 				pr_err("host/IPv6 addr expected after inet6");
13607c478bd9Sstevel@tonic-gate 			pf_ipaddr_match(dir, token, IPV6_ONLY);
13617c478bd9Sstevel@tonic-gate 			opstack++;
13627c478bd9Sstevel@tonic-gate 			next();
13637c478bd9Sstevel@tonic-gate 			break;
13647c478bd9Sstevel@tonic-gate 		}
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 		if (EQ("proto")) {
13677c478bd9Sstevel@tonic-gate 			next();
13687c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
13697c478bd9Sstevel@tonic-gate 				pr_err("IP proto type expected");
1370605445d5Sdg199075 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
13710990bc30Sdg199075 			pf_compare_value(
1372b127ac41SPhilip Kirk 			    IPV4_TYPE_HEADER_OFFSET + dl.dl_link_header_len, 1,
13730990bc30Sdg199075 			    tokenval);
13747c478bd9Sstevel@tonic-gate 			opstack++;
13757c478bd9Sstevel@tonic-gate 			next();
13767c478bd9Sstevel@tonic-gate 			break;
13777c478bd9Sstevel@tonic-gate 		}
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 		if (EQ("broadcast")) {
1380605445d5Sdg199075 			pf_clear_offset_register();
1381b127ac41SPhilip Kirk 			pf_compare_value(dl.dl_link_dest_offset, 4, 0xffffffff);
13827c478bd9Sstevel@tonic-gate 			opstack++;
13837c478bd9Sstevel@tonic-gate 			next();
13847c478bd9Sstevel@tonic-gate 			break;
13857c478bd9Sstevel@tonic-gate 		}
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 		if (EQ("multicast")) {
1388605445d5Sdg199075 			pf_clear_offset_register();
1389b127ac41SPhilip Kirk 			pf_compare_value_mask(
1390b127ac41SPhilip Kirk 			    dl.dl_link_dest_offset, 1, 0x01, 0x01);
13917c478bd9Sstevel@tonic-gate 			opstack++;
13927c478bd9Sstevel@tonic-gate 			next();
13937c478bd9Sstevel@tonic-gate 			break;
13947c478bd9Sstevel@tonic-gate 		}
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 		if (EQ("ethertype")) {
13977c478bd9Sstevel@tonic-gate 			next();
13987c478bd9Sstevel@tonic-gate 			if (tokentype != NUMBER)
13997c478bd9Sstevel@tonic-gate 				pr_err("ether type expected");
1400605445d5Sdg199075 			pf_match_ethertype(tokenval);
14017c478bd9Sstevel@tonic-gate 			opstack++;
14027c478bd9Sstevel@tonic-gate 			next();
14037c478bd9Sstevel@tonic-gate 			break;
14047c478bd9Sstevel@tonic-gate 		}
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 		if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
14077c478bd9Sstevel@tonic-gate 			if (EQ("dstnet"))
14087c478bd9Sstevel@tonic-gate 				dir = TO;
14097c478bd9Sstevel@tonic-gate 			else if (EQ("srcnet"))
14107c478bd9Sstevel@tonic-gate 				dir = FROM;
14117c478bd9Sstevel@tonic-gate 			next();
14127c478bd9Sstevel@tonic-gate 			pf_netaddr_match(dir, token);
14137c478bd9Sstevel@tonic-gate 			dir = ANY;
14147c478bd9Sstevel@tonic-gate 			opstack++;
14157c478bd9Sstevel@tonic-gate 			next();
14167c478bd9Sstevel@tonic-gate 			break;
14177c478bd9Sstevel@tonic-gate 		}
14187c478bd9Sstevel@tonic-gate 
1419b127ac41SPhilip Kirk 		if (EQ("zone")) {
1420b127ac41SPhilip Kirk 			next();
1421b127ac41SPhilip Kirk 			if (tokentype != NUMBER)
1422b127ac41SPhilip Kirk 				pr_err("zoneid expected after inet");
14230a0e9771SDarren Reed 			pf_match_zone(dir, BE_32((uint32_t)(tokenval)));
1424b127ac41SPhilip Kirk 			opstack++;
1425b127ac41SPhilip Kirk 			next();
1426b127ac41SPhilip Kirk 			break;
1427b127ac41SPhilip Kirk 		}
1428b127ac41SPhilip Kirk 
14297c478bd9Sstevel@tonic-gate 		/*
14307c478bd9Sstevel@tonic-gate 		 * Give up on anything that's obviously
14317c478bd9Sstevel@tonic-gate 		 * not a primary.
14327c478bd9Sstevel@tonic-gate 		 */
14337c478bd9Sstevel@tonic-gate 		if (EQ("and") || EQ("or") ||
14347c478bd9Sstevel@tonic-gate 		    EQ("not") || EQ("decnet") || EQ("apple") ||
14357c478bd9Sstevel@tonic-gate 		    EQ("length") || EQ("less") || EQ("greater") ||
14367c478bd9Sstevel@tonic-gate 		    EQ("port") || EQ("srcport") || EQ("dstport") ||
14377c478bd9Sstevel@tonic-gate 		    EQ("rpc") || EQ("gateway") || EQ("nofrag") ||
1438d04ccbb3Scarlsonj 		    EQ("bootp") || EQ("dhcp") || EQ("dhcp6") ||
1439d04ccbb3Scarlsonj 		    EQ("slp") || EQ("ldap")) {
14407c478bd9Sstevel@tonic-gate 			break;
14417c478bd9Sstevel@tonic-gate 		}
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 		if (EQ("host") || EQ("between") ||
14447c478bd9Sstevel@tonic-gate 		    tokentype == ALPHA || /* assume its a hostname */
14457c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_IP ||
14467c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_IP6 ||
14477c478bd9Sstevel@tonic-gate 		    tokentype == ADDR_ETHER) {
14487c478bd9Sstevel@tonic-gate 			if (EQ("host") || EQ("between"))
14497c478bd9Sstevel@tonic-gate 				next();
14507c478bd9Sstevel@tonic-gate 			if (eaddr || tokentype == ADDR_ETHER) {
14517c478bd9Sstevel@tonic-gate 				pf_etheraddr_match(dir, token);
14527c478bd9Sstevel@tonic-gate 			} else if (tokentype == ALPHA) {
14537c478bd9Sstevel@tonic-gate 				pf_ipaddr_match(dir, token, IPV4_AND_IPV6);
14547c478bd9Sstevel@tonic-gate 			} else if (tokentype == ADDR_IP) {
14557c478bd9Sstevel@tonic-gate 				pf_ipaddr_match(dir, token, IPV4_ONLY);
14567c478bd9Sstevel@tonic-gate 			} else {
14577c478bd9Sstevel@tonic-gate 				pf_ipaddr_match(dir, token, IPV6_ONLY);
14587c478bd9Sstevel@tonic-gate 			}
14597c478bd9Sstevel@tonic-gate 			dir = ANY;
14607c478bd9Sstevel@tonic-gate 			eaddr = 0;
14617c478bd9Sstevel@tonic-gate 			opstack++;
14627c478bd9Sstevel@tonic-gate 			next();
14637c478bd9Sstevel@tonic-gate 			break;
14647c478bd9Sstevel@tonic-gate 		}
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 		break;	/* unknown token */
14677c478bd9Sstevel@tonic-gate 	}
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate static void
pf_alternation()14717c478bd9Sstevel@tonic-gate pf_alternation()
14727c478bd9Sstevel@tonic-gate {
14737c478bd9Sstevel@tonic-gate 	int s = opstack;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	pf_primary();
14767c478bd9Sstevel@tonic-gate 	for (;;) {
14777c478bd9Sstevel@tonic-gate 		if (EQ("and"))
14787c478bd9Sstevel@tonic-gate 			next();
14797c478bd9Sstevel@tonic-gate 		pf_primary();
14807c478bd9Sstevel@tonic-gate 		if (opstack != s + 2)
14817c478bd9Sstevel@tonic-gate 			break;
14827c478bd9Sstevel@tonic-gate 		pf_emit(ENF_AND);
14837c478bd9Sstevel@tonic-gate 		opstack--;
14847c478bd9Sstevel@tonic-gate 	}
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate static void
pf_expression()14887c478bd9Sstevel@tonic-gate pf_expression()
14897c478bd9Sstevel@tonic-gate {
14907c478bd9Sstevel@tonic-gate 	pf_alternation();
14917c478bd9Sstevel@tonic-gate 	while (EQ("or") || EQ(",")) {
14927c478bd9Sstevel@tonic-gate 		if (inBrace)
14937c478bd9Sstevel@tonic-gate 			inBraceOR++;
14947c478bd9Sstevel@tonic-gate 		else
14957c478bd9Sstevel@tonic-gate 			foundOR++;
14967c478bd9Sstevel@tonic-gate 		next();
14977c478bd9Sstevel@tonic-gate 		pf_alternation();
14987c478bd9Sstevel@tonic-gate 		pf_emit(ENF_OR);
14997c478bd9Sstevel@tonic-gate 		opstack--;
15007c478bd9Sstevel@tonic-gate 	}
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate /*
15047c478bd9Sstevel@tonic-gate  * Attempt to compile the expression
15057c478bd9Sstevel@tonic-gate  * in the string "e".  If we can generate
15067c478bd9Sstevel@tonic-gate  * pf code for it then return 1 - otherwise
15077c478bd9Sstevel@tonic-gate  * return 0 and leave it up to the user-level
15087c478bd9Sstevel@tonic-gate  * filter.
15097c478bd9Sstevel@tonic-gate  */
15107c478bd9Sstevel@tonic-gate int
pf_compile(char * e,int print)1511*cd93bdd3SToomas Soome pf_compile(char *e, int print)
15127c478bd9Sstevel@tonic-gate {
15137c478bd9Sstevel@tonic-gate 	char *argstr;
15147c478bd9Sstevel@tonic-gate 	char *sav_str, *ptr, *sav_ptr;
15157c478bd9Sstevel@tonic-gate 	int inBr = 0, aheadOR = 0;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	argstr = strdup(e);
15187c478bd9Sstevel@tonic-gate 	sav_str = e;
15197c478bd9Sstevel@tonic-gate 	tkp = argstr;
15207c478bd9Sstevel@tonic-gate 	dir = ANY;
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	pfp = &pf.Pf_Filter[0];
15237c478bd9Sstevel@tonic-gate 	if (setjmp(env)) {
15247c478bd9Sstevel@tonic-gate 		return (0);
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	/*
15287c478bd9Sstevel@tonic-gate 	 * Set media specific packet offsets that this code uses.
15297c478bd9Sstevel@tonic-gate 	 */
1530b127ac41SPhilip Kirk 	if (interface->mac_type == DL_ETHER) {
1531b127ac41SPhilip Kirk 		dl.dl_type = DL_ETHER;
1532b127ac41SPhilip Kirk 		dl.dl_match_fn = pf_match_ethertype;
1533041bde0aSSebastien Roy 		dl.dl_trans_map_tbl = ether_transport_mapping_table;
1534041bde0aSSebastien Roy 		dl.dl_net_map_tbl = ether_network_mapping_table;
1535b127ac41SPhilip Kirk 		dl.dl_link_header_len = 14;
1536b127ac41SPhilip Kirk 		dl.dl_link_type_offset = 12;
1537b127ac41SPhilip Kirk 		dl.dl_link_dest_offset = 0;
1538b127ac41SPhilip Kirk 		dl.dl_link_src_offset = 6;
1539b127ac41SPhilip Kirk 		dl.dl_link_addr_len = 6;
1540b127ac41SPhilip Kirk 	}
1541b127ac41SPhilip Kirk 
15427c478bd9Sstevel@tonic-gate 	if (interface->mac_type == DL_IB) {
1543b127ac41SPhilip Kirk 		dl.dl_type = DL_IB;
1544b127ac41SPhilip Kirk 		dl.dl_link_header_len = 4;
1545b127ac41SPhilip Kirk 		dl.dl_link_type_offset = 0;
1546b127ac41SPhilip Kirk 		dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1547b127ac41SPhilip Kirk 		dl.dl_link_addr_len = 20;
1548b127ac41SPhilip Kirk 		dl.dl_match_fn = pf_match_ibtype;
1549041bde0aSSebastien Roy 		dl.dl_trans_map_tbl = ib_transport_mapping_table;
1550041bde0aSSebastien Roy 		dl.dl_net_map_tbl = ib_network_mapping_table;
1551b127ac41SPhilip Kirk 	}
1552b127ac41SPhilip Kirk 
1553b127ac41SPhilip Kirk 	if (interface->mac_type == DL_IPNET) {
1554b127ac41SPhilip Kirk 		dl.dl_type = DL_IPNET;
1555b127ac41SPhilip Kirk 		dl.dl_link_header_len = 24;
1556b127ac41SPhilip Kirk 		dl.dl_link_type_offset = 0;
1557b127ac41SPhilip Kirk 		dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1558b127ac41SPhilip Kirk 		dl.dl_link_addr_len = -1;
1559b127ac41SPhilip Kirk 		dl.dl_match_fn = pf_match_ipnettype;
1560041bde0aSSebastien Roy 		dl.dl_trans_map_tbl = ipnet_transport_mapping_table;
1561041bde0aSSebastien Roy 		dl.dl_net_map_tbl = ipnet_network_mapping_table;
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	next();
15657c478bd9Sstevel@tonic-gate 	pf_expression();
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	if (tokentype != EOL) {
15687c478bd9Sstevel@tonic-gate 		/*
15697c478bd9Sstevel@tonic-gate 		 * The idea here is to do as much filtering as possible in
15707c478bd9Sstevel@tonic-gate 		 * the kernel. So even if we find a token we don't understand,
15717c478bd9Sstevel@tonic-gate 		 * we try to see if we can still set up a portion of the filter
15727c478bd9Sstevel@tonic-gate 		 * in the kernel and use the userland filter to filter the
15737c478bd9Sstevel@tonic-gate 		 * remaining stuff. Obviously, if our filter expression is of
15747c478bd9Sstevel@tonic-gate 		 * type A AND B, we can filter A in kernel and then apply B
15757c478bd9Sstevel@tonic-gate 		 * to the packets that got through. The same is not true for
15767c478bd9Sstevel@tonic-gate 		 * a filter of type A OR B. We can't apply A first and then B
15777c478bd9Sstevel@tonic-gate 		 * on the packets filtered through A.
15787c478bd9Sstevel@tonic-gate 		 *
15797c478bd9Sstevel@tonic-gate 		 * (We need to keep track of the fact when we find an OR,
15807c478bd9Sstevel@tonic-gate 		 * and the fact that we are inside brackets when we find OR.
15817c478bd9Sstevel@tonic-gate 		 * The variable 'foundOR' tells us if there was an OR behind,
15827c478bd9Sstevel@tonic-gate 		 * 'inBraceOR' tells us if we found an OR before we could find
15837c478bd9Sstevel@tonic-gate 		 * the end brace i.e. ')', and variable 'aheadOR' checks if
15847c478bd9Sstevel@tonic-gate 		 * there is an OR in the expression ahead. if either of these
15857c478bd9Sstevel@tonic-gate 		 * cases become true, we can't split the filtering)
15867c478bd9Sstevel@tonic-gate 		 */
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 		if (foundOR || inBraceOR) {
15897c478bd9Sstevel@tonic-gate 			/* FORGET IN KERNEL FILTERING */
15907c478bd9Sstevel@tonic-gate 			return (0);
15917c478bd9Sstevel@tonic-gate 		} else {
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 			/* CHECK IF NO OR AHEAD */
15947c478bd9Sstevel@tonic-gate 			sav_ptr = (char *)((uintptr_t)sav_str +
1595*cd93bdd3SToomas Soome 			    (uintptr_t)sav_tkp - (uintptr_t)argstr);
15967c478bd9Sstevel@tonic-gate 			ptr = sav_ptr;
15977c478bd9Sstevel@tonic-gate 			while (*ptr != '\0') {
15987c478bd9Sstevel@tonic-gate 				switch (*ptr) {
15997c478bd9Sstevel@tonic-gate 				case '(':
16007c478bd9Sstevel@tonic-gate 					inBr++;
16017c478bd9Sstevel@tonic-gate 					break;
16027c478bd9Sstevel@tonic-gate 				case ')':
16037c478bd9Sstevel@tonic-gate 					inBr--;
16047c478bd9Sstevel@tonic-gate 					break;
16057c478bd9Sstevel@tonic-gate 				case 'o':
16067c478bd9Sstevel@tonic-gate 				case 'O':
16077c478bd9Sstevel@tonic-gate 					if ((*(ptr + 1) == 'R' ||
16087c478bd9Sstevel@tonic-gate 					    *(ptr + 1) == 'r') && !inBr)
16097c478bd9Sstevel@tonic-gate 						aheadOR = 1;
16107c478bd9Sstevel@tonic-gate 					break;
16117c478bd9Sstevel@tonic-gate 				case ',':
16127c478bd9Sstevel@tonic-gate 					if (!inBr)
16137c478bd9Sstevel@tonic-gate 						aheadOR = 1;
16147c478bd9Sstevel@tonic-gate 					break;
16157c478bd9Sstevel@tonic-gate 				}
16167c478bd9Sstevel@tonic-gate 				ptr++;
16177c478bd9Sstevel@tonic-gate 			}
16187c478bd9Sstevel@tonic-gate 			if (!aheadOR) {
16197c478bd9Sstevel@tonic-gate 				/* NO OR AHEAD, SPLIT UP THE FILTERING */
16207c478bd9Sstevel@tonic-gate 				pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
16217c478bd9Sstevel@tonic-gate 				pf.Pf_Priority = 5;
16227c478bd9Sstevel@tonic-gate 				if (print) {
16237c478bd9Sstevel@tonic-gate 					pf_codeprint(&pf.Pf_Filter[0],
16247c478bd9Sstevel@tonic-gate 					    pf.Pf_FilterLen);
16257c478bd9Sstevel@tonic-gate 				}
16267c478bd9Sstevel@tonic-gate 				compile(sav_ptr, print);
16277c478bd9Sstevel@tonic-gate 				return (2);
16287c478bd9Sstevel@tonic-gate 			} else
16297c478bd9Sstevel@tonic-gate 				return (0);
16307c478bd9Sstevel@tonic-gate 		}
16317c478bd9Sstevel@tonic-gate 	}
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
16347c478bd9Sstevel@tonic-gate 	pf.Pf_Priority = 5;	/* unimportant, so long as > 2 */
16357c478bd9Sstevel@tonic-gate 	if (print) {
16367c478bd9Sstevel@tonic-gate 		pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen);
16377c478bd9Sstevel@tonic-gate 	}
16387c478bd9Sstevel@tonic-gate 	return (1);
16397c478bd9Sstevel@tonic-gate }
1640