net/ipv6/xfrm6_policy.c

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

File Facts

System
Linux kernel
Corpus path
net/ipv6/xfrm6_policy.c
Extension
.c
Size
7194 bytes
Lines
322
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

// SPDX-License-Identifier: GPL-2.0
/*
 * xfrm6_policy.c: based on xfrm4_policy.c
 *
 * Authors:
 *	Mitsuru KANDA @USAGI
 *	Kazunori MIYAZAWA @USAGI
 *	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
 *		IPv6 support
 *	YOSHIFUJI Hideaki
 *		Split up af-specific portion
 *
 */

#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <net/addrconf.h>
#include <net/dst.h>
#include <net/xfrm.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/l3mdev.h>

static struct dst_entry *xfrm6_dst_lookup(const struct xfrm_dst_lookup_params *params)
{
	struct flowi6 fl6;
	struct dst_entry *dst;
	int err;

	memset(&fl6, 0, sizeof(fl6));
	fl6.flowi6_l3mdev = l3mdev_master_ifindex_by_index(params->net,
							   params->oif);
	fl6.flowi6_mark = params->mark;
	memcpy(&fl6.daddr, params->daddr, sizeof(fl6.daddr));
	if (params->saddr)
		memcpy(&fl6.saddr, params->saddr, sizeof(fl6.saddr));

	fl6.flowi4_proto = params->ipproto;
	fl6.uli = params->uli;

	dst = ip6_route_output(params->net, NULL, &fl6);

	err = dst->error;
	if (dst->error) {
		dst_release(dst);
		dst = ERR_PTR(err);
	}

	return dst;
}

static int xfrm6_get_saddr(xfrm_address_t *saddr,
			   const struct xfrm_dst_lookup_params *params)
{
	struct dst_entry *dst;
	struct net_device *dev;
	struct inet6_dev *idev;
	int err;

	dst = xfrm6_dst_lookup(params);
	if (IS_ERR(dst))
		return -EHOSTUNREACH;

	idev = ip6_dst_idev(dst);
	if (!idev) {
		dst_release(dst);
		return -EHOSTUNREACH;
	}
	dev = idev->dev;
	err = ipv6_dev_get_saddr(dev_net(dev), dev, &params->daddr->in6, 0,
				 &saddr->in6);
	dst_release(dst);
	if (err)
		return -EHOSTUNREACH;
	return 0;
}

static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
			  const struct flowi *fl)
{
	struct rt6_info *rt = dst_rt6_info(xdst->route);

	xdst->u.dst.dev = dev;
	netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);

	xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
	if (!xdst->u.rt6.rt6i_idev) {
		netdev_put(dev, &xdst->u.dst.dev_tracker);

Annotation

Implementation Notes