net/ipv6/xfrm6_input.c

Source file repositories/reference/linux-study-clean/net/ipv6/xfrm6_input.c

File Facts

System
Linux kernel
Corpus path
net/ipv6/xfrm6_input.c
Extension
.c
Size
7679 bytes
Lines
326
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... */
	ip6h = ipv6_hdr(skb);
	ip6h->payload_len = htons(ntohs(ip6h->payload_len) - len);
	if (skb->len < ip6hlen + 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 xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
{
	int ret;

	if (skb->protocol == htons(ETH_P_IP))
		return xfrm4_udp_encap_rcv(sk, skb);

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

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

	return ret;
}

struct sk_buff *xfrm6_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;

	if (skb->protocol == htons(ETH_P_IP))
		return xfrm4_gro_udp_encap_rcv(sk, head, skb);

	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();

Annotation

Implementation Notes