]> The Tcpdump Group git mirrors - libpcap/commitdiff
Only add VLAN tags for Ethernet.
authorGuy Harris <[email protected]>
Sun, 19 Aug 2012 00:07:20 +0000 (17:07 -0700)
committerGuy Harris <[email protected]>
Sun, 19 Aug 2012 00:07:53 +0000 (17:07 -0700)
The code to insert VLAN tags was assuming Ethernet packets; that's not
the case, for example, if you're capturing on the "any" device, as the
packet headers aren't Ethernet headers.  Have a flag in the pcap
structure to indicate whether to check for and add VLAN tags, and set it
only if we're using PF_PACKET sockets, we're getting Ethernet headers,
and, if we're using the memory-mapped capture mechanism, it's not
version 1.

This should fix SourceForge bug 3525828.

pcap-int.h
pcap-linux.c

index 8444e62cee846ea087fd789d7b7e4cf1a95d52eb..a34ee8e7d9b4ea2c103e9f263785dee97b939522 100644 (file)
@@ -144,6 +144,7 @@ struct pcap_md {
        char    *mondevice;     /* mac80211 monitor device we created */
        u_char  *mmapbuf;       /* memory-mapped region pointer */
        size_t  mmapbuflen;     /* size of region */
+       int     add_vlan_tags;  /* 1 if we should insert VLAN tags */
        u_int   tp_version;     /* version of tpacket_hdr for mmaped ring */
        u_int   tp_hdrlen;      /* hdrlen of tpacket_hdr for mmaped ring */
        u_char  *oneshot_buffer; /* buffer for copy of packet */
index 8168e474778d9e9a7dc8d62216e69cf418c657ec..caf1a256342242e79380692a3d027a479044596f 100644 (file)
@@ -1618,32 +1618,34 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
        }
 
 #if defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI)
-       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-               struct tpacket_auxdata *aux;
-               unsigned int len;
-               struct vlan_tag *tag;
-
-               if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
-                   cmsg->cmsg_level != SOL_PACKET ||
-                   cmsg->cmsg_type != PACKET_AUXDATA)
-                       continue;
+       if (handle->md.add_vlan_tags) {
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                       struct tpacket_auxdata *aux;
+                       unsigned int len;
+                       struct vlan_tag *tag;
 
-               aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
-               if (aux->tp_vlan_tci == 0)
-                       continue;
+                       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) ||
+                           cmsg->cmsg_level != SOL_PACKET ||
+                           cmsg->cmsg_type != PACKET_AUXDATA)
+                               continue;
 
-               len = packet_len > iov.iov_len ? iov.iov_len : packet_len;
-               if (len < 2 * ETH_ALEN)
-                       break;
+                       aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg);
+                       if (aux->tp_vlan_tci == 0)
+                               continue;
 
-               bp -= VLAN_TAG_LEN;
-               memmove(bp, bp + VLAN_TAG_LEN, 2 * ETH_ALEN);
+                       len = packet_len > iov.iov_len ? iov.iov_len : packet_len;
+                       if (len < 2 * ETH_ALEN)
+                               break;
+
+                       bp -= VLAN_TAG_LEN;
+                       memmove(bp, bp + VLAN_TAG_LEN, 2 * ETH_ALEN);
 
-               tag = (struct vlan_tag *)(bp + 2 * ETH_ALEN);
-               tag->vlan_tpid = htons(ETH_P_8021Q);
-               tag->vlan_tci = htons(aux->tp_vlan_tci);
+                       tag = (struct vlan_tag *)(bp + 2 * ETH_ALEN);
+                       tag->vlan_tpid = htons(ETH_P_8021Q);
+                       tag->vlan_tci = htons(aux->tp_vlan_tci);
 
-               packet_len += VLAN_TAG_LEN;
+                       packet_len += VLAN_TAG_LEN;
+               }
        }
 #endif /* defined(HAVE_PACKET_AUXDATA) && defined(HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI) */
 #endif /* HAVE_PF_PACKET_SOCKETS */
@@ -3181,6 +3183,19 @@ activate_new(pcap_t *handle)
        }
        handle->bufsize = handle->snapshot;
 
+       /*
+        * Only enable the insertion of VLAN tags if the link-layer
+        * header type is Ethernet.  If it should be supported on
+        * any other link-layer type, the code that inserts them
+        * must be modified to insert them in the proper place, which
+        * differs from link-layer header type to link-layer header
+        * type.
+        */
+       if (handle->linktype == DLT_EN10MB)
+               handle->md.add_vlan_tags = 1;
+       else
+               handle->md.add_vlan_tags = 0;
+
        /* Save the socket FD in the pcap structure */
        handle->fd = sock_fd;
 
@@ -3268,6 +3283,14 @@ activate_mmap(pcap_t *handle, int *status)
        handle->getnonblock_op = pcap_getnonblock_mmap;
        handle->oneshot_callback = pcap_oneshot_mmap;
        handle->selectable_fd = handle->fd;
+
+       /*
+        * We only support inserting VLAN tags for tpacket V2;
+        * if we're using v1, disable it.
+        */
+       if (handle->md.tp_version == TPACKET_V1)
+               handle->md.add_vlan_tags = 0;
+
        return 1;
 }
 #else /* HAVE_PACKET_RING */
@@ -4020,7 +4043,7 @@ pcap_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback,
                }
 
 #ifdef HAVE_TPACKET2
-               if (handle->md.tp_version == TPACKET_V2 && h.h2->tp_vlan_tci &&
+               if (handle->md.add_vlan_tags && h.h2->tp_vlan_tci &&
                    tp_snaplen >= 2 * ETH_ALEN) {
                        struct vlan_tag *tag;
 
@@ -5213,6 +5236,11 @@ activate_old(pcap_t *handle)
         */
        handle->offset   = 0;
 
+       /*
+        * No support for getting VLAN tags to insert.
+        */
+       handle->md.add_vlan_tags = 0;
+
        return 1;
 }