Commit bf46390f authored by David S. Miller's avatar David S. Miller

Merge branch 'genetlink-per-op-type-policies'

Jakub Kicinski says:

====================
genetlink: support per op type policies

While writing new genetlink families I was increasingly annoyed by the fact
that we don't support different policies for do and dump callbacks.
This makes it hard to do proper input validation for dumps which usually
have a lot more narrow range of accepted attributes.

There is also a minor inconvenience of not supporting different per_doit
and post_doit callbacks per op.

This series addresses those problems by introducing another op format.

v3:
 - minor fixes to patch 12 after I took it for a spin with a real family
 - adjust commit msg in patch 8
v2: https://lore.kernel.org/all/20221102213338.194672-1-kuba@kernel.org/
 - wait for net changes to propagate
 - restore the missing comment in patch 1
 - drop extra space in patch 3
 - improve commit message in patch 4
v1: https://lore.kernel.org/all/20221018230728.1039524-1-kuba@kernel.org/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e2dbda0f aba22ca8
......@@ -18,12 +18,11 @@ struct genl_multicast_group {
u8 flags;
};
struct genl_ops;
struct genl_split_ops;
struct genl_info;
/**
* struct genl_family - generic netlink family
* @id: protocol family identifier (private)
* @hdrsize: length of user specific header in bytes
* @name: name of family
* @version: protocol version
......@@ -43,12 +42,13 @@ struct genl_info;
* @resv_start_op: first operation for which reserved fields of the header
* can be validated and policies are required (see below);
* new families should leave this field at zero
* @mcgrp_offset: starting number of multicast group IDs in this family
* (private)
* @ops: the operations supported by this family
* @n_ops: number of operations supported by this family
* @small_ops: the small-struct operations supported by this family
* @n_small_ops: number of small-struct operations supported by this family
* @split_ops: the split do/dump form of operation definition
* @n_split_ops: number of entries in @split_ops, not that with split do/dump
* ops the number of entries is not the same as number of commands
*
* Attribute policies (the combination of @policy and @maxattr fields)
* can be attached at the family level or at the operation level.
......@@ -58,29 +58,35 @@ struct genl_info;
* if policy is not provided core will reject all TLV attributes.
*/
struct genl_family {
int id; /* private */
unsigned int hdrsize;
char name[GENL_NAMSIZ];
unsigned int version;
unsigned int maxattr;
unsigned int mcgrp_offset; /* private */
u8 netnsok:1;
u8 parallel_ops:1;
u8 n_ops;
u8 n_small_ops;
u8 n_split_ops;
u8 n_mcgrps;
u8 resv_start_op;
const struct nla_policy *policy;
int (*pre_doit)(const struct genl_ops *ops,
int (*pre_doit)(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
void (*post_doit)(const struct genl_ops *ops,
void (*post_doit)(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
const struct genl_ops * ops;
const struct genl_small_ops *small_ops;
const struct genl_split_ops *split_ops;
const struct genl_multicast_group *mcgrps;
struct module *module;
/* private: internal use only */
/* protocol family identifier */
int id;
/* starting number of multicast group IDs in this family */
unsigned int mcgrp_offset;
};
/**
......@@ -181,6 +187,58 @@ struct genl_ops {
u8 validate;
};
/**
* struct genl_split_ops - generic netlink operations (do/dump split version)
* @cmd: command identifier
* @internal_flags: flags used by the family
* @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM)
* @validate: validation flags from enum genl_validate_flags
* @policy: netlink policy (takes precedence over family policy)
* @maxattr: maximum number of attributes supported
*
* Do callbacks:
* @pre_doit: called before an operation's @doit callback, it may
* do additional, common, filtering and return an error
* @doit: standard command callback
* @post_doit: called after an operation's @doit callback, it may
* undo operations done by pre_doit, for example release locks
*
* Dump callbacks:
* @start: start callback for dumps
* @dumpit: callback for dumpers
* @done: completion callback for dumps
*
* Do callbacks can be used if %GENL_CMD_CAP_DO is set in @flags.
* Dump callbacks can be used if %GENL_CMD_CAP_DUMP is set in @flags.
* Exactly one of those flags must be set.
*/
struct genl_split_ops {
union {
struct {
int (*pre_doit)(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
int (*doit)(struct sk_buff *skb,
struct genl_info *info);
void (*post_doit)(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
};
struct {
int (*start)(struct netlink_callback *cb);
int (*dumpit)(struct sk_buff *skb,
struct netlink_callback *cb);
int (*done)(struct netlink_callback *cb);
};
};
const struct nla_policy *policy;
unsigned int maxattr;
u8 cmd;
u8 internal_flags;
u8 flags;
u8 validate;
};
/**
* struct genl_dumpit_info - info that is available during dumpit op call
* @family: generic netlink family - for internal genl code usage
......@@ -189,7 +247,7 @@ struct genl_ops {
*/
struct genl_dumpit_info {
const struct genl_family *family;
struct genl_ops op;
struct genl_split_ops op;
struct nlattr **attrs;
};
......
......@@ -1267,7 +1267,8 @@ batadv_get_vlan_from_info(struct batadv_priv *bat_priv, struct net *net,
*
* 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,
static int batadv_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info)
{
struct net *net = genl_info_net(info);
......@@ -1332,7 +1333,8 @@ static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
* @skb: Netlink message with request data
* @info: receiver information
*/
static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
static void batadv_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info)
{
struct batadv_hard_iface *hard_iface;
......
......@@ -770,7 +770,7 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
#define DEVLINK_NL_FLAG_NEED_RATE_NODE BIT(3)
#define DEVLINK_NL_FLAG_NEED_LINECARD BIT(4)
static int devlink_nl_pre_doit(const struct genl_ops *ops,
static int devlink_nl_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
struct devlink_linecard *linecard;
......@@ -828,7 +828,7 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops,
return err;
}
static void devlink_nl_post_doit(const struct genl_ops *ops,
static void devlink_nl_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
struct devlink_linecard *linecard;
......
......@@ -1620,7 +1620,7 @@ static const struct genl_small_ops dropmon_ops[] = {
},
};
static int net_dm_nl_pre_doit(const struct genl_ops *ops,
static int net_dm_nl_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
mutex_lock(&net_dm_mutex);
......@@ -1628,7 +1628,7 @@ static int net_dm_nl_pre_doit(const struct genl_ops *ops,
return 0;
}
static void net_dm_nl_post_doit(const struct genl_ops *ops,
static void net_dm_nl_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
mutex_unlock(&net_dm_mutex);
......
......@@ -2157,7 +2157,8 @@ static int nl802154_del_llsec_seclevel(struct sk_buff *skb,
#define NL802154_FLAG_CHECK_NETDEV_UP 0x08
#define NL802154_FLAG_NEED_WPAN_DEV 0x10
static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
static int nl802154_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info)
{
struct cfg802154_registered_device *rdev;
......@@ -2219,7 +2220,8 @@ static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
return 0;
}
static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
static void nl802154_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info)
{
if (info->user_ptr[1]) {
......
This diff is collapsed.
......@@ -16140,7 +16140,8 @@ static u32 nl80211_internal_flags[] = {
#undef SELECTOR
};
static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
static int nl80211_pre_doit(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev = NULL;
......@@ -16241,7 +16242,8 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
return err;
}
static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
static void nl80211_post_doit(const struct genl_split_ops *ops,
struct sk_buff *skb,
struct genl_info *info)
{
u32 internal_flags = nl80211_internal_flags[ops->internal_flags];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment