Merge branch 'genetlink-support-per-command-policy-dump'
Jakub Kicinski says: ==================== genetlink: support per-command policy dump The objective of this series is to dump ethtool policies to be able to tell which flags are supported by the kernel. Current release adds ETHTOOL_FLAG_STATS for dumping extra stats, but because of strict checking we need to make sure that the flag is actually supported before setting it in a request. Ethtool policies are per command, and so far only dumping family policies was supported. The series adds new set of "light" ops to genl families which don't have all the callbacks, and won't have the policy. Most of families are then moved to these ops. This gives us 4096B in savings on an allyesconfig build (not counting the growth that would have happened when policy is added): text data bss dec hex 244415581 227958581 78372980 550747142 20d3bc06 244415581 227962677 78372980 550751238 20d3cc06 Next 5 patches deal the dumping per-op policy. v3: The actually patch to dump per-op policy was taken out and will come in a series from Johannes, to make sure uAPI is consistent from the start. For dump-specific policies I think it should be fine to add a new pair of members to the "full" ops, and not overthink it. v2: - remove the stale comment in taskstats - split patch 8 -> 8, 9 - now the getfamily policy is also in the op - make cmd u32 v1: - replace remaining uses of "light" with "small" - fix dump (ops can't be on the stack there) - coding changes in patch 4 - new patch 7 - don't echo op in responses - to make dump all easier Dave - this series will cause a very trivial conflict with the patch I sent to net. Both sides add some kdoc to struct genl_ops so we'll need to keep it all. I'm sending this already because I also need to restructure ethool policies in time for 5.10 if we want to use it for the stats flag. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
678cdd4967
@ -2183,7 +2183,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct genl_ops nbd_connect_genl_ops[] = {
|
||||
static const struct genl_small_ops nbd_connect_genl_ops[] = {
|
||||
{
|
||||
.cmd = NBD_CMD_CONNECT,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -2215,8 +2215,8 @@ static struct genl_family nbd_genl_family __ro_after_init = {
|
||||
.name = NBD_GENL_FAMILY_NAME,
|
||||
.version = NBD_GENL_VERSION,
|
||||
.module = THIS_MODULE,
|
||||
.ops = nbd_connect_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(nbd_connect_genl_ops),
|
||||
.small_ops = nbd_connect_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(nbd_connect_genl_ops),
|
||||
.maxattr = NBD_ATTR_MAX,
|
||||
.policy = nbd_attr_policy,
|
||||
.mcgrps = nbd_mcast_grps,
|
||||
|
@ -1339,7 +1339,7 @@ static const struct nla_policy gtp_genl_policy[GTPA_MAX + 1] = {
|
||||
[GTPA_O_TEI] = { .type = NLA_U32, },
|
||||
};
|
||||
|
||||
static const struct genl_ops gtp_genl_ops[] = {
|
||||
static const struct genl_small_ops gtp_genl_ops[] = {
|
||||
{
|
||||
.cmd = GTP_CMD_NEWPDP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -1369,8 +1369,8 @@ static struct genl_family gtp_genl_family __ro_after_init = {
|
||||
.policy = gtp_genl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = gtp_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(gtp_genl_ops),
|
||||
.small_ops = gtp_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(gtp_genl_ops),
|
||||
.mcgrps = gtp_genl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(gtp_genl_mcgrps),
|
||||
};
|
||||
|
@ -583,7 +583,7 @@ static const struct nla_policy hwsim_genl_policy[MAC802154_HWSIM_ATTR_MAX + 1] =
|
||||
};
|
||||
|
||||
/* Generic Netlink operations array */
|
||||
static const struct genl_ops hwsim_nl_ops[] = {
|
||||
static const struct genl_small_ops hwsim_nl_ops[] = {
|
||||
{
|
||||
.cmd = MAC802154_HWSIM_CMD_NEW_RADIO,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -628,8 +628,8 @@ static struct genl_family hwsim_genl_family __ro_after_init = {
|
||||
.maxattr = MAC802154_HWSIM_ATTR_MAX,
|
||||
.policy = hwsim_genl_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = hwsim_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(hwsim_nl_ops),
|
||||
.small_ops = hwsim_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(hwsim_nl_ops),
|
||||
.mcgrps = hwsim_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
|
||||
};
|
||||
|
@ -3285,7 +3285,7 @@ done:
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static const struct genl_ops macsec_genl_ops[] = {
|
||||
static const struct genl_small_ops macsec_genl_ops[] = {
|
||||
{
|
||||
.cmd = MACSEC_CMD_GET_TXSC,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -3361,8 +3361,8 @@ static struct genl_family macsec_fam __ro_after_init = {
|
||||
.policy = macsec_genl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = macsec_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(macsec_genl_ops),
|
||||
.small_ops = macsec_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(macsec_genl_ops),
|
||||
};
|
||||
|
||||
static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
|
||||
|
@ -2795,7 +2795,7 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb,
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct genl_ops team_nl_ops[] = {
|
||||
static const struct genl_small_ops team_nl_ops[] = {
|
||||
{
|
||||
.cmd = TEAM_CMD_NOOP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -2832,8 +2832,8 @@ static struct genl_family team_nl_family __ro_after_init = {
|
||||
.policy = team_nl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = team_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(team_nl_ops),
|
||||
.small_ops = team_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(team_nl_ops),
|
||||
.mcgrps = team_nl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(team_nl_mcgrps),
|
||||
};
|
||||
|
@ -3964,7 +3964,7 @@ done:
|
||||
}
|
||||
|
||||
/* Generic Netlink operations array */
|
||||
static const struct genl_ops hwsim_ops[] = {
|
||||
static const struct genl_small_ops hwsim_ops[] = {
|
||||
{
|
||||
.cmd = HWSIM_CMD_REGISTER,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -4008,8 +4008,8 @@ static struct genl_family hwsim_genl_family __ro_after_init = {
|
||||
.policy = hwsim_genl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = hwsim_ops,
|
||||
.n_ops = ARRAY_SIZE(hwsim_ops),
|
||||
.small_ops = hwsim_ops,
|
||||
.n_small_ops = ARRAY_SIZE(hwsim_ops),
|
||||
.mcgrps = hwsim_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
|
||||
};
|
||||
|
@ -436,7 +436,7 @@ static int tcmu_genl_set_features(struct sk_buff *skb, struct genl_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct genl_ops tcmu_genl_ops[] = {
|
||||
static const struct genl_small_ops tcmu_genl_ops[] = {
|
||||
{
|
||||
.cmd = TCMU_CMD_SET_FEATURES,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -474,8 +474,8 @@ static struct genl_family tcmu_genl_family __ro_after_init = {
|
||||
.mcgrps = tcmu_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(tcmu_mcgrps),
|
||||
.netnsok = true,
|
||||
.ops = tcmu_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(tcmu_genl_ops),
|
||||
.small_ops = tcmu_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(tcmu_genl_ops),
|
||||
};
|
||||
|
||||
#define tcmu_cmd_set_dbi_cur(cmd, index) ((cmd)->dbi_cur = (index))
|
||||
|
@ -545,7 +545,7 @@ static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
|
||||
{
|
||||
struct param p = { .msg = skb };
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
int cmd = info->ops->cmd;
|
||||
int cmd = info->op.cmd;
|
||||
int ret;
|
||||
void *hdr;
|
||||
|
||||
@ -601,7 +601,7 @@ out_free_msg:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct genl_ops thermal_genl_ops[] = {
|
||||
static const struct genl_small_ops thermal_genl_ops[] = {
|
||||
{
|
||||
.cmd = THERMAL_GENL_CMD_TZ_GET_ID,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -635,8 +635,8 @@ static struct genl_family thermal_gnl_family __ro_after_init = {
|
||||
.version = THERMAL_GENL_VERSION,
|
||||
.maxattr = THERMAL_GENL_ATTR_MAX,
|
||||
.policy = thermal_genl_policy,
|
||||
.ops = thermal_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(thermal_genl_ops),
|
||||
.small_ops = thermal_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(thermal_genl_ops),
|
||||
.mcgrps = thermal_genl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),
|
||||
};
|
||||
|
@ -62,7 +62,7 @@ static int user_cmd(struct sk_buff *skb, struct genl_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct genl_ops dlm_nl_ops[] = {
|
||||
static const struct genl_small_ops dlm_nl_ops[] = {
|
||||
{
|
||||
.cmd = DLM_CMD_HELLO,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -73,8 +73,8 @@ static const struct genl_ops dlm_nl_ops[] = {
|
||||
static struct genl_family family __ro_after_init = {
|
||||
.name = DLM_GENL_NAME,
|
||||
.version = DLM_GENL_VERSION,
|
||||
.ops = dlm_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(dlm_nl_ops),
|
||||
.small_ops = dlm_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(dlm_nl_ops),
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -41,6 +41,8 @@ struct genl_info;
|
||||
* (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
|
||||
*/
|
||||
struct genl_family {
|
||||
int id; /* private */
|
||||
@ -48,8 +50,12 @@ struct genl_family {
|
||||
char name[GENL_NAMSIZ];
|
||||
unsigned int version;
|
||||
unsigned int maxattr;
|
||||
bool netnsok;
|
||||
bool parallel_ops;
|
||||
unsigned int mcgrp_offset; /* private */
|
||||
u8 netnsok:1;
|
||||
u8 parallel_ops:1;
|
||||
u8 n_ops;
|
||||
u8 n_small_ops;
|
||||
u8 n_mcgrps;
|
||||
const struct nla_policy *policy;
|
||||
int (*pre_doit)(const struct genl_ops *ops,
|
||||
struct sk_buff *skb,
|
||||
@ -58,10 +64,8 @@ struct genl_family {
|
||||
struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
const struct genl_ops * ops;
|
||||
const struct genl_small_ops *small_ops;
|
||||
const struct genl_multicast_group *mcgrps;
|
||||
unsigned int n_ops;
|
||||
unsigned int n_mcgrps;
|
||||
unsigned int mcgrp_offset; /* private */
|
||||
struct module *module;
|
||||
};
|
||||
|
||||
@ -108,28 +112,33 @@ enum genl_validate_flags {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct genl_info - info that is available during dumpit op call
|
||||
* @family: generic netlink family - for internal genl code usage
|
||||
* @ops: generic netlink ops - for internal genl code usage
|
||||
* @attrs: netlink attributes
|
||||
* struct genl_small_ops - generic netlink operations (small version)
|
||||
* @cmd: command identifier
|
||||
* @internal_flags: flags used by the family
|
||||
* @flags: flags
|
||||
* @validate: validation flags from enum genl_validate_flags
|
||||
* @doit: standard command callback
|
||||
* @dumpit: callback for dumpers
|
||||
*
|
||||
* This is a cut-down version of struct genl_ops for users who don't need
|
||||
* most of the ancillary infra and want to save space.
|
||||
*/
|
||||
struct genl_dumpit_info {
|
||||
const struct genl_family *family;
|
||||
const struct genl_ops *ops;
|
||||
struct nlattr **attrs;
|
||||
struct genl_small_ops {
|
||||
int (*doit)(struct sk_buff *skb, struct genl_info *info);
|
||||
int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
u8 cmd;
|
||||
u8 internal_flags;
|
||||
u8 flags;
|
||||
u8 validate;
|
||||
};
|
||||
|
||||
static inline const struct genl_dumpit_info *
|
||||
genl_dumpit_info(struct netlink_callback *cb)
|
||||
{
|
||||
return cb->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct genl_ops - generic netlink operations
|
||||
* @cmd: command identifier
|
||||
* @internal_flags: flags used by the family
|
||||
* @flags: flags
|
||||
* @maxattr: maximum number of attributes supported
|
||||
* @policy: netlink policy (takes precedence over family policy)
|
||||
* @doit: standard command callback
|
||||
* @start: start callback for dumps
|
||||
* @dumpit: callback for dumpers
|
||||
@ -142,12 +151,32 @@ struct genl_ops {
|
||||
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_info - info that is available during dumpit op call
|
||||
* @family: generic netlink family - for internal genl code usage
|
||||
* @ops: generic netlink ops - for internal genl code usage
|
||||
* @attrs: netlink attributes
|
||||
*/
|
||||
struct genl_dumpit_info {
|
||||
const struct genl_family *family;
|
||||
struct genl_ops op;
|
||||
struct nlattr **attrs;
|
||||
};
|
||||
|
||||
static inline const struct genl_dumpit_info *
|
||||
genl_dumpit_info(struct netlink_callback *cb)
|
||||
{
|
||||
return cb->data;
|
||||
}
|
||||
|
||||
int genl_register_family(struct genl_family *family);
|
||||
int genl_unregister_family(const struct genl_family *family);
|
||||
void genl_notify(const struct genl_family *family, struct sk_buff *skb,
|
||||
|
@ -1935,11 +1935,14 @@ void nla_get_range_unsigned(const struct nla_policy *pt,
|
||||
void nla_get_range_signed(const struct nla_policy *pt,
|
||||
struct netlink_range_validation_signed *range);
|
||||
|
||||
struct netlink_policy_dump_state;
|
||||
|
||||
int netlink_policy_dump_start(const struct nla_policy *policy,
|
||||
unsigned int maxtype,
|
||||
unsigned long *state);
|
||||
bool netlink_policy_dump_loop(unsigned long state);
|
||||
int netlink_policy_dump_write(struct sk_buff *skb, unsigned long state);
|
||||
void netlink_policy_dump_free(unsigned long state);
|
||||
struct netlink_policy_dump_state **state);
|
||||
bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state);
|
||||
int netlink_policy_dump_write(struct sk_buff *skb,
|
||||
struct netlink_policy_dump_state *state);
|
||||
void netlink_policy_dump_free(struct netlink_policy_dump_state *state);
|
||||
|
||||
#endif
|
||||
|
@ -34,17 +34,13 @@ struct kmem_cache *taskstats_cache;
|
||||
|
||||
static struct genl_family family;
|
||||
|
||||
static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
|
||||
static const struct nla_policy taskstats_cmd_get_policy[] = {
|
||||
[TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 },
|
||||
[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
|
||||
[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
|
||||
[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
|
||||
|
||||
/*
|
||||
* We have to use TASKSTATS_CMD_ATTR_MAX here, it is the maxattr in the family.
|
||||
* Make sure they are always aligned.
|
||||
*/
|
||||
static const struct nla_policy cgroupstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
|
||||
static const struct nla_policy cgroupstats_cmd_get_policy[] = {
|
||||
[CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
@ -649,47 +645,25 @@ static const struct genl_ops taskstats_ops[] = {
|
||||
.cmd = TASKSTATS_CMD_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = taskstats_user_cmd,
|
||||
/* policy enforced later */
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_HASPOL,
|
||||
.policy = taskstats_cmd_get_policy,
|
||||
.maxattr = ARRAY_SIZE(taskstats_cmd_get_policy) - 1,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = CGROUPSTATS_CMD_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.doit = cgroupstats_user_cmd,
|
||||
/* policy enforced later */
|
||||
.flags = GENL_CMD_CAP_HASPOL,
|
||||
.policy = cgroupstats_cmd_get_policy,
|
||||
.maxattr = ARRAY_SIZE(cgroupstats_cmd_get_policy) - 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int taskstats_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
const struct nla_policy *policy = NULL;
|
||||
|
||||
switch (ops->cmd) {
|
||||
case TASKSTATS_CMD_GET:
|
||||
policy = taskstats_cmd_get_policy;
|
||||
break;
|
||||
case CGROUPSTATS_CMD_GET:
|
||||
policy = cgroupstats_cmd_get_policy;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return nlmsg_validate_deprecated(info->nlhdr, GENL_HDRLEN,
|
||||
TASKSTATS_CMD_ATTR_MAX, policy,
|
||||
info->extack);
|
||||
}
|
||||
|
||||
static struct genl_family family __ro_after_init = {
|
||||
.name = TASKSTATS_GENL_NAME,
|
||||
.version = TASKSTATS_GENL_VERSION,
|
||||
.maxattr = TASKSTATS_CMD_ATTR_MAX,
|
||||
.module = THIS_MODULE,
|
||||
.ops = taskstats_ops,
|
||||
.n_ops = ARRAY_SIZE(taskstats_ops),
|
||||
.pre_doit = taskstats_pre_doit,
|
||||
};
|
||||
|
||||
/* Needed early in initialization */
|
||||
|
@ -1350,7 +1350,7 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct genl_ops batadv_netlink_ops[] = {
|
||||
static const struct genl_small_ops batadv_netlink_ops[] = {
|
||||
{
|
||||
.cmd = BATADV_CMD_GET_MESH,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -1484,8 +1484,8 @@ struct genl_family batadv_netlink_family __ro_after_init = {
|
||||
.pre_doit = batadv_pre_doit,
|
||||
.post_doit = batadv_post_doit,
|
||||
.module = THIS_MODULE,
|
||||
.ops = batadv_netlink_ops,
|
||||
.n_ops = ARRAY_SIZE(batadv_netlink_ops),
|
||||
.small_ops = batadv_netlink_ops,
|
||||
.n_small_ops = ARRAY_SIZE(batadv_netlink_ops),
|
||||
.mcgrps = batadv_netlink_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(batadv_netlink_mcgrps),
|
||||
};
|
||||
|
@ -7139,7 +7139,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
|
||||
[DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
static const struct genl_ops devlink_nl_ops[] = {
|
||||
static const struct genl_small_ops devlink_nl_ops[] = {
|
||||
{
|
||||
.cmd = DEVLINK_CMD_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -7464,8 +7464,8 @@ static struct genl_family devlink_nl_family __ro_after_init = {
|
||||
.pre_doit = devlink_nl_pre_doit,
|
||||
.post_doit = devlink_nl_post_doit,
|
||||
.module = THIS_MODULE,
|
||||
.ops = devlink_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(devlink_nl_ops),
|
||||
.small_ops = devlink_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(devlink_nl_ops),
|
||||
.mcgrps = devlink_nl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
|
||||
};
|
||||
|
@ -1575,7 +1575,7 @@ static const struct nla_policy net_dm_nl_policy[NET_DM_ATTR_MAX + 1] = {
|
||||
[NET_DM_ATTR_HW_DROPS] = {. type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static const struct genl_ops dropmon_ops[] = {
|
||||
static const struct genl_small_ops dropmon_ops[] = {
|
||||
{
|
||||
.cmd = NET_DM_CMD_CONFIG,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -1625,8 +1625,8 @@ static struct genl_family net_drop_monitor_family __ro_after_init = {
|
||||
.pre_doit = net_dm_nl_pre_doit,
|
||||
.post_doit = net_dm_nl_post_doit,
|
||||
.module = THIS_MODULE,
|
||||
.ops = dropmon_ops,
|
||||
.n_ops = ARRAY_SIZE(dropmon_ops),
|
||||
.small_ops = dropmon_ops,
|
||||
.n_small_ops = ARRAY_SIZE(dropmon_ops),
|
||||
.mcgrps = dropmon_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(dropmon_mcgrps),
|
||||
};
|
||||
|
@ -493,7 +493,7 @@ fail:
|
||||
return res;
|
||||
}
|
||||
|
||||
static const struct genl_ops hsr_ops[] = {
|
||||
static const struct genl_small_ops hsr_ops[] = {
|
||||
{
|
||||
.cmd = HSR_C_GET_NODE_STATUS,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -518,8 +518,8 @@ static struct genl_family hsr_genl_family __ro_after_init = {
|
||||
.policy = hsr_genl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = hsr_ops,
|
||||
.n_ops = ARRAY_SIZE(hsr_ops),
|
||||
.small_ops = hsr_ops,
|
||||
.n_small_ops = ARRAY_SIZE(hsr_ops),
|
||||
.mcgrps = hsr_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(hsr_mcgrps),
|
||||
};
|
||||
|
@ -81,7 +81,7 @@ int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info)
|
||||
return genlmsg_reply(msg, info);
|
||||
}
|
||||
|
||||
static const struct genl_ops ieee802154_ops[] = {
|
||||
static const struct genl_small_ops ieee802154_ops[] = {
|
||||
/* see nl-phy.c */
|
||||
IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
|
||||
ieee802154_dump_phy),
|
||||
@ -130,8 +130,8 @@ struct genl_family nl802154_family __ro_after_init = {
|
||||
.maxattr = IEEE802154_ATTR_MAX,
|
||||
.policy = ieee802154_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = ieee802154_ops,
|
||||
.n_ops = ARRAY_SIZE(ieee802154_ops),
|
||||
.small_ops = ieee802154_ops,
|
||||
.n_small_ops = ARRAY_SIZE(ieee802154_ops),
|
||||
.mcgrps = ieee802154_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(ieee802154_mcgrps),
|
||||
};
|
||||
|
@ -911,7 +911,7 @@ static int fou_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static const struct genl_ops fou_nl_ops[] = {
|
||||
static const struct genl_small_ops fou_nl_ops[] = {
|
||||
{
|
||||
.cmd = FOU_CMD_ADD,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -940,8 +940,8 @@ static struct genl_family fou_nl_family __ro_after_init = {
|
||||
.policy = fou_nl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = fou_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(fou_nl_ops),
|
||||
.small_ops = fou_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(fou_nl_ops),
|
||||
};
|
||||
|
||||
size_t fou_encap_hlen(struct ip_tunnel_encap *e)
|
||||
|
@ -943,7 +943,7 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct genl_ops tcp_metrics_nl_ops[] = {
|
||||
static const struct genl_small_ops tcp_metrics_nl_ops[] = {
|
||||
{
|
||||
.cmd = TCP_METRICS_CMD_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -966,8 +966,8 @@ static struct genl_family tcp_metrics_nl_family __ro_after_init = {
|
||||
.policy = tcp_metrics_nl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = tcp_metrics_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(tcp_metrics_nl_ops),
|
||||
.small_ops = tcp_metrics_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(tcp_metrics_nl_ops),
|
||||
};
|
||||
|
||||
static unsigned int tcpmhash_entries;
|
||||
|
@ -914,7 +914,7 @@ static const struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_ops l2tp_nl_ops[] = {
|
||||
static const struct genl_small_ops l2tp_nl_ops[] = {
|
||||
{
|
||||
.cmd = L2TP_CMD_NOOP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -981,8 +981,8 @@ static struct genl_family l2tp_nl_family __ro_after_init = {
|
||||
.policy = l2tp_nl_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = l2tp_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(l2tp_nl_ops),
|
||||
.small_ops = l2tp_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(l2tp_nl_ops),
|
||||
.mcgrps = l2tp_multicast_group,
|
||||
.n_mcgrps = ARRAY_SIZE(l2tp_multicast_group),
|
||||
};
|
||||
|
@ -1054,7 +1054,7 @@ fail:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static struct genl_ops mptcp_pm_ops[] = {
|
||||
static struct genl_small_ops mptcp_pm_ops[] = {
|
||||
{
|
||||
.cmd = MPTCP_PM_CMD_ADD_ADDR,
|
||||
.doit = mptcp_nl_cmd_add_addr,
|
||||
@ -1093,8 +1093,8 @@ static struct genl_family mptcp_genl_family __ro_after_init = {
|
||||
.policy = mptcp_pm_policy,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = mptcp_pm_ops,
|
||||
.n_ops = ARRAY_SIZE(mptcp_pm_ops),
|
||||
.small_ops = mptcp_pm_ops,
|
||||
.n_small_ops = ARRAY_SIZE(mptcp_pm_ops),
|
||||
.mcgrps = mptcp_pm_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(mptcp_pm_mcgrps),
|
||||
};
|
||||
|
@ -716,7 +716,7 @@ static int ncsi_set_channel_mask_nl(struct sk_buff *msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct genl_ops ncsi_ops[] = {
|
||||
static const struct genl_small_ops ncsi_ops[] = {
|
||||
{
|
||||
.cmd = NCSI_CMD_PKG_INFO,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -762,8 +762,8 @@ static struct genl_family ncsi_genl_family __ro_after_init = {
|
||||
.maxattr = NCSI_ATTR_MAX,
|
||||
.policy = ncsi_genl_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = ncsi_ops,
|
||||
.n_ops = ARRAY_SIZE(ncsi_ops),
|
||||
.small_ops = ncsi_ops,
|
||||
.n_small_ops = ARRAY_SIZE(ncsi_ops),
|
||||
};
|
||||
|
||||
int ncsi_init_netlink(struct net_device *dev)
|
||||
|
@ -3893,7 +3893,7 @@ out:
|
||||
}
|
||||
|
||||
|
||||
static const struct genl_ops ip_vs_genl_ops[] = {
|
||||
static const struct genl_small_ops ip_vs_genl_ops[] = {
|
||||
{
|
||||
.cmd = IPVS_CMD_NEW_SERVICE,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -4001,8 +4001,8 @@ static struct genl_family ip_vs_genl_family __ro_after_init = {
|
||||
.policy = ip_vs_cmd_policy,
|
||||
.netnsok = true, /* Make ipvsadm to work on netns */
|
||||
.module = THIS_MODULE,
|
||||
.ops = ip_vs_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(ip_vs_genl_ops),
|
||||
.small_ops = ip_vs_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(ip_vs_genl_ops),
|
||||
};
|
||||
|
||||
static int __init ip_vs_genl_register(void)
|
||||
|
@ -304,7 +304,7 @@ static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
|
||||
/* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static const struct genl_ops netlbl_calipso_ops[] = {
|
||||
static const struct genl_small_ops netlbl_calipso_ops[] = {
|
||||
{
|
||||
.cmd = NLBL_CALIPSO_C_ADD,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -342,8 +342,8 @@ static struct genl_family netlbl_calipso_gnl_family __ro_after_init = {
|
||||
.maxattr = NLBL_CALIPSO_A_MAX,
|
||||
.policy = calipso_genl_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = netlbl_calipso_ops,
|
||||
.n_ops = ARRAY_SIZE(netlbl_calipso_ops),
|
||||
.small_ops = netlbl_calipso_ops,
|
||||
.n_small_ops = ARRAY_SIZE(netlbl_calipso_ops),
|
||||
};
|
||||
|
||||
/* NetLabel Generic NETLINK Protocol Functions
|
||||
|
@ -724,7 +724,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static const struct genl_ops netlbl_cipsov4_ops[] = {
|
||||
static const struct genl_small_ops netlbl_cipsov4_ops[] = {
|
||||
{
|
||||
.cmd = NLBL_CIPSOV4_C_ADD,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -762,8 +762,8 @@ static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
|
||||
.maxattr = NLBL_CIPSOV4_A_MAX,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = netlbl_cipsov4_ops,
|
||||
.n_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
|
||||
.small_ops = netlbl_cipsov4_ops,
|
||||
.n_small_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -757,7 +757,7 @@ version_failure:
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static const struct genl_ops netlbl_mgmt_genl_ops[] = {
|
||||
static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_ADD,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -823,8 +823,8 @@ static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
|
||||
.maxattr = NLBL_MGMT_A_MAX,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = netlbl_mgmt_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
|
||||
.small_ops = netlbl_mgmt_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1301,7 +1301,7 @@ unlabel_staticlistdef_return:
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static const struct genl_ops netlbl_unlabel_genl_ops[] = {
|
||||
static const struct genl_small_ops netlbl_unlabel_genl_ops[] = {
|
||||
{
|
||||
.cmd = NLBL_UNLABEL_C_STATICADD,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -1367,8 +1367,8 @@ static struct genl_family netlbl_unlabel_gnl_family __ro_after_init = {
|
||||
.maxattr = NLBL_UNLABEL_A_MAX,
|
||||
.policy = netlbl_unlabel_genl_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = netlbl_unlabel_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(netlbl_unlabel_genl_ops),
|
||||
.small_ops = netlbl_unlabel_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(netlbl_unlabel_genl_ops),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -107,16 +107,83 @@ static const struct genl_family *genl_family_find_byname(char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct genl_ops *genl_get_cmd(u8 cmd,
|
||||
const struct genl_family *family)
|
||||
static int genl_get_cmd_cnt(const struct genl_family *family)
|
||||
{
|
||||
return family->n_ops + family->n_small_ops;
|
||||
}
|
||||
|
||||
static void genl_op_from_full(const struct genl_family *family,
|
||||
unsigned int i, struct genl_ops *op)
|
||||
{
|
||||
*op = family->ops[i];
|
||||
|
||||
if (!op->maxattr)
|
||||
op->maxattr = family->maxattr;
|
||||
if (!op->policy)
|
||||
op->policy = family->policy;
|
||||
}
|
||||
|
||||
static int genl_get_cmd_full(u8 cmd, const struct genl_family *family,
|
||||
struct genl_ops *op)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < family->n_ops; i++)
|
||||
if (family->ops[i].cmd == cmd)
|
||||
return &family->ops[i];
|
||||
if (family->ops[i].cmd == cmd) {
|
||||
genl_op_from_full(family, i, op);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void genl_op_from_small(const struct genl_family *family,
|
||||
unsigned int i, struct genl_ops *op)
|
||||
{
|
||||
memset(op, 0, sizeof(*op));
|
||||
op->doit = family->small_ops[i].doit;
|
||||
op->dumpit = family->small_ops[i].dumpit;
|
||||
op->cmd = family->small_ops[i].cmd;
|
||||
op->internal_flags = family->small_ops[i].internal_flags;
|
||||
op->flags = family->small_ops[i].flags;
|
||||
op->validate = family->small_ops[i].validate;
|
||||
|
||||
op->maxattr = family->maxattr;
|
||||
op->policy = family->policy;
|
||||
}
|
||||
|
||||
static int genl_get_cmd_small(u8 cmd, const struct genl_family *family,
|
||||
struct genl_ops *op)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < family->n_small_ops; i++)
|
||||
if (family->small_ops[i].cmd == cmd) {
|
||||
genl_op_from_small(family, i, op);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int genl_get_cmd(u8 cmd, const struct genl_family *family,
|
||||
struct genl_ops *op)
|
||||
{
|
||||
if (!genl_get_cmd_full(cmd, family, op))
|
||||
return 0;
|
||||
return genl_get_cmd_small(cmd, family, op);
|
||||
}
|
||||
|
||||
static void genl_get_cmd_by_index(unsigned int i,
|
||||
const struct genl_family *family,
|
||||
struct genl_ops *op)
|
||||
{
|
||||
if (i < family->n_ops)
|
||||
genl_op_from_full(family, i, op);
|
||||
else if (i < family->n_ops + family->n_small_ops)
|
||||
genl_op_from_small(family, i - family->n_ops, op);
|
||||
else
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
static int genl_allocate_reserve_groups(int n_groups, int *first_id)
|
||||
@ -286,22 +353,25 @@ static void genl_unregister_mc_groups(const struct genl_family *family)
|
||||
|
||||
static int genl_validate_ops(const struct genl_family *family)
|
||||
{
|
||||
const struct genl_ops *ops = family->ops;
|
||||
unsigned int n_ops = family->n_ops;
|
||||
int i, j;
|
||||
|
||||
if (WARN_ON(n_ops && !ops))
|
||||
if (WARN_ON(family->n_ops && !family->ops) ||
|
||||
WARN_ON(family->n_small_ops && !family->small_ops))
|
||||
return -EINVAL;
|
||||
|
||||
if (!n_ops)
|
||||
return 0;
|
||||
for (i = 0; i < genl_get_cmd_cnt(family); i++) {
|
||||
struct genl_ops op;
|
||||
|
||||
for (i = 0; i < n_ops; i++) {
|
||||
if (ops[i].dumpit == NULL && ops[i].doit == NULL)
|
||||
genl_get_cmd_by_index(i, family, &op);
|
||||
if (op.dumpit == NULL && op.doit == NULL)
|
||||
return -EINVAL;
|
||||
for (j = i + 1; j < n_ops; j++)
|
||||
if (ops[i].cmd == ops[j].cmd)
|
||||
for (j = i + 1; j < genl_get_cmd_cnt(family); j++) {
|
||||
struct genl_ops op2;
|
||||
|
||||
genl_get_cmd_by_index(j, family, &op2);
|
||||
if (op.cmd == op2.cmd)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -467,16 +537,16 @@ genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
|
||||
struct nlattr **attrbuf;
|
||||
int err;
|
||||
|
||||
if (!family->maxattr)
|
||||
if (!ops->maxattr)
|
||||
return NULL;
|
||||
|
||||
attrbuf = kmalloc_array(family->maxattr + 1,
|
||||
attrbuf = kmalloc_array(ops->maxattr + 1,
|
||||
sizeof(struct nlattr *), GFP_KERNEL);
|
||||
if (!attrbuf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = __nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
|
||||
family->policy, validate, extack);
|
||||
err = __nlmsg_parse(nlh, hdrlen, attrbuf, ops->maxattr, ops->policy,
|
||||
validate, extack);
|
||||
if (err) {
|
||||
kfree(attrbuf);
|
||||
return ERR_PTR(err);
|
||||
@ -524,7 +594,7 @@ no_attrs:
|
||||
return -ENOMEM;
|
||||
}
|
||||
info->family = ctx->family;
|
||||
info->ops = ops;
|
||||
info->op = *ops;
|
||||
info->attrs = attrs;
|
||||
|
||||
cb->data = info;
|
||||
@ -546,7 +616,7 @@ no_attrs:
|
||||
|
||||
static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_ops *ops = genl_dumpit_info(cb)->ops;
|
||||
const struct genl_ops *ops = &genl_dumpit_info(cb)->op;
|
||||
int rc;
|
||||
|
||||
genl_lock();
|
||||
@ -558,7 +628,7 @@ static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
static int genl_lock_done(struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
const struct genl_ops *ops = info->ops;
|
||||
const struct genl_ops *ops = &info->op;
|
||||
int rc = 0;
|
||||
|
||||
if (ops->done) {
|
||||
@ -574,7 +644,7 @@ static int genl_lock_done(struct netlink_callback *cb)
|
||||
static int genl_parallel_done(struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
const struct genl_ops *ops = info->ops;
|
||||
const struct genl_ops *ops = &info->op;
|
||||
int rc = 0;
|
||||
|
||||
if (ops->done)
|
||||
@ -682,9 +752,9 @@ static int genl_family_rcv_msg(const struct genl_family *family,
|
||||
struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct genl_ops *ops;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct genlmsghdr *hdr = nlmsg_data(nlh);
|
||||
struct genl_ops op;
|
||||
int hdrlen;
|
||||
|
||||
/* this family doesn't exist in this netns */
|
||||
@ -695,24 +765,23 @@ static int genl_family_rcv_msg(const struct genl_family *family,
|
||||
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
|
||||
return -EINVAL;
|
||||
|
||||
ops = genl_get_cmd(hdr->cmd, family);
|
||||
if (ops == NULL)
|
||||
if (genl_get_cmd(hdr->cmd, family, &op))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((ops->flags & GENL_ADMIN_PERM) &&
|
||||
if ((op.flags & GENL_ADMIN_PERM) &&
|
||||
!netlink_capable(skb, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if ((ops->flags & GENL_UNS_ADMIN_PERM) &&
|
||||
if ((op.flags & GENL_UNS_ADMIN_PERM) &&
|
||||
!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
|
||||
return genl_family_rcv_msg_dumpit(family, skb, nlh, extack,
|
||||
ops, hdrlen, net);
|
||||
&op, hdrlen, net);
|
||||
else
|
||||
return genl_family_rcv_msg_doit(family, skb, nlh, extack,
|
||||
ops, hdrlen, net);
|
||||
&op, hdrlen, net);
|
||||
}
|
||||
|
||||
static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
@ -765,7 +834,7 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
|
||||
nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (family->n_ops) {
|
||||
if (genl_get_cmd_cnt(family)) {
|
||||
struct nlattr *nla_ops;
|
||||
int i;
|
||||
|
||||
@ -773,23 +842,25 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
|
||||
if (nla_ops == NULL)
|
||||
goto nla_put_failure;
|
||||
|
||||
for (i = 0; i < family->n_ops; i++) {
|
||||
for (i = 0; i < genl_get_cmd_cnt(family); i++) {
|
||||
struct nlattr *nest;
|
||||
const struct genl_ops *ops = &family->ops[i];
|
||||
u32 op_flags = ops->flags;
|
||||
struct genl_ops op;
|
||||
u32 op_flags;
|
||||
|
||||
if (ops->dumpit)
|
||||
genl_get_cmd_by_index(i, family, &op);
|
||||
op_flags = op.flags;
|
||||
if (op.dumpit)
|
||||
op_flags |= GENL_CMD_CAP_DUMP;
|
||||
if (ops->doit)
|
||||
if (op.doit)
|
||||
op_flags |= GENL_CMD_CAP_DO;
|
||||
if (family->policy)
|
||||
if (op.policy)
|
||||
op_flags |= GENL_CMD_CAP_HASPOL;
|
||||
|
||||
nest = nla_nest_start_noflag(skb, i + 1);
|
||||
if (nest == NULL)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) ||
|
||||
if (nla_put_u32(skb, CTRL_ATTR_OP_ID, op.cmd) ||
|
||||
nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags))
|
||||
goto nla_put_failure;
|
||||
|
||||
@ -945,7 +1016,7 @@ ctrl_build_mcgrp_msg(const struct genl_family *family,
|
||||
return skb;
|
||||
}
|
||||
|
||||
static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
|
||||
static const struct nla_policy ctrl_policy_family[] = {
|
||||
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
|
||||
[CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
|
||||
.len = GENL_NAMSIZ - 1 },
|
||||
@ -1039,47 +1110,54 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
struct ctrl_dump_policy_ctx {
|
||||
struct netlink_policy_dump_state *state;
|
||||
u16 fam_id;
|
||||
};
|
||||
|
||||
static const struct nla_policy ctrl_policy_policy[] = {
|
||||
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
|
||||
[CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
|
||||
.len = GENL_NAMSIZ - 1 },
|
||||
};
|
||||
|
||||
static int ctrl_dumppolicy_start(struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
|
||||
struct nlattr **tb = info->attrs;
|
||||
const struct genl_family *rt;
|
||||
unsigned int fam_id = cb->args[0];
|
||||
int err;
|
||||
|
||||
if (!fam_id) {
|
||||
struct nlattr *tb[CTRL_ATTR_MAX + 1];
|
||||
BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
|
||||
|
||||
err = genlmsg_parse(cb->nlh, &genl_ctrl, tb,
|
||||
genl_ctrl.maxattr,
|
||||
genl_ctrl.policy, cb->extack);
|
||||
if (err)
|
||||
return err;
|
||||
if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
|
||||
return -EINVAL;
|
||||
|
||||
if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
|
||||
return -EINVAL;
|
||||
|
||||
if (tb[CTRL_ATTR_FAMILY_ID]) {
|
||||
fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
} else {
|
||||
rt = genl_family_find_byname(
|
||||
nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
|
||||
if (!rt)
|
||||
return -ENOENT;
|
||||
fam_id = rt->id;
|
||||
}
|
||||
if (tb[CTRL_ATTR_FAMILY_ID]) {
|
||||
ctx->fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
} else {
|
||||
rt = genl_family_find_byname(
|
||||
nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
|
||||
if (!rt)
|
||||
return -ENOENT;
|
||||
ctx->fam_id = rt->id;
|
||||
}
|
||||
|
||||
rt = genl_family_find_byid(fam_id);
|
||||
rt = genl_family_find_byid(ctx->fam_id);
|
||||
if (!rt)
|
||||
return -ENOENT;
|
||||
|
||||
if (!rt->policy)
|
||||
return -ENODATA;
|
||||
|
||||
err = netlink_policy_dump_start(rt->policy, rt->maxattr, &cb->args[1]);
|
||||
if (err)
|
||||
return err;
|
||||
return netlink_policy_dump_start(rt->policy, rt->maxattr, &ctx->state);
|
||||
}
|
||||
|
||||
while (netlink_policy_dump_loop(cb->args[1])) {
|
||||
static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
|
||||
|
||||
while (netlink_policy_dump_loop(ctx->state)) {
|
||||
void *hdr;
|
||||
struct nlattr *nest;
|
||||
|
||||
@ -1089,14 +1167,14 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (!hdr)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, rt->id))
|
||||
if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
|
||||
goto nla_put_failure;
|
||||
|
||||
nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
|
||||
if (!nest)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (netlink_policy_dump_write(skb, cb->args[1]))
|
||||
if (netlink_policy_dump_write(skb, ctx->state))
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
@ -1109,13 +1187,14 @@ nla_put_failure:
|
||||
break;
|
||||
}
|
||||
|
||||
cb->args[0] = fam_id;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int ctrl_dumppolicy_done(struct netlink_callback *cb)
|
||||
{
|
||||
netlink_policy_dump_free(cb->args[1]);
|
||||
struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
|
||||
|
||||
netlink_policy_dump_free(ctx->state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1123,11 +1202,16 @@ static const struct genl_ops genl_ctrl_ops[] = {
|
||||
{
|
||||
.cmd = CTRL_CMD_GETFAMILY,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.policy = ctrl_policy_family,
|
||||
.maxattr = ARRAY_SIZE(ctrl_policy_family) - 1,
|
||||
.doit = ctrl_getfamily,
|
||||
.dumpit = ctrl_dumpfamily,
|
||||
},
|
||||
{
|
||||
.cmd = CTRL_CMD_GETPOLICY,
|
||||
.policy = ctrl_policy_policy,
|
||||
.maxattr = ARRAY_SIZE(ctrl_policy_policy) - 1,
|
||||
.start = ctrl_dumppolicy_start,
|
||||
.dumpit = ctrl_dumppolicy,
|
||||
.done = ctrl_dumppolicy_done,
|
||||
},
|
||||
@ -1146,8 +1230,6 @@ static struct genl_family genl_ctrl __ro_after_init = {
|
||||
.id = GENL_ID_CTRL,
|
||||
.name = "nlctrl",
|
||||
.version = 0x2,
|
||||
.maxattr = CTRL_ATTR_MAX,
|
||||
.policy = ctrl_policy,
|
||||
.netnsok = true,
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#define INITIAL_POLICIES_ALLOC 10
|
||||
|
||||
struct nl_policy_dump {
|
||||
struct netlink_policy_dump_state {
|
||||
unsigned int policy_idx;
|
||||
unsigned int attr_idx;
|
||||
unsigned int n_alloc;
|
||||
@ -24,11 +24,11 @@ struct nl_policy_dump {
|
||||
} policies[];
|
||||
};
|
||||
|
||||
static int add_policy(struct nl_policy_dump **statep,
|
||||
static int add_policy(struct netlink_policy_dump_state **statep,
|
||||
const struct nla_policy *policy,
|
||||
unsigned int maxtype)
|
||||
{
|
||||
struct nl_policy_dump *state = *statep;
|
||||
struct netlink_policy_dump_state *state = *statep;
|
||||
unsigned int n_alloc, i;
|
||||
|
||||
if (!policy || !maxtype)
|
||||
@ -62,7 +62,7 @@ static int add_policy(struct nl_policy_dump **statep,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int get_policy_idx(struct nl_policy_dump *state,
|
||||
static unsigned int get_policy_idx(struct netlink_policy_dump_state *state,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -78,13 +78,13 @@ static unsigned int get_policy_idx(struct nl_policy_dump *state,
|
||||
|
||||
int netlink_policy_dump_start(const struct nla_policy *policy,
|
||||
unsigned int maxtype,
|
||||
unsigned long *_state)
|
||||
struct netlink_policy_dump_state **statep)
|
||||
{
|
||||
struct nl_policy_dump *state;
|
||||
struct netlink_policy_dump_state *state;
|
||||
unsigned int policy_idx;
|
||||
int err;
|
||||
|
||||
if (*_state)
|
||||
if (*statep)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -128,27 +128,26 @@ int netlink_policy_dump_start(const struct nla_policy *policy,
|
||||
}
|
||||
}
|
||||
|
||||
*_state = (unsigned long)state;
|
||||
*statep = state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool netlink_policy_dump_finished(struct nl_policy_dump *state)
|
||||
static bool
|
||||
netlink_policy_dump_finished(struct netlink_policy_dump_state *state)
|
||||
{
|
||||
return state->policy_idx >= state->n_alloc ||
|
||||
!state->policies[state->policy_idx].policy;
|
||||
}
|
||||
|
||||
bool netlink_policy_dump_loop(unsigned long _state)
|
||||
bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state)
|
||||
{
|
||||
struct nl_policy_dump *state = (void *)_state;
|
||||
|
||||
return !netlink_policy_dump_finished(state);
|
||||
}
|
||||
|
||||
int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
|
||||
int netlink_policy_dump_write(struct sk_buff *skb,
|
||||
struct netlink_policy_dump_state *state)
|
||||
{
|
||||
struct nl_policy_dump *state = (void *)_state;
|
||||
const struct nla_policy *pt;
|
||||
struct nlattr *policy, *attr;
|
||||
enum netlink_attribute_type type;
|
||||
@ -306,9 +305,7 @@ nla_put_failure:
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
void netlink_policy_dump_free(unsigned long _state)
|
||||
void netlink_policy_dump_free(struct netlink_policy_dump_state *state)
|
||||
{
|
||||
struct nl_policy_dump *state = (void *)_state;
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
|
@ -2231,7 +2231,7 @@ exit_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct genl_ops ct_limit_genl_ops[] = {
|
||||
static struct genl_small_ops ct_limit_genl_ops[] = {
|
||||
{ .cmd = OVS_CT_LIMIT_CMD_SET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN
|
||||
@ -2263,8 +2263,8 @@ struct genl_family dp_ct_limit_genl_family __ro_after_init = {
|
||||
.policy = ct_limit_policy,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.ops = ct_limit_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(ct_limit_genl_ops),
|
||||
.small_ops = ct_limit_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(ct_limit_genl_ops),
|
||||
.mcgrps = &ovs_ct_limit_multicast_group,
|
||||
.n_mcgrps = 1,
|
||||
.module = THIS_MODULE,
|
||||
|
@ -652,7 +652,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
|
||||
[OVS_PACKET_ATTR_HASH] = { .type = NLA_U64 },
|
||||
};
|
||||
|
||||
static const struct genl_ops dp_packet_genl_ops[] = {
|
||||
static const struct genl_small_ops dp_packet_genl_ops[] = {
|
||||
{ .cmd = OVS_PACKET_CMD_EXECUTE,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
|
||||
@ -668,8 +668,8 @@ static struct genl_family dp_packet_genl_family __ro_after_init = {
|
||||
.policy = packet_policy,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.ops = dp_packet_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(dp_packet_genl_ops),
|
||||
.small_ops = dp_packet_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(dp_packet_genl_ops),
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
@ -1453,7 +1453,7 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
|
||||
[OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static const struct genl_ops dp_flow_genl_ops[] = {
|
||||
static const struct genl_small_ops dp_flow_genl_ops[] = {
|
||||
{ .cmd = OVS_FLOW_CMD_NEW,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
|
||||
@ -1485,8 +1485,8 @@ static struct genl_family dp_flow_genl_family __ro_after_init = {
|
||||
.policy = flow_policy,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.ops = dp_flow_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(dp_flow_genl_ops),
|
||||
.small_ops = dp_flow_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(dp_flow_genl_ops),
|
||||
.mcgrps = &ovs_dp_flow_multicast_group,
|
||||
.n_mcgrps = 1,
|
||||
.module = THIS_MODULE,
|
||||
@ -1918,7 +1918,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
|
||||
PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
|
||||
};
|
||||
|
||||
static const struct genl_ops dp_datapath_genl_ops[] = {
|
||||
static const struct genl_small_ops dp_datapath_genl_ops[] = {
|
||||
{ .cmd = OVS_DP_CMD_NEW,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
|
||||
@ -1950,8 +1950,8 @@ static struct genl_family dp_datapath_genl_family __ro_after_init = {
|
||||
.policy = datapath_policy,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.ops = dp_datapath_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(dp_datapath_genl_ops),
|
||||
.small_ops = dp_datapath_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(dp_datapath_genl_ops),
|
||||
.mcgrps = &ovs_dp_datapath_multicast_group,
|
||||
.n_mcgrps = 1,
|
||||
.module = THIS_MODULE,
|
||||
@ -2401,7 +2401,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
|
||||
[OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
|
||||
};
|
||||
|
||||
static const struct genl_ops dp_vport_genl_ops[] = {
|
||||
static const struct genl_small_ops dp_vport_genl_ops[] = {
|
||||
{ .cmd = OVS_VPORT_CMD_NEW,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
|
||||
@ -2433,8 +2433,8 @@ struct genl_family dp_vport_genl_family __ro_after_init = {
|
||||
.policy = vport_policy,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.ops = dp_vport_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(dp_vport_genl_ops),
|
||||
.small_ops = dp_vport_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(dp_vport_genl_ops),
|
||||
.mcgrps = &ovs_dp_vport_multicast_group,
|
||||
.n_mcgrps = 1,
|
||||
.module = THIS_MODULE,
|
||||
|
@ -672,7 +672,7 @@ bool ovs_meter_execute(struct datapath *dp, struct sk_buff *skb,
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct genl_ops dp_meter_genl_ops[] = {
|
||||
static struct genl_small_ops dp_meter_genl_ops[] = {
|
||||
{ .cmd = OVS_METER_CMD_FEATURES,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.flags = 0, /* OK for unprivileged users. */
|
||||
@ -711,8 +711,8 @@ struct genl_family dp_meter_genl_family __ro_after_init = {
|
||||
.policy = meter_policy,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.ops = dp_meter_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(dp_meter_genl_ops),
|
||||
.small_ops = dp_meter_genl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(dp_meter_genl_ops),
|
||||
.mcgrps = &ovs_meter_multicast_group,
|
||||
.n_mcgrps = 1,
|
||||
.module = THIS_MODULE,
|
||||
|
@ -96,7 +96,7 @@ static int psample_nl_cmd_get_group_dumpit(struct sk_buff *msg,
|
||||
return msg->len;
|
||||
}
|
||||
|
||||
static const struct genl_ops psample_nl_ops[] = {
|
||||
static const struct genl_small_ops psample_nl_ops[] = {
|
||||
{
|
||||
.cmd = PSAMPLE_CMD_GET_GROUP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -112,8 +112,8 @@ static struct genl_family psample_nl_family __ro_after_init = {
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.mcgrps = psample_nl_mcgrps,
|
||||
.ops = psample_nl_ops,
|
||||
.n_ops = ARRAY_SIZE(psample_nl_ops),
|
||||
.small_ops = psample_nl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(psample_nl_ops),
|
||||
.n_mcgrps = ARRAY_SIZE(psample_nl_mcgrps),
|
||||
};
|
||||
|
||||
|
@ -1337,7 +1337,7 @@ send:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct genl_ops tipc_genl_compat_ops[] = {
|
||||
static const struct genl_small_ops tipc_genl_compat_ops[] = {
|
||||
{
|
||||
.cmd = TIPC_GENL_CMD,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -1352,8 +1352,8 @@ static struct genl_family tipc_genl_compat_family __ro_after_init = {
|
||||
.maxattr = 0,
|
||||
.netnsok = true,
|
||||
.module = THIS_MODULE,
|
||||
.ops = tipc_genl_compat_ops,
|
||||
.n_ops = ARRAY_SIZE(tipc_genl_compat_ops),
|
||||
.small_ops = tipc_genl_compat_ops,
|
||||
.n_small_ops = ARRAY_SIZE(tipc_genl_compat_ops),
|
||||
};
|
||||
|
||||
int __init tipc_netlink_compat_start(void)
|
||||
|
@ -401,7 +401,7 @@ static const struct nla_policy wimax_gnl_policy[WIMAX_GNL_ATTR_MAX + 1] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_ops wimax_gnl_ops[] = {
|
||||
static const struct genl_small_ops wimax_gnl_ops[] = {
|
||||
{
|
||||
.cmd = WIMAX_GNL_OP_MSG_FROM_USER,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -560,8 +560,8 @@ struct genl_family wimax_gnl_family __ro_after_init = {
|
||||
.maxattr = WIMAX_GNL_ATTR_MAX,
|
||||
.policy = wimax_gnl_policy,
|
||||
.module = THIS_MODULE,
|
||||
.ops = wimax_gnl_ops,
|
||||
.n_ops = ARRAY_SIZE(wimax_gnl_ops),
|
||||
.small_ops = wimax_gnl_ops,
|
||||
.n_small_ops = ARRAY_SIZE(wimax_gnl_ops),
|
||||
.mcgrps = wimax_gnl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(wimax_gnl_mcgrps),
|
||||
};
|
||||
|
@ -14665,6 +14665,9 @@ static const struct genl_ops nl80211_ops[] = {
|
||||
.internal_flags = NL80211_FLAG_NEED_WIPHY |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_small_ops nl80211_small_ops[] = {
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_WIPHY,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
@ -15526,6 +15529,8 @@ static struct genl_family nl80211_fam __ro_after_init = {
|
||||
.module = THIS_MODULE,
|
||||
.ops = nl80211_ops,
|
||||
.n_ops = ARRAY_SIZE(nl80211_ops),
|
||||
.small_ops = nl80211_small_ops,
|
||||
.n_small_ops = ARRAY_SIZE(nl80211_small_ops),
|
||||
.mcgrps = nl80211_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
|
||||
.parallel_ops = true,
|
||||
|
Loading…
Reference in New Issue
Block a user