Commit 1a50307b authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso Committed by David S. Miller

netlink: fix NETLINK_RECV_NO_ENOBUFS in netlink_set_err()

Currently, ENOBUFS errors are reported to the socket via
netlink_set_err() even if NETLINK_RECV_NO_ENOBUFS is set. However,
that should not happen. This fixes this problem and it changes the
prototype of netlink_set_err() to return the number of sockets that
have set the NETLINK_RECV_NO_ENOBUFS socket option. This return
value is used in the next patch in these bugfix series.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 73852e81
...@@ -188,7 +188,7 @@ extern int netlink_has_listeners(struct sock *sk, unsigned int group); ...@@ -188,7 +188,7 @@ extern int netlink_has_listeners(struct sock *sk, unsigned int group);
extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
__u32 group, gfp_t allocation); __u32 group, gfp_t allocation);
extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); extern int netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
extern int netlink_register_notifier(struct notifier_block *nb); extern int netlink_register_notifier(struct notifier_block *nb);
extern int netlink_unregister_notifier(struct notifier_block *nb); extern int netlink_unregister_notifier(struct notifier_block *nb);
......
...@@ -1093,6 +1093,7 @@ static inline int do_one_set_err(struct sock *sk, ...@@ -1093,6 +1093,7 @@ static inline int do_one_set_err(struct sock *sk,
struct netlink_set_err_data *p) struct netlink_set_err_data *p)
{ {
struct netlink_sock *nlk = nlk_sk(sk); struct netlink_sock *nlk = nlk_sk(sk);
int ret = 0;
if (sk == p->exclude_sk) if (sk == p->exclude_sk)
goto out; goto out;
...@@ -1104,10 +1105,15 @@ static inline int do_one_set_err(struct sock *sk, ...@@ -1104,10 +1105,15 @@ static inline int do_one_set_err(struct sock *sk,
!test_bit(p->group - 1, nlk->groups)) !test_bit(p->group - 1, nlk->groups))
goto out; goto out;
if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS) {
ret = 1;
goto out;
}
sk->sk_err = p->code; sk->sk_err = p->code;
sk->sk_error_report(sk); sk->sk_error_report(sk);
out: out:
return 0; return ret;
} }
/** /**
...@@ -1116,12 +1122,16 @@ static inline int do_one_set_err(struct sock *sk, ...@@ -1116,12 +1122,16 @@ static inline int do_one_set_err(struct sock *sk,
* @pid: the PID of a process that we want to skip (if any) * @pid: the PID of a process that we want to skip (if any)
* @groups: the broadcast group that will notice the error * @groups: the broadcast group that will notice the error
* @code: error code, must be negative (as usual in kernelspace) * @code: error code, must be negative (as usual in kernelspace)
*
* This function returns the number of broadcast listeners that have set the
* NETLINK_RECV_NO_ENOBUFS socket option.
*/ */
void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) int netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
{ {
struct netlink_set_err_data info; struct netlink_set_err_data info;
struct hlist_node *node; struct hlist_node *node;
struct sock *sk; struct sock *sk;
int ret = 0;
info.exclude_sk = ssk; info.exclude_sk = ssk;
info.pid = pid; info.pid = pid;
...@@ -1132,9 +1142,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) ...@@ -1132,9 +1142,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
read_lock(&nl_table_lock); read_lock(&nl_table_lock);
sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list)
do_one_set_err(sk, &info); ret += do_one_set_err(sk, &info);
read_unlock(&nl_table_lock); read_unlock(&nl_table_lock);
return ret;
} }
EXPORT_SYMBOL(netlink_set_err); EXPORT_SYMBOL(netlink_set_err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment