net/netfilter/nft_payload.c

Source file repositories/reference/linux-study-clean/net/netfilter/nft_payload.c

File Facts

System
Linux kernel
Corpus path
net/netfilter/nft_payload.c
Extension
.c
Size
27289 bytes
Lines
1055
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct nft_payload_set {
	enum nft_payload_bases	base:8;
	u16			offset;
	u8			len;
	u8			sreg;
	u8			csum_type;
	u8			csum_offset;
	u8			csum_flags;
};

/* This is not struct vlan_hdr. */
struct nft_payload_vlan_hdr {
	__be16			h_vlan_proto;
	__be16			h_vlan_TCI;
};

static bool
nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u16 offset, u8 len,
		     int *vlan_hlen)
{
	struct nft_payload_vlan_hdr *vlanh;
	__be16 vlan_proto;
	u16 vlan_tci;

	if (offset >= offsetof(struct vlan_ethhdr, h_vlan_encapsulated_proto)) {
		*vlan_hlen = VLAN_HLEN;
		return true;
	}

	switch (offset) {
	case offsetof(struct vlan_ethhdr, h_vlan_proto):
		if (len == 2) {
			vlan_proto = nft_reg_load_be16(src);
			skb->vlan_proto = vlan_proto;
		} else if (len == 4) {
			vlanh = (struct nft_payload_vlan_hdr *)src;
			__vlan_hwaccel_put_tag(skb, vlanh->h_vlan_proto,
					       ntohs(vlanh->h_vlan_TCI));
		} else {
			return false;
		}
		break;
	case offsetof(struct vlan_ethhdr, h_vlan_TCI):
		if (len != 2)
			return false;

		vlan_tci = ntohs(nft_reg_load_be16(src));
		skb->vlan_tci = vlan_tci;
		break;
	default:
		return false;
	}

	return true;
}

static void nft_payload_set_eval(const struct nft_expr *expr,
				 struct nft_regs *regs,
				 const struct nft_pktinfo *pkt)
{
	const struct nft_payload_set *priv = nft_expr_priv(expr);
	const u32 *src = &regs->data[priv->sreg];
	int offset, csum_offset, vlan_hlen = 0;
	struct sk_buff *skb = pkt->skb;
	__wsum fsum, tsum;

	switch (priv->base) {
	case NFT_PAYLOAD_LL_HEADER:
		if (!skb_mac_header_was_set(skb))
			goto err;

		if (skb_vlan_tag_present(skb) &&
		    nft_payload_need_vlan_adjust(priv->offset, priv->len)) {
			if (!nft_payload_set_vlan(src, skb,
						  priv->offset, priv->len,
						  &vlan_hlen))
				goto err;

			if (!vlan_hlen)
				return;
		}

		offset = skb_mac_header(skb) - skb->data - vlan_hlen;
		break;
	case NFT_PAYLOAD_NETWORK_HEADER:
		offset = skb_network_offset(skb);
		break;
	case NFT_PAYLOAD_TRANSPORT_HEADER:
		if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
			goto err;

Annotation

Implementation Notes