Skip to content

Commit

Permalink
netlink: fix NETLINK_RECV_NO_ENOBUFS in netlink_set_err()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
ummakynes authored and davem330 committed Mar 20, 2010
1 parent 73852e8 commit 1a50307
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 4 deletions.
2 changes: 1 addition & 1 deletion include/linux/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
__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_unregister_notifier(struct notifier_block *nb);

Expand Down
17 changes: 14 additions & 3 deletions net/netlink/af_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@ static inline int do_one_set_err(struct sock *sk,
struct netlink_set_err_data *p)
{
struct netlink_sock *nlk = nlk_sk(sk);
int ret = 0;

if (sk == p->exclude_sk)
goto out;
Expand All @@ -1104,10 +1105,15 @@ static inline int do_one_set_err(struct sock *sk,
!test_bit(p->group - 1, nlk->groups))
goto out;

if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS) {
ret = 1;
goto out;
}

sk->sk_err = p->code;
sk->sk_error_report(sk);
out:
return 0;
return ret;
}

/**
Expand All @@ -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)
* @groups: the broadcast group that will notice the error
* @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 hlist_node *node;
struct sock *sk;
int ret = 0;

info.exclude_sk = ssk;
info.pid = pid;
Expand All @@ -1132,9 +1142,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
read_lock(&nl_table_lock);

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);
return ret;
}
EXPORT_SYMBOL(netlink_set_err);

Expand Down

0 comments on commit 1a50307

Please sign in to comment.