int bpf_pop_vlan(struct bpf_context *pctx) { struct bpf_dp_context *ctx = container_of(pctx, struct bpf_dp_context, context); struct sk_buff *skb = ctx->skb; if (unlikely(!skb)) return -EINVAL; ctx->context.vlan_tag = 0; if (vlan_tx_tag_present(skb)) { skb->vlan_tci = 0; } else { if (skb->protocol != htons(ETH_P_8021Q) || skb->len < VLAN_ETH_HLEN) return 0; if (!pskb_may_pull(skb, ETH_HLEN)) return 0; __skb_pull(skb, ETH_HLEN); skb = vlan_untag(skb); if (!skb) { ctx->skb = NULL; return -ENOMEM; } __skb_push(skb, ETH_HLEN); skb->vlan_tci = 0; ctx->context.length = skb->len; ctx->skb = skb; } /* move next vlan tag to hw accel tag */ if (skb->protocol != htons(ETH_P_8021Q) || skb->len < VLAN_ETH_HLEN) return 0; if (!pskb_may_pull(skb, ETH_HLEN)) return 0; __skb_pull(skb, ETH_HLEN); skb = vlan_untag(skb); if (!skb) { ctx->skb = NULL; return -ENOMEM; } __skb_push(skb, ETH_HLEN); ctx->context.vlan_tag = vlan_tx_tag_get(skb); ctx->context.length = skb->len; ctx->skb = skb; return 0; }
/* Strip the tag from the packet. Will return skb with tci set 0. */ static struct sk_buff *br_vlan_untag(struct sk_buff *skb) { if (skb->protocol != htons(ETH_P_8021Q)) { skb->vlan_tci = 0; return skb; } skb->vlan_tci = 0; skb = vlan_untag(skb); if (skb) skb->vlan_tci = 0; return skb; }
/* Called under RCU */ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, struct sk_buff *skb, u16 *vid) { int err; /* If VLAN filtering is disabled on the bridge, all packets are * permitted. */ if (!br->vlan_enabled) return true; /* If there are no vlan in the permitted list, all packets are * rejected. */ if (!v) goto drop; /* If vlan tx offload is disabled on bridge device and frame was * sent from vlan device on the bridge device, it does not have * HW accelerated vlan tag. */ if (unlikely(!vlan_tx_tag_present(skb) && (skb->protocol == htons(ETH_P_8021Q) || skb->protocol == htons(ETH_P_8021AD)))) { skb = vlan_untag(skb); if (unlikely(!skb)) return false; } err = br_vlan_get_tag(skb, vid); if (!*vid) { u16 pvid = br_get_pvid(v); /* Frame had a tag with VID 0 or did not have a tag. * See if pvid is set on this port. That tells us which * vlan untagged or priority-tagged traffic belongs to. */ if (pvid == VLAN_N_VID) goto drop; /* PVID is set on this port. Any untagged or priority-tagged * ingress frame is considered to belong to this vlan. */ *vid = pvid; if (likely(err)) /* Untagged Frame. */ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid); else /* Priority-tagged Frame. * At this point, We know that skb->vlan_tci had * VLAN_TAG_PRESENT bit and its VID field was 0x000. * We update only VID field and preserve PCP field. */ skb->vlan_tci |= pvid; return true; } /* Frame had a valid vlan tag. See if vlan is allowed */ if (test_bit(*vid, v->vlan_bitmap)) return true; drop: kfree_skb(skb); return false; }