// SPDX-License-Identifier: GPL-2.0
/*
* XFRM virtual interface
*
* Copyright (C) 2018 secunet Security Networks AG
*
* Author:
* Steffen Klassert <steffen.klassert@secunet.com>
*/
#include <linux/module.h>
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/sockios.h>
#include <linux/icmp.h>
#include <linux/if.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/net.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_link.h>
#include <linux/if_arp.h>
#include <linux/icmpv6.h>
#include <linux/init.h>
#include <linux/route.h>
#include <linux/rtnetlink.h>
#include <linux/netfilter_ipv6.h>
#include <linux/slab.h>
#include <linux/hash.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <net/icmp.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/ip_tunnels.h>
#include <net/addrconf.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
#include <net/dst_metadata.h>
#include <net/netns/generic.h>
#include <linux/etherdevice.h>
static int xfrmi_dev_init(struct net_device *dev);
static void xfrmi_dev_setup(struct net_device *dev);
static struct rtnl_link_ops xfrmi_link_ops __read_mostly;
static unsigned int xfrmi_net_id __read_mostly;
static const struct net_device_ops xfrmi_netdev_ops;
#define XFRMI_HASH_BITS 8
#define XFRMI_HASH_SIZE BIT(XFRMI_HASH_BITS)
struct xfrmi_net {
/* lists for storing interfaces in use */
struct xfrm_if __rcu *xfrmi[XFRMI_HASH_SIZE];
struct xfrm_if __rcu *collect_md_xfrmi;
};
static const struct nla_policy xfrm_lwt_policy[LWT_XFRM_MAX + 1] = {
[LWT_XFRM_IF_ID] = NLA_POLICY_MIN(NLA_U32, 1),
[LWT_XFRM_LINK] = NLA_POLICY_MIN(NLA_U32, 1),
};
static void xfrmi_destroy_state(struct lwtunnel_state *lwt)
{
}
static int xfrmi_build_state(struct net *net, struct nlattr *nla,
unsigned int family, const void *cfg,
struct lwtunnel_state **ts,
struct netlink_ext_ack *extack)
{
struct nlattr *tb[LWT_XFRM_MAX + 1];
struct lwtunnel_state *new_state;
struct xfrm_md_info *info;
int ret;
ret = nla_parse_nested(tb, LWT_XFRM_MAX, nla, xfrm_lwt_policy, extack);
if (ret < 0)
return ret;
if (!tb[LWT_XFRM_IF_ID]) {
NL_SET_ERR_MSG(extack, "if_id must be set");
return -EINVAL;
}
new_state = lwtunnel_state_alloc(sizeof(*info));
if (!new_state) {
NL_SET_ERR_MSG(extack, "failed to create encap info");
return -ENOMEM;
}
new_state->type = LWTUNNEL_ENCAP_XFRM;
info = lwt_xfrm_info(new_state);
info->if_id = nla_get_u32(tb[LWT_XFRM_IF_ID]);
if (tb[LWT_XFRM_LINK])
info->link = nla_get_u32(tb[LWT_XFRM_LINK]);
*ts = new_state;
return 0;
}
static int xfrmi_fill_encap_info(struct sk_buff *skb,
struct lwtunnel_state *lwt)
{
struct xfrm_md_info *info = lwt_xfrm_info(lwt);
if (nla_put_u32(skb, LWT_XFRM_IF_ID, info->if_id) ||
(info->