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 }