Commit be064def authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

net: genetlink: push doit/dumpit code from genl_family_rcv_msg



Currently the function genl_family_rcv_msg() is quite big. Since it is
quite convenient, push code that is related to doit and dumpit ops into
separate functions.

Do small changes on the way, like rc/err unification, NULL check etc.

Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 248d45f1
Loading
Loading
Loading
Loading
+96 −77
Original line number Diff line number Diff line
@@ -498,63 +498,33 @@ static int genl_lock_done(struct netlink_callback *cb)
	return rc;
}

static int genl_family_rcv_msg(const struct genl_family *family,
static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
				      struct sk_buff *skb,
				      struct nlmsghdr *nlh,
			       struct netlink_ext_ack *extack)
				      struct netlink_ext_ack *extack,
				      const struct genl_ops *ops,
				      int hdrlen, struct net *net)
{
	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;

	/* 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) {
		int rc;
	int err;

		if (ops->dumpit == NULL)
	if (!ops->dumpit)
		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)
			if (ops->validate & GENL_DONT_VALIDATE_DUMP_STRICT)
				validate = NL_VALIDATE_LIBERAL;
				rc = __nla_validate(nlmsg_attrdata(nlh, hdrlen),
			err = __nla_validate(nlmsg_attrdata(nlh, hdrlen),
					     nlmsg_attrlen(nlh, hdrlen),
						    family->maxattr,
						    family->policy,
					     family->maxattr, family->policy,
					     validate, extack);
				if (rc)
					return rc;
			if (err)
				return err;
		}
	}

@@ -569,7 +539,7 @@ static int genl_family_rcv_msg(const struct genl_family *family,
		};

		genl_unlock();
			rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
		err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
		genl_lock();

	} else {
@@ -580,13 +550,24 @@ static int genl_family_rcv_msg(const struct genl_family *family,
			.done = ops->done,
		};

			rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
		err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
	}

		return rc;
	return err;
}

	if (ops->doit == NULL)
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) {
@@ -638,6 +619,44 @@ out:
	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)
{