+#if defined(SKF_AD_VLAN_TAG) && defined(SKF_AD_VLAN_TAG_PRESENT)
+static int skf_ad_vlan_tag_present_supported(int bpf_extensions) {
+ return bpf_extensions >= SKF_AD_VLAN_TAG_PRESENT;
+}
+
+static struct block *
+gen_vlan_bpf_extensions(int vlan_num) {
+ struct block *b0, *b1;
+ struct slist *s;
+ int val = 0, len, r;
+
+ len = sizeof(val);
+ r = getsockopt(bpf_pcap->fd, SOL_SOCKET, SO_BPF_EXTENSIONS, &val, &len);
+ if (r < 0)
+ return NULL;
+
+ if (!skf_ad_vlan_tag_present_supported(val))
+ return NULL;
+
+ /* generate new filter code based on extracting packet
+ * metadata */
+ s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT;
+
+ b0 = new_block(JMP(BPF_JEQ));
+ b0->stmts = s;
+ b0->s.k = 1;
+
+ if (vlan_num >= 0) {
+ s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;
+
+ b1 = new_block(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(int vlan_num) {
+ struct block *b0, *b1;
+
+ /* check for VLAN, including QinQ */
+ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+ (bpf_int32)ETHERTYPE_8021Q);
+ b1 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+ (bpf_int32)ETHERTYPE_8021QINQ);
+ gen_or(b0,b1);
+ b0 = b1;
+
+ /* If a specific VLAN is requested, check VLAN id */
+ if (vlan_num >= 0) {
+ b1 = gen_mcmp(OR_MACPL, 0, BPF_H,
+ (bpf_int32)vlan_num, 0x0fff);
+ gen_and(b0, b1);
+ b0 = b1;
+ }
+
+ off_macpl += 4;
+ off_linktype += 4;
+
+ return b0;
+}
+