]> The Tcpdump Group git mirrors - libpcap/blobdiff - gencode.c
Clean up the ether_hostton() stuff.
[libpcap] / gencode.c
index b0cadc32d702e6483c46d4e440a618c6d76d0d46..5a91747d88b6cd76e4c9678d121e9fe6f974ed30 100644 (file)
--- a/gencode.c
+++ b/gencode.c
  */
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
+#include <pcap-types.h>
 #ifdef _WIN32
-#include <pcap-stdinc.h>
-#else /* _WIN32 */
-#if HAVE_INTTYPES_H
-#include <inttypes.h>
-#elif HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#ifdef HAVE_SYS_BITYPES_H
-#include <sys/bitypes.h>
-#endif
-#include <sys/types.h>
-#include <sys/socket.h>
-#endif /* _WIN32 */
-
-#ifndef _WIN32
-
-#ifdef __NetBSD__
-#include <sys/param.h>
-#endif
+  #include <ws2tcpip.h>
+#else
+  #include <sys/socket.h>
 
-#include <netinet/in.h>
-#include <arpa/inet.h>
+  #ifdef __NetBSD__
+    #include <sys/param.h>
+  #endif
 
+  #include <netinet/in.h>
+  #include <arpa/inet.h>
 #endif /* _WIN32 */
 
 #include <stdlib.h>
@@ -102,9 +90,9 @@ struct in6_addr
   {
     union
       {
-       u_int8_t                u6_addr8[16];
-       u_int16_t       u6_addr16[8];
-       u_int32_t       u6_addr32[4];
+       uint8_t         u6_addr8[16];
+       uint16_t        u6_addr16[8];
+       uint32_t        u6_addr32[4];
       } in6_u;
 #define s6_addr                        in6_u.u6_addr8
 #define s6_addr16              in6_u.u6_addr16
@@ -121,8 +109,8 @@ typedef unsigned short      sa_family_t;
 struct sockaddr_in6
   {
     __SOCKADDR_COMMON (sin6_);
-    u_int16_t sin6_port;               /* Transport layer port # */
-    u_int32_t sin6_flowinfo;   /* IPv6 flow information */
+    uint16_t sin6_port;                /* Transport layer port # */
+    uint32_t sin6_flowinfo;    /* IPv6 flow information */
     struct in6_addr sin6_addr; /* IPv6 address */
   };
 
@@ -357,6 +345,11 @@ struct _compiler_state {
         */
        int is_geneve;
 
+       /*
+        * TRUE if we need variable length part of VLAN offset
+        */
+       int is_vlan_vloffset;
+
        /*
         * These are offsets for the ATM pseudo-header.
         */
@@ -523,7 +516,8 @@ static struct block *gen_host6(compiler_state_t *, struct in6_addr *,
     struct in6_addr *, int, int, int);
 #endif
 #ifndef INET6
-static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int);
+static struct block *gen_gateway(compiler_state_t *, const u_char *,
+    bpf_u_int32 **, int, int);
 #endif
 static struct block *gen_ipfrag(compiler_state_t *);
 static struct block *gen_portatom(compiler_state_t *, int, bpf_int32);
@@ -663,6 +657,9 @@ int
 pcap_compile(pcap_t *p, struct bpf_program *program,
             const char *buf, int optimize, bpf_u_int32 mask)
 {
+#ifdef _WIN32
+       static int done = 0;
+#endif
        compiler_state_t cstate;
        const char * volatile xbuf = buf;
        yyscan_t scanner = NULL;
@@ -670,14 +667,6 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        u_int len;
        int  rc;
 
-#ifdef _WIN32
-       static int done = 0;
-
-       if (!done)
-               pcap_wsockinit();
-       done = 1;
-#endif
-
        /*
         * If this pcap_t hasn't been activated, it doesn't have a
         * link-layer type, so we can't use it.
@@ -685,12 +674,41 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
        if (!p->activated) {
                pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "not-yet-activated pcap_t passed to pcap_compile");
-               rc = -1;
-               goto quit;
+               return (-1);
        }
+
+#ifdef _WIN32
+       if (!done)
+               pcap_wsockinit();
+       done = 1;
+#endif
+
+#ifdef HAVE_REMOTE
+       /*
+        * If the device on which we're capturing need to be notified
+        * that a new filter is being compiled, do so.
+        *
+        * This allows them to save a copy of it, in case, for example,
+        * they're implementing a form of remote packet capture, and
+        * want the remote machine to filter out the packets in which
+        * it's sending the packets it's captured.
+        *
+        * XXX - the fact that we happen to be compiling a filter
+        * doesn't necessarily mean we'll be installing it as the
+        * filter for this pcap_t; we might be running it from userland
+        * on captured packets to do packet classification.  We really
+        * need a better way of handling this, but this is all that
+        * the WinPcap code did.
+        */
+       if (p->save_current_filter_op != NULL)
+               (p->save_current_filter_op)(p, buf);
+#endif
+
        initchunks(&cstate);
        cstate.no_optimize = 0;
+#ifdef INET6
        cstate.ai = NULL;
+#endif
        cstate.ic.root = NULL;
        cstate.ic.cur_mark = 0;
        cstate.bpf_pcap = p;
@@ -1071,6 +1089,11 @@ init_linktype(compiler_state_t *cstate, pcap_t *p)
         */
        cstate->is_geneve = 0;
 
+       /*
+        * No variable length VLAN offset by default
+        */
+       cstate->is_vlan_vloffset = 0;
+
        /*
         * And assume we're not doing SS7.
         */
@@ -1994,6 +2017,41 @@ gen_ether_linktype(compiler_state_t *cstate, int proto)
        }
 }
 
