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