net/xfrm/xfrm_nat_keepalive.c

Source file repositories/reference/linux-study-clean/net/xfrm/xfrm_nat_keepalive.c

File Facts

System
Linux kernel
Corpus path
net/xfrm/xfrm_nat_keepalive.c
Extension
.c
Size
7028 bytes
Lines
303
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

struct nat_keepalive {
	struct net *net;
	u16 family;
	xfrm_address_t saddr;
	xfrm_address_t daddr;
	__be16 encap_sport;
	__be16 encap_dport;
	__u32 smark;
};

static void nat_keepalive_init(struct nat_keepalive *ka, struct xfrm_state *x)
{
	ka->net = xs_net(x);
	ka->family = x->props.family;
	ka->saddr = x->props.saddr;
	ka->daddr = x->id.daddr;
	ka->encap_sport = x->encap->encap_sport;
	ka->encap_dport = x->encap->encap_dport;
	ka->smark = xfrm_smark_get(0, x);
}

static int nat_keepalive_send_ipv4(struct sk_buff *skb,
				   struct nat_keepalive *ka)
{
	struct net *net = ka->net;
	struct flowi4 fl4;
	struct rtable *rt;
	struct sock *sk;
	__u8 tos = 0;
	int err;

	flowi4_init_output(&fl4, 0 /* oif */, skb->mark, tos,
			   RT_SCOPE_UNIVERSE, IPPROTO_UDP, 0,
			   ka->daddr.a4, ka->saddr.a4, ka->encap_dport,
			   ka->encap_sport, sock_net_uid(net, NULL));

	rt = ip_route_output_key(net, &fl4);
	if (IS_ERR(rt))
		return PTR_ERR(rt);

	skb_dst_set(skb, &rt->dst);

	local_lock_nested_bh(&nat_keepalive_sk_ipv4.bh_lock);
	sk = this_cpu_read(nat_keepalive_sk_ipv4.sock);
	sock_net_set(sk, net);
	err = ip_build_and_send_pkt(skb, sk, fl4.saddr, fl4.daddr, NULL, tos);
	sock_net_set(sk, &init_net);
	local_unlock_nested_bh(&nat_keepalive_sk_ipv4.bh_lock);
	return err;
}

#if IS_ENABLED(CONFIG_IPV6)
static int nat_keepalive_send_ipv6(struct sk_buff *skb,
				   struct nat_keepalive *ka,
				   struct udphdr *uh)
{
	struct net *net = ka->net;
	struct dst_entry *dst;
	struct flowi6 fl6;
	struct sock *sk;
	__wsum csum;
	int err;

	csum = skb_checksum(skb, 0, skb->len, 0);
	uh->check = csum_ipv6_magic(&ka->saddr.in6, &ka->daddr.in6,
				    skb->len, IPPROTO_UDP, csum);
	if (uh->check == 0)
		uh->check = CSUM_MANGLED_0;

	memset(&fl6, 0, sizeof(fl6));
	fl6.flowi6_mark = skb->mark;
	fl6.saddr = ka->saddr.in6;
	fl6.daddr = ka->daddr.in6;
	fl6.flowi6_proto = IPPROTO_UDP;
	fl6.fl6_sport = ka->encap_sport;
	fl6.fl6_dport = ka->encap_dport;

	local_lock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock);
	sk = this_cpu_read(nat_keepalive_sk_ipv6.sock);
	sock_net_set(sk, net);
	dst = ip6_dst_lookup_flow(net, sk, &fl6, NULL);
	if (IS_ERR(dst)) {
		local_unlock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock);
		return PTR_ERR(dst);
	}

	skb_dst_set(skb, dst);
	err = ip6_xmit(sk, skb, &fl6, skb->mark, NULL, 0, 0);
	sock_net_set(sk, &init_net);
	local_unlock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock);

Annotation

Implementation Notes