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;
}
Esempio n. 3
0
File: br_vlan.c Progetto: 7799/linux
/* 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;
}