aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2009-02-06 02:56:36 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-06 02:56:36 -0500
commitff491a7334acfd74e515c896632e37e401f52676 (patch)
tree0e3663706a706029d6fc749ef7f66cdd03925231 /net
parent612e244c12215f6f74973ea3b89bff96450dc530 (diff)
netlink: change return-value logic of netlink_broadcast()
Currently, netlink_broadcast() reports errors to the caller if no messages at all were delivered: 1) If, at least, one message has been delivered correctly, returns 0. 2) Otherwise, if no messages at all were delivered due to skb_clone() failure, return -ENOBUFS. 3) Otherwise, if there are no listeners, return -ESRCH. With this patch, the caller knows if the delivery of any of the messages to the listeners have failed: 1) If it fails to deliver any message (for whatever reason), return -ENOBUFS. 2) Otherwise, if all messages were delivered OK, returns 0. 3) Otherwise, if no listeners, return -ESRCH. In the current ctnetlink code and in Netfilter in general, we can add reliable logging and connection tracking event delivery by dropping the packets whose events were not successfully delivered over Netlink. Of course, this option would be settable via /proc as this approach reduces performance (in terms of filtered connections per seconds by a stateful firewall) but providing reliable logging and event delivery (for conntrackd) in return. This patch also changes some clients of netlink_broadcast() that may report ENOBUFS errors via printk. This error handling is not of any help. Instead, the userspace daemons that are listening to those netlink messages should resync themselves with the kernel-side if they hit ENOBUFS. BTW, netlink_broadcast() clients include those that call cn_netlink_send(), nlmsg_multicast() and genlmsg_multicast() since they internally call netlink_broadcast() and return its error value. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/netlink/af_netlink.c8
-rw-r--r--net/wimax/op-msg.c9
-rw-r--r--net/wimax/stack.c12
3 files changed, 13 insertions, 16 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 9eb895c7a2a9..6ee69c27f806 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -950,6 +950,7 @@ struct netlink_broadcast_data {
950 u32 pid; 950 u32 pid;
951 u32 group; 951 u32 group;
952 int failure; 952 int failure;
953 int delivery_failure;
953 int congested; 954 int congested;
954 int delivered; 955 int delivered;
955 gfp_t allocation; 956 gfp_t allocation;
@@ -999,6 +1000,7 @@ static inline int do_one_broadcast(struct sock *sk,
999 p->skb2 = NULL; 1000 p->skb2 = NULL;
1000 } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { 1001 } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) {
1001 netlink_overrun(sk); 1002 netlink_overrun(sk);
1003 p->delivery_failure = 1;
1002 } else { 1004 } else {
1003 p->congested |= val; 1005 p->congested |= val;
1004 p->delivered = 1; 1006 p->delivered = 1;
@@ -1025,6 +1027,7 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
1025 info.pid = pid; 1027 info.pid = pid;
1026 info.group = group; 1028 info.group = group;
1027 info.failure = 0; 1029 info.failure = 0;
1030 info.delivery_failure = 0;
1028 info.congested = 0; 1031 info.congested = 0;
1029 info.delivered = 0; 1032 info.delivered = 0;
1030 info.allocation = allocation; 1033 info.allocation = allocation;
@@ -1045,13 +1048,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
1045 if (info.skb2) 1048 if (info.skb2)
1046 kfree_skb(info.skb2); 1049 kfree_skb(info.skb2);
1047 1050
1051 if (info.delivery_failure || info.failure)
1052 return -ENOBUFS;
1053
1048 if (info.delivered) { 1054 if (info.delivered) {
1049 if (info.congested && (allocation & __GFP_WAIT)) 1055 if (info.congested && (allocation & __GFP_WAIT))
1050 yield(); 1056 yield();
1051 return 0; 1057 return 0;
1052 } 1058 }
1053 if (info.failure)
1054 return -ENOBUFS;
1055 return -ESRCH; 1059 return -ESRCH;
1056} 1060}
1057EXPORT_SYMBOL(netlink_broadcast); 1061EXPORT_SYMBOL(netlink_broadcast);
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c
index cb3b4ad53683..5d149c1b5f0d 100644
--- a/net/wimax/op-msg.c
+++ b/net/wimax/op-msg.c
@@ -258,7 +258,6 @@ EXPORT_SYMBOL_GPL(wimax_msg_len);
258 */ 258 */
259int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) 259int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
260{ 260{
261 int result;
262 struct device *dev = wimax_dev->net_dev->dev.parent; 261 struct device *dev = wimax_dev->net_dev->dev.parent;
263 void *msg = skb->data; 262 void *msg = skb->data;
264 size_t size = skb->len; 263 size_t size = skb->len;
@@ -266,11 +265,9 @@ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
266 265
267 d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size); 266 d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
268 d_dump(2, dev, msg, size); 267 d_dump(2, dev, msg, size);
269 result = genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL); 268 genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
270 d_printf(1, dev, "CTX: genl multicast result %d\n", result); 269 d_printf(1, dev, "CTX: genl multicast done\n");
271 if (result == -ESRCH) /* Nobody connected, ignore it */ 270 return 0;
272 result = 0; /* btw, the skb is freed already */
273 return result;
274} 271}
275EXPORT_SYMBOL_GPL(wimax_msg_send); 272EXPORT_SYMBOL_GPL(wimax_msg_send);
276 273
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 3869c0327882..a0ee76b52510 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -163,16 +163,12 @@ int wimax_gnl_re_state_change_send(
163 struct device *dev = wimax_dev_to_dev(wimax_dev); 163 struct device *dev = wimax_dev_to_dev(wimax_dev);
164 d_fnstart(3, dev, "(wimax_dev %p report_skb %p)\n", 164 d_fnstart(3, dev, "(wimax_dev %p report_skb %p)\n",
165 wimax_dev, report_skb); 165 wimax_dev, report_skb);
166 if (report_skb == NULL) 166 if (report_skb == NULL) {
167 result = -ENOMEM;
167 goto out; 168 goto out;
168 genlmsg_end(report_skb, header);
169 result = genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
170 if (result == -ESRCH) /* Nobody connected, ignore it */
171 result = 0; /* btw, the skb is freed already */
172 if (result < 0) {
173 dev_err(dev, "RE_STCH: Error sending: %d\n", result);
174 nlmsg_free(report_skb);
175 } 169 }
170 genlmsg_end(report_skb, header);
171 genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
176out: 172out:
177 d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n", 173 d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
178 wimax_dev, report_skb, result); 174 wimax_dev, report_skb, result);