+static struct block *
+gen_loopback_linktype(compiler_state_t *cstate, int proto)
+{
+       /*
+        * For DLT_NULL, the link-layer header is a 32-bit word
+        * containing an AF_ value in *host* byte order, and for
+        * DLT_ENC, the link-layer header begins with a 32-bit
+        * word containing an AF_ value in host byte order.
+        *
+        * In addition, if we're reading a saved capture file,
+        * the host byte order in the capture may not be the
+        * same as the host byte order on this machine.
+        *
+        * For DLT_LOOP, the link-layer header is a 32-bit
+        * word containing an AF_ value in *network* byte order.
+        */
+       if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) {
+               /*
+                * The AF_ value is in host byte order, but the BPF
+                * interpreter will convert it to network byte order.
+                *
+                * If this is a save file, and it's from a machine
+                * with the opposite byte order to ours, we byte-swap
+                * the AF_ value.
+                *
+                * Then we run it through "htonl()", and generate
+                * code to compare against the result.
+                */
+               if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
+                       proto = SWAPLONG(proto);
+               proto = htonl(proto);
+       }
+       return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
+}
+
 /*
  * "proto" is an Ethernet type value and for IPNET, if it is not IPv4
  * or IPv6 then we have an error.
@@ -2762,6 +2820,28 @@ insert_compute_vloffsets(compiler_state_t *cstate, struct block *b)
                break;
        }
 
+       /*
+        * If there there is no initialization yet and we need variable
+        * length offsets for VLAN, initialize them to zero
+        */
+       if (s == NULL && cstate->is_vlan_vloffset) {
+               struct slist *s2;
+
+               if (cstate->off_linkpl.reg == -1)
+                       cstate->off_linkpl.reg = alloc_reg(cstate);
+               if (cstate->off_linktype.reg == -1)
+                       cstate->off_linktype.reg = alloc_reg(cstate);
+
+               s = new_stmt(cstate, BPF_LD|BPF_W|BPF_IMM);
+               s->s.k = 0;
+               s2 = new_stmt(cstate, BPF_ST);
+               s2->s.k = cstate->off_linkpl.reg;
+               sappend(s, s2);
+               s2 = new_stmt(cstate, BPF_ST);
+               s2->s.k = cstate->off_linktype.reg;
+               sappend(s, s2);
+       }
+
        /*
         * If we have any offset-loading code, append all the
         * existing statements in the block to those statements,
@@ -2930,6 +3010,14 @@ gen_prevlinkhdr_check(compiler_state_t *cstate)
        /*NOTREACHED*/
 }
 
