diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 25 |
1 files changed, 23 insertions, 2 deletions
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 | ||
89 | static inline struct netlink_sock *nlk_sk(struct sock *sk) | 90 | static 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 | } |