The error pointer argument in netlink message handlers is used
to signal the special case where processing has to be interrupted
because a dump was started but no error happened. Instead it is
simpler and more clear to return -EINTR and have netlink_run_queue()
deal with getting the queue right.
nfnetlink passed on this error pointer to its subsystem handlers
but only uses it to signal the start of a netlink dump. Therefore
it can be removed there as well.
This patch also cleans up the error handling in the affected
message handlers to be consistent since it had to be touched anyway.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
struct nfnl_callback
{
int (*call)(struct sock *nl, struct sk_buff *skb,
struct nfnl_callback
{
int (*call)(struct sock *nl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *cda[], int *errp);
+ struct nlmsghdr *nlh, struct nfattr *cda[]);
u_int16_t attr_count; /* number of nfattr's */
};
u_int16_t attr_count; /* number of nfattr's */
};
extern void netlink_run_queue(struct sock *sk, unsigned int *qlen,
int (*cb)(struct sk_buff *,
extern void netlink_run_queue(struct sock *sk, unsigned int *qlen,
int (*cb)(struct sk_buff *,
- struct nlmsghdr *, int *));
extern void netlink_queue_skip(struct nlmsghdr *nlh,
struct sk_buff *skb);
extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb,
extern void netlink_queue_skip(struct nlmsghdr *nlh,
struct sk_buff *skb);
extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb,
/* Process one rtnetlink message. */
/* Process one rtnetlink message. */
-static __inline__ int
-rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
+static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
rtnl_doit_func doit;
int sz_idx, kind;
{
rtnl_doit_func doit;
int sz_idx, kind;
int err;
type = nlh->nlmsg_type;
int err;
type = nlh->nlmsg_type;
-
- /* Unknown message: reply with EINVAL */
return 0;
family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;
return 0;
family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;
- if (family >= NPROTO) {
- *errp = -EAFNOSUPPORT;
- return -1;
- }
+ if (family >= NPROTO)
+ return -EAFNOSUPPORT;
sz_idx = type>>2;
kind = type&3;
sz_idx = type>>2;
kind = type&3;
- if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) {
- *errp = -EPERM;
- return -1;
- }
+ if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN))
+ return -EPERM;
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
rtnl_dumpit_func dumpit;
dumpit = rtnl_get_dumpit(family, type);
if (dumpit == NULL)
if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
rtnl_dumpit_func dumpit;
dumpit = rtnl_get_dumpit(family, type);
if (dumpit == NULL)
- goto err_inval;
-
- if ((*errp = netlink_dump_start(rtnl, skb, nlh,
- dumpit, NULL)) != 0) {
- return -1;
- }
- netlink_queue_skip(nlh, skb);
- return -1;
+ err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+ if (err == 0)
+ err = -EINTR;
+ return err;
}
memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
min_len = rtm_min[sz_idx];
if (nlh->nlmsg_len < min_len)
}
memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
min_len = rtm_min[sz_idx];
if (nlh->nlmsg_len < min_len)
if (nlh->nlmsg_len > min_len) {
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
if (nlh->nlmsg_len > min_len) {
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
unsigned flavor = attr->rta_type;
if (flavor) {
if (flavor > rta_max[sz_idx])
unsigned flavor = attr->rta_type;
if (flavor) {
if (flavor > rta_max[sz_idx])
rta_buf[flavor-1] = attr;
}
attr = RTA_NEXT(attr, attrlen);
rta_buf[flavor-1] = attr;
}
attr = RTA_NEXT(attr, attrlen);
doit = rtnl_get_doit(family, type);
if (doit == NULL)
doit = rtnl_get_doit(family, type);
if (doit == NULL)
- goto err_inval;
- err = doit(skb, nlh, (void *)&rta_buf[0]);
-
- *errp = err;
- return err;
-err_inval:
- *errp = -EINVAL;
- return -1;
+ return doit(skb, nlh, (void *)&rta_buf[0]);
}
static void rtnetlink_rcv(struct sock *sk, int len)
}
static void rtnetlink_rcv(struct sock *sk, int len)
static int
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
static int
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *cda[])
{
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
{
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
static int
ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
static int
ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *cda[])
{
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
{
struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
int err = 0;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
int err = 0;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
#ifndef CONFIG_NF_CT_ACCT
if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO)
return -ENOTSUPP;
#endif
#ifndef CONFIG_NF_CT_ACCT
if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO)
return -ENOTSUPP;
#endif
- if ((*errp = netlink_dump_start(ctnl, skb, nlh,
- ctnetlink_dump_table,
- ctnetlink_done)) != 0)
- return -EINVAL;
-
- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (rlen > skb->len)
- rlen = skb->len;
- skb_pull(skb, rlen);
- return 0;
+ err = netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
+ ctnetlink_done);
+ if (err == 0)
+ err = -EINTR;
+ return err;
}
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
}
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
static int
ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
static int
ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *cda[])
{
struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_tuple_hash *h = NULL;
{
struct nf_conntrack_tuple otuple, rtuple;
struct nf_conntrack_tuple_hash *h = NULL;
static int
ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
static int
ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *cda[])
{
struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp;
{
struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp;
return -EINVAL;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
return -EINVAL;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
- u32 rlen;
-
- if ((*errp = netlink_dump_start(ctnl, skb, nlh,
- ctnetlink_exp_dump_table,
- ctnetlink_done)) != 0)
- return -EINVAL;
- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (rlen > skb->len)
- rlen = skb->len;
- skb_pull(skb, rlen);
- return 0;
+ err = netlink_dump_start(ctnl, skb, nlh,
+ ctnetlink_exp_dump_table,
+ ctnetlink_done);
+ if (err == 0)
+ err = -EINTR;
+ return err;
}
if (cda[CTA_EXPECT_MASTER-1])
}
if (cda[CTA_EXPECT_MASTER-1])
static int
ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
static int
ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *cda[])
{
struct nf_conntrack_expect *exp, *tmp;
struct nf_conntrack_tuple tuple;
{
struct nf_conntrack_expect *exp, *tmp;
struct nf_conntrack_tuple tuple;
static int
ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
static int
ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *cda[])
{
struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp;
{
struct nf_conntrack_tuple tuple;
struct nf_conntrack_expect *exp;
EXPORT_SYMBOL_GPL(nfnetlink_unicast);
/* Process one complete nfnetlink message. */
EXPORT_SYMBOL_GPL(nfnetlink_unicast);
/* Process one complete nfnetlink message. */
-static int nfnetlink_rcv_msg(struct sk_buff *skb,
- struct nlmsghdr *nlh, int *errp)
+static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct nfnl_callback *nc;
struct nfnetlink_subsystem *ss;
{
struct nfnl_callback *nc;
struct nfnetlink_subsystem *ss;
- if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
- *errp = -EPERM;
- return -1;
- }
+ if (security_netlink_recv(skb, CAP_NET_ADMIN))
+ return -EPERM;
/* Only requests are handled by kernel now. */
if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
/* Only requests are handled by kernel now. */
if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
ss = nfnetlink_get_subsys(type);
if (!ss)
#endif
ss = nfnetlink_get_subsys(type);
if (!ss)
#endif
}
nc = nfnetlink_find_client(type, ss);
if (!nc)
}
nc = nfnetlink_find_client(type, ss);
if (!nc)
err = nfnetlink_check_attributes(ss, nlh, cda);
if (err < 0)
err = nfnetlink_check_attributes(ss, nlh, cda);
if (err < 0)
- goto err_inval;
-
- err = nc->call(nfnl, skb, nlh, cda, errp);
- *errp = err;
- return err;
+ return err;
+ return nc->call(nfnl, skb, nlh, cda);
-
-err_inval:
- *errp = -EINVAL;
- return -1;
}
static void nfnetlink_rcv(struct sock *sk, int len)
}
static void nfnetlink_rcv(struct sock *sk, int len)
static int
nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
static int
nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *nfqa[])
static int
nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
static int
nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *nfula[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *nfula[])
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t group_num = ntohs(nfmsg->res_id);
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t group_num = ntohs(nfmsg->res_id);
static int
nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
static int
nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *nfqa[])
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
static int
nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
static int
nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *nfqa[])
static int
nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
static int
nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+ struct nlmsghdr *nlh, struct nfattr *nfqa[])
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
}
static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
}
static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
- struct nlmsghdr *, int *))
{
struct nlmsghdr *nlh;
int err;
{
struct nlmsghdr *nlh;
int err;
if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
goto skip;
if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
goto skip;
- if (cb(skb, nlh, &err) < 0) {
- /* Not an error, but we have to interrupt processing
- * here. Note: that in this case we do not pull
- * message from skb, it will be processed later.
- */
- if (err == 0)
- return -1;
+ err = cb(skb, nlh);
+ if (err == -EINTR) {
+ /* Not an error, but we interrupt processing */
+ netlink_queue_skip(nlh, skb);
+ return err;
}
skip:
if (nlh->nlmsg_flags & NLM_F_ACK || err)
}
skip:
if (nlh->nlmsg_flags & NLM_F_ACK || err)
*
* qlen must be initialized to 0 before the initial entry, afterwards
* the function may be called repeatedly until qlen reaches 0.
*
* qlen must be initialized to 0 before the initial entry, afterwards
* the function may be called repeatedly until qlen reaches 0.
+ *
+ * The callback function may return -EINTR to signal that processing
+ * of netlink messages shall be interrupted. In this case the message
+ * currently being processed will NOT be requeued onto the receive
+ * queue.
*/
void netlink_run_queue(struct sock *sk, unsigned int *qlen,
*/
void netlink_run_queue(struct sock *sk, unsigned int *qlen,
- int (*cb)(struct sk_buff *, struct nlmsghdr *, int *))
+ int (*cb)(struct sk_buff *, struct nlmsghdr *))
-static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
- int *errp)
+static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct genl_ops *ops;
struct genl_family *family;
struct genl_info info;
struct genlmsghdr *hdr = nlmsg_data(nlh);
{
struct genl_ops *ops;
struct genl_family *family;
struct genl_info info;
struct genlmsghdr *hdr = nlmsg_data(nlh);
- int hdrlen, err = -EINVAL;
family = genl_family_find_byid(nlh->nlmsg_type);
family = genl_family_find_byid(nlh->nlmsg_type);
- if (family == NULL) {
- err = -ENOENT;
- goto errout;
- }
+ if (family == NULL)
+ return -ENOENT;
hdrlen = GENL_HDRLEN + family->hdrsize;
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
hdrlen = GENL_HDRLEN + family->hdrsize;
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
ops = genl_get_cmd(hdr->cmd, family);
ops = genl_get_cmd(hdr->cmd, family);
- if (ops == NULL) {
- err = -EOPNOTSUPP;
- goto errout;
- }
+ if (ops == NULL)
+ return -EOPNOTSUPP;
- if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) {
- err = -EPERM;
- goto errout;
- }
+ if ((ops->flags & GENL_ADMIN_PERM) &&
+ security_netlink_recv(skb, CAP_NET_ADMIN))
+ return -EPERM;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (nlh->nlmsg_flags & NLM_F_DUMP) {
- if (ops->dumpit == NULL) {
- err = -EOPNOTSUPP;
- goto errout;
- }
+ if (ops->dumpit == NULL)
+ return -EOPNOTSUPP;
- *errp = err = netlink_dump_start(genl_sock, skb, nlh,
- ops->dumpit, ops->done);
+ err = netlink_dump_start(genl_sock, skb, nlh,
+ ops->dumpit, ops->done);
- skb_pull(skb, min(NLMSG_ALIGN(nlh->nlmsg_len),
- skb->len));
- return -1;
+ err = -EINTR;
+ return err;
- if (ops->doit == NULL) {
- err = -EOPNOTSUPP;
- goto errout;
- }
+ if (ops->doit == NULL)
+ return -EOPNOTSUPP;
if (family->attrbuf) {
err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
ops->policy);
if (err < 0)
if (family->attrbuf) {
err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
ops->policy);
if (err < 0)
}
info.snd_seq = nlh->nlmsg_seq;
}
info.snd_seq = nlh->nlmsg_seq;
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
info.attrs = family->attrbuf;
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
info.attrs = family->attrbuf;
- *errp = err = ops->doit(skb, &info);
- return err;
-
-errout:
- *errp = err;
- return -1;
+ return ops->doit(skb, &info);
}
static void genl_rcv(struct sock *sk, int len)
}
static void genl_rcv(struct sock *sk, int len)
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
};
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
};
-static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
+static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct rtattr *xfrma[XFRMA_MAX];
struct xfrm_link *link;
{
struct rtattr *xfrma[XFRMA_MAX];
struct xfrm_link *link;
+ int type, min_len, err;
-
- /* Unknown message: reply with EINVAL */
type -= XFRM_MSG_BASE;
link = &xfrm_dispatch[type];
/* All operations require privileges, even GET */
type -= XFRM_MSG_BASE;
link = &xfrm_dispatch[type];
/* All operations require privileges, even GET */
- if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
- *errp = -EPERM;
- return -1;
- }
+ if (security_netlink_recv(skb, CAP_NET_ADMIN))
+ return -EPERM;
if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
(nlh->nlmsg_flags & NLM_F_DUMP)) {
if (link->dump == NULL)
if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
(nlh->nlmsg_flags & NLM_F_DUMP)) {
if (link->dump == NULL)
- goto err_einval;
-
- if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh,
- link->dump, NULL)) != 0) {
- return -1;
- }
- netlink_queue_skip(nlh, skb);
- return -1;
+ err = netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL);
+ if (err == 0)
+ err = -EINTR;
+ return err;
}
memset(xfrma, 0, sizeof(xfrma));
if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type]))
}
memset(xfrma, 0, sizeof(xfrma));
if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type]))
if (nlh->nlmsg_len > min_len) {
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
if (nlh->nlmsg_len > min_len) {
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
unsigned short flavor = attr->rta_type;
if (flavor) {
if (flavor > XFRMA_MAX)
unsigned short flavor = attr->rta_type;
if (flavor) {
if (flavor > XFRMA_MAX)
xfrma[flavor - 1] = attr;
}
attr = RTA_NEXT(attr, attrlen);
xfrma[flavor - 1] = attr;
}
attr = RTA_NEXT(attr, attrlen);
}
if (link->doit == NULL)
}
if (link->doit == NULL)
- goto err_einval;
- *errp = link->doit(skb, nlh, xfrma);
-
- return *errp;
-err_einval:
- *errp = -EINVAL;
- return -1;
+ return link->doit(skb, nlh, xfrma);
}
static void xfrm_netlink_rcv(struct sock *sk, int len)
}
static void xfrm_netlink_rcv(struct sock *sk, int len)