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