aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c55
1 files changed, 44 insertions, 11 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 5b33879c6422..b73d4e61c5ac 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;
@@ -1045,10 +1049,9 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
1045 1049
1046 netlink_unlock_table(); 1050 netlink_unlock_table();
1047 1051
1048 if (info.skb2) 1052 kfree_skb(info.skb2);
1049 kfree_skb(info.skb2);
1050 1053
1051 if (info.delivery_failure || info.failure) 1054 if (info.delivery_failure)
1052 return -ENOBUFS; 1055 return -ENOBUFS;
1053 1056
1054 if (info.delivered) { 1057 if (info.delivered) {
@@ -1088,6 +1091,13 @@ out:
1088 return 0; 1091 return 0;
1089} 1092}
1090 1093
1094/**
1095 * netlink_set_err - report error to broadcast listeners
1096 * @ssk: the kernel netlink socket, as returned by netlink_kernel_create()
1097 * @pid: the PID of a process that we want to skip (if any)
1098 * @groups: the broadcast group that will notice the error
1099 * @code: error code, must be negative (as usual in kernelspace)
1100 */
1091void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) 1101void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
1092{ 1102{
1093 struct netlink_set_err_data info; 1103 struct netlink_set_err_data info;
@@ -1097,7 +1107,8 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
1097 info.exclude_sk = ssk; 1107 info.exclude_sk = ssk;
1098 info.pid = pid; 1108 info.pid = pid;
1099 info.group = group; 1109 info.group = group;
1100 info.code = code; 1110 /* sk->sk_err wants a positive error value */
1111 info.code = -code;
1101 1112
1102 read_lock(&nl_table_lock); 1113 read_lock(&nl_table_lock);
1103 1114
@@ -1164,6 +1175,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
1164 err = 0; 1175 err = 0;
1165 break; 1176 break;
1166 } 1177 }
1178 case NETLINK_BROADCAST_ERROR:
1179 if (val)
1180 nlk->flags |= NETLINK_BROADCAST_SEND_ERROR;
1181 else
1182 nlk->flags &= ~NETLINK_BROADCAST_SEND_ERROR;
1183 err = 0;
1184 break;
1167 default: 1185 default:
1168 err = -ENOPROTOOPT; 1186 err = -ENOPROTOOPT;
1169 } 1187 }
@@ -1196,6 +1214,16 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
1196 return -EFAULT; 1214 return -EFAULT;
1197 err = 0; 1215 err = 0;
1198 break; 1216 break;
1217 case NETLINK_BROADCAST_ERROR:
1218 if (len < sizeof(int))
1219 return -EINVAL;
1220 len = sizeof(int);
1221 val = nlk->flags & NETLINK_BROADCAST_SEND_ERROR ? 1 : 0;
1222 if (put_user(len, optlen) ||
1223 put_user(val, optval))
1224 return -EFAULT;
1225 err = 0;
1226 break;
1199 default: 1227 default:
1200 err = -ENOPROTOOPT; 1228 err = -ENOPROTOOPT;
1201 } 1229 }
@@ -1522,8 +1550,7 @@ EXPORT_SYMBOL(netlink_set_nonroot);
1522 1550
1523static void netlink_destroy_callback(struct netlink_callback *cb) 1551static void netlink_destroy_callback(struct netlink_callback *cb)
1524{ 1552{
1525 if (cb->skb) 1553 kfree_skb(cb->skb);
1526 kfree_skb(cb->skb);
1527 kfree(cb); 1554 kfree(cb);
1528} 1555}
1529 1556
@@ -1740,12 +1767,18 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
1740 exclude_pid = pid; 1767 exclude_pid = pid;
1741 } 1768 }
1742 1769
1743 /* errors reported via destination sk->sk_err */ 1770 /* errors reported via destination sk->sk_err, but propagate
1744 nlmsg_multicast(sk, skb, exclude_pid, group, flags); 1771 * delivery errors if NETLINK_BROADCAST_ERROR flag is set */
1772 err = nlmsg_multicast(sk, skb, exclude_pid, group, flags);
1745 } 1773 }
1746 1774
1747 if (report) 1775 if (report) {
1748 err = nlmsg_unicast(sk, skb, pid); 1776 int err2;
1777
1778 err2 = nlmsg_unicast(sk, skb, pid);
1779 if (!err || err == -ESRCH)
1780 err = err2;
1781 }
1749 1782
1750 return err; 1783 return err;
1751} 1784}