diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
| -rw-r--r-- | net/netlink/af_netlink.c | 20 | 
1 files changed, 17 insertions, 3 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 320d0423a24..795424396af 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -683,6 +683,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,  	struct netlink_sock *nlk = nlk_sk(sk);  	struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; +	if (alen < sizeof(addr->sa_family)) +		return -EINVAL; +  	if (addr->sa_family == AF_UNSPEC) {  		sk->sk_state	= NETLINK_UNCONNECTED;  		nlk->dst_pid	= 0; @@ -1093,6 +1096,7 @@ static inline int do_one_set_err(struct sock *sk,  				 struct netlink_set_err_data *p)  {  	struct netlink_sock *nlk = nlk_sk(sk); +	int ret = 0;  	if (sk == p->exclude_sk)  		goto out; @@ -1104,10 +1108,15 @@ static inline int do_one_set_err(struct sock *sk,  	    !test_bit(p->group - 1, nlk->groups))  		goto out; +	if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS) { +		ret = 1; +		goto out; +	} +  	sk->sk_err = p->code;  	sk->sk_error_report(sk);  out: -	return 0; +	return ret;  }  /** @@ -1116,12 +1125,16 @@ out:   * @pid: the PID of a process that we want to skip (if any)   * @groups: the broadcast group that will notice the error   * @code: error code, must be negative (as usual in kernelspace) + * + * This function returns the number of broadcast listeners that have set the + * NETLINK_RECV_NO_ENOBUFS socket option.   */ -void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) +int netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)  {  	struct netlink_set_err_data info;  	struct hlist_node *node;  	struct sock *sk; +	int ret = 0;  	info.exclude_sk = ssk;  	info.pid = pid; @@ -1132,9 +1145,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)  	read_lock(&nl_table_lock);  	sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) -		do_one_set_err(sk, &info); +		ret += do_one_set_err(sk, &info);  	read_unlock(&nl_table_lock); +	return ret;  }  EXPORT_SYMBOL(netlink_set_err);  |