+/*
+ * The three different values we should check for when checking for an
+ * IPv6 packet with DLT_NULL.
+ */
+#define BSD_AFNUM_INET6_BSD    24      /* NetBSD, OpenBSD, BSD/OS, Npcap */
+#define BSD_AFNUM_INET6_FREEBSD        28      /* FreeBSD */
+#define BSD_AFNUM_INET6_DARWIN 30      /* OS X, iOS, other Darwin-based OSes */
+
 /*
  * Generate code to match a particular packet type by matching the
  * link-layer type field or fields in the 802.2 LLC header.
@@ -3150,39 +3238,71 @@ gen_linktype(compiler_state_t *cstate, int proto)
        case DLT_NULL:
        case DLT_LOOP:
        case DLT_ENC:
-               /*
-                * For DLT_NULL, the link-layer header is a 32-bit
-                * word containing an AF_ value in *host* byte order,
-                * and for DLT_ENC, the link-layer header begins
-                * with a 32-bit work containing an AF_ value in
-                * host byte order.
-                *
-                * In addition, if we're reading a saved capture file,
-                * the host byte order in the capture may not be the
-                * same as the host byte order on this machine.
-                *
-                * For DLT_LOOP, the link-layer header is a 32-bit
-                * word containing an AF_ value in *network* byte order.
-                *
-                * XXX - AF_ values may, unfortunately, be platform-
-                * dependent; for example, FreeBSD's AF_INET6 is 24
-                * whilst NetBSD's and OpenBSD's is 26.
-                *
-                * This means that, when reading a capture file, just
-                * checking for our AF_INET6 value won't work if the
-                * capture file came from another OS.
-                */
                switch (proto) {
 
                case ETHERTYPE_IP:
-                       proto = AF_INET;
-                       break;
+                       return (gen_loopback_linktype(cstate, AF_INET));
 
-#ifdef INET6
                case ETHERTYPE_IPV6:
-                       proto = AF_INET6;
-                       break;
-#endif
+                       /*
+                        * AF_ values may, unfortunately, be platform-
+                        * dependent; AF_INET isn't, because everybody
+                        * used 4.2BSD's value, but AF_INET6 is, because
+                        * 4.2BSD didn't have a value for it (given that
+                        * IPv6 didn't exist back in the early 1980's),
+                        * and they all picked their own values.
+                        *
+                        * This means that, if we're reading from a
+                        * savefile, we need to check for all the
+                        * possible values.
+                        *
+                        * If we're doing a live capture, we only need
+                        * to check for this platform's value; however,
+                        * Npcap uses 24, which isn't Windows's AF_INET6
+                        * value.  (Given the multiple different values,
+                        * programs that read pcap files shouldn't be
+                        * checking for their platform's AF_INET6 value
+                        * anyway, they should check for all of the
+                        * possible values. and they might as well do
+                        * that even for live captures.)
+                        */
+                       if (cstate->bpf_pcap->rfile != NULL) {
+                               /*
+                                * Savefile - check for all three
+                                * possible IPv6 values.
+                                */
+                               b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_BSD);
+                               b1 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_FREEBSD);
+                               gen_or(b0, b1);
+                               b0 = gen_loopback_linktype(cstate, BSD_AFNUM_INET6_DARWIN);
+                               gen_or(b0, b1);
+                               return (b1);
+                       } else {
+                               /*
+                                * Live capture, so we only need to
+                                * check for the value used on this
+                                * platform.
+                                */
+#ifdef _WIN32
+                               /*
+                                * Npcap doesn't use Windows's AF_INET6,
+                                * as that collides with AF_IPX on
+                                * some BSDs (both have the value 23).
+                                * Instead, it uses 24.
+                                */
+                               return (gen_loopback_linktype(cstate, 24));
+#else /* _WIN32 */
+#ifdef AF_INET6
+                               return (gen_loopback_linktype(cstate, AF_INET6));
+#else /* AF_INET6 */
+                               /*
+                                * I guess this platform doesn't support
+                                * IPv6, so we just reject all packets.
+                                */
+                               return gen_false(cstate);
+#endif /* AF_INET6 */
+#endif /* _WIN32 */
+                       }
 
                default:
                        /*
@@ -3193,25 +3313,6 @@ gen_linktype(compiler_state_t *cstate, int proto)
                        return gen_false(cstate);
                }
 
-               if (cstate->linktype == DLT_NULL || cstate->linktype == DLT_ENC) {
-                       /*
-                        * The AF_ value is in host byte order, but
-                        * the BPF interpreter will convert it to
-                        * network byte order.
-                        *
-                        * If this is a save file, and it's from a
-                        * machine with the opposite byte order to
-                        * ours, we byte-swap the AF_ value.
-                        *
-                        * Then we run it through "htonl()", and
-                        * generate code to compare against the result.
-                        */
-                       if (cstate->bpf_pcap->rfile != NULL && cstate->bpf_pcap->swapped)
-                               proto = SWAPLONG(proto);
-                       proto = htonl(proto);
-               }
-               return (gen_cmp(cstate, OR_LINKHDR, 0, BPF_W, (bpf_int32)proto));
-
 #ifdef HAVE_NET_PFVAR_H
        case DLT_PFLOG:
                /*
@@ -3787,7 +3888,7 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
 {
        struct block *b0, *b1;
        u_int offset;
-       u_int32_t *a, *m;
+       uint32_t *a, *m;
 
        switch (dir) {
 
@@ -3816,8 +3917,8 @@ gen_hostop6(compiler_state_t *cstate, struct in6_addr *addr,
                abort();
        }
        /* this order is important */
-       a = (u_int32_t *)addr;
-       m = (u_int32_t *)mask;
+       a = (uint32_t *)addr;
+       m = (uint32_t *)mask;
        b1 = gen_mcmp(cstate, OR_LINKPL, offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3]));
        b0 = gen_mcmp(cstate, OR_LINKPL, offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2]));
        gen_and(b0, b1);
@@ -4846,11 +4947,8 @@ gen_host6(compiler_state_t *cstate, struct in6_addr *addr,
 
 #ifndef INET6
 static struct block *
-gen_gateway(eaddr, alist, proto, dir)
-       const u_char *eaddr;
-       bpf_u_int32 **alist;
-       int proto;
-       int dir;
+gen_gateway(compiler_state_t *cstate, const u_char *eaddr, bpf_u_int32 **alist,
+    int proto, int dir)
 {
        struct block *b0, *b1, *tmp;
 
@@ -6414,7 +6512,7 @@ gen_scode(compiler_state_t *cstate, const char *name, struct qual q)
                alist = pcap_nametoaddr(name);
                if (alist == NULL || *alist == NULL)
                        bpf_error(cstate, "unknown host '%s'", name);
-               b = gen_gateway(eaddr, alist, proto, dir);
+               b = gen_gateway(cstate, eaddr, alist, proto, dir);
                free(eaddr);
                return b;
 #else
@@ -6607,7 +6705,7 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
        struct in6_addr *addr;
        struct in6_addr mask;
        struct block *b;
-       u_int32_t *a, *m;
+       uint32_t *a, *m;
 
        if (s2)
                bpf_error(cstate, "no mask %s supported", s2);
@@ -6629,8 +6727,8 @@ gen_mcode6(compiler_state_t *cstate, const char *s1, const char *s2,
                        (0xff << (8 - masklen % 8)) & 0xff;
        }
 
-       a = (u_int32_t *)addr;
-       m = (u_int32_t *)&mask;
+       a = (uint32_t *)addr;
+       m = (uint32_t *)&mask;
        if ((a[0] & ~m[0]) || (a[1] & ~m[1])
         || (a[2] & ~m[2]) || (a[3] & ~m[3])) {
                bpf_error(cstate, "non-network bits set in \"%s/%d\"", s1, masklen);
@@ -7891,11 +7989,143 @@ gen_ahostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
        /* NOTREACHED */
 }
 
+static struct block *
+gen_vlan_tpid_test(compiler_state_t *cstate)
+{
+       struct block *b0, *b1;
+
+       /* check for VLAN, including QinQ */
+       b0 = gen_linktype(cstate, ETHERTYPE_8021Q);
+       b1 = gen_linktype(cstate, ETHERTYPE_8021AD);
+       gen_or(b0,b1);
+       b0 = b1;
+       b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ);
+       gen_or(b0,b1);
+
+       return b1;
+}
+
+static struct block *
+gen_vlan_vid_test(compiler_state_t *cstate, int vlan_num)
+{
+       return gen_mcmp(cstate, OR_LINKPL, 0, BPF_H, (bpf_int32)vlan_num, 0x0fff);
+}
+
+static struct block *
+gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num)
+{
+       struct block *b0, *b1;
+
+       b0 = gen_vlan_tpid_test(cstate);
+
+       if (vlan_num >= 0) {
+               b1 = gen_vlan_vid_test(cstate, vlan_num);
+               gen_and(b0, b1);
+               b0 = b1;
+       }
+
+       /*
+        * Both payload and link header type follow the VLAN tags so that
+        * both need to be updated.
+        */
+       cstate->off_linkpl.constant_part += 4;
+       cstate->off_linktype.constant_part += 4;
+
+       return b0;
+}
+
 #if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
+/* add v to variable part of off */
+static void
+gen_vlan_vloffset_add(compiler_state_t *cstate, bpf_abs_offset *off, int v, struct slist *s)
+{
+       struct slist *s2;
+
+       if (!off->is_variable)
+               off->is_variable = 1;
+       if (off->reg == -1)
+               off->reg = alloc_reg(cstate);
+
+       s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
+       s2->s.k = off->reg;
+       sappend(s, s2);
+       s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_IMM);
+       s2->s.k = v;
+       sappend(s, s2);
+       s2 = new_stmt(cstate, BPF_ST);
+       s2->s.k = off->reg;
+       sappend(s, s2);
+}
+
+/*
+ * patch block b_tpid (VLAN TPID test) to update variable parts of link payload
+ * and link type offsets first
+ */
+static void
+gen_vlan_patch_tpid_test(compiler_state_t *cstate, struct block *b_tpid)
+{
+       struct slist s;
+
+       /* offset determined at run time, shift variable part */
+       s.next = NULL;
+       cstate->is_vlan_vloffset = 1;
+       gen_vlan_vloffset_add(cstate, &cstate->off_linkpl, 4, &s);
+       gen_vlan_vloffset_add(cstate, &cstate->off_linktype, 4, &s);
+
+       /* we get a pointer to a chain of or-ed blocks, patch first of them */
+       sappend(s.next, b_tpid->head->stmts);
+       b_tpid->head->stmts = s.next;
+}
+
+/*
+ * patch block b_vid (VLAN id test) to load VID value either from packet
+ * metadata (using BPF extensions) if SKF_AD_VLAN_TAG_PRESENT is true
+ */
+static void
+gen_vlan_patch_vid_test(compiler_state_t *cstate, struct block *b_vid)
+{
+       struct slist *s, *s2, *sjeq;
+       unsigned cnt;
+
+       s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+       s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+       /* true -> next instructions, false -> beginning of b_vid */
+       sjeq = new_stmt(cstate, JMP(BPF_JEQ));
+       sjeq->s.k = 1;
+       sjeq->s.jf = b_vid->stmts;
+       sappend(s, sjeq);
+
+       s2 = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
+       s2->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
+       sappend(s, s2);
+       sjeq->s.jt = s2;
+
+       /* jump to the test in b_vid (bypass loading VID from packet data) */
+       cnt = 0;
+       for (s2 = b_vid->stmts; s2; s2 = s2->next)
+               cnt++;
+       s2 = new_stmt(cstate, JMP(BPF_JA));
+       s2->s.k = cnt;
+       sappend(s, s2);
+
+       /* insert our statements at the beginning of b_vid */
+       sappend(s, b_vid->stmts);
+       b_vid->stmts = s;
+}
+
+/*
+ * Generate check for "vlan" or "vlan <id>" on systems with support for BPF
+ * extensions.  Even if kernel supports VLAN BPF extensions, (outermost) VLAN
+ * tag can be either in metadata or in packet data; therefore if the
+ * SKF_AD_VLAN_TAG_PRESENT test is negative, we need to check link
+ * header for VLAN tag. As the decision is done at run time, we need
+ * update variable part of the offsets
+ */
 static struct block *
 gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
 {
-        struct block *b0, *b1;
+        struct block *b0, *b_tpid, *b_vid;
         struct slist *s;
 
         /* generate new filter code based on extracting packet
@@ -7907,58 +8137,33 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
         b0->stmts = s;
         b0->s.k = 1;
 
-        if (vlan_num >= 0) {
-                s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
-                s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
-
-                b1 = new_block(cstate, JMP(BPF_JEQ));
-                b1->stmts = s;
-                b1->s.k = (bpf_int32) vlan_num;
-
-                gen_and(b0,b1);
-                b0 = b1;
-        }
-
-        return b0;
-}
-#endif
-
-static struct block *
-gen_vlan_no_bpf_extensions(compiler_state_t *cstate, int vlan_num)
-{
-        struct block *b0, *b1;
-
-        /* check for VLAN, including QinQ */
-        b0 = gen_linktype(cstate, ETHERTYPE_8021Q);
-        b1 = gen_linktype(cstate, ETHERTYPE_8021AD);
-        gen_or(b0,b1);
-        b0 = b1;
-        b1 = gen_linktype(cstate, ETHERTYPE_8021QINQ);
-        gen_or(b0,b1);
-        b0 = b1;
-
-        /* If a specific VLAN is requested, check VLAN id */
-        if (vlan_num >= 0) {
-                b1 = gen_mcmp(cstate, OR_LINKPL, 0, BPF_H,
-                              (bpf_int32)vlan_num, 0x0fff);
-                gen_and(b0, b1);
-                b0 = b1;
-        }
-
        /*
-        * The payload follows the full header, including the
-        * VLAN tags, so skip past this VLAN tag.
+        * This is tricky. We need to insert the statements updating variable
+        * parts of offsets before the the traditional TPID and VID tests so
+        * that they are called whenever SKF_AD_VLAN_TAG_PRESENT fails but
+        * we do not want this update to affect those checks. That's why we
+        * generate both test blocks first and insert the statements updating
+        * variable parts of both offsets after that. This wouldn't work if
+        * there already were variable length link header when entering this
+        * function but gen_vlan_bpf_extensions() isn't called in that case.
         */
-        cstate->off_linkpl.constant_part += 4;
-
-       /*
-        * The link-layer type information follows the VLAN tags, so
-        * skip past this VLAN tag.
-        */
-        cstate->off_linktype.constant_part += 4;
+       b_tpid = gen_vlan_tpid_test(cstate);
+       if (vlan_num >= 0)
+               b_vid = gen_vlan_vid_test(cstate, vlan_num);
+
+       gen_vlan_patch_tpid_test(cstate, b_tpid);
+       gen_or(b0, b_tpid);
+       b0 = b_tpid;
+
+       if (vlan_num >= 0) {
+               gen_vlan_patch_vid_test(cstate, b_vid);
+               gen_and(b0, b_vid);
+               b0 = b_vid;
+       }
 
         return b0;
 }
+#endif
 
 /*
  * support IEEE 802.1Q VLAN trunk over ethernet