aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2009-02-17 20:40:43 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-20 04:01:08 -0500
commitbe0c22a46cfb79ab2342bb28fde99afa94ef868e (patch)
treeda112ef3066d75a7e5adcfe3355ad2b60ef1929b
parent2d96cf8cdfd625da51e5d237d564cd75d3147547 (diff)
netlink: add NETLINK_BROADCAST_ERROR socket option
This patch adds NETLINK_BROADCAST_ERROR which is a netlink socket option that the listener can set to make netlink_broadcast() return errors in the delivery to the caller. This option is useful if the caller of netlink_broadcast() do something with the result of the message delivery, like in ctnetlink where it drops a network packet if the event delivery failed, this is used to enable reliable logging and state-synchronization. If this socket option is not set, netlink_broadcast() only reports ESRCH errors and silently ignore ENOBUFS errors, which is what most netlink_broadcast() callers should do. This socket option is based on a suggestion from Patrick McHardy. Patrick McHardy can exchange this patch for a beer from me ;). Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Acked-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netlink.h1
-rw-r--r--net/netlink/af_netlink.c25
2 files changed, 24 insertions, 2 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 51b09a1f46c3..1e6bf995435c 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -103,6 +103,7 @@ struct nlmsgerr
103#define NETLINK_ADD_MEMBERSHIP 1 103#define NETLINK_ADD_MEMBERSHIP 1
104#define NETLINK_DROP_MEMBERSHIP 2 104#define NETLINK_DROP_MEMBERSHIP 2
105#define NETLINK_PKTINFO 3 105#define NETLINK_PKTINFO 3
106#define NETLINK_BROADCAST_ERROR 4
106 107
107struct nl_pktinfo 108struct nl_pktinfo
108{ 109{
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 6ee69c27f806..ed587be1e1c2 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -85,6 +85,7 @@ struct netlink_sock {
85 85
86#define NETLINK_KERNEL_SOCKET 0x1 86#define NETLINK_KERNEL_SOCKET 0x1
87#define NETLINK_RECV_PKTINFO 0x2 87#define NETLINK_RECV_PKTINFO 0x2
88#define NETLINK_BROADCAST_SEND_ERROR 0x4
88 89
89static inline struct netlink_sock *nlk_sk(struct sock *sk) 90static inline struct netlink_sock *nlk_sk(struct sock *sk)
90{ 91{
@@ -995,12 +996,15 @@ static inline int do_one_broadcast(struct sock *sk,
995 netlink_overrun(sk); 996 netlink_overrun(sk);
996 /* Clone failed. Notify ALL listeners. */ 997 /* Clone failed. Notify ALL listeners. */
997 p->failure = 1; 998 p->failure = 1;
999 if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)
1000 p->delivery_failure = 1;
998 } else if (sk_filter(sk, p->skb2)) { 1001 } else if (sk_filter(sk, p->skb2)) {
999 kfree_skb(p->skb2); 1002 kfree_skb(p->skb2);
1000 p->skb2 = NULL; 1003 p->skb2 = NULL;
1001 } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { 1004 } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) {
1002 netlink_overrun(sk); 1005 netlink_overrun(sk);
1003 p->delivery_failure = 1; 1006 if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)
1007 p->delivery_failure = 1;
1004 } else { 1008 } else {
1005 p->congested |= val; 1009 p->congested |= val;
1006 p->delivered = 1; 1010 p->delivered = 1;
@@ -1048,7 +1052,7 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
1048 if (info.skb2) 1052 if (info.skb2)
1049 kfree_skb(info.skb2); 1053 kfree_skb(info.skb2);
1050 1054
1051 if (info.delivery_failure || info.failure) 1055 if (info.delivery_failure)
1052 return -ENOBUFS; 1056 return -ENOBUFS;
1053 1057
1054 if (info.delivered) { 1058 if (info.delivered) {
@@ -1163,6 +1167,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
1163 err = 0; 1167 err = 0;
1164 break; 1168 break;
1165 } 1169 }
1170 case NETLINK_BROADCAST_ERROR:
1171 if (val)
1172 nlk->flags |= NETLINK_BROADCAST_SEND_ERROR;
1173 else
1174 nlk->flags &= ~NETLINK_BROADCAST_SEND_ERROR;
1175 err = 0;
1176 break;
1166 default: 1177 default:
1167 err = -ENOPROTOOPT; 1178 err = -ENOPROTOOPT;
1168 } 1179 }
@@ -1195,6 +1206,16 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
1195 return -EFAULT; 1206 return -EFAULT;
1196 err = 0; 1207 err = 0;
1197 break; 1208 break;
1209 case NETLINK_BROADCAST_ERROR:
1210 if (len < sizeof(int))
1211 return -EINVAL;
1212 len = sizeof(int);
1213 val = nlk->flags & NETLINK_BROADCAST_SEND_ERROR ? 1 : 0;
1214 if (put_user(len, optlen) ||
1215 put_user(val, optval))
1216 return -EFAULT;
1217 err = 0;
1218 break;
1198 default: 1219 default:
1199 err = -ENOPROTOOPT; 1220 err = -ENOPROTOOPT;
1200 } 1221 }