net/ipv4/xfrm4_input.c

Source file repositories/reference/linux-study-clean/net/ipv4/xfrm4_input.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/xfrm4_input.c
Extension
.c
Size
5550 bytes
Lines
232
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration 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

if (len == 1 && udpdata[0] == 0xff) {
			return -EINVAL;
		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
			/* ESP Packet without Non-ESP header */
			len = sizeof(struct udphdr);
		} else
			/* Must be an IKE packet.. pass it through */
			return 1;
		break;
	}

	/* At this point we are sure that this is an ESPinUDP packet,
	 * so we need to remove 'len' bytes from the packet (the UDP
	 * header and optional ESP marker bytes) and then modify the
	 * protocol to ESP, and then call into the transform receiver.
	 */
	if (skb_unclone(skb, GFP_ATOMIC))
		return -EINVAL;

	/* Now we can update and verify the packet length... */
	iph = ip_hdr(skb);
	iphlen = iph->ihl << 2;
	iph->tot_len = htons(ntohs(iph->tot_len) - len);
	if (skb->len < iphlen + len) {
		/* packet is too small!?! */
		return -EINVAL;
	}

	/* pull the data buffer up to the ESP header and set the
	 * transport header to point to ESP.  Keep UDP on the stack
	 * for later.
	 */
	if (pull) {
		__skb_pull(skb, len);
		skb_reset_transport_header(skb);
	} else {
		skb_set_transport_header(skb, len);
	}

	/* process ESP */
	return 0;
}

/* If it's a keepalive packet, then just eat it.
 * If it's an encapsulated packet, then pass it to the
 * IPsec xfrm input.
 * Returns 0 if skb passed to xfrm or was dropped.
 * Returns >0 if skb should be passed to UDP.
 * Returns <0 if skb should be resubmitted (-ret is protocol)
 */
int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
{
	int ret;

	ret = __xfrm4_udp_encap_rcv(sk, skb, true);
	if (!ret)
		return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0,
				       udp_sk(sk)->encap_type);

	if (ret < 0) {
		kfree_skb(skb);
		return 0;
	}

	return ret;
}
EXPORT_SYMBOL(xfrm4_udp_encap_rcv);

struct sk_buff *xfrm4_gro_udp_encap_rcv(struct sock *sk, struct list_head *head,
					struct sk_buff *skb)
{
	int offset = skb_gro_offset(skb);
	const struct net_offload *ops;
	struct sk_buff *pp = NULL;
	int len, dlen;
	__u8 *udpdata;
	__be32 *udpdata32;

	len = skb->len - offset;
	dlen = offset + min(len, 8);
	udpdata = skb_gro_header(skb, dlen, offset);
	udpdata32 = (__be32 *)udpdata;
	if (unlikely(!udpdata))
		return NULL;

	rcu_read_lock();
	ops = rcu_dereference(inet_offloads[IPPROTO_ESP]);
	if (!ops || !ops->callbacks.gro_receive)
		goto out;

Annotation

Implementation Notes