diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2010-03-18 10:24:42 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-04-01 19:02:08 -0400 |
commit | 9e9b5dce350fd6f34c2c6b7440951481fb594a29 (patch) | |
tree | 28b0d6dc72d1e85f8f6bf7e88f145959997794a2 | |
parent | 7532d2c8a05ad49913e05716e96c3b402e1ca8ae (diff) |
netlink: fix NETLINK_RECV_NO_ENOBUFS in netlink_set_err()
[ Upstream commit 1a50307ba1826e4da0024e64b245ce4eadf7688a ]
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | include/linux/netlink.h | 2 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 17 |
2 files changed, 15 insertions, 4 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index fde27c017326..6eaca5e1e8ca 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h | |||
@@ -188,7 +188,7 @@ extern int netlink_has_listeners(struct sock *sk, unsigned int group); | |||
188 | extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); | 188 | extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); |
189 | extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, | 189 | extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, |
190 | __u32 group, gfp_t allocation); | 190 | __u32 group, gfp_t allocation); |
191 | extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); | 191 | extern int netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); |
192 | extern int netlink_register_notifier(struct notifier_block *nb); | 192 | extern int netlink_register_notifier(struct notifier_block *nb); |
193 | extern int netlink_unregister_notifier(struct notifier_block *nb); | 193 | extern int netlink_unregister_notifier(struct notifier_block *nb); |
194 | 194 | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 4c5972ba8c78..0052d3c3fe00 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1093,6 +1093,7 @@ static inline int do_one_set_err(struct sock *sk, | |||
1093 | struct netlink_set_err_data *p) | 1093 | struct netlink_set_err_data *p) |
1094 | { | 1094 | { |
1095 | struct netlink_sock *nlk = nlk_sk(sk); | 1095 | struct netlink_sock *nlk = nlk_sk(sk); |
1096 | int ret = 0; | ||
1096 | 1097 | ||
1097 | if (sk == p->exclude_sk) | 1098 | if (sk == p->exclude_sk) |
1098 | goto out; | 1099 | goto out; |
@@ -1104,10 +1105,15 @@ static inline int do_one_set_err(struct sock *sk, | |||
1104 | !test_bit(p->group - 1, nlk->groups)) | 1105 | !test_bit(p->group - 1, nlk->groups)) |
1105 | goto out; | 1106 | goto out; |
1106 | 1107 | ||
1108 | if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS) { | ||
1109 | ret = 1; | ||
1110 | goto out; | ||
1111 | } | ||
1112 | |||
1107 | sk->sk_err = p->code; | 1113 | sk->sk_err = p->code; |
1108 | sk->sk_error_report(sk); | 1114 | sk->sk_error_report(sk); |
1109 | out: | 1115 | out: |
1110 | return 0; | 1116 | return ret; |
1111 | } | 1117 | } |
1112 | 1118 | ||
1113 | /** | 1119 | /** |
@@ -1116,12 +1122,16 @@ out: | |||
1116 | * @pid: the PID of a process that we want to skip (if any) | 1122 | * @pid: the PID of a process that we want to skip (if any) |
1117 | * @groups: the broadcast group that will notice the error | 1123 | * @groups: the broadcast group that will notice the error |
1118 | * @code: error code, must be negative (as usual in kernelspace) | 1124 | * @code: error code, must be negative (as usual in kernelspace) |
1125 | * | ||
1126 | * This function returns the number of broadcast listeners that have set the | ||
1127 | * NETLINK_RECV_NO_ENOBUFS socket option. | ||
1119 | */ | 1128 | */ |
1120 | void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | 1129 | int netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) |
1121 | { | 1130 | { |
1122 | struct netlink_set_err_data info; | 1131 | struct netlink_set_err_data info; |
1123 | struct hlist_node *node; | 1132 | struct hlist_node *node; |
1124 | struct sock *sk; | 1133 | struct sock *sk; |
1134 | int ret = 0; | ||
1125 | 1135 | ||
1126 | info.exclude_sk = ssk; | 1136 | info.exclude_sk = ssk; |
1127 | info.pid = pid; | 1137 | info.pid = pid; |
@@ -1132,9 +1142,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | |||
1132 | read_lock(&nl_table_lock); | 1142 | read_lock(&nl_table_lock); |
1133 | 1143 | ||
1134 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) | 1144 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) |
1135 | do_one_set_err(sk, &info); | 1145 | ret += do_one_set_err(sk, &info); |
1136 | 1146 | ||
1137 | read_unlock(&nl_table_lock); | 1147 | read_unlock(&nl_table_lock); |
1148 | return ret; | ||
1138 | } | 1149 | } |
1139 | EXPORT_SYMBOL(netlink_set_err); | 1150 | EXPORT_SYMBOL(netlink_set_err); |
1140 | 1151 | ||