// SPDX-License-Identifier: GPL-2.0+
/*
* IPv6 IOAM implementation
*
* Author:
* Justin Iurman <justin.iurman@uliege.be>
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/ioam6.h>
#include <linux/ioam6_genl.h>
#include <linux/rhashtable.h>
#include <linux/netdevice.h>
#include <net/addrconf.h>
#include <net/genetlink.h>
#include <net/ioam6.h>
#include <net/sch_generic.h>
static void ioam6_ns_release(struct ioam6_namespace *ns)
{
kfree_rcu(ns, rcu);
}
static void ioam6_sc_release(struct ioam6_schema *sc)
{
kfree_rcu(sc, rcu);
}
static void ioam6_free_ns(void *ptr, void *arg)
{
struct ioam6_namespace *ns = (struct ioam6_namespace *)ptr;
if (ns)
ioam6_ns_release(ns);
}
static void ioam6_free_sc(void *ptr, void *arg)
{
struct ioam6_schema *sc = (struct ioam6_schema *)ptr;
if (sc)
ioam6_sc_release(sc);
}
static int ioam6_ns_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
{
const struct ioam6_namespace *ns = obj;
return (ns->id != *(__be16 *)arg->key);
}
static int ioam6_sc_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
{
const struct ioam6_schema *sc = obj;
return (sc->id != *(u32 *)arg->key);
}
static const struct rhashtable_params rht_ns_params = {
.key_len = sizeof(__be16),
.key_offset = offsetof(struct ioam6_namespace, id),
.head_offset = offsetof(struct ioam6_namespace, head),
.automatic_shrinking = true,
.obj_cmpfn = ioam6_ns_cmpfn,
};
static const struct rhashtable_params rht_sc_params = {
.key_len = sizeof(u32),
.key_offset = offsetof(struct ioam6_schema, id),
.head_offset = offsetof(struct ioam6_schema, head),
.automatic_shrinking = true,
.obj_cmpfn = ioam6_sc_cmpfn,
};
static struct genl_family ioam6_genl_family;
static const struct nla_policy ioam6_genl_policy_addns[] = {
[IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
[IOAM6_ATTR_NS_DATA] = { .type = NLA_U32 },
[IOAM6_ATTR_NS_DATA_WIDE] = { .type = NLA_U64 },
};
static const struct nla_policy ioam6_genl_policy_delns[] = {
[IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
};
static const struct nla_policy ioam6_genl_policy_addsc[] = {
[IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
[IOAM6_ATTR_SC_DATA] = { .type = NLA_BINARY,
.len = IOAM6_MAX_SCHEMA_DATA_LEN },
};
static const struct nla_policy ioam6_genl_policy_delsc[] = {
[IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
};
static const struct nla_policy ioam6_genl_policy_ns_sc[] = {
[IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
[IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
[IOAM6_ATTR_SC_NONE] = { .type = NLA_FLAG },
};
static int ioam6_genl_addns(struct sk_buff *skb, struct genl_info *info)
{
struct ioam6_pernet_data *nsdata;
struct ioam6_namespace *ns;
u64 data64;
u32 data32;
__be16 id;
int err;
if (!info->attrs[IOAM6_ATTR_NS_ID])
return -EINVAL;
id = cpu_to_be16