@@ -1933,6 +1933,7 @@ pcap_setfilter_linux_common(pcap_t *hand
return -1;
#endif /* SO_ATTACH_FILTER */
+ printf("Using %s filter\n", handle->md.use_bpf?"kernel":"userland");
return 0;
}
@@ -3072,23 +3073,6 @@ pcap_read_linux_mmap(pcap_t *handle, int
return -1;
}
- /* run filter on received packet
- * If the kernel filtering is enabled we need to run the
- * filter until all the frames present into the ring
- * at filter creation time are processed.
- * In such case md.use_bpf is used as a counter for the
- * packet we need to filter.
- * Note: alternatively it could be possible to stop applying
- * the filter when the ring became empty, but it can possibly
- * happen a lot later... */
- bp = (unsigned char*)h.raw + tp_mac;
- run_bpf = (!handle->md.use_bpf) ||
- ((handle->md.use_bpf>1) && handle->md.use_bpf--);
- if (run_bpf && handle->fcode.bf_insns &&
- (bpf_filter(handle->fcode.bf_insns, bp,
- tp_len, tp_snaplen) == 0))
- goto skip;
-
/*
* Do checks based on packet direction.
*/
@@ -3117,11 +3101,7 @@ pcap_read_linux_mmap(pcap_t *handle, int
goto skip;
}
- /* get required packet info from ring header */
- pcaphdr.ts.tv_sec = tp_sec;
- pcaphdr.ts.tv_usec = tp_usec;
- pcaphdr.caplen = tp_snaplen;
- pcaphdr.len = tp_len;
+ bp = (unsigned char*)h.raw + tp_mac;
/* if required build in place the sll header*/
if (handle->md.cooked) {
@@ -3163,27 +3143,58 @@ pcap_read_linux_mmap(pcap_t *handle, int
hdrp->sll_protocol = sll->sll_protocol;
/* update packet len */
- pcaphdr.caplen += SLL_HDR_LEN;
- pcaphdr.len += SLL_HDR_LEN;
+ tp_snaplen += SLL_HDR_LEN;
+ tp_len += SLL_HDR_LEN;
}
#ifdef HAVE_TPACKET2
- if (handle->md.tp_version == TPACKET_V2 && h.h2->tp_vlan_tci &&
- tp_snaplen >= 2 * ETH_ALEN) {
+ /*
+ * Add VLAN TAG if set in TPACKET2
+ */
+ if (handle->md.tp_version == TPACKET_V2 && (h.h2->tp_vlan_tci)) {
struct vlan_tag *tag;
+ int ethlen;
bp -= VLAN_TAG_LEN;
- memmove(bp, bp + VLAN_TAG_LEN, 2 * ETH_ALEN);
- tag = (struct vlan_tag *)(bp + 2 * ETH_ALEN);
+ if (!handle->md.cooked) {
+ ethlen = 2 * ETH_ALEN;
+ } else {
+ ethlen = sizeof(struct sll_header) - sizeof(sll->sll_protocol);
+ }
+ memmove(bp, bp + VLAN_TAG_LEN, ethlen);
+ tag = (struct vlan_tag *)(bp + ethlen);
+
tag->vlan_tpid = htons(ETH_P_8021Q);
tag->vlan_tci = htons(h.h2->tp_vlan_tci);
- pcaphdr.caplen += VLAN_TAG_LEN;
- pcaphdr.len += VLAN_TAG_LEN;
+ tp_snaplen += VLAN_TAG_LEN;
+ tp_len += VLAN_TAG_LEN;
}
#endif
+ /* run filter on received packet
+ * If the kernel filtering is enabled we need to run the
+ * filter until all the frames present into the ring
+ * at filter creation time are processed.
+ * In such case md.use_bpf is used as a counter for the
+ * packet we need to filter.
+ * Note: alternatively it could be possible to stop applying
+ * the filter when the ring became empty, but it can possibly
+ * happen a lot later... */
+ run_bpf = (!handle->md.use_bpf) ||
+ ((handle->md.use_bpf>1) && handle->md.use_bpf--);
+ if (run_bpf && handle->fcode.bf_insns &&
+ (bpf_filter(handle->fcode.bf_insns, bp,
+ tp_len, tp_snaplen) == 0))
+ goto skip;
+
+ /* get required packet info from ring header */
+ pcaphdr.ts.tv_sec = tp_sec;
+ pcaphdr.ts.tv_usec = tp_usec;
+ pcaphdr.caplen = tp_snaplen;
+ pcaphdr.len = tp_len;
+
/*
* The only way to tell the kernel to cut off the
* packet at a snapshot length is with a filter program;
@@ -4270,6 +4281,7 @@ iface_get_arptype(int fd, const char *de
}
#ifdef SO_ATTACH_FILTER
+static u_int orig_nl;
static int
fix_program(pcap_t *handle, struct sock_fprog *fcode, int is_mmapped)
{
@@ -4295,6 +4307,13 @@ fix_program(pcap_t *handle, struct sock_
fcode->len = len;
fcode->filter = (struct sock_filter *) f;
+ /*
+ * Is filter testing some encapsulated packets - VLAN, MPLS?
+ * put to userland after encapsulated packet is restored from TCI
+ */
+ if (handle->md.tp_version == TPACKET_V2 && orig_nl!=-1U)
+ return 0;
+
for (i = 0; i < len; ++i) {
p = &f[i];
/*