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