]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
Fix a typo; this fixes bug 1854436.
[libpcap] / gencode.c
index f5081e4f5a9d551f8f448f2f5f1ef02cfb7992e6..177ff925c36071a199735acab0cd9d08db796d49 100644 (file)
--- a/gencode.c
+++ b/gencode.c
@@ -21,7 +21,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.48 2007-06-11 09:52:04 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.54 2007-10-26 00:47:36 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -73,7 +73,12 @@ static const char rcsid[] _U_ =
 #include "ppp.h"
 #include "sll.h"
 #include "arcnet.h"
-#include "pf.h"
+#ifdef HAVE_NET_PFVAR_H
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <net/if_pflog.h>
+#endif
 #ifndef offsetof
 #define offsetof(s, e) ((size_t)&((s *)0)->e)
 #endif
@@ -100,8 +105,12 @@ static const char rcsid[] _U_ =
 static jmp_buf top_ctx;
 static pcap_t *bpf_pcap;
 
+#ifdef WIN32
 /* Hack for updating VLAN, MPLS, and PPPoE offsets. */
+static u_int   orig_linktype = (u_int)-1, orig_nl = (u_int)-1, label_stack_depth = (u_int)-1;
+#else
 static u_int   orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;
+#endif
 
 /* XXX */
 #ifdef PCAP_FDDIPAD
@@ -125,6 +134,7 @@ bpf_error(const char *fmt, ...)
 
 static void init_linktype(pcap_t *);
 
+static void init_regs(void);
 static int alloc_reg(void);
 static void free_reg(int);
 
@@ -189,6 +199,7 @@ static inline struct block *gen_false(void);
 static struct block *gen_ether_linktype(int);
 static struct block *gen_linux_sll_linktype(int);
 static void insert_radiotap_load_llprefixlen(struct block *);
+static void insert_ppi_load_llprefixlen(struct block *);
 static void insert_load_llprefixlen(struct block *);
 static struct slist *gen_llprefixlen(void);
 static struct block *gen_linktype(int);
@@ -238,6 +249,7 @@ static struct slist *xfer_to_a(struct arth *);
 static struct block *gen_mac_multicast(int);
 static struct block *gen_len(int, int);
 
+static struct block *gen_ppi_dlt_check(void);
 static struct block *gen_msg_abbrev(int type);
 
 static void *
@@ -358,6 +370,7 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        n_errors = 0;
        root = NULL;
        bpf_pcap = p;
+       init_regs();
        if (setjmp(top_ctx)) {
                lex_cleanup();
                freechunks();
@@ -473,10 +486,20 @@ merge(b0, b1)
        *p = b1;
 }
 
+
 void
 finish_parse(p)
        struct block *p;
 {
+       struct block *ppi_dlt_check;
+       
+       ppi_dlt_check = gen_ppi_dlt_check();
+
+       if (ppi_dlt_check != NULL)
+       {
+               gen_and(ppi_dlt_check, p);
+       }
+
        backpatch(p, gen_retblk(snaplen));
        p->sense = !p->sense;
        backpatch(p, gen_retblk(0));
@@ -497,6 +520,7 @@ finish_parse(p)
         * require the length of that header, doing more for that
         * header length isn't really worth the effort.
         */
+
        insert_load_llprefixlen(root);
 }
 
@@ -1008,6 +1032,16 @@ init_linktype(p)
                off_nl_nosnap = 27;     /* Radio+802.11+802.2 */
                return;
 
+               
+               /* 
+                * At the moment we treat PPI as normal Radiotap encoded
+                * packets. The difference is in the function that generates
+                * the code at the beginning to compute the header length.
+                * Since this code generator of PPI supports bare 802.11
+                * encapsulation only (i.e. the encapsulated DLT should be
+                * DLT_IEEE802_11) we generate code to check for this too.
+                */
+       case DLT_PPI:
        case DLT_IEEE802_11_RADIO:
                /*
                 * Same as 802.11, but with an additional header before
@@ -1148,12 +1182,13 @@ init_linktype(p)
                off_nl_nosnap = 44;     /* XXX - what does it do with 802.3 packets? */
                return;
 
+#ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                off_linktype = 0;
-               /* XXX read this from pf.h? */
                off_nl = PFLOG_HDRLEN;
                off_nl_nosnap = PFLOG_HDRLEN;   /* no 802.2 LLC */
                return;
+#endif
 
         case DLT_JUNIPER_MFR:
         case DLT_JUNIPER_MLFR:
@@ -1234,6 +1269,17 @@ init_linktype(p)
                off_nl_nosnap = -1;
                return;
 
+       case DLT_MTP2_WITH_PHDR:
+               off_li = 6;
+               off_sio = 7;
+               off_opc = 8;
+               off_dpc = 8;
+               off_sls = 11;
+               off_linktype = -1;
+               off_nl = -1;
+               off_nl_nosnap = -1;
+               return;
+
 #ifdef DLT_PFSYNC
        case DLT_PFSYNC:
                off_linktype = -1;
@@ -1318,6 +1364,7 @@ gen_load_llrel(offset, size)
        return s;
 }
 
+
 /*
  * Load a value relative to the beginning of the specified header.
  */
@@ -1879,6 +1926,104 @@ insert_radiotap_load_llprefixlen(b)
        }
 }
 
+/* 
+ * At the moment we treat PPI as normal Radiotap encoded
+ * packets. The difference is in the function that generates
+ * the code at the beginning to compute the header length.
+ * Since this code generator of PPI supports bare 802.11
+ * encapsulation only (i.e. the encapsulated DLT should be
+ * DLT_IEEE802_11) we generate code to check for this too.
+ */
+static void
+insert_ppi_load_llprefixlen(b)
+       struct block *b;
+{
+       struct slist *s1, *s2;
+       
+       /*
+        * Prepend to the statements in this block code to load the
+        * length of the radiotap header into the register assigned
+        * to hold that length, if one has been assigned.
+        */
+       if (reg_ll_size != -1) {
+           /*
+                * The 2 bytes at offsets of 2 and 3 from the beginning
+                * of the radiotap header are the length of the radiotap
+                * header; unfortunately, it's little-endian, so we have
+                * to load it a byte at a time and construct the value.
+                */
+
+               /*
+                * Load the high-order byte, at an offset of 3, shift it
+                * left a byte, and put the result in the X register.
+                */
+               s1 = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+               s1->s.k = 3;
+               s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K);
+               sappend(s1, s2);
+               s2->s.k = 8;
+               s2 = new_stmt(BPF_MISC|BPF_TAX);
+               sappend(s1, s2);
+
+               /*
+                * Load the next byte, at an offset of 2, and OR the
+                * value from the X register into it.
+                */
+               s2 = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+               sappend(s1, s2);
+               s2->s.k = 2;
+               s2 = new_stmt(BPF_ALU|BPF_OR|BPF_X);
+               sappend(s1, s2);
+
+               /*
+                * Now allocate a register to hold that value and store
+                * it.
+                */
+               s2 = new_stmt(BPF_ST);
+               s2->s.k = reg_ll_size;
+               sappend(s1, s2);
+
+               /*
+                * Now move it into the X register.
+                */
+               s2 = new_stmt(BPF_MISC|BPF_TAX);
+               sappend(s1, s2);
+
+               /*
+                * Now append all the existing statements in this
+                * block to these statements.
+                */
+               sappend(s1, b->stmts);
+               b->stmts = s1;
+
+       }
+}
+       
+static struct block *
+gen_ppi_dlt_check(void)
+{
+       struct slist *s_load_dlt;
+       struct block *b;
+
+       if (linktype == DLT_PPI)
+       {
+               /* Create the statements that check for the DLT
+                */
+               s_load_dlt = new_stmt(BPF_LD|BPF_W|BPF_ABS);
+               s_load_dlt->s.k = 4;
+
+               b = new_block(JMP(BPF_JEQ));
+
+               b->stmts = s_load_dlt;
+               b->s.k = SWAPLONG(DLT_IEEE802_11);
+       }
+       else
+       {
+               b = NULL;
+       }
+
+       return b;
+}
 
 static void
 insert_load_llprefixlen(b)
@@ -1886,8 +2031,21 @@ insert_load_llprefixlen(b)
 {
        switch (linktype) {
 
+       /* 
+        * At the moment we treat PPI as normal Radiotap encoded
+        * packets. The difference is in the function that generates
+        * the code at the beginning to compute the header length.
+        * Since this code generator of PPI supports bare 802.11
+        * encapsulation only (i.e. the encapsulated DLT should be
+        * DLT_IEEE802_11) we generate code to check for this too.
+        */
+       case DLT_PPI:
+               insert_ppi_load_llprefixlen(b);
+               break;
+
        case DLT_IEEE802_11_RADIO:
                insert_radiotap_load_llprefixlen(b);
+               break;
        }
 }
 
@@ -1914,6 +2072,38 @@ gen_radiotap_llprefixlen(void)
        return s;
 }
 
+/* 
+ * At the moment we treat PPI as normal Radiotap encoded
+ * packets. The difference is in the function that generates
+ * the code at the beginning to compute the header length.
+ * Since this code generator of PPI supports bare 802.11
+ * encapsulation only (i.e. the encapsulated DLT should be
+ * DLT_IEEE802_11) we generate code to check for this too.
+ */
+static struct slist *
+gen_ppi_llprefixlen(void)
+{
+       struct slist *s;
+
+       if (reg_ll_size == -1) {
+               /*
+                * We haven't yet assigned a register for the length
+                * of the radiotap header; allocate one.
+                */
+               reg_ll_size = alloc_reg();
+       }
+
+       /*
+        * Load the register containing the radiotap length
+        * into the X register.
+        */
+       s = new_stmt(BPF_LDX|BPF_MEM);
+       s->s.k = reg_ll_size;
+       return s;
+}
+
+
+
 /*
  * Generate code to compute the link-layer header length, if necessary,
  * putting it into the X register, and to return either a pointer to a
@@ -1925,6 +2115,10 @@ gen_llprefixlen(void)
 {
        switch (linktype) {
 
+       case DLT_PPI:
+               return gen_ppi_llprefixlen();
+
+       
        case DLT_IEEE802_11_RADIO:
                return gen_radiotap_llprefixlen();
 
@@ -1987,6 +2181,7 @@ gen_linktype(proto)
                }
                break;
 
+       case DLT_PPI:
        case DLT_FDDI:
        case DLT_IEEE802:
        case DLT_IEEE802_11:
@@ -2239,6 +2434,7 @@ gen_linktype(proto)
                }
                return (gen_cmp(OR_LINK, 0, BPF_W, (bpf_int32)proto));
 
+#ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                /*
                 * af field is host byte order in contrast to the rest of
@@ -2256,6 +2452,7 @@ gen_linktype(proto)
                        return gen_false();
                /*NOTREACHED*/
                break;
+#endif /* HAVE_NET_PFVAR_H */
 
        case DLT_ARCNET:
        case DLT_ARCNET_LINUX:
@@ -3133,22 +3330,22 @@ gen_dnhostop(addr, dir)
        tmp = gen_mcmp(OR_NET, 2, BPF_H,
            (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF));
        b1 = gen_cmp(OR_NET, 2 + 1 + offset_lh,
-           BPF_H, (bpf_int32)ntohs(addr));
+           BPF_H, (bpf_int32)ntohs((u_short)addr));
        gen_and(tmp, b1);
        /* Check for pad = 0, long header case */
        tmp = gen_mcmp(OR_NET, 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7);
-       b2 = gen_cmp(OR_NET, 2 + offset_lh, BPF_H, (bpf_int32)ntohs(addr));
+       b2 = gen_cmp(OR_NET, 2 + offset_lh, BPF_H, (bpf_int32)ntohs((u_short)addr));
        gen_and(tmp, b2);
        gen_or(b2, b1);
        /* Check for pad = 1, short header case */
        tmp = gen_mcmp(OR_NET, 2, BPF_H,
            (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF));
-       b2 = gen_cmp(OR_NET, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs(addr));
+       b2 = gen_cmp(OR_NET, 2 + 1 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
        gen_and(tmp, b2);
        gen_or(b2, b1);
        /* Check for pad = 0, short header case */
        tmp = gen_mcmp(OR_NET, 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7);
-       b2 = gen_cmp(OR_NET, 2 + offset_sh, BPF_H, (bpf_int32)ntohs(addr));
+       b2 = gen_cmp(OR_NET, 2 + offset_sh, BPF_H, (bpf_int32)ntohs((u_short)addr));
        gen_and(tmp, b2);
        gen_or(b2, b1);
 
@@ -3469,6 +3666,7 @@ gen_gateway(eaddr, alist, proto, dir)
                     break;
                case DLT_IEEE802_11:
                case DLT_IEEE802_11_RADIO_AVS:
+               case DLT_PPI:
                case DLT_IEEE802_11_RADIO:
                case DLT_PRISM_HEADER:
                     b0 = gen_wlanhostop(eaddr, Q_OR);
@@ -4274,6 +4472,9 @@ gen_protochain(v, proto, dir)
        if (linktype == DLT_IEEE802_11_RADIO)
                bpf_error("'protochain' not supported with radiotap headers");
 
+       if (linktype == DLT_PPI)
+               bpf_error("'protochain' not supported with PPI headers");
+
        no_optimize = 1; /*this code is not compatible with optimzer yet */
 
        /*
@@ -4533,6 +4734,7 @@ gen_protochain(v, proto, dir)
 #endif
 }
 
+
 /*
  * Generate code that checks whether the packet is a packet for protocol
  * <proto> and whether the type field in that protocol's header has
@@ -4822,6 +5024,7 @@ gen_scode(name, q)
                        case DLT_IEEE802_11_RADIO_AVS:
                        case DLT_IEEE802_11_RADIO:
                        case DLT_PRISM_HEADER:
+                       case DLT_PPI:
                                eaddr = pcap_ether_hostton(name);
                                if (eaddr == NULL)
                                        bpf_error(
@@ -5105,6 +5308,7 @@ gen_mcode(s1, s2, masklen, q)
                /* NOTREACHED */
        }
        /* NOTREACHED */
+       return NULL;
 }
 
 struct block *
@@ -5273,6 +5477,7 @@ gen_mcode6(s1, s2, masklen, q)
                bpf_error("invalid qualifier against IPv6 address");
                /* NOTREACHED */
        }
+       return NULL;
 }
 #endif /*INET6*/
 
@@ -5291,39 +5496,41 @@ gen_ecode(eaddr, q)
                 return gen_fhostop(eaddr, (int)q.dir);
             case DLT_IEEE802:
                 return gen_thostop(eaddr, (int)q.dir);
-           case DLT_IEEE802_11:
-           case DLT_IEEE802_11_RADIO_AVS:
-           case DLT_IEEE802_11_RADIO:
-           case DLT_PRISM_HEADER:
-                return gen_wlanhostop(eaddr, (int)q.dir);
-            case DLT_SUNATM:
-               if (is_lane) {
-                       /*
-                        * Check that the packet doesn't begin with an
-                        * LE Control marker.  (We've already generated
-                        * a test for LANE.)
-                        */
-                       tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
-                           0xFF00);
-                       gen_not(tmp);
-
-                       /*
-                        * Now check the MAC address.
-                        */
-                       b = gen_ehostop(eaddr, (int)q.dir);
-                       gen_and(tmp, b);
-                       return b;
-               }
-                break;
-           case DLT_IP_OVER_FC:
+                       case DLT_IEEE802_11:
+                       case DLT_IEEE802_11_RADIO_AVS:
+                       case DLT_IEEE802_11_RADIO:
+                       case DLT_PRISM_HEADER:
+                       case DLT_PPI:
+                               return gen_wlanhostop(eaddr, (int)q.dir);
+                       case DLT_SUNATM:
+                               if (is_lane) {
+                                       /*
+                                        * Check that the packet doesn't begin with an
+                                        * LE Control marker.  (We've already generated
+                                        * a test for LANE.)
+                                        */
+                                       tmp = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,
+                                               0xFF00);
+                                       gen_not(tmp);
+
+                                       /*
+                                        * Now check the MAC address.
+                                        */
+                                       b = gen_ehostop(eaddr, (int)q.dir);
+                                       gen_and(tmp, b);
+                                       return b;
+                               }
+                               break;
+                       case DLT_IP_OVER_FC:
                 return gen_ipfchostop(eaddr, (int)q.dir);
             default:
-               bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
+                               bpf_error("ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
                 break;
             }
        }
        bpf_error("ethernet address used in non-ether expression");
        /* NOTREACHED */
+       return NULL;
 }
 
 void
@@ -5735,6 +5942,16 @@ gen_arth(code, a0, a1)
 static int regused[BPF_MEMWORDS];
 static int curreg;
 
+/*
+ * Initialize the table of used registers and the current register.
+ */
+static void
+init_regs()
+{
+       curreg = 0;
+       memset(regused, 0, sizeof regused);
+}
+
 /*
  * Return the next free register.
  */
@@ -5753,6 +5970,7 @@ alloc_reg()
        }
        bpf_error("too many registers needed to evaluate expression");
        /* NOTREACHED */
+       return 0;
 }
 
 /*
@@ -5878,6 +6096,7 @@ gen_broadcast(proto)
                 case DLT_IEEE802_11:
                 case DLT_IEEE802_11_RADIO_AVS:
                 case DLT_IEEE802_11_RADIO:
+                               case DLT_PPI:
                 case DLT_PRISM_HEADER:
                     return gen_wlanhostop(ebroadcast, Q_DST);
                 case DLT_IP_OVER_FC:
@@ -5918,6 +6137,7 @@ gen_broadcast(proto)
        }
        bpf_error("only link-layer/IP broadcast filters supported");
        /* NOTREACHED */
+       return NULL;
 }
 
 /*
@@ -5971,6 +6191,7 @@ gen_multicast(proto)
                     return gen_mac_multicast(2);
                 case DLT_IEEE802_11:
                 case DLT_IEEE802_11_RADIO_AVS:
+                               case DLT_PPI:
                 case DLT_IEEE802_11_RADIO:
                 case DLT_PRISM_HEADER:
                     /*
@@ -6127,6 +6348,7 @@ gen_multicast(proto)
        }
        bpf_error("link-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channel");
        /* NOTREACHED */
+       return NULL;
 }
 
 /*
@@ -6172,10 +6394,12 @@ gen_inbound(dir)
                }
                break;
 
+#ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                b0 = gen_cmp(OR_LINK, offsetof(struct pfloghdr, dir), BPF_B,
                    (bpf_int32)((dir == 0) ? PF_IN : PF_OUT));
                break;
+#endif
 
        case DLT_PPP_PPPD:
                if (dir) {
@@ -6223,6 +6447,7 @@ gen_inbound(dir)
        return (b0);
 }
 
+#ifdef HAVE_NET_PFVAR_H
 /* PF firewall log matched interface */
 struct block *
 gen_pf_ifname(const char *ifname)
@@ -6332,6 +6557,55 @@ gen_pf_action(int action)
 
        return (b0);
 }
+#else /* !HAVE_NET_PFVAR_H */
+struct block *
+gen_pf_ifname(const char *ifname)
+{
+       bpf_error("libpcap was compiled without pf support");
+       /* NOTREACHED */
+       return (NULL);
+}
+
+struct block *
+gen_pf_ruleset(char *ruleset)
+{
+       bpf_error("libpcap was compiled on a machine without pf support");
+       /* NOTREACHED */
+       return (NULL);
+}
+
+struct block *
+gen_pf_rnr(int rnr)
+{
+       bpf_error("libpcap was compiled on a machine without pf support");
+       /* NOTREACHED */
+       return (NULL);
+}
+
+struct block *
+gen_pf_srnr(int srnr)
+{
+       bpf_error("libpcap was compiled on a machine without pf support");
+       /* NOTREACHED */
+       return (NULL);
+}
+
+struct block *
+gen_pf_reason(int reason)
+{
+       bpf_error("libpcap was compiled on a machine without pf support");
+       /* NOTREACHED */
+       return (NULL);
+}
+
+struct block *
+gen_pf_action(int action)
+{
+       bpf_error("libpcap was compiled on a machine without pf support");
+       /* NOTREACHED */
+       return (NULL);
+}
+#endif /* HAVE_NET_PFVAR_H */
 
 struct block *
 gen_acode(eaddr, q)
@@ -6344,6 +6618,7 @@ gen_acode(eaddr, q)
        }
        bpf_error("ARCnet address used in non-arc expression");
        /* NOTREACHED */
+       return NULL;
 }
 
 static struct block *
@@ -6767,14 +7042,16 @@ gen_mtp2type_abbrev(type)
        switch (type) {
 
        case M_FISU:
-               if (linktype != DLT_MTP2)
+               if ( (linktype != DLT_MTP2) &&
+                    (linktype != DLT_MTP2_WITH_PHDR) )
                        bpf_error("'fisu' supported only on MTP2");
                /* gen_ncmp(offrel, offset, size, mask, jtype, reverse, value) */
                b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JEQ, 0, 0);
                break;
 
        case M_LSSU:
-               if (linktype != DLT_MTP2)
+               if ( (linktype != DLT_MTP2) &&
+                    (linktype != DLT_MTP2_WITH_PHDR) )
                        bpf_error("'lssu' supported only on MTP2");
                b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 1, 2);
                b1 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 0);
@@ -6782,7 +7059,8 @@ gen_mtp2type_abbrev(type)
                break;
 
        case M_MSU:
-               if (linktype != DLT_MTP2)
+               if ( (linktype != DLT_MTP2) &&
+                    (linktype != DLT_MTP2_WITH_PHDR) )
                        bpf_error("'msu' supported only on MTP2");
                b0 = gen_ncmp(OR_PACKET, off_li, BPF_B, 0x3f, BPF_JGT, 0, 2);
                break;