Commit c4a7a8d9 authored by Sven Eckelmann's avatar Sven Eckelmann Committed by Simon Wunderlich
Browse files

batman-adv: Move common genl doit code pre/post hooks



The commit ff4c92d8 ("genetlink: introduce pre_doit/post_doit hooks")
intoduced a mechanism to run specific code for doit hooks before/after the
hooks are run. Since all doit hooks are requiring the batadv softif, it
should be retrieved/freed in these helpers to simplify the code.

Signed-off-by: default avatarSven Eckelmann <sven@narfation.org>
Signed-off-by: default avatarSimon Wunderlich <sw@simonwunderlich.de>
parent 180cf62c
Loading
Loading
Loading
Loading
+100 −43
Original line number Diff line number Diff line
@@ -20,8 +20,10 @@
#include "main.h"

#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/genetlink.h>
@@ -54,6 +56,8 @@
#include "tp_meter.h"
#include "translation-table.h"

struct net;

struct genl_family batadv_netlink_family;

/* multicast groups */
@@ -61,6 +65,18 @@ enum batadv_netlink_multicast_groups {
	BATADV_NL_MCGRP_TPMETER,
};

/**
 * enum batadv_genl_ops_flags - flags for genl_ops's internal_flags
 */
enum batadv_genl_ops_flags {
	/**
	 * @BATADV_FLAG_NEED_MESH: request requires valid soft interface in
	 *  attribute BATADV_ATTR_MESH_IFINDEX and expects a pointer to it to be
	 *  saved in info->user_ptr[0]
	 */
	BATADV_FLAG_NEED_MESH = BIT(0),
};

static const struct genl_multicast_group batadv_netlink_mcgrps[] = {
	[BATADV_NL_MCGRP_TPMETER] = { .name = BATADV_NL_MCAST_GROUP_TPMETER },
};
@@ -329,40 +345,24 @@ err_genlmsg:
static int
batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info)
{
	struct net *net = genl_info_net(info);
	struct net_device *soft_iface;
	struct batadv_priv *bat_priv;
	struct batadv_priv *bat_priv = info->user_ptr[0];
	struct sk_buff *msg = NULL;
	u32 test_length;
	void *msg_head;
	int ifindex;
	u32 cookie;
	u8 *dst;
	int ret;

	if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
		return -EINVAL;

	if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS])
		return -EINVAL;

	if (!info->attrs[BATADV_ATTR_TPMETER_TEST_TIME])
		return -EINVAL;

	ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
	if (!ifindex)
		return -EINVAL;

	dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);

	test_length = nla_get_u32(info->attrs[BATADV_ATTR_TPMETER_TEST_TIME]);

	soft_iface = dev_get_by_index(net, ifindex);
	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
		ret = -ENODEV;
		goto out;
	}

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg) {
		ret = -ENOMEM;
@@ -377,15 +377,11 @@ batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info)
		goto out;
	}

	bat_priv = netdev_priv(soft_iface);
	batadv_tp_start(bat_priv, dst, test_length, &cookie);

	ret = batadv_netlink_tp_meter_put(msg, cookie);

 out:
	if (soft_iface)
		dev_put(soft_iface);

	if (ret) {
		if (msg)
			nlmsg_free(msg);
@@ -406,38 +402,17 @@ batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info)
static int
batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info)
{
	struct net *net = genl_info_net(info);
	struct net_device *soft_iface;
	struct batadv_priv *bat_priv;
	int ifindex;
	struct batadv_priv *bat_priv = info->user_ptr[0];
	u8 *dst;
	int ret = 0;

	if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
		return -EINVAL;

	if (!info->attrs[BATADV_ATTR_ORIG_ADDRESS])
		return -EINVAL;

	ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);
	if (!ifindex)
		return -EINVAL;

	dst = nla_data(info->attrs[BATADV_ATTR_ORIG_ADDRESS]);

	soft_iface = dev_get_by_index(net, ifindex);
	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
		ret = -ENODEV;
		goto out;
	}

	bat_priv = netdev_priv(soft_iface);
	batadv_tp_stop(bat_priv, dst, BATADV_TP_REASON_CANCEL);

out:
	if (soft_iface)
		dev_put(soft_iface);

	return ret;
}

@@ -545,6 +520,84 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb)
	return msg->len;
}

/**
 * batadv_get_softif_from_info() - Retrieve soft interface from genl attributes
 * @net: the applicable net namespace
 * @info: receiver information
 *
 * Return: Pointer to soft interface (with increased refcnt) on success, error
 *  pointer on error
 */
static struct net_device *
batadv_get_softif_from_info(struct net *net, struct genl_info *info)
{
	struct net_device *soft_iface;
	int ifindex;

	if (!info->attrs[BATADV_ATTR_MESH_IFINDEX])
		return ERR_PTR(-EINVAL);

	ifindex = nla_get_u32(info->attrs[BATADV_ATTR_MESH_IFINDEX]);

	soft_iface = dev_get_by_index(net, ifindex);
	if (!soft_iface)
		return ERR_PTR(-ENODEV);

	if (!batadv_softif_is_valid(soft_iface))
		goto err_put_softif;

	return soft_iface;

err_put_softif:
	dev_put(soft_iface);

	return ERR_PTR(-EINVAL);
}

/**
 * batadv_pre_doit() - Prepare batman-adv genl doit request
 * @ops: requested netlink operation
 * @skb: Netlink message with request data
 * @info: receiver information
 *
 * Return: 0 on success or negative error number in case of failure
 */
static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
			   struct genl_info *info)
{
	struct net *net = genl_info_net(info);
	struct net_device *soft_iface;
	struct batadv_priv *bat_priv;

	if (ops->internal_flags & BATADV_FLAG_NEED_MESH) {
		soft_iface = batadv_get_softif_from_info(net, info);
		if (IS_ERR(soft_iface))
			return PTR_ERR(soft_iface);

		bat_priv = netdev_priv(soft_iface);
		info->user_ptr[0] = bat_priv;
	}

	return 0;
}

/**
 * batadv_post_doit() - End batman-adv genl doit request
 * @ops: requested netlink operation
 * @skb: Netlink message with request data
 * @info: receiver information
 */
static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
			     struct genl_info *info)
{
	struct batadv_priv *bat_priv;

	if (ops->internal_flags & BATADV_FLAG_NEED_MESH && info->user_ptr[0]) {
		bat_priv = info->user_ptr[0];
		dev_put(bat_priv->soft_iface);
	}
}

static const struct genl_ops batadv_netlink_ops[] = {
	{
		.cmd = BATADV_CMD_GET_MESH_INFO,
@@ -557,12 +610,14 @@ static const struct genl_ops batadv_netlink_ops[] = {
		.flags = GENL_ADMIN_PERM,
		.policy = batadv_netlink_policy,
		.doit = batadv_netlink_tp_meter_start,
		.internal_flags = BATADV_FLAG_NEED_MESH,
	},
	{
		.cmd = BATADV_CMD_TP_METER_CANCEL,
		.flags = GENL_ADMIN_PERM,
		.policy = batadv_netlink_policy,
		.doit = batadv_netlink_tp_meter_cancel,
		.internal_flags = BATADV_FLAG_NEED_MESH,
	},
	{
		.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
@@ -639,6 +694,8 @@ struct genl_family batadv_netlink_family __ro_after_init = {
	.version = 1,
	.maxattr = BATADV_ATTR_MAX,
	.netnsok = true,
	.pre_doit = batadv_pre_doit,
	.post_doit = batadv_post_doit,
	.module = THIS_MODULE,
	.ops = batadv_netlink_ops,
	.n_ops = ARRAY_SIZE(batadv_netlink_ops),