diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 88 |
1 files changed, 72 insertions, 16 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3ae3cb816563..8b6bbb3032b0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -85,6 +85,8 @@ 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 | ||
89 | #define NETLINK_RECV_NO_ENOBUFS 0x8 | ||
88 | 90 | ||
89 | static inline struct netlink_sock *nlk_sk(struct sock *sk) | 91 | static inline struct netlink_sock *nlk_sk(struct sock *sk) |
90 | { | 92 | { |
@@ -716,10 +718,15 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, | |||
716 | 718 | ||
717 | static void netlink_overrun(struct sock *sk) | 719 | static void netlink_overrun(struct sock *sk) |
718 | { | 720 | { |
719 | if (!test_and_set_bit(0, &nlk_sk(sk)->state)) { | 721 | struct netlink_sock *nlk = nlk_sk(sk); |
720 | sk->sk_err = ENOBUFS; | 722 | |
721 | sk->sk_error_report(sk); | 723 | if (!(nlk->flags & NETLINK_RECV_NO_ENOBUFS)) { |
724 | if (!test_and_set_bit(0, &nlk_sk(sk)->state)) { | ||
725 | sk->sk_err = ENOBUFS; | ||
726 | sk->sk_error_report(sk); | ||
727 | } | ||
722 | } | 728 | } |
729 | atomic_inc(&sk->sk_drops); | ||
723 | } | 730 | } |
724 | 731 | ||
725 | static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) | 732 | static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) |
@@ -950,6 +957,7 @@ struct netlink_broadcast_data { | |||
950 | u32 pid; | 957 | u32 pid; |
951 | u32 group; | 958 | u32 group; |
952 | int failure; | 959 | int failure; |
960 | int delivery_failure; | ||
953 | int congested; | 961 | int congested; |
954 | int delivered; | 962 | int delivered; |
955 | gfp_t allocation; | 963 | gfp_t allocation; |
@@ -994,11 +1002,15 @@ static inline int do_one_broadcast(struct sock *sk, | |||
994 | netlink_overrun(sk); | 1002 | netlink_overrun(sk); |
995 | /* Clone failed. Notify ALL listeners. */ | 1003 | /* Clone failed. Notify ALL listeners. */ |
996 | p->failure = 1; | 1004 | p->failure = 1; |
1005 | if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR) | ||
1006 | p->delivery_failure = 1; | ||
997 | } else if (sk_filter(sk, p->skb2)) { | 1007 | } else if (sk_filter(sk, p->skb2)) { |
998 | kfree_skb(p->skb2); | 1008 | kfree_skb(p->skb2); |
999 | p->skb2 = NULL; | 1009 | p->skb2 = NULL; |
1000 | } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { | 1010 | } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { |
1001 | netlink_overrun(sk); | 1011 | netlink_overrun(sk); |
1012 | if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR) | ||
1013 | p->delivery_failure = 1; | ||
1002 | } else { | 1014 | } else { |
1003 | p->congested |= val; | 1015 | p->congested |= val; |
1004 | p->delivered = 1; | 1016 | p->delivered = 1; |
@@ -1025,6 +1037,7 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | |||
1025 | info.pid = pid; | 1037 | info.pid = pid; |
1026 | info.group = group; | 1038 | info.group = group; |
1027 | info.failure = 0; | 1039 | info.failure = 0; |
1040 | info.delivery_failure = 0; | ||
1028 | info.congested = 0; | 1041 | info.congested = 0; |
1029 | info.delivered = 0; | 1042 | info.delivered = 0; |
1030 | info.allocation = allocation; | 1043 | info.allocation = allocation; |
@@ -1042,16 +1055,16 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | |||
1042 | 1055 | ||
1043 | netlink_unlock_table(); | 1056 | netlink_unlock_table(); |
1044 | 1057 | ||
1045 | if (info.skb2) | 1058 | kfree_skb(info.skb2); |
1046 | kfree_skb(info.skb2); | 1059 | |
1060 | if (info.delivery_failure) | ||
1061 | return -ENOBUFS; | ||
1047 | 1062 | ||
1048 | if (info.delivered) { | 1063 | if (info.delivered) { |
1049 | if (info.congested && (allocation & __GFP_WAIT)) | 1064 | if (info.congested && (allocation & __GFP_WAIT)) |
1050 | yield(); | 1065 | yield(); |
1051 | return 0; | 1066 | return 0; |
1052 | } | 1067 | } |
1053 | if (info.failure) | ||
1054 | return -ENOBUFS; | ||
1055 | return -ESRCH; | 1068 | return -ESRCH; |
1056 | } | 1069 | } |
1057 | EXPORT_SYMBOL(netlink_broadcast); | 1070 | EXPORT_SYMBOL(netlink_broadcast); |
@@ -1110,6 +1123,7 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | |||
1110 | 1123 | ||
1111 | read_unlock(&nl_table_lock); | 1124 | read_unlock(&nl_table_lock); |
1112 | } | 1125 | } |
1126 | EXPORT_SYMBOL(netlink_set_err); | ||
1113 | 1127 | ||
1114 | /* must be called with netlink table grabbed */ | 1128 | /* must be called with netlink table grabbed */ |
1115 | static void netlink_update_socket_mc(struct netlink_sock *nlk, | 1129 | static void netlink_update_socket_mc(struct netlink_sock *nlk, |
@@ -1167,6 +1181,22 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
1167 | err = 0; | 1181 | err = 0; |
1168 | break; | 1182 | break; |
1169 | } | 1183 | } |
1184 | case NETLINK_BROADCAST_ERROR: | ||
1185 | if (val) | ||
1186 | nlk->flags |= NETLINK_BROADCAST_SEND_ERROR; | ||
1187 | else | ||
1188 | nlk->flags &= ~NETLINK_BROADCAST_SEND_ERROR; | ||
1189 | err = 0; | ||
1190 | break; | ||
1191 | case NETLINK_NO_ENOBUFS: | ||
1192 | if (val) { | ||
1193 | nlk->flags |= NETLINK_RECV_NO_ENOBUFS; | ||
1194 | clear_bit(0, &nlk->state); | ||
1195 | wake_up_interruptible(&nlk->wait); | ||
1196 | } else | ||
1197 | nlk->flags &= ~NETLINK_RECV_NO_ENOBUFS; | ||
1198 | err = 0; | ||
1199 | break; | ||
1170 | default: | 1200 | default: |
1171 | err = -ENOPROTOOPT; | 1201 | err = -ENOPROTOOPT; |
1172 | } | 1202 | } |
@@ -1199,6 +1229,26 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname, | |||
1199 | return -EFAULT; | 1229 | return -EFAULT; |
1200 | err = 0; | 1230 | err = 0; |
1201 | break; | 1231 | break; |
1232 | case NETLINK_BROADCAST_ERROR: | ||
1233 | if (len < sizeof(int)) | ||
1234 | return -EINVAL; | ||
1235 | len = sizeof(int); | ||
1236 | val = nlk->flags & NETLINK_BROADCAST_SEND_ERROR ? 1 : 0; | ||
1237 | if (put_user(len, optlen) || | ||
1238 | put_user(val, optval)) | ||
1239 | return -EFAULT; | ||
1240 | err = 0; | ||
1241 | break; | ||
1242 | case NETLINK_NO_ENOBUFS: | ||
1243 | if (len < sizeof(int)) | ||
1244 | return -EINVAL; | ||
1245 | len = sizeof(int); | ||
1246 | val = nlk->flags & NETLINK_RECV_NO_ENOBUFS ? 1 : 0; | ||
1247 | if (put_user(len, optlen) || | ||
1248 | put_user(val, optval)) | ||
1249 | return -EFAULT; | ||
1250 | err = 0; | ||
1251 | break; | ||
1202 | default: | 1252 | default: |
1203 | err = -ENOPROTOOPT; | 1253 | err = -ENOPROTOOPT; |
1204 | } | 1254 | } |
@@ -1525,8 +1575,7 @@ EXPORT_SYMBOL(netlink_set_nonroot); | |||
1525 | 1575 | ||
1526 | static void netlink_destroy_callback(struct netlink_callback *cb) | 1576 | static void netlink_destroy_callback(struct netlink_callback *cb) |
1527 | { | 1577 | { |
1528 | if (cb->skb) | 1578 | kfree_skb(cb->skb); |
1529 | kfree_skb(cb->skb); | ||
1530 | kfree(cb); | 1579 | kfree(cb); |
1531 | } | 1580 | } |
1532 | 1581 | ||
@@ -1743,12 +1792,18 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, | |||
1743 | exclude_pid = pid; | 1792 | exclude_pid = pid; |
1744 | } | 1793 | } |
1745 | 1794 | ||
1746 | /* errors reported via destination sk->sk_err */ | 1795 | /* errors reported via destination sk->sk_err, but propagate |
1747 | nlmsg_multicast(sk, skb, exclude_pid, group, flags); | 1796 | * delivery errors if NETLINK_BROADCAST_ERROR flag is set */ |
1797 | err = nlmsg_multicast(sk, skb, exclude_pid, group, flags); | ||
1748 | } | 1798 | } |
1749 | 1799 | ||
1750 | if (report) | 1800 | if (report) { |
1751 | err = nlmsg_unicast(sk, skb, pid); | 1801 | int err2; |
1802 | |||
1803 | err2 = nlmsg_unicast(sk, skb, pid); | ||
1804 | if (!err || err == -ESRCH) | ||
1805 | err = err2; | ||
1806 | } | ||
1752 | 1807 | ||
1753 | return err; | 1808 | return err; |
1754 | } | 1809 | } |
@@ -1849,12 +1904,12 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
1849 | if (v == SEQ_START_TOKEN) | 1904 | if (v == SEQ_START_TOKEN) |
1850 | seq_puts(seq, | 1905 | seq_puts(seq, |
1851 | "sk Eth Pid Groups " | 1906 | "sk Eth Pid Groups " |
1852 | "Rmem Wmem Dump Locks\n"); | 1907 | "Rmem Wmem Dump Locks Drops\n"); |
1853 | else { | 1908 | else { |
1854 | struct sock *s = v; | 1909 | struct sock *s = v; |
1855 | struct netlink_sock *nlk = nlk_sk(s); | 1910 | struct netlink_sock *nlk = nlk_sk(s); |
1856 | 1911 | ||
1857 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %d\n", | 1912 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d\n", |
1858 | s, | 1913 | s, |
1859 | s->sk_protocol, | 1914 | s->sk_protocol, |
1860 | nlk->pid, | 1915 | nlk->pid, |
@@ -1862,7 +1917,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
1862 | atomic_read(&s->sk_rmem_alloc), | 1917 | atomic_read(&s->sk_rmem_alloc), |
1863 | atomic_read(&s->sk_wmem_alloc), | 1918 | atomic_read(&s->sk_wmem_alloc), |
1864 | nlk->cb, | 1919 | nlk->cb, |
1865 | atomic_read(&s->sk_refcnt) | 1920 | atomic_read(&s->sk_refcnt), |
1921 | atomic_read(&s->sk_drops) | ||
1866 | ); | 1922 | ); |
1867 | 1923 | ||
1868 | } | 1924 | } |