Merge branch 'net-genetlink-parse-attrs-for-dumpit-callback'
Jiri Pirko says: ==================== net: genetlink: parse attrs for dumpit() callback In generic netlink, parsing attributes for doit() callback is already implemented. They are available in info->attrs. For dumpit() however, each user which is interested in attributes have to parse it manually. Even though the attributes may be (depending on flag) already validated (by parse function). Make usage of attributes in dumpit() more convenient and prepare info->attrs too. Patchset also make the existing users of genl_family_attrbuf() converted to use info->attrs and removes the helper. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
d44dc74132
|
@ -75,8 +75,6 @@ struct genl_family {
|
|||
struct module *module;
|
||||
};
|
||||
|
||||
struct nlattr **genl_family_attrbuf(const struct genl_family *family);
|
||||
|
||||
/**
|
||||
* struct genl_info - receiving information
|
||||
* @snd_seq: sending sequence number
|
||||
|
@ -127,6 +125,24 @@ enum genl_validate_flags {
|
|||
GENL_DONT_VALIDATE_DUMP_STRICT = BIT(2),
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
const struct genl_ops *ops;
|
||||
struct nlattr **attrs;
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -3943,29 +3943,19 @@ static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
|
|||
static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
u64 ret_offset, start_offset, end_offset = 0;
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct devlink_region *region;
|
||||
struct nlattr *chunks_attr;
|
||||
const char *region_name;
|
||||
struct devlink *devlink;
|
||||
struct nlattr **attrs;
|
||||
bool dump = true;
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
start_offset = *((u64 *)&cb->args[0]);
|
||||
|
||||
attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
|
||||
if (!attrs)
|
||||
return -ENOMEM;
|
||||
|
||||
err = nlmsg_parse_deprecated(cb->nlh,
|
||||
GENL_HDRLEN + devlink_nl_family.hdrsize,
|
||||
attrs, DEVLINK_ATTR_MAX,
|
||||
devlink_nl_family.policy, cb->extack);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
mutex_lock(&devlink_mutex);
|
||||
devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
|
||||
if (IS_ERR(devlink)) {
|
||||
|
@ -4042,7 +4032,6 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
|
|||
genlmsg_end(skb, hdr);
|
||||
mutex_unlock(&devlink->lock);
|
||||
mutex_unlock(&devlink_mutex);
|
||||
kfree(attrs);
|
||||
|
||||
return skb->len;
|
||||
|
||||
|
@ -4052,8 +4041,6 @@ out_unlock:
|
|||
mutex_unlock(&devlink->lock);
|
||||
out_dev:
|
||||
mutex_unlock(&devlink_mutex);
|
||||
out_free:
|
||||
kfree(attrs);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -4995,21 +4982,10 @@ devlink_health_reporter_get_from_info(struct devlink *devlink,
|
|||
static struct devlink_health_reporter *
|
||||
devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
struct devlink_health_reporter *reporter;
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct devlink *devlink;
|
||||
struct nlattr **attrs;
|
||||
int err;
|
||||
|
||||
attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
|
||||
if (!attrs)
|
||||
return NULL;
|
||||
|
||||
err = nlmsg_parse_deprecated(cb->nlh,
|
||||
GENL_HDRLEN + devlink_nl_family.hdrsize,
|
||||
attrs, DEVLINK_ATTR_MAX,
|
||||
devlink_nl_family.policy, cb->extack);
|
||||
if (err)
|
||||
goto free;
|
||||
|
||||
mutex_lock(&devlink_mutex);
|
||||
devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
|
||||
|
@ -5018,12 +4994,9 @@ devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
|
|||
|
||||
reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
|
||||
mutex_unlock(&devlink_mutex);
|
||||
kfree(attrs);
|
||||
return reporter;
|
||||
unlock:
|
||||
mutex_unlock(&devlink_mutex);
|
||||
free:
|
||||
kfree(attrs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -6154,7 +6127,8 @@ static const struct genl_ops devlink_nl_ops[] = {
|
|||
},
|
||||
{
|
||||
.cmd = DEVLINK_CMD_REGION_READ,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
.dumpit = devlink_nl_cmd_region_read_dumpit,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
|
||||
|
|
|
@ -236,21 +236,14 @@ nl802154_prepare_wpan_dev_dump(struct sk_buff *skb,
|
|||
struct cfg802154_registered_device **rdev,
|
||||
struct wpan_dev **wpan_dev)
|
||||
{
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
int err;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
if (!cb->args[0]) {
|
||||
err = nlmsg_parse_deprecated(cb->nlh,
|
||||
GENL_HDRLEN + nl802154_fam.hdrsize,
|
||||
genl_family_attrbuf(&nl802154_fam),
|
||||
nl802154_fam.maxattr,
|
||||
nl802154_policy, NULL);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
*wpan_dev = __cfg802154_wpan_dev_from_attrs(sock_net(skb->sk),
|
||||
genl_family_attrbuf(&nl802154_fam));
|
||||
info->attrs);
|
||||
if (IS_ERR(*wpan_dev)) {
|
||||
err = PTR_ERR(*wpan_dev);
|
||||
goto out_unlock;
|
||||
|
@ -557,17 +550,8 @@ static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
|
|||
struct netlink_callback *cb,
|
||||
struct nl802154_dump_wpan_phy_state *state)
|
||||
{
|
||||
struct nlattr **tb = genl_family_attrbuf(&nl802154_fam);
|
||||
int ret = nlmsg_parse_deprecated(cb->nlh,
|
||||
GENL_HDRLEN + nl802154_fam.hdrsize,
|
||||
tb, nl802154_fam.maxattr,
|
||||
nl802154_policy, NULL);
|
||||
|
||||
/* TODO check if we can handle error here,
|
||||
* we have no backward compatibility
|
||||
*/
|
||||
if (ret)
|
||||
return 0;
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
struct nlattr **tb = info->attrs;
|
||||
|
||||
if (tb[NL802154_ATTR_WPAN_PHY])
|
||||
state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
|
||||
|
@ -2203,7 +2187,8 @@ static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
|
|||
static const struct genl_ops nl802154_ops[] = {
|
||||
{
|
||||
.cmd = NL802154_CMD_GET_WPAN_PHY,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
.doit = nl802154_get_wpan_phy,
|
||||
.dumpit = nl802154_dump_wpan_phy,
|
||||
.done = nl802154_dump_wpan_phy_done,
|
||||
|
@ -2343,7 +2328,8 @@ static const struct genl_ops nl802154_ops[] = {
|
|||
},
|
||||
{
|
||||
.cmd = NL802154_CMD_GET_SEC_KEY,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
/* TODO .doit by matching key id? */
|
||||
.dumpit = nl802154_dump_llsec_key,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
|
@ -2369,7 +2355,8 @@ static const struct genl_ops nl802154_ops[] = {
|
|||
/* TODO unique identifier must short+pan OR extended_addr */
|
||||
{
|
||||
.cmd = NL802154_CMD_GET_SEC_DEV,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
/* TODO .doit by matching extended_addr? */
|
||||
.dumpit = nl802154_dump_llsec_dev,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
|
@ -2395,7 +2382,8 @@ static const struct genl_ops nl802154_ops[] = {
|
|||
/* TODO remove complete devkey, put it as nested? */
|
||||
{
|
||||
.cmd = NL802154_CMD_GET_SEC_DEVKEY,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
/* TODO doit by matching ??? */
|
||||
.dumpit = nl802154_dump_llsec_devkey,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
|
@ -2420,7 +2408,8 @@ static const struct genl_ops nl802154_ops[] = {
|
|||
},
|
||||
{
|
||||
.cmd = NL802154_CMD_GET_SEC_LEVEL,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
/* TODO .doit by matching frame_type? */
|
||||
.dumpit = nl802154_dump_llsec_seclevel,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
|
|
|
@ -458,10 +458,58 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
|
|||
}
|
||||
EXPORT_SYMBOL(genlmsg_put);
|
||||
|
||||
static struct genl_dumpit_info *genl_dumpit_info_alloc(void)
|
||||
{
|
||||
return kmalloc(sizeof(struct genl_dumpit_info), GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void genl_dumpit_info_free(const struct genl_dumpit_info *info)
|
||||
{
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
static struct nlattr **
|
||||
genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
|
||||
struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack,
|
||||
const struct genl_ops *ops,
|
||||
int hdrlen,
|
||||
enum genl_validate_flags no_strict_flag)
|
||||
{
|
||||
enum netlink_validation validate = ops->validate & no_strict_flag ?
|
||||
NL_VALIDATE_LIBERAL :
|
||||
NL_VALIDATE_STRICT;
|
||||
struct nlattr **attrbuf;
|
||||
int err;
|
||||
|
||||
if (family->maxattr && family->parallel_ops) {
|
||||
attrbuf = kmalloc_array(family->maxattr + 1,
|
||||
sizeof(struct nlattr *), GFP_KERNEL);
|
||||
if (!attrbuf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
} else {
|
||||
attrbuf = family->attrbuf;
|
||||
}
|
||||
|
||||
err = __nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
|
||||
family->policy, validate, extack);
|
||||
if (err && family->maxattr && family->parallel_ops) {
|
||||
kfree(attrbuf);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
return attrbuf;
|
||||
}
|
||||
|
||||
static void genl_family_rcv_msg_attrs_free(const struct genl_family *family,
|
||||
struct nlattr **attrbuf)
|
||||
{
|
||||
if (family->maxattr && family->parallel_ops)
|
||||
kfree(attrbuf);
|
||||
}
|
||||
|
||||
static int genl_lock_start(struct netlink_callback *cb)
|
||||
{
|
||||
/* our ops are always const - netlink API doesn't propagate that */
|
||||
const struct genl_ops *ops = cb->data;
|
||||
const struct genl_ops *ops = genl_dumpit_info(cb)->ops;
|
||||
int rc = 0;
|
||||
|
||||
if (ops->start) {
|
||||
|
@ -474,8 +522,7 @@ static int genl_lock_start(struct netlink_callback *cb)
|
|||
|
||||
static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
/* our ops are always const - netlink API doesn't propagate that */
|
||||
const struct genl_ops *ops = cb->data;
|
||||
const struct genl_ops *ops = genl_dumpit_info(cb)->ops;
|
||||
int rc;
|
||||
|
||||
genl_lock();
|
||||
|
@ -486,8 +533,8 @@ static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
|
||||
static int genl_lock_done(struct netlink_callback *cb)
|
||||
{
|
||||
/* our ops are always const - netlink API doesn't propagate that */
|
||||
const struct genl_ops *ops = cb->data;
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
const struct genl_ops *ops = info->ops;
|
||||
int rc = 0;
|
||||
|
||||
if (ops->done) {
|
||||
|
@ -495,120 +542,112 @@ static int genl_lock_done(struct netlink_callback *cb)
|
|||
rc = ops->done(cb);
|
||||
genl_unlock();
|
||||
}
|
||||
genl_family_rcv_msg_attrs_free(info->family, info->attrs);
|
||||
genl_dumpit_info_free(info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int genl_family_rcv_msg(const struct genl_family *family,
|
||||
struct sk_buff *skb,
|
||||
struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
static int genl_parallel_done(struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_ops *ops;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct genl_info info;
|
||||
struct genlmsghdr *hdr = nlmsg_data(nlh);
|
||||
struct nlattr **attrbuf;
|
||||
int hdrlen, err;
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
const struct genl_ops *ops = info->ops;
|
||||
int rc = 0;
|
||||
|
||||
/* this family doesn't exist in this netns */
|
||||
if (!family->netnsok && !net_eq(net, &init_net))
|
||||
return -ENOENT;
|
||||
if (ops->done)
|
||||
rc = ops->done(cb);
|
||||
genl_family_rcv_msg_attrs_free(info->family, info->attrs);
|
||||
genl_dumpit_info_free(info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
|
||||
struct sk_buff *skb,
|
||||
struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack,
|
||||
const struct genl_ops *ops,
|
||||
int hdrlen, struct net *net)
|
||||
{
|
||||
struct genl_dumpit_info *info;
|
||||
struct nlattr **attrs = NULL;
|
||||
int err;
|
||||
|
||||
if (!ops->dumpit)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ops->validate & GENL_DONT_VALIDATE_DUMP)
|
||||
goto no_attrs;
|
||||
|
||||
hdrlen = GENL_HDRLEN + family->hdrsize;
|
||||
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
|
||||
return -EINVAL;
|
||||
|
||||
ops = genl_get_cmd(hdr->cmd, family);
|
||||
if (ops == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
if (!family->maxattr)
|
||||
goto no_attrs;
|
||||
|
||||
if ((ops->flags & GENL_ADMIN_PERM) &&
|
||||
!netlink_capable(skb, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
attrs = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
|
||||
ops, hdrlen,
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT);
|
||||
if (IS_ERR(attrs))
|
||||
return PTR_ERR(attrs);
|
||||
|
||||
if ((ops->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) {
|
||||
int rc;
|
||||
|
||||
if (ops->dumpit == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(ops->validate & GENL_DONT_VALIDATE_DUMP)) {
|
||||
int hdrlen = GENL_HDRLEN + family->hdrsize;
|
||||
|
||||
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
|
||||
return -EINVAL;
|
||||
|
||||
if (family->maxattr) {
|
||||
unsigned int validate = NL_VALIDATE_STRICT;
|
||||
|
||||
if (ops->validate &
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT)
|
||||
validate = NL_VALIDATE_LIBERAL;
|
||||
rc = __nla_validate(nlmsg_attrdata(nlh, hdrlen),
|
||||
nlmsg_attrlen(nlh, hdrlen),
|
||||
family->maxattr,
|
||||
family->policy,
|
||||
validate, extack);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!family->parallel_ops) {
|
||||
struct netlink_dump_control c = {
|
||||
.module = family->module,
|
||||
/* we have const, but the netlink API doesn't */
|
||||
.data = (void *)ops,
|
||||
.start = genl_lock_start,
|
||||
.dump = genl_lock_dumpit,
|
||||
.done = genl_lock_done,
|
||||
};
|
||||
|
||||
genl_unlock();
|
||||
rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
|
||||
genl_lock();
|
||||
|
||||
} else {
|
||||
struct netlink_dump_control c = {
|
||||
.module = family->module,
|
||||
.start = ops->start,
|
||||
.dump = ops->dumpit,
|
||||
.done = ops->done,
|
||||
};
|
||||
|
||||
rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
|
||||
}
|
||||
|
||||
return rc;
|
||||
no_attrs:
|
||||
/* Allocate dumpit info. It is going to be freed by done() callback. */
|
||||
info = genl_dumpit_info_alloc();
|
||||
if (!info) {
|
||||
genl_family_rcv_msg_attrs_free(family, attrs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ops->doit == NULL)
|
||||
info->family = family;
|
||||
info->ops = ops;
|
||||
info->attrs = attrs;
|
||||
|
||||
if (!family->parallel_ops) {
|
||||
struct netlink_dump_control c = {
|
||||
.module = family->module,
|
||||
.data = info,
|
||||
.start = genl_lock_start,
|
||||
.dump = genl_lock_dumpit,
|
||||
.done = genl_lock_done,
|
||||
};
|
||||
|
||||
genl_unlock();
|
||||
err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
|
||||
genl_lock();
|
||||
|
||||
} else {
|
||||
struct netlink_dump_control c = {
|
||||
.module = family->module,
|
||||
.data = info,
|
||||
.start = ops->start,
|
||||
.dump = ops->dumpit,
|
||||
.done = genl_parallel_done,
|
||||
};
|
||||
|
||||
err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int genl_family_rcv_msg_doit(const struct genl_family *family,
|
||||
struct sk_buff *skb,
|
||||
struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack,
|
||||
const struct genl_ops *ops,
|
||||
int hdrlen, struct net *net)
|
||||
{
|
||||
struct nlattr **attrbuf;
|
||||
struct genl_info info;
|
||||
int err;
|
||||
|
||||
if (!ops->doit)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (family->maxattr && family->parallel_ops) {
|
||||
attrbuf = kmalloc_array(family->maxattr + 1,
|
||||
sizeof(struct nlattr *),
|
||||
GFP_KERNEL);
|
||||
if (attrbuf == NULL)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
attrbuf = family->attrbuf;
|
||||
|
||||
if (attrbuf) {
|
||||
enum netlink_validation validate = NL_VALIDATE_STRICT;
|
||||
|
||||
if (ops->validate & GENL_DONT_VALIDATE_STRICT)
|
||||
validate = NL_VALIDATE_LIBERAL;
|
||||
|
||||
err = __nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
|
||||
family->policy, validate, extack);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
attrbuf = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
|
||||
ops, hdrlen,
|
||||
GENL_DONT_VALIDATE_STRICT);
|
||||
if (IS_ERR(attrbuf))
|
||||
return PTR_ERR(attrbuf);
|
||||
|
||||
info.snd_seq = nlh->nlmsg_seq;
|
||||
info.snd_portid = NETLINK_CB(skb).portid;
|
||||
|
@ -632,12 +671,49 @@ static int genl_family_rcv_msg(const struct genl_family *family,
|
|||
family->post_doit(ops, skb, &info);
|
||||
|
||||
out:
|
||||
if (family->parallel_ops)
|
||||
kfree(attrbuf);
|
||||
genl_family_rcv_msg_attrs_free(family, attrbuf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int genl_family_rcv_msg(const struct genl_family *family,
|
||||
struct sk_buff *skb,
|
||||
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);
|
||||
int hdrlen;
|
||||
|
||||
/* this family doesn't exist in this netns */
|
||||
if (!family->netnsok && !net_eq(net, &init_net))
|
||||
return -ENOENT;
|
||||
|
||||
hdrlen = GENL_HDRLEN + family->hdrsize;
|
||||
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
|
||||
return -EINVAL;
|
||||
|
||||
ops = genl_get_cmd(hdr->cmd, family);
|
||||
if (ops == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((ops->flags & GENL_ADMIN_PERM) &&
|
||||
!netlink_capable(skb, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if ((ops->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);
|
||||
else
|
||||
return genl_family_rcv_msg_doit(family, skb, nlh, extack,
|
||||
ops, hdrlen, net);
|
||||
}
|
||||
|
||||
static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
|
@ -1088,25 +1164,6 @@ problem:
|
|||
|
||||
subsys_initcall(genl_init);
|
||||
|
||||
/**
|
||||
* genl_family_attrbuf - return family's attrbuf
|
||||
* @family: the family
|
||||
*
|
||||
* Return the family's attrbuf, while validating that it's
|
||||
* actually valid to access it.
|
||||
*
|
||||
* You cannot use this function with a family that has parallel_ops
|
||||
* and you can only use it within (pre/post) doit/dumpit callbacks.
|
||||
*/
|
||||
struct nlattr **genl_family_attrbuf(const struct genl_family *family)
|
||||
{
|
||||
if (!WARN_ON(family->parallel_ops))
|
||||
lockdep_assert_held(&genl_mutex);
|
||||
|
||||
return family->attrbuf;
|
||||
}
|
||||
EXPORT_SYMBOL(genl_family_attrbuf);
|
||||
|
||||
static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
|
||||
gfp_t flags)
|
||||
{
|
||||
|
|
|
@ -102,22 +102,14 @@ nla_put_failure:
|
|||
|
||||
static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
|
||||
{
|
||||
struct nlattr **attrbuf = genl_family_attrbuf(&nfc_genl_family);
|
||||
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
||||
struct nfc_dev *dev;
|
||||
int rc;
|
||||
u32 idx;
|
||||
|
||||
rc = nlmsg_parse_deprecated(cb->nlh,
|
||||
GENL_HDRLEN + nfc_genl_family.hdrsize,
|
||||
attrbuf, nfc_genl_family.maxattr,
|
||||
nfc_genl_policy, NULL);
|
||||
if (rc < 0)
|
||||
return ERR_PTR(rc);
|
||||
|
||||
if (!attrbuf[NFC_ATTR_DEVICE_INDEX])
|
||||
if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
idx = nla_get_u32(attrbuf[NFC_ATTR_DEVICE_INDEX]);
|
||||
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
||||
|
||||
dev = nfc_get_device(idx);
|
||||
if (!dev)
|
||||
|
@ -1697,7 +1689,8 @@ static const struct genl_ops nfc_genl_ops[] = {
|
|||
},
|
||||
{
|
||||
.cmd = NFC_CMD_GET_TARGET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
.dumpit = nfc_genl_dump_targets,
|
||||
.done = nfc_genl_dump_targets_done,
|
||||
},
|
||||
|
|
|
@ -176,7 +176,8 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
|
|||
},
|
||||
{
|
||||
.cmd = TIPC_NL_PUBL_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
.dumpit = tipc_nl_publ_dump,
|
||||
},
|
||||
{
|
||||
|
@ -239,7 +240,8 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
|
|||
},
|
||||
{
|
||||
.cmd = TIPC_NL_MON_PEER_GET,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
.dumpit = tipc_nl_node_dump_monitor_peer,
|
||||
},
|
||||
{
|
||||
|
@ -250,7 +252,8 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
|
|||
#ifdef CONFIG_TIPC_MEDIA_UDP
|
||||
{
|
||||
.cmd = TIPC_NL_UDP_GET_REMOTEIP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||
.validate = GENL_DONT_VALIDATE_STRICT |
|
||||
GENL_DONT_VALIDATE_DUMP_STRICT,
|
||||
.dumpit = tipc_udp_nl_dump_remoteip,
|
||||
},
|
||||
#endif
|
||||
|
@ -268,18 +271,6 @@ struct genl_family tipc_genl_family __ro_after_init = {
|
|||
.n_ops = ARRAY_SIZE(tipc_genl_v2_ops),
|
||||
};
|
||||
|
||||
int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr)
|
||||
{
|
||||
u32 maxattr = tipc_genl_family.maxattr;
|
||||
|
||||
*attr = genl_family_attrbuf(&tipc_genl_family);
|
||||
if (!*attr)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return nlmsg_parse_deprecated(nlh, GENL_HDRLEN, *attr, maxattr,
|
||||
tipc_nl_policy, NULL);
|
||||
}
|
||||
|
||||
int __init tipc_netlink_start(void)
|
||||
{
|
||||
int res;
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <net/netlink.h>
|
||||
|
||||
extern struct genl_family tipc_genl_family;
|
||||
int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***buf);
|
||||
|
||||
struct tipc_nl_msg {
|
||||
struct sk_buff *skb;
|
||||
|
|
|
@ -186,6 +186,7 @@ static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
|
|||
struct sk_buff *buf;
|
||||
struct nlmsghdr *nlmsg;
|
||||
struct netlink_callback cb;
|
||||
struct nlattr **attrbuf;
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
cb.nlh = (struct nlmsghdr *)arg->data;
|
||||
|
@ -201,19 +202,28 @@ static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
attrbuf = kmalloc_array(tipc_genl_family.maxattr + 1,
|
||||
sizeof(struct nlattr *), GFP_KERNEL);
|
||||
if (!attrbuf) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
do {
|
||||
int rem;
|
||||
|
||||
len = (*cmd->dumpit)(buf, &cb);
|
||||
|
||||
nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
|
||||
struct nlattr **attrs;
|
||||
|
||||
err = tipc_nlmsg_parse(nlmsg, &attrs);
|
||||
err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN,
|
||||
attrbuf,
|
||||
tipc_genl_family.maxattr,
|
||||
tipc_genl_family.policy,
|
||||
NULL);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = (*cmd->format)(msg, attrs);
|
||||
err = (*cmd->format)(msg, attrbuf);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
|
@ -231,6 +241,7 @@ static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
|
|||
err = 0;
|
||||
|
||||
err_out:
|
||||
kfree(attrbuf);
|
||||
tipc_dump_done(&cb);
|
||||
kfree_skb(buf);
|
||||
|
||||
|
|
|
@ -2484,13 +2484,9 @@ int tipc_nl_node_dump_monitor_peer(struct sk_buff *skb,
|
|||
int err;
|
||||
|
||||
if (!prev_node) {
|
||||
struct nlattr **attrs;
|
||||
struct nlattr **attrs = genl_dumpit_info(cb)->attrs;
|
||||
struct nlattr *mon[TIPC_NLA_MON_MAX + 1];
|
||||
|
||||
err = tipc_nlmsg_parse(cb->nlh, &attrs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!attrs[TIPC_NLA_MON])
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -3588,13 +3588,9 @@ int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
struct tipc_sock *tsk;
|
||||
|
||||
if (!tsk_portid) {
|
||||
struct nlattr **attrs;
|
||||
struct nlattr **attrs = genl_dumpit_info(cb)->attrs;
|
||||
struct nlattr *sock[TIPC_NLA_SOCK_MAX + 1];
|
||||
|
||||
err = tipc_nlmsg_parse(cb->nlh, &attrs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!attrs[TIPC_NLA_SOCK])
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -448,15 +448,11 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
int i;
|
||||
|
||||
if (!bid && !skip_cnt) {
|
||||
struct nlattr **attrs = genl_dumpit_info(cb)->attrs;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct nlattr *battrs[TIPC_NLA_BEARER_MAX + 1];
|
||||
struct nlattr **attrs;
|
||||
char *bname;
|
||||
|
||||
err = tipc_nlmsg_parse(cb->nlh, &attrs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!attrs[TIPC_NLA_BEARER])
|
||||
return -EINVAL;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче