xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pf.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stddef.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <sys/isa_defs.h>
35 
36 #include <sys/socket.h>
37 #include <sys/vlan.h>
38 #include <net/if.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 #include <netinet/if_ether.h>
43 #include <netinet/tcp.h>
44 #include <netinet/udp.h>
45 #include <inet/ip.h>
46 #include <inet/ip6.h>
47 #include <netdb.h>
48 #include <rpc/rpc.h>
49 #include <setjmp.h>
50 
51 #include <sys/pfmod.h>
52 #include "snoop.h"
53 #include "snoop_vlan.h"
54 
55 /*
56  * This module generates code for the kernel packet filter.
57  * The kernel packet filter is more efficient since it
58  * operates without context switching or moving data into
59  * the capture buffer.  On the other hand, it is limited
60  * in its filtering ability i.e. can't cope with variable
61  * length headers, can't compare the packet size, 1 and 4 octet
62  * comparisons are awkward, code space is limited to ENMAXFILTERS
63  * halfwords, etc.
64  * The parser is the same for the user-level packet filter though
65  * more limited in the variety of expressions it can generate
66  * code for.  If the pf compiler finds an expression it can't
67  * handle, it tries to set up a split filter in kernel and do the
68  * remaining filtering in userland. If that also fails, it resorts
69  * to userland filter. (See additional comment in pf_compile)
70  */
71 
72 extern struct Pf_ext_packetfilt pf;
73 static ushort_t *pfp;
74 jmp_buf env;
75 
76 int eaddr;	/* need ethernet addr */
77 
78 int opstack;	/* operand stack depth */
79 
80 #define	EQ(val)		(strcmp(token, val) == 0)
81 #define	IPV4_ONLY	0
82 #define	IPV6_ONLY	1
83 #define	IPV4_AND_IPV6	2
84 
85 typedef struct {
86 	int	transport_protocol;
87 	int	network_protocol;
88 	/*
89 	 * offset is the offset in bytes from the beginning
90 	 * of the network protocol header to where the transport
91 	 * protocol type is.
92 	 */
93 	int	offset;
94 } transport_protocol_table_t;
95 
96 typedef struct network_table {
97 	char *nmt_name;
98 	int nmt_val;
99 } network_table_t;
100 
101 static network_table_t ether_network_mapping_table[] = {
102 	{ "pup", ETHERTYPE_PUP },
103 	{ "ip", ETHERTYPE_IP },
104 	{ "arp", ETHERTYPE_ARP },
105 	{ "revarp", ETHERTYPE_REVARP },
106 	{ "at", ETHERTYPE_AT },
107 	{ "aarp", ETHERTYPE_AARP },
108 	{ "vlan", ETHERTYPE_VLAN },
109 	{ "ip6", ETHERTYPE_IPV6 },
110 	{ "slow", ETHERTYPE_SLOW },
111 	{ "ppoed", ETHERTYPE_PPPOED },
112 	{ "ppoes", ETHERTYPE_PPPOES },
113 	{ "NULL", -1 }
114 
115 };
116 
117 static network_table_t ib_network_mapping_table[] = {
118 	{ "pup", ETHERTYPE_PUP },
119 	{ "ip", ETHERTYPE_IP },
120 	{ "arp", ETHERTYPE_ARP },
121 	{ "revarp", ETHERTYPE_REVARP },
122 	{ "at", ETHERTYPE_AT },
123 	{ "aarp", ETHERTYPE_AARP },
124 	{ "vlan", ETHERTYPE_VLAN },
125 	{ "ip6", ETHERTYPE_IPV6 },
126 	{ "slow", ETHERTYPE_SLOW },
127 	{ "ppoed", ETHERTYPE_PPPOED },
128 	{ "ppoes", ETHERTYPE_PPPOES },
129 	{ "NULL", -1 }
130 
131 };
132 
133 static network_table_t ipnet_network_mapping_table[] = {
134 	{ "ip", (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION) },
135 	{ "ip6", (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION) },
136 	{ "NULL", -1 }
137 
138 };
139 
140 static transport_protocol_table_t ether_transport_mapping_table[] = {
141 	{IPPROTO_TCP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
142 	{IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
143 	{IPPROTO_UDP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
144 	{IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
145 	{IPPROTO_OSPF, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
146 	{IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
147 	{IPPROTO_SCTP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
148 	{IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
149 	{IPPROTO_ICMP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
150 	{IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
151 	{IPPROTO_ENCAP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
152 	{IPPROTO_ESP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
153 	{IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
154 	{IPPROTO_AH, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
155 	{IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
156 	{-1, 0, 0}	/* must be the final entry */
157 };
158 
159 static transport_protocol_table_t ipnet_transport_mapping_table[] = {
160 	{IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
161 	    IPV4_TYPE_HEADER_OFFSET},
162 	{IPPROTO_TCP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
163 	    IPV6_TYPE_HEADER_OFFSET},
164 	{IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
165 	    IPV4_TYPE_HEADER_OFFSET},
166 	{IPPROTO_UDP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
167 	    IPV6_TYPE_HEADER_OFFSET},
168 	{IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
169 	    IPV4_TYPE_HEADER_OFFSET},
170 	{IPPROTO_OSPF, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
171 	    IPV6_TYPE_HEADER_OFFSET},
172 	{IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
173 	    IPV4_TYPE_HEADER_OFFSET},
174 	{IPPROTO_SCTP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
175 	    IPV6_TYPE_HEADER_OFFSET},
176 	{IPPROTO_ICMP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
177 	    IPV4_TYPE_HEADER_OFFSET},
178 	{IPPROTO_ICMPV6, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
179 	    IPV6_TYPE_HEADER_OFFSET},
180 	{IPPROTO_ENCAP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
181 	    IPV4_TYPE_HEADER_OFFSET},
182 	{IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
183 	    IPV4_TYPE_HEADER_OFFSET},
184 	{IPPROTO_ESP, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
185 	    IPV6_TYPE_HEADER_OFFSET},
186 	{IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV4_VERSION),
187 	    IPV4_TYPE_HEADER_OFFSET},
188 	{IPPROTO_AH, (DL_IPNETINFO_VERSION << 8 | IPV6_VERSION),
189 	    IPV6_TYPE_HEADER_OFFSET},
190 	{-1, 0, 0}	/* must be the final entry */
191 };
192 
193 static transport_protocol_table_t ib_transport_mapping_table[] = {
194 	{IPPROTO_TCP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
195 	{IPPROTO_TCP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
196 	{IPPROTO_UDP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
197 	{IPPROTO_UDP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
198 	{IPPROTO_OSPF, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
199 	{IPPROTO_OSPF, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
200 	{IPPROTO_SCTP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
201 	{IPPROTO_SCTP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
202 	{IPPROTO_ICMP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
203 	{IPPROTO_ICMPV6, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
204 	{IPPROTO_ENCAP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
205 	{IPPROTO_ESP, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
206 	{IPPROTO_ESP, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
207 	{IPPROTO_AH, ETHERTYPE_IP,   IPV4_TYPE_HEADER_OFFSET},
208 	{IPPROTO_AH, ETHERTYPE_IPV6, IPV6_TYPE_HEADER_OFFSET},
209 	{-1, 0, 0}	/* must be the final entry */
210 };
211 
212 typedef struct datalink {
213 	uint_t	dl_type;
214 	void	(*dl_match_fn)(uint_t datatype);
215 	transport_protocol_table_t *dl_transport_mapping_table;
216 	network_table_t *dl_net_map_tbl;
217 	int dl_link_header_len;
218 	int dl_link_type_offset;
219 	int dl_link_dest_offset;
220 	int dl_link_src_offset;
221 	int dl_link_addr_len;
222 } datalink_t;
223 
224 datalink_t	dl;
225 
226 #define	IPV4_SRCADDR_OFFSET	(dl.dl_link_header_len + 12)
227 #define	IPV4_DSTADDR_OFFSET	(dl.dl_link_header_len + 16)
228 #define	IPV6_SRCADDR_OFFSET	(dl.dl_link_header_len + 8)
229 #define	IPV6_DSTADDR_OFFSET	(dl.dl_link_header_len + 24)
230 
231 #define	IPNET_SRCZONE_OFFSET 8
232 #define	IPNET_DSTZONE_OFFSET 16
233 
234 static int inBrace = 0, inBraceOR = 0;
235 static int foundOR = 0;
236 char *tkp, *sav_tkp;
237 char *token;
238 enum { EOL, ALPHA, NUMBER, FIELD, ADDR_IP, ADDR_ETHER, SPECIAL,
239 	ADDR_IP6 } tokentype;
240 uint_t tokenval;
241 
242 enum direction { ANY, TO, FROM };
243 enum direction dir;
244 
245 extern void next();
246 
247 static void pf_expression();
248 static void pf_check_vlan_tag(uint_t offset);
249 static void pf_clear_offset_register();
250 static void pf_emit_load_offset(uint_t offset);
251 static void pf_match_ethertype(uint_t ethertype);
252 static void pf_match_ipnettype(uint_t type);
253 static void pf_match_ibtype(uint_t type);
254 static void pf_check_transport_protocol(uint_t transport_protocol);
255 static void pf_compare_value_mask_generic(int offset, uint_t len,
256     uint_t val, int mask, uint_t op);
257 
258 /*
259  * This pointer points to the function that last generated
260  * instructions to change the offset register.  It's used
261  * for comparisons to see if we need to issue more instructions
262  * to change the register.
263  *
264  * It's initialized to pf_clear_offset_register because the offset
265  * register in pfmod is initialized to zero, similar to the state
266  * it would be in after executing the instructions issued by
267  * pf_clear_offset_register.
268  */
269 static void *last_offset_operation = (void*)pf_clear_offset_register;
270 
271 static void
272 pf_emit(x)
273 	ushort_t x;
274 {
275 	if (pfp > &pf.Pf_Filter[PF_MAXFILTERS - 1])
276 		longjmp(env, 1);
277 	*pfp++ = x;
278 }
279 
280 static void
281 pf_codeprint(code, len)
282 	ushort_t *code;
283 	int len;
284 {
285 	ushort_t *pc;
286 	ushort_t *plast = code + len;
287 	int op, action;
288 
289 	if (len > 0) {
290 		printf("Kernel Filter:\n");
291 	}
292 
293 	for (pc = code; pc < plast; pc++) {
294 		printf("\t%3d: ", pc - code);
295 
296 		op = *pc & 0xfc00;	/* high 10 bits */
297 		action = *pc & 0x3ff;	/* low   6 bits */
298 
299 		switch (action) {
300 		case ENF_PUSHLIT:
301 			printf("PUSHLIT ");
302 			break;
303 		case ENF_PUSHZERO:
304 			printf("PUSHZERO ");
305 			break;
306 #ifdef ENF_PUSHONE
307 		case ENF_PUSHONE:
308 			printf("PUSHONE ");
309 			break;
310 #endif
311 #ifdef ENF_PUSHFFFF
312 		case ENF_PUSHFFFF:
313 			printf("PUSHFFFF ");
314 			break;
315 #endif
316 #ifdef ENF_PUSHFF00
317 		case ENF_PUSHFF00:
318 			printf("PUSHFF00 ");
319 			break;
320 #endif
321 #ifdef ENF_PUSH00FF
322 		case ENF_PUSH00FF:
323 			printf("PUSH00FF ");
324 			break;
325 #endif
326 		case ENF_LOAD_OFFSET:
327 			printf("LOAD_OFFSET ");
328 			break;
329 		case ENF_BRTR:
330 			printf("BRTR ");
331 			break;
332 		case ENF_BRFL:
333 			printf("BRFL ");
334 			break;
335 		case ENF_POP:
336 			printf("POP ");
337 			break;
338 		}
339 
340 		if (action >= ENF_PUSHWORD)
341 			printf("PUSHWORD %d ", action - ENF_PUSHWORD);
342 
343 		switch (op) {
344 		case ENF_EQ:
345 			printf("EQ ");
346 			break;
347 		case ENF_LT:
348 			printf("LT ");
349 			break;
350 		case ENF_LE:
351 			printf("LE ");
352 			break;
353 		case ENF_GT:
354 			printf("GT ");
355 			break;
356 		case ENF_GE:
357 			printf("GE ");
358 			break;
359 		case ENF_AND:
360 			printf("AND ");
361 			break;
362 		case ENF_OR:
363 			printf("OR ");
364 			break;
365 		case ENF_XOR:
366 			printf("XOR ");
367 			break;
368 		case ENF_COR:
369 			printf("COR ");
370 			break;
371 		case ENF_CAND:
372 			printf("CAND ");
373 			break;
374 		case ENF_CNOR:
375 			printf("CNOR ");
376 			break;
377 		case ENF_CNAND:
378 			printf("CNAND ");
379 			break;
380 		case ENF_NEQ:
381 			printf("NEQ ");
382 			break;
383 		}
384 
385 		if (action == ENF_PUSHLIT ||
386 		    action == ENF_LOAD_OFFSET ||
387 		    action == ENF_BRTR ||
388 		    action == ENF_BRFL) {
389 			pc++;
390 			printf("\n\t%3d:   %d (0x%04x)", pc - code, *pc, *pc);
391 		}
392 
393 		printf("\n");
394 	}
395 }
396 
397 /*
398  * Emit packet filter code to check a
399  * field in the packet for a particular value.
400  * Need different code for each field size.
401  * Since the pf can only compare 16 bit quantities
402  * we have to use masking to compare byte values.
403  * Long word (32 bit) quantities have to be done
404  * as two 16 bit comparisons.
405  */
406 static void
407 pf_compare_value(int offset, uint_t len, uint_t val)
408 {
409 	/*
410 	 * If the property being filtered on is absent in the media
411 	 * packet, error out.
412 	 */
413 	if (offset == -1)
414 		pr_err("filter option unsupported on media");
415 
416 	switch (len) {
417 	case 1:
418 		pf_emit(ENF_PUSHWORD + offset / 2);
419 #if defined(_BIG_ENDIAN)
420 		if (offset % 2)
421 #else
422 		if (!(offset % 2))
423 #endif
424 		{
425 #ifdef ENF_PUSH00FF
426 			pf_emit(ENF_PUSH00FF | ENF_AND);
427 #else
428 			pf_emit(ENF_PUSHLIT | ENF_AND);
429 			pf_emit(0x00FF);
430 #endif
431 			pf_emit(ENF_PUSHLIT | ENF_EQ);
432 			pf_emit(val);
433 		} else {
434 #ifdef ENF_PUSHFF00
435 			pf_emit(ENF_PUSHFF00 | ENF_AND);
436 #else
437 			pf_emit(ENF_PUSHLIT | ENF_AND);
438 			pf_emit(0xFF00);
439 #endif
440 			pf_emit(ENF_PUSHLIT | ENF_EQ);
441 			pf_emit(val << 8);
442 		}
443 		break;
444 
445 	case 2:
446 		pf_emit(ENF_PUSHWORD + offset / 2);
447 		pf_emit(ENF_PUSHLIT | ENF_EQ);
448 		pf_emit((ushort_t)val);
449 		break;
450 
451 	case 4:
452 		pf_emit(ENF_PUSHWORD + offset / 2);
453 		pf_emit(ENF_PUSHLIT | ENF_EQ);
454 #if defined(_BIG_ENDIAN)
455 		pf_emit(val >> 16);
456 #elif defined(_LITTLE_ENDIAN)
457 		pf_emit(val & 0xffff);
458 #else
459 #error One of _BIG_ENDIAN and _LITTLE_ENDIAN must be defined
460 #endif
461 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
462 		pf_emit(ENF_PUSHLIT | ENF_EQ);
463 #if defined(_BIG_ENDIAN)
464 		pf_emit(val & 0xffff);
465 #else
466 		pf_emit(val >> 16);
467 #endif
468 		pf_emit(ENF_AND);
469 		break;
470 	}
471 }
472 
473 /*
474  * same as pf_compare_value, but only for emiting code to
475  * compare ipv6 addresses.
476  */
477 static void
478 pf_compare_value_v6(int offset, uint_t len, struct in6_addr val)
479 {
480 	int i;
481 
482 	for (i = 0; i < len; i += 2) {
483 		pf_emit(ENF_PUSHWORD + offset / 2 + i / 2);
484 		pf_emit(ENF_PUSHLIT | ENF_EQ);
485 		pf_emit(*(uint16_t *)&val.s6_addr[i]);
486 		if (i != 0)
487 			pf_emit(ENF_AND);
488 	}
489 }
490 
491 
492 /*
493  * Same as above except mask the field value
494  * before doing the comparison.  The comparison checks
495  * to make sure the values are equal.
496  */
497 static void
498 pf_compare_value_mask(int offset, uint_t len, uint_t val, int mask)
499 {
500 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_EQ);
501 }
502 
503 /*
504  * Same as above except the values are compared to see if they are not
505  * equal.
506  */
507 static void
508 pf_compare_value_mask_neq(int offset, uint_t len, uint_t val, int mask)
509 {
510 	pf_compare_value_mask_generic(offset, len, val, mask, ENF_NEQ);
511 }
512 
513 /*
514  * Similar to pf_compare_value.
515  *
516  * This is the utility function that does the actual work to compare
517  * two values using a mask.  The comparison operation is passed into
518  * the function.
519  */
520 static void
521 pf_compare_value_mask_generic(int offset, uint_t len, uint_t val, int mask,
522     uint_t op)
523 {
524 	/*
525 	 * If the property being filtered on is absent in the media
526 	 * packet, error out.
527 	 */
528 	if (offset == -1)
529 		pr_err("filter option unsupported on media");
530 
531 	switch (len) {
532 	case 1:
533 		pf_emit(ENF_PUSHWORD + offset / 2);
534 #if defined(_BIG_ENDIAN)
535 		if (offset % 2)
536 #else
537 		if (!offset % 2)
538 #endif
539 		{
540 			pf_emit(ENF_PUSHLIT | ENF_AND);
541 			pf_emit(mask & 0x00ff);
542 			pf_emit(ENF_PUSHLIT | op);
543 			pf_emit(val);
544 		} else {
545 			pf_emit(ENF_PUSHLIT | ENF_AND);
546 			pf_emit((mask << 8) & 0xff00);
547 			pf_emit(ENF_PUSHLIT | op);
548 			pf_emit(val << 8);
549 		}
550 		break;
551 
552 	case 2:
553 		pf_emit(ENF_PUSHWORD + offset / 2);
554 		pf_emit(ENF_PUSHLIT | ENF_AND);
555 		pf_emit(htons((ushort_t)mask));
556 		pf_emit(ENF_PUSHLIT | op);
557 		pf_emit(htons((ushort_t)val));
558 		break;
559 
560 	case 4:
561 		pf_emit(ENF_PUSHWORD + offset / 2);
562 		pf_emit(ENF_PUSHLIT | ENF_AND);
563 		pf_emit(htons((ushort_t)((mask >> 16) & 0xffff)));
564 		pf_emit(ENF_PUSHLIT | op);
565 		pf_emit(htons((ushort_t)((val >> 16) & 0xffff)));
566 
567 		pf_emit(ENF_PUSHWORD + (offset / 2) + 1);
568 		pf_emit(ENF_PUSHLIT | ENF_AND);
569 		pf_emit(htons((ushort_t)(mask & 0xffff)));
570 		pf_emit(ENF_PUSHLIT | op);
571 		pf_emit(htons((ushort_t)(val & 0xffff)));
572 
573 		pf_emit(ENF_AND);
574 		break;
575 	}
576 }
577 
578 /*
579  * Like pf_compare_value() but compare on a 64-bit zoneid value.
580  * The argument val passed in is in network byte order.
581  */
582 static void
583 pf_compare_zoneid(int offset, uint64_t val)
584 {
585 	int i;
586 
587 	for (i = 0; i < sizeof (uint64_t) / 2; i ++) {
588 		pf_emit(ENF_PUSHWORD + offset / 2 + i);
589 		pf_emit(ENF_PUSHLIT | ENF_EQ);
590 		pf_emit(((uint16_t *)&val)[i]);
591 		if (i != 0)
592 			pf_emit(ENF_AND);
593 	}
594 }
595 
596 /*
597  * Generate pf code to match an IPv4 or IPv6 address.
598  */
599 static void
600 pf_ipaddr_match(which, hostname, inet_type)
601 	enum direction which;
602 	char *hostname;
603 	int inet_type;
604 {
605 	bool_t found_host;
606 	uint_t *addr4ptr;
607 	uint_t addr4;
608 	struct in6_addr *addr6ptr;
609 	int h_addr_index;
610 	struct hostent *hp = NULL;
611 	int error_num = 0;
612 	boolean_t first = B_TRUE;
613 	int pass = 0;
614 
615 	/*
616 	 * The addr4offset and addr6offset variables simplify the code which
617 	 * generates the address comparison filter.  With these two variables,
618 	 * duplicate code need not exist for the TO and FROM case.
619 	 * A value of -1 describes the ANY case (TO and FROM).
620 	 */
621 	int addr4offset;
622 	int addr6offset;
623 
624 	found_host = 0;
625 
626 	if (tokentype == ADDR_IP) {
627 		hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
628 		if (hp == NULL) {
629 			if (error_num == TRY_AGAIN) {
630 				pr_err("could not resolve %s (try again later)",
631 				    hostname);
632 			} else {
633 				pr_err("could not resolve %s", hostname);
634 			}
635 		}
636 		inet_type = IPV4_ONLY;
637 	} else if (tokentype == ADDR_IP6) {
638 		hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
639 		if (hp == NULL) {
640 			if (error_num == TRY_AGAIN) {
641 				pr_err("could not resolve %s (try again later)",
642 				    hostname);
643 			} else {
644 				pr_err("could not resolve %s", hostname);
645 			}
646 		}
647 		inet_type = IPV6_ONLY;
648 	} else if (tokentype == ALPHA) {
649 		/* Some hostname i.e. tokentype is ALPHA */
650 		switch (inet_type) {
651 		case IPV4_ONLY:
652 			/* Only IPv4 address is needed */
653 			hp = getipnodebyname(hostname, AF_INET, 0, &error_num);
654 			if (hp != NULL) {
655 				found_host = 1;
656 			}
657 			break;
658 		case IPV6_ONLY:
659 			/* Only IPv6 address is needed */
660 			hp = getipnodebyname(hostname, AF_INET6, 0, &error_num);
661 			if (hp != NULL) {
662 				found_host = 1;
663 			}
664 			break;
665 		case IPV4_AND_IPV6:
666 			/* Both IPv4 and IPv6 are needed */
667 			hp = getipnodebyname(hostname, AF_INET6,
668 			    AI_ALL | AI_V4MAPPED, &error_num);
669 			if (hp != NULL) {
670 				found_host = 1;
671 			}
672 			break;
673 		default:
674 			found_host = 0;
675 		}
676 
677 		if (!found_host) {
678 			if (error_num == TRY_AGAIN) {
679 				pr_err("could not resolve %s (try again later)",
680 				    hostname);
681 			} else {
682 				pr_err("could not resolve %s", hostname);
683 			}
684 		}
685 	} else {
686 		pr_err("unknown token type: %s", hostname);
687 	}
688 
689 	switch (which) {
690 	case TO:
691 		addr4offset = IPV4_DSTADDR_OFFSET;
692 		addr6offset = IPV6_DSTADDR_OFFSET;
693 		break;
694 	case FROM:
695 		addr4offset = IPV4_SRCADDR_OFFSET;
696 		addr6offset = IPV6_SRCADDR_OFFSET;
697 		break;
698 	case ANY:
699 		addr4offset = -1;
700 		addr6offset = -1;
701 		break;
702 	}
703 
704 	if (hp != NULL && hp->h_addrtype == AF_INET) {
705 		for (; dl.dl_net_map_tbl->nmt_val != -1;
706 		    dl.dl_net_map_tbl++) {
707 			if (strcmp("ip",
708 				dl.dl_net_map_tbl->nmt_name) == 0) {
709 				dl.dl_match_fn(
710 					dl.dl_net_map_tbl->nmt_val);
711 			}
712 		}
713 		if (dl.dl_type == DL_ETHER)
714 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
715 		h_addr_index = 0;
716 		addr4ptr = (uint_t *)hp->h_addr_list[h_addr_index];
717 		while (addr4ptr != NULL) {
718 			if (addr4offset == -1) {
719 				pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
720 				    *addr4ptr);
721 				if (h_addr_index != 0)
722 					pf_emit(ENF_OR);
723 				pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
724 				    *addr4ptr);
725 				pf_emit(ENF_OR);
726 			} else {
727 				pf_compare_value(addr4offset, 4,
728 				    *addr4ptr);
729 				if (h_addr_index != 0)
730 					pf_emit(ENF_OR);
731 			}
732 			addr4ptr = (uint_t *)hp->h_addr_list[++h_addr_index];
733 		}
734 		pf_emit(ENF_AND);
735 	} else {
736 		/* first pass: IPv4 addresses */
737 		h_addr_index = 0;
738 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
739 		first = B_TRUE;
740 		while (addr6ptr != NULL) {
741 			if (IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
742 				if (first) {
743 					for (; dl.dl_net_map_tbl->nmt_val != -1;
744 					    dl.dl_net_map_tbl++) {
745 						if (strcmp("ip",
746 							dl.dl_net_map_tbl->
747 							nmt_name) == 0) {
748 							dl.dl_match_fn(
749 								dl.
750 								dl_net_map_tbl->
751 								nmt_val);
752 						}
753 					}
754 					if (dl.dl_type == DL_ETHER) {
755 						pf_check_vlan_tag(
756 							ENCAP_ETHERTYPE_OFF/2);
757 					}
758 					pass++;
759 				}
760 				IN6_V4MAPPED_TO_INADDR(addr6ptr,
761 				    (struct in_addr *)&addr4);
762 				if (addr4offset == -1) {
763 					pf_compare_value(IPV4_SRCADDR_OFFSET, 4,
764 					    addr4);
765 					if (!first)
766 						pf_emit(ENF_OR);
767 					pf_compare_value(IPV4_DSTADDR_OFFSET, 4,
768 					    addr4);
769 					pf_emit(ENF_OR);
770 				} else {
771 					pf_compare_value(addr4offset, 4,
772 					    addr4);
773 					if (!first)
774 						pf_emit(ENF_OR);
775 				}
776 				if (first)
777 					first = B_FALSE;
778 			}
779 			addr6ptr = (struct in6_addr *)
780 				hp->h_addr_list[++h_addr_index];
781 		}
782 		if (!first) {
783 			pf_emit(ENF_AND);
784 		}
785 		/* second pass: IPv6 addresses */
786 		h_addr_index = 0;
787 		addr6ptr = (struct in6_addr *)hp->h_addr_list[h_addr_index];
788 		first = B_TRUE;
789 		while (addr6ptr != NULL) {
790 			if (!IN6_IS_ADDR_V4MAPPED(addr6ptr)) {
791 				if (first) {
792 					for (; dl.dl_net_map_tbl->nmt_val != -1;
793 					    dl.dl_net_map_tbl++) {
794 						if (strcmp("ip6",
795 							dl.dl_net_map_tbl->
796 							nmt_name) == 0) {
797 							dl.dl_match_fn(
798 								dl.
799 								dl_net_map_tbl->
800 								nmt_val);
801 						}
802 					}
803 					if (dl.dl_type == DL_ETHER) {
804 						pf_check_vlan_tag(
805 							ENCAP_ETHERTYPE_OFF/2);
806 					}
807 					pass++;
808 				}
809 				if (addr6offset == -1) {
810 					pf_compare_value_v6(IPV6_SRCADDR_OFFSET,
811 					    16, *addr6ptr);
812 					if (!first)
813 						pf_emit(ENF_OR);
814 					pf_compare_value_v6(IPV6_DSTADDR_OFFSET,
815 					    16, *addr6ptr);
816 					pf_emit(ENF_OR);
817 				} else {
818 					pf_compare_value_v6(addr6offset, 16,
819 					    *addr6ptr);
820 					if (!first)
821 						pf_emit(ENF_OR);
822 				}
823 				if (first)
824 					first = B_FALSE;
825 			}
826 			addr6ptr = (struct in6_addr *)
827 				hp->h_addr_list[++h_addr_index];
828 		}
829 		if (!first) {
830 			pf_emit(ENF_AND);
831 		}
832 		if (pass == 2) {
833 			pf_emit(ENF_OR);
834 		}
835 	}
836 
837 	if (hp != NULL) {
838 		freehostent(hp);
839 	}
840 }
841 
842 
843 static void
844 pf_compare_address(int offset, uint_t len, uchar_t *addr)
845 {
846 	uint32_t val;
847 	uint16_t sval;
848 	boolean_t didone = B_FALSE;
849 
850 	/*
851 	 * If the property being filtered on is absent in the media
852 	 * packet, error out.
853 	 */
854 	if (offset == -1)
855 		pr_err("filter option unsupported on media");
856 
857 	while (len > 0) {
858 		if (len >= 4) {
859 			(void) memcpy(&val, addr, 4);
860 			pf_compare_value(offset, 4, val);
861 			addr += 4;
862 			offset += 4;
863 			len -= 4;
864 		} else if (len >= 2) {
865 			(void) memcpy(&sval, addr, 2);
866 			pf_compare_value(offset, 2, sval);
867 			addr += 2;
868 			offset += 2;
869 			len -= 2;
870 		} else {
871 			pf_compare_value(offset++, 1, *addr++);
872 			len--;
873 		}
874 		if (didone)
875 			pf_emit(ENF_AND);
876 		didone = B_TRUE;
877 	}
878 }
879 
880 /*
881  * Compare ethernet addresses.
882  */
883 static void
884 pf_etheraddr_match(which, hostname)
885 	enum direction which;
886 	char *hostname;
887 {
888 	struct ether_addr e, *ep = NULL;
889 
890 	if (isxdigit(*hostname))
891 		ep = ether_aton(hostname);
892 	if (ep == NULL) {
893 		if (ether_hostton(hostname, &e))
894 			if (!arp_for_ether(hostname, &e))
895 				pr_err("cannot obtain ether addr for %s",
896 					hostname);
897 		ep = &e;
898 	}
899 
900 	pf_clear_offset_register();
901 
902 	switch (which) {
903 	case TO:
904 		pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
905 		    (uchar_t *)ep);
906 		break;
907 	case FROM:
908 		pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
909 		    (uchar_t *)ep);
910 		break;
911 	case ANY:
912 		pf_compare_address(dl.dl_link_dest_offset, dl.dl_link_addr_len,
913 		    (uchar_t *)ep);
914 		pf_compare_address(dl.dl_link_src_offset, dl.dl_link_addr_len,
915 		    (uchar_t *)ep);
916 		pf_emit(ENF_OR);
917 		break;
918 	}
919 }
920 
921 /*
922  * Emit code to compare the network part of
923  * an IP address.
924  */
925 static void
926 pf_netaddr_match(which, netname)
927 	enum direction which;
928 	char *netname;
929 {
930 	uint_t addr;
931 	uint_t mask = 0xff000000;
932 	struct netent *np;
933 
934 	if (isdigit(*netname)) {
935 		addr = inet_network(netname);
936 	} else {
937 		np = getnetbyname(netname);
938 		if (np == NULL)
939 			pr_err("net %s not known", netname);
940 		addr = np->n_net;
941 	}
942 
943 	/*
944 	 * Left justify the address and figure
945 	 * out a mask based on the supplied address.
946 	 * Set the mask according to the number of zero
947 	 * low-order bytes.
948 	 * Note: this works only for whole octet masks.
949 	 */
950 	if (addr) {
951 		while ((addr & ~mask) != 0) {
952 			mask |= (mask >> 8);
953 		}
954 	}
955 
956 	pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
957 
958 	switch (which) {
959 	case TO:
960 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
961 		break;
962 	case FROM:
963 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
964 		break;
965 	case ANY:
966 		pf_compare_value_mask(IPV4_SRCADDR_OFFSET, 4, addr, mask);
967 		pf_compare_value_mask(IPV4_DSTADDR_OFFSET, 4, addr, mask);
968 		pf_emit(ENF_OR);
969 		break;
970 	}
971 }
972 
973 /*
974  * Emit code to match on src or destination zoneid.
975  * The zoneid passed in is in network byte order.
976  */
977 static void
978 pf_match_zone(enum direction which, uint64_t zoneid)
979 {
980 	if (dl.dl_type != DL_IPNET)
981 		pr_err("zone filter option unsupported on media");
982 
983 	switch (which) {
984 	case TO:
985 		pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
986 		break;
987 	case FROM:
988 		pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
989 		break;
990 	case ANY:
991 		pf_compare_zoneid(IPNET_SRCZONE_OFFSET, zoneid);
992 		pf_compare_zoneid(IPNET_DSTZONE_OFFSET, zoneid);
993 		pf_emit(ENF_OR);
994 		break;
995 	}
996 }
997 
998 /*
999  * A helper function to keep the code to emit instructions
1000  * to change the offset register in one place.
1001  *
1002  * INPUTS: offset - An value representing an offset in 16-bit
1003  *                  words.
1004  * OUTPUTS:  If there is enough room in the storage for the
1005  *           packet filtering program, instructions to load
1006  *           a constant to the offset register.  Otherwise,
1007  *           nothing.
1008  */
1009 static void
1010 pf_emit_load_offset(uint_t offset)
1011 {
1012 	pf_emit(ENF_LOAD_OFFSET | ENF_NOP);
1013 	pf_emit(offset);
1014 }
1015 
1016 /*
1017  * Clear pfmod's offset register.
1018  *
1019  * INPUTS:  none
1020  * OUTPUTS:  Instructions to clear the offset register if
1021  *           there is enough space remaining in the packet
1022  *           filtering program structure's storage, and
1023  *           the last thing done to the offset register was
1024  *           not clearing the offset register.  Otherwise,
1025  *           nothing.
1026  */
1027 static void
1028 pf_clear_offset_register()
1029 {
1030 	if (last_offset_operation != (void*)pf_clear_offset_register) {
1031 		pf_emit_load_offset(0);
1032 		last_offset_operation = (void*)pf_clear_offset_register;
1033 	}
1034 }
1035 
1036 /*
1037  * This function will issue opcodes to check if a packet
1038  * is VLAN tagged, and if so, update the offset register
1039  * with the appropriate offset.
1040  *
1041  * Note that if the packet is not VLAN tagged, then the offset
1042  * register will be cleared.
1043  *
1044  * If the interface type is not an ethernet type, then this
1045  * function returns without doing anything.
1046  *
1047  * If the last attempt to change the offset register occured because
1048  * of a call to this function that was called with the same offset,
1049  * then we don't issue packet filtering instructions.
1050  *
1051  * INPUTS:  offset - an offset in 16 bit words.  The function
1052  *                   will set the offset register to this
1053  *                   value if the packet is VLAN tagged.
1054  * OUTPUTS:  If the conditions are met, packet filtering instructions.
1055  */
1056 static void
1057 pf_check_vlan_tag(uint_t offset)
1058 {
1059 	static uint_t last_offset = 0;
1060 
1061 	if ((interface->mac_type == DL_ETHER ||
1062 	    interface->mac_type == DL_CSMACD) &&
1063 	    (last_offset_operation != (void*)pf_check_vlan_tag ||
1064 	    last_offset != offset)) {
1065 		/*
1066 		 * First thing is to clear the offset register.
1067 		 * We don't know what state it is in, and if it
1068 		 * is not zero, then we have no idea what we load
1069 		 * when we execute ENF_PUSHWORD.
1070 		 */
1071 		pf_clear_offset_register();
1072 
1073 		/*
1074 		 * Check the ethertype.
1075 		 */
1076 		pf_compare_value(dl.dl_link_type_offset, 2,
1077 		    htons(ETHERTYPE_VLAN));
1078 
1079 		/*
1080 		 * And if it's not VLAN, don't load offset to the offset
1081 		 * register.
1082 		 */
1083 		pf_emit(ENF_BRFL | ENF_NOP);
1084 		pf_emit(3);
1085 
1086 		/*
1087 		 * Otherwise, load offset to the offset register.
1088 		 */
1089 		pf_emit_load_offset(offset);
1090 
1091 		/*
1092 		 * Now get rid of the results of the comparison,
1093 		 * we don't want the results of the comparison to affect
1094 		 * other logic in the packet filtering program.
1095 		 */
1096 		pf_emit(ENF_POP | ENF_NOP);
1097 
1098 		/*
1099 		 * Set the last operation at the end, or any time
1100 		 * after the call to pf_clear_offset because
1101 		 * pf_clear_offset uses it.
1102 		 */
1103 		last_offset_operation = (void*)pf_check_vlan_tag;
1104 		last_offset = offset;
1105 	}
1106 }
1107 
1108 /*
1109  * Utility function used to emit packet filtering code
1110  * to match an ethertype.
1111  *
1112  * INPUTS:  ethertype - The ethertype we want to check for.
1113  *                      Don't call htons on the ethertype before
1114  *                      calling this function.
1115  * OUTPUTS:  If there is sufficient storage available, packet
1116  *           filtering code to check an ethertype.  Otherwise,
1117  *           nothing.
1118  */
1119 static void
1120 pf_match_ethertype(uint_t ethertype)
1121 {
1122 	/*
1123 	 * If the user wants to filter on ethertype VLAN,
1124 	 * then clear the offset register so that the offset
1125 	 * for ENF_PUSHWORD points to the right place in the
1126 	 * packet.
1127 	 *
1128 	 * Otherwise, call pf_check_vlan_tag to set the offset
1129 	 * register such that the contents of the offset register
1130 	 * plus the argument for ENF_PUSHWORD point to the right
1131 	 * part of the packet, whether or not the packet is VLAN
1132 	 * tagged.  We call pf_check_vlan_tag with an offset of
1133 	 * two words because if the packet is VLAN tagged, we have
1134 	 * to move past the ethertype in the ethernet header, and
1135 	 * past the lower two octets of the VLAN header to get to
1136 	 * the ethertype in the VLAN header.
1137 	 */
1138 	if (ethertype == ETHERTYPE_VLAN)
1139 		pf_clear_offset_register();
1140 	else
1141 		pf_check_vlan_tag(2);
1142 
1143 	pf_compare_value(dl.dl_link_type_offset, 2, htons(ethertype));
1144 }
1145 
1146 static void
1147 pf_match_ipnettype(uint_t type)
1148 {
1149 	pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1150 }
1151 
1152 static void
1153 pf_match_ibtype(uint_t type)
1154 {
1155 	pf_compare_value(dl.dl_link_type_offset, 2, htons(type));
1156 }
1157 
1158 /*
1159  * This function uses the table above to generate a
1160  * piece of a packet filtering program to check a transport
1161  * protocol type.
1162  *
1163  * INPUTS:  tranport_protocol - the transport protocol we're
1164  *                              interested in.
1165  * OUTPUTS:  If there is sufficient storage, then packet filtering
1166  *           code to check a transport protocol type.  Otherwise,
1167  *           nothing.
1168  */
1169 static void
1170 pf_check_transport_protocol(uint_t transport_protocol)
1171 {
1172 	int i = 0;
1173 	uint_t number_of_matches = 0;
1174 
1175 	for (; dl.dl_transport_mapping_table->transport_protocol != -1;
1176 	    dl.dl_transport_mapping_table++) {
1177 		if (transport_protocol ==
1178 		    (uint_t)dl.dl_transport_mapping_table->transport_protocol) {
1179 			number_of_matches++;
1180 			dl.dl_match_fn(dl.dl_transport_mapping_table->
1181 			    network_protocol);
1182 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
1183 			pf_compare_value(
1184 			    dl.dl_transport_mapping_table->offset +
1185 			    dl.dl_link_header_len, 1,
1186 			    transport_protocol);
1187 			pf_emit(ENF_AND);
1188 			if (number_of_matches > 1) {
1189 				/*
1190 				 * Since we have two or more matches, in
1191 				 * order to have a correct and complete
1192 				 * program we need to OR the result of
1193 				 * each block of comparisons together.
1194 				 */
1195 				pf_emit(ENF_OR);
1196 			}
1197 		}
1198 	}
1199 }
1200 
1201 static void
1202 pf_matchfn(char *proto)
1203 {
1204 	for (; dl.dl_net_map_tbl->nmt_val != -1; dl.dl_net_map_tbl++) {
1205 		if (strcmp(proto, dl.dl_net_map_tbl->nmt_name) == 0)
1206 			dl.dl_match_fn(dl.dl_net_map_tbl->nmt_val);
1207 	}
1208 }
1209 
1210 static void
1211 pf_primary()
1212 {
1213 	for (;;) {
1214 		if (tokentype == FIELD)
1215 			break;
1216 
1217 		if (EQ("ip")) {
1218 			pf_matchfn("ip");
1219 			opstack++;
1220 			next();
1221 			break;
1222 		}
1223 
1224 		if (EQ("ip6")) {
1225 			pf_matchfn("ip6");
1226 			opstack++;
1227 			next();
1228 			break;
1229 		}
1230 
1231 		if (EQ("pppoe")) {
1232 			pf_matchfn("pppoe");
1233 			pf_match_ethertype(ETHERTYPE_PPPOES);
1234 			pf_emit(ENF_OR);
1235 			opstack++;
1236 			next();
1237 			break;
1238 		}
1239 
1240 		if (EQ("pppoed")) {
1241 			pf_matchfn("pppoed");
1242 			opstack++;
1243 			next();
1244 			break;
1245 		}
1246 
1247 		if (EQ("pppoes")) {
1248 			pf_matchfn("pppoes");
1249 			opstack++;
1250 			next();
1251 			break;
1252 		}
1253 
1254 		if (EQ("arp")) {
1255 			pf_matchfn("arp");
1256 			opstack++;
1257 			next();
1258 			break;
1259 		}
1260 
1261 		if (EQ("vlan")) {
1262 			pf_matchfn("vlan");
1263 			pf_compare_value_mask_neq(VLAN_ID_OFFSET, 2,
1264 			    0, VLAN_ID_MASK);
1265 			pf_emit(ENF_AND);
1266 			opstack++;
1267 			next();
1268 			break;
1269 		}
1270 
1271 		if (EQ("vlan-id")) {
1272 			next();
1273 			if (tokentype != NUMBER)
1274 				pr_err("VLAN ID expected");
1275 			pf_matchfn("vlan-id");
1276 			pf_compare_value_mask(VLAN_ID_OFFSET, 2, tokenval,
1277 			    VLAN_ID_MASK);
1278 			pf_emit(ENF_AND);
1279 			opstack++;
1280 			next();
1281 			break;
1282 		}
1283 
1284 		if (EQ("rarp")) {
1285 			pf_matchfn("rarp");
1286 			opstack++;
1287 			next();
1288 			break;
1289 		}
1290 
1291 		if (EQ("tcp")) {
1292 			pf_check_transport_protocol(IPPROTO_TCP);
1293 			opstack++;
1294 			next();
1295 			break;
1296 		}
1297 
1298 		if (EQ("udp")) {
1299 			pf_check_transport_protocol(IPPROTO_UDP);
1300 			opstack++;
1301 			next();
1302 			break;
1303 		}
1304 
1305 		if (EQ("ospf")) {
1306 			pf_check_transport_protocol(IPPROTO_OSPF);
1307 			opstack++;
1308 			next();
1309 			break;
1310 		}
1311 
1312 
1313 		if (EQ("sctp")) {
1314 			pf_check_transport_protocol(IPPROTO_SCTP);
1315 			opstack++;
1316 			next();
1317 			break;
1318 		}
1319 
1320 		if (EQ("icmp")) {
1321 			pf_check_transport_protocol(IPPROTO_ICMP);
1322 			opstack++;
1323 			next();
1324 			break;
1325 		}
1326 
1327 		if (EQ("icmp6")) {
1328 			pf_check_transport_protocol(IPPROTO_ICMPV6);
1329 			opstack++;
1330 			next();
1331 			break;
1332 		}
1333 
1334 		if (EQ("ip-in-ip")) {
1335 			pf_check_transport_protocol(IPPROTO_ENCAP);
1336 			opstack++;
1337 			next();
1338 			break;
1339 		}
1340 
1341 		if (EQ("esp")) {
1342 			pf_check_transport_protocol(IPPROTO_ESP);
1343 			opstack++;
1344 			next();
1345 			break;
1346 		}
1347 
1348 		if (EQ("ah")) {
1349 			pf_check_transport_protocol(IPPROTO_AH);
1350 			opstack++;
1351 			next();
1352 			break;
1353 		}
1354 
1355 		if (EQ("(")) {
1356 			inBrace++;
1357 			next();
1358 			pf_expression();
1359 			if (EQ(")")) {
1360 				if (inBrace)
1361 					inBraceOR--;
1362 				inBrace--;
1363 				next();
1364 			}
1365 			break;
1366 		}
1367 
1368 		if (EQ("to") || EQ("dst")) {
1369 			dir = TO;
1370 			next();
1371 			continue;
1372 		}
1373 
1374 		if (EQ("from") || EQ("src")) {
1375 			dir = FROM;
1376 			next();
1377 			continue;
1378 		}
1379 
1380 		if (EQ("ether")) {
1381 			eaddr = 1;
1382 			next();
1383 			continue;
1384 		}
1385 
1386 		if (EQ("inet")) {
1387 			next();
1388 			if (EQ("host"))
1389 				next();
1390 			if (tokentype != ALPHA && tokentype != ADDR_IP)
1391 				pr_err("host/IPv4 addr expected after inet");
1392 			pf_ipaddr_match(dir, token, IPV4_ONLY);
1393 			opstack++;
1394 			next();
1395 			break;
1396 		}
1397 
1398 		if (EQ("inet6")) {
1399 			next();
1400 			if (EQ("host"))
1401 				next();
1402 			if (tokentype != ALPHA && tokentype != ADDR_IP6)
1403 				pr_err("host/IPv6 addr expected after inet6");
1404 			pf_ipaddr_match(dir, token, IPV6_ONLY);
1405 			opstack++;
1406 			next();
1407 			break;
1408 		}
1409 
1410 		if (EQ("proto")) {
1411 			next();
1412 			if (tokentype != NUMBER)
1413 				pr_err("IP proto type expected");
1414 			pf_check_vlan_tag(ENCAP_ETHERTYPE_OFF/2);
1415 			pf_compare_value(
1416 			    IPV4_TYPE_HEADER_OFFSET + dl.dl_link_header_len, 1,
1417 			    tokenval);
1418 			opstack++;
1419 			next();
1420 			break;
1421 		}
1422 
1423 		if (EQ("broadcast")) {
1424 			pf_clear_offset_register();
1425 			pf_compare_value(dl.dl_link_dest_offset, 4, 0xffffffff);
1426 			opstack++;
1427 			next();
1428 			break;
1429 		}
1430 
1431 		if (EQ("multicast")) {
1432 			pf_clear_offset_register();
1433 			pf_compare_value_mask(
1434 			    dl.dl_link_dest_offset, 1, 0x01, 0x01);
1435 			opstack++;
1436 			next();
1437 			break;
1438 		}
1439 
1440 		if (EQ("ethertype")) {
1441 			next();
1442 			if (tokentype != NUMBER)
1443 				pr_err("ether type expected");
1444 			pf_match_ethertype(tokenval);
1445 			opstack++;
1446 			next();
1447 			break;
1448 		}
1449 
1450 		if (EQ("net") || EQ("dstnet") || EQ("srcnet")) {
1451 			if (EQ("dstnet"))
1452 				dir = TO;
1453 			else if (EQ("srcnet"))
1454 				dir = FROM;
1455 			next();
1456 			pf_netaddr_match(dir, token);
1457 			dir = ANY;
1458 			opstack++;
1459 			next();
1460 			break;
1461 		}
1462 
1463 		if (EQ("zone")) {
1464 			next();
1465 			if (tokentype != NUMBER)
1466 				pr_err("zoneid expected after inet");
1467 			pf_match_zone(dir, BE_64((uint64_t)(tokenval)));
1468 			opstack++;
1469 			next();
1470 			break;
1471 		}
1472 
1473 		/*
1474 		 * Give up on anything that's obviously
1475 		 * not a primary.
1476 		 */
1477 		if (EQ("and") || EQ("or") ||
1478 		    EQ("not") || EQ("decnet") || EQ("apple") ||
1479 		    EQ("length") || EQ("less") || EQ("greater") ||
1480 		    EQ("port") || EQ("srcport") || EQ("dstport") ||
1481 		    EQ("rpc") || EQ("gateway") || EQ("nofrag") ||
1482 		    EQ("bootp") || EQ("dhcp") || EQ("dhcp6") ||
1483 		    EQ("slp") || EQ("ldap")) {
1484 			break;
1485 		}
1486 
1487 		if (EQ("host") || EQ("between") ||
1488 		    tokentype == ALPHA || /* assume its a hostname */
1489 		    tokentype == ADDR_IP ||
1490 		    tokentype == ADDR_IP6 ||
1491 		    tokentype == ADDR_ETHER) {
1492 			if (EQ("host") || EQ("between"))
1493 				next();
1494 			if (eaddr || tokentype == ADDR_ETHER) {
1495 				pf_etheraddr_match(dir, token);
1496 			} else if (tokentype == ALPHA) {
1497 				pf_ipaddr_match(dir, token, IPV4_AND_IPV6);
1498 			} else if (tokentype == ADDR_IP) {
1499 				pf_ipaddr_match(dir, token, IPV4_ONLY);
1500 			} else {
1501 				pf_ipaddr_match(dir, token, IPV6_ONLY);
1502 			}
1503 			dir = ANY;
1504 			eaddr = 0;
1505 			opstack++;
1506 			next();
1507 			break;
1508 		}
1509 
1510 		break;	/* unknown token */
1511 	}
1512 }
1513 
1514 static void
1515 pf_alternation()
1516 {
1517 	int s = opstack;
1518 
1519 	pf_primary();
1520 	for (;;) {
1521 		if (EQ("and"))
1522 			next();
1523 		pf_primary();
1524 		if (opstack != s + 2)
1525 			break;
1526 		pf_emit(ENF_AND);
1527 		opstack--;
1528 	}
1529 }
1530 
1531 static void
1532 pf_expression()
1533 {
1534 	pf_alternation();
1535 	while (EQ("or") || EQ(",")) {
1536 		if (inBrace)
1537 			inBraceOR++;
1538 		else
1539 			foundOR++;
1540 		next();
1541 		pf_alternation();
1542 		pf_emit(ENF_OR);
1543 		opstack--;
1544 	}
1545 }
1546 
1547 /*
1548  * Attempt to compile the expression
1549  * in the string "e".  If we can generate
1550  * pf code for it then return 1 - otherwise
1551  * return 0 and leave it up to the user-level
1552  * filter.
1553  */
1554 int
1555 pf_compile(e, print)
1556 	char *e;
1557 	int print;
1558 {
1559 	char *argstr;
1560 	char *sav_str, *ptr, *sav_ptr;
1561 	int inBr = 0, aheadOR = 0;
1562 
1563 	argstr = strdup(e);
1564 	sav_str = e;
1565 	tkp = argstr;
1566 	dir = ANY;
1567 
1568 	pfp = &pf.Pf_Filter[0];
1569 	if (setjmp(env)) {
1570 		return (0);
1571 	}
1572 
1573 	/*
1574 	 * Set media specific packet offsets that this code uses.
1575 	 */
1576 	if (interface->mac_type == DL_ETHER) {
1577 		dl.dl_type = DL_ETHER;
1578 		dl.dl_match_fn = pf_match_ethertype;
1579 		dl.dl_transport_mapping_table =
1580 		    &ether_transport_mapping_table[0];
1581 		dl.dl_net_map_tbl =
1582 		    &ether_network_mapping_table[0];
1583 		dl.dl_link_header_len = 14;
1584 		dl.dl_link_type_offset = 12;
1585 		dl.dl_link_dest_offset = 0;
1586 		dl.dl_link_src_offset = 6;
1587 		dl.dl_link_addr_len = 6;
1588 	}
1589 
1590 	if (interface->mac_type == DL_IB) {
1591 		dl.dl_type = DL_IB;
1592 		dl.dl_link_header_len = 4;
1593 		dl.dl_link_type_offset = 0;
1594 		dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1595 		dl.dl_link_addr_len = 20;
1596 		dl.dl_match_fn = pf_match_ibtype;
1597 		dl.dl_transport_mapping_table =
1598 		    &ib_transport_mapping_table[0];
1599 		dl.dl_net_map_tbl =
1600 		    &ib_network_mapping_table[0];
1601 	}
1602 
1603 	if (interface->mac_type == DL_IPNET) {
1604 		dl.dl_type = DL_IPNET;
1605 		dl.dl_link_header_len = 24;
1606 		dl.dl_link_type_offset = 0;
1607 		dl.dl_link_dest_offset = dl.dl_link_src_offset = -1;
1608 		dl.dl_link_addr_len = -1;
1609 		dl.dl_match_fn = pf_match_ipnettype;
1610 		dl.dl_transport_mapping_table =
1611 		    &ipnet_transport_mapping_table[0];
1612 		dl.dl_net_map_tbl =
1613 		    &ipnet_network_mapping_table[0];
1614 	}
1615 
1616 	next();
1617 	pf_expression();
1618 
1619 	if (tokentype != EOL) {
1620 		/*
1621 		 * The idea here is to do as much filtering as possible in
1622 		 * the kernel. So even if we find a token we don't understand,
1623 		 * we try to see if we can still set up a portion of the filter
1624 		 * in the kernel and use the userland filter to filter the
1625 		 * remaining stuff. Obviously, if our filter expression is of
1626 		 * type A AND B, we can filter A in kernel and then apply B
1627 		 * to the packets that got through. The same is not true for
1628 		 * a filter of type A OR B. We can't apply A first and then B
1629 		 * on the packets filtered through A.
1630 		 *
1631 		 * (We need to keep track of the fact when we find an OR,
1632 		 * and the fact that we are inside brackets when we find OR.
1633 		 * The variable 'foundOR' tells us if there was an OR behind,
1634 		 * 'inBraceOR' tells us if we found an OR before we could find
1635 		 * the end brace i.e. ')', and variable 'aheadOR' checks if
1636 		 * there is an OR in the expression ahead. if either of these
1637 		 * cases become true, we can't split the filtering)
1638 		 */
1639 
1640 		if (foundOR || inBraceOR) {
1641 			/* FORGET IN KERNEL FILTERING */
1642 			return (0);
1643 		} else {
1644 
1645 			/* CHECK IF NO OR AHEAD */
1646 			sav_ptr = (char *)((uintptr_t)sav_str +
1647 						(uintptr_t)sav_tkp -
1648 						(uintptr_t)argstr);
1649 			ptr = sav_ptr;
1650 			while (*ptr != '\0') {
1651 				switch (*ptr) {
1652 				case '(':
1653 					inBr++;
1654 					break;
1655 				case ')':
1656 					inBr--;
1657 					break;
1658 				case 'o':
1659 				case 'O':
1660 					if ((*(ptr + 1) == 'R' ||
1661 						*(ptr + 1) == 'r') && !inBr)
1662 						aheadOR = 1;
1663 					break;
1664 				case ',':
1665 					if (!inBr)
1666 						aheadOR = 1;
1667 					break;
1668 				}
1669 				ptr++;
1670 			}
1671 			if (!aheadOR) {
1672 				/* NO OR AHEAD, SPLIT UP THE FILTERING */
1673 				pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1674 				pf.Pf_Priority = 5;
1675 				if (print) {
1676 					pf_codeprint(&pf.Pf_Filter[0],
1677 							pf.Pf_FilterLen);
1678 				}
1679 				compile(sav_ptr, print);
1680 				return (2);
1681 			} else
1682 				return (0);
1683 		}
1684 	}
1685 
1686 	pf.Pf_FilterLen = pfp - &pf.Pf_Filter[0];
1687 	pf.Pf_Priority = 5;	/* unimportant, so long as > 2 */
1688 	if (print) {
1689 		pf_codeprint(&pf.Pf_Filter[0], pf.Pf_FilterLen);
1690 	}
1691 	return (1);
1692 }
1693