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: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
73852e8151
commit
1a50307ba1
@@ -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,
|
|||||||
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,
|
|||||||
!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 @@ out:
|
|||||||
* @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)
|
|||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user