diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 427 | 
1 files changed, 265 insertions, 162 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 911b71b26b0..42989968940 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -28,9 +28,8 @@   * See the GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING.  If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING.  If not, see + * <http://www.gnu.org/licenses/>.   *   * Please send any bug reports or fixes you make to the   * email address(es): @@ -65,12 +64,14 @@  #include <linux/crypto.h>  #include <linux/slab.h>  #include <linux/file.h> +#include <linux/compat.h>  #include <net/ip.h>  #include <net/icmp.h>  #include <net/route.h>  #include <net/ipv6.h>  #include <net/inet_common.h> +#include <net/busy_poll.h>  #include <linux/socket.h> /* for sa_family_t */  #include <linux/export.h> @@ -83,7 +84,7 @@ static int sctp_writeable(struct sock *sk);  static void sctp_wfree(struct sk_buff *skb);  static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,  				size_t msg_len); -static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); +static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p);  static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);  static int sctp_wait_for_accept(struct sock *sk, long timeo);  static void sctp_wait_for_close(struct sock *sk, long timeo); @@ -273,7 +274,7 @@ static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len)  {  	int retval = 0; -	sctp_lock_sock(sk); +	lock_sock(sk);  	pr_debug("%s: sk:%p, addr:%p, addr_len:%d\n", __func__, sk,  		 addr, addr_len); @@ -285,7 +286,7 @@ static int sctp_bind(struct sock *sk, struct sockaddr *addr, int addr_len)  	else  		retval = -EINVAL; -	sctp_release_sock(sk); +	release_sock(sk);  	return retval;  } @@ -953,7 +954,7 @@ int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw)   *   * Returns 0 if ok, <0 errno code on error.   */ -static int sctp_setsockopt_bindx(struct sock* sk, +static int sctp_setsockopt_bindx(struct sock *sk,  				 struct sockaddr __user *addrs,  				 int addrs_size, int op)  { @@ -1040,7 +1041,7 @@ out:   * Common routine for handling connect() and sctp_connectx().   * Connect will come in with just a single address.   */ -static int __sctp_connect(struct sock* sk, +static int __sctp_connect(struct sock *sk,  			  struct sockaddr *kaddrs,  			  int addrs_size,  			  sctp_assoc_t *assoc_id) @@ -1300,7 +1301,7 @@ out_free:   *   * Returns >=0 if ok, <0 errno code on error.   */ -static int __sctp_setsockopt_connectx(struct sock* sk, +static int __sctp_setsockopt_connectx(struct sock *sk,  				      struct sockaddr __user *addrs,  				      int addrs_size,  				      sctp_assoc_t *assoc_id) @@ -1338,7 +1339,7 @@ static int __sctp_setsockopt_connectx(struct sock* sk,   * This is an older interface.  It's kept for backward compatibility   * to the option that doesn't provide association id.   */ -static int sctp_setsockopt_connectx_old(struct sock* sk, +static int sctp_setsockopt_connectx_old(struct sock *sk,  					struct sockaddr __user *addrs,  					int addrs_size)  { @@ -1351,7 +1352,7 @@ static int sctp_setsockopt_connectx_old(struct sock* sk,   * indication to the call.  Error is always negative and association id is   * always positive.   */ -static int sctp_setsockopt_connectx(struct sock* sk, +static int sctp_setsockopt_connectx(struct sock *sk,  				    struct sockaddr __user *addrs,  				    int addrs_size)  { @@ -1369,12 +1370,20 @@ static int sctp_setsockopt_connectx(struct sock* sk,  /*   * New (hopefully final) interface for the API.   * We use the sctp_getaddrs_old structure so that use-space library - * can avoid any unnecessary allocations.   The only defferent part + * can avoid any unnecessary allocations. The only different part   * is that we store the actual length of the address buffer into the - * addrs_num structure member.  That way we can re-use the existing + * addrs_num structure member. That way we can re-use the existing   * code.   */ -static int sctp_getsockopt_connectx3(struct sock* sk, int len, +#ifdef CONFIG_COMPAT +struct compat_sctp_getaddrs_old { +	sctp_assoc_t	assoc_id; +	s32		addr_num; +	compat_uptr_t	addrs;		/* struct sockaddr * */ +}; +#endif + +static int sctp_getsockopt_connectx3(struct sock *sk, int len,  				     char __user *optval,  				     int __user *optlen)  { @@ -1382,16 +1391,30 @@ static int sctp_getsockopt_connectx3(struct sock* sk, int len,  	sctp_assoc_t assoc_id = 0;  	int err = 0; -	if (len < sizeof(param)) -		return -EINVAL; +#ifdef CONFIG_COMPAT +	if (is_compat_task()) { +		struct compat_sctp_getaddrs_old param32; -	if (copy_from_user(¶m, optval, sizeof(param))) -		return -EFAULT; +		if (len < sizeof(param32)) +			return -EINVAL; +		if (copy_from_user(¶m32, optval, sizeof(param32))) +			return -EFAULT; -	err = __sctp_setsockopt_connectx(sk, -			(struct sockaddr __user *)param.addrs, -			param.addr_num, &assoc_id); +		param.assoc_id = param32.assoc_id; +		param.addr_num = param32.addr_num; +		param.addrs = compat_ptr(param32.addrs); +	} else +#endif +	{ +		if (len < sizeof(param)) +			return -EINVAL; +		if (copy_from_user(¶m, optval, sizeof(param))) +			return -EFAULT; +	} +	err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *) +					 param.addrs, param.addr_num, +					 &assoc_id);  	if (err == 0 || err == -EINPROGRESS) {  		if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))  			return -EFAULT; @@ -1462,7 +1485,7 @@ static void sctp_close(struct sock *sk, long timeout)  	pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); -	sctp_lock_sock(sk); +	lock_sock(sk);  	sk->sk_shutdown = SHUTDOWN_MASK;  	sk->sk_state = SCTP_SS_CLOSING; @@ -1506,13 +1529,13 @@ static void sctp_close(struct sock *sk, long timeout)  		sctp_wait_for_close(sk, timeout);  	/* This will run the backlog queue.  */ -	sctp_release_sock(sk); +	release_sock(sk);  	/* Supposedly, no process has access to the socket, but  	 * the net layers still may.  	 */ -	sctp_local_bh_disable(); -	sctp_bh_lock_sock(sk); +	local_bh_disable(); +	bh_lock_sock(sk);  	/* Hold the sock, since sk_common_release() will put sock_put()  	 * and we have just a little more cleanup. @@ -1520,8 +1543,8 @@ static void sctp_close(struct sock *sk, long timeout)  	sock_hold(sk);  	sk_common_release(sk); -	sctp_bh_unlock_sock(sk); -	sctp_local_bh_enable(); +	bh_unlock_sock(sk); +	local_bh_enable();  	sock_put(sk); @@ -1569,7 +1592,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,  	struct net *net = sock_net(sk);  	struct sctp_sock *sp;  	struct sctp_endpoint *ep; -	struct sctp_association *new_asoc=NULL, *asoc=NULL; +	struct sctp_association *new_asoc = NULL, *asoc = NULL;  	struct sctp_transport *transport, *chunk_tp;  	struct sctp_chunk *chunk;  	union sctp_addr to; @@ -1666,7 +1689,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,  	pr_debug("%s: about to look up association\n", __func__); -	sctp_lock_sock(sk); +	lock_sock(sk);  	/* If a msg_name has been specified, assume this is to be used.  */  	if (msg_name) { @@ -1744,7 +1767,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,  		 * either the default or the user specified stream counts.  		 */  		if (sinfo) { -			if (!sinit || (sinit && !sinit->sinit_num_ostreams)) { +			if (!sinit || !sinit->sinit_num_ostreams) {  				/* Check against the defaults. */  				if (sinfo->sinfo_stream >=  				    sp->initmsg.sinit_num_ostreams) { @@ -1950,7 +1973,7 @@ out_free:  		sctp_association_free(asoc);  	}  out_unlock: -	sctp_release_sock(sk); +	release_sock(sk);  out_nounlock:  	return sctp_error(sk, msg_flags, err); @@ -2036,7 +2059,7 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,  		 "addr_len:%p)\n", __func__, sk, msg, len, noblock, flags,  		 addr_len); -	sctp_lock_sock(sk); +	lock_sock(sk);  	if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) {  		err = -ENOTCONN; @@ -2120,7 +2143,7 @@ out_free:  		sctp_ulpevent_free(event);  	}  out: -	sctp_release_sock(sk); +	release_sock(sk);  	return err;  } @@ -2196,6 +2219,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,  				     unsigned int optlen)  {  	struct sctp_sock *sp = sctp_sk(sk); +	struct net *net = sock_net(sk);  	/* Applicable to UDP-style socket only */  	if (sctp_style(sk, TCP)) @@ -2205,6 +2229,9 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,  	if (copy_from_user(&sp->autoclose, optval, optlen))  		return -EFAULT; +	if (sp->autoclose > net->sctp.max_autoclose) +		sp->autoclose = net->sctp.max_autoclose; +  	return 0;  } @@ -2459,7 +2486,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,  	int hb_change, pmtud_change, sackdelay_change;  	if (optlen != sizeof(struct sctp_paddrparams)) -		return - EINVAL; +		return -EINVAL;  	if (copy_from_user(¶ms, optval, optlen))  		return -EFAULT; @@ -2480,7 +2507,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,  	/* If an address other than INADDR_ANY is specified, and  	 * no transport is found, then the request is invalid.  	 */ -	if (!sctp_is_any(sk, ( union sctp_addr *)¶ms.spp_address)) { +	if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) {  		trans = sctp_addr_id2transport(sk, ¶ms.spp_address,  					       params.spp_assoc_id);  		if (!trans) @@ -2524,6 +2551,16 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,  	return 0;  } +static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags) +{ +	return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; +} + +static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags) +{ +	return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; +} +  /*   * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)   * @@ -2575,8 +2612,11 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,  		if (params.sack_delay == 0 && params.sack_freq == 0)  			return 0;  	} else if (optlen == sizeof(struct sctp_assoc_value)) { -		pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n"); -		pr_warn("Use struct sctp_sack_info instead\n"); +		pr_warn_ratelimited(DEPRECATED +				    "%s (pid %d) " +				    "Use of struct sctp_assoc_value in delayed_ack socket option.\n" +				    "Use struct sctp_sack_info instead\n", +				    current->comm, task_pid_nr(current));  		if (copy_from_user(¶ms, optval, optlen))  			return -EFAULT; @@ -2585,7 +2625,7 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,  		else  			params.sack_freq = 0;  	} else -		return - EINVAL; +		return -EINVAL;  	/* Validate value parameter. */  	if (params.sack_delay > 500) @@ -2604,37 +2644,31 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,  			asoc->sackdelay =  				msecs_to_jiffies(params.sack_delay);  			asoc->param_flags = -				(asoc->param_flags & ~SPP_SACKDELAY) | -				SPP_SACKDELAY_ENABLE; +				sctp_spp_sackdelay_enable(asoc->param_flags);  		} else {  			sp->sackdelay = params.sack_delay;  			sp->param_flags = -				(sp->param_flags & ~SPP_SACKDELAY) | -				SPP_SACKDELAY_ENABLE; +				sctp_spp_sackdelay_enable(sp->param_flags);  		}  	}  	if (params.sack_freq == 1) {  		if (asoc) {  			asoc->param_flags = -				(asoc->param_flags & ~SPP_SACKDELAY) | -				SPP_SACKDELAY_DISABLE; +				sctp_spp_sackdelay_disable(asoc->param_flags);  		} else {  			sp->param_flags = -				(sp->param_flags & ~SPP_SACKDELAY) | -				SPP_SACKDELAY_DISABLE; +				sctp_spp_sackdelay_disable(sp->param_flags);  		}  	} else if (params.sack_freq > 1) {  		if (asoc) {  			asoc->sackfreq = params.sack_freq;  			asoc->param_flags = -				(asoc->param_flags & ~SPP_SACKDELAY) | -				SPP_SACKDELAY_ENABLE; +				sctp_spp_sackdelay_enable(asoc->param_flags);  		} else {  			sp->sackfreq = params.sack_freq;  			sp->param_flags = -				(sp->param_flags & ~SPP_SACKDELAY) | -				SPP_SACKDELAY_ENABLE; +				sctp_spp_sackdelay_enable(sp->param_flags);  		}  	} @@ -2646,18 +2680,15 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,  				trans->sackdelay =  					msecs_to_jiffies(params.sack_delay);  				trans->param_flags = -					(trans->param_flags & ~SPP_SACKDELAY) | -					SPP_SACKDELAY_ENABLE; +					sctp_spp_sackdelay_enable(trans->param_flags);  			}  			if (params.sack_freq == 1) {  				trans->param_flags = -					(trans->param_flags & ~SPP_SACKDELAY) | -					SPP_SACKDELAY_DISABLE; +					sctp_spp_sackdelay_disable(trans->param_flags);  			} else if (params.sack_freq > 1) {  				trans->sackfreq = params.sack_freq;  				trans->param_flags = -					(trans->param_flags & ~SPP_SACKDELAY) | -					SPP_SACKDELAY_ENABLE; +					sctp_spp_sackdelay_enable(trans->param_flags);  			}  		}  	} @@ -2811,6 +2842,8 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne  {  	struct sctp_rtoinfo rtoinfo;  	struct sctp_association *asoc; +	unsigned long rto_min, rto_max; +	struct sctp_sock *sp = sctp_sk(sk);  	if (optlen != sizeof (struct sctp_rtoinfo))  		return -EINVAL; @@ -2824,26 +2857,36 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne  	if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP))  		return -EINVAL; +	rto_max = rtoinfo.srto_max; +	rto_min = rtoinfo.srto_min; + +	if (rto_max) +		rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max; +	else +		rto_max = asoc ? asoc->rto_max : sp->rtoinfo.srto_max; + +	if (rto_min) +		rto_min = asoc ? msecs_to_jiffies(rto_min) : rto_min; +	else +		rto_min = asoc ? asoc->rto_min : sp->rtoinfo.srto_min; + +	if (rto_min > rto_max) +		return -EINVAL; +  	if (asoc) {  		if (rtoinfo.srto_initial != 0)  			asoc->rto_initial =  				msecs_to_jiffies(rtoinfo.srto_initial); -		if (rtoinfo.srto_max != 0) -			asoc->rto_max = msecs_to_jiffies(rtoinfo.srto_max); -		if (rtoinfo.srto_min != 0) -			asoc->rto_min = msecs_to_jiffies(rtoinfo.srto_min); +		asoc->rto_max = rto_max; +		asoc->rto_min = rto_min;  	} else {  		/* If there is no association or the association-id = 0  		 * set the values to the endpoint.  		 */ -		struct sctp_sock *sp = sctp_sk(sk); -  		if (rtoinfo.srto_initial != 0)  			sp->rtoinfo.srto_initial = rtoinfo.srto_initial; -		if (rtoinfo.srto_max != 0) -			sp->rtoinfo.srto_max = rtoinfo.srto_max; -		if (rtoinfo.srto_min != 0) -			sp->rtoinfo.srto_min = rtoinfo.srto_min; +		sp->rtoinfo.srto_max = rto_max; +		sp->rtoinfo.srto_min = rto_min;  	}  	return 0; @@ -2979,8 +3022,11 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned  	int val;  	if (optlen == sizeof(int)) { -		pr_warn("Use of int in maxseg socket option deprecated\n"); -		pr_warn("Use struct sctp_assoc_value instead\n"); +		pr_warn_ratelimited(DEPRECATED +				    "%s (pid %d) " +				    "Use of int in maxseg socket option.\n" +				    "Use struct sctp_assoc_value instead\n", +				    current->comm, task_pid_nr(current));  		if (copy_from_user(&val, optval, optlen))  			return -EFAULT;  		params.assoc_id = 0; @@ -3237,8 +3283,11 @@ static int sctp_setsockopt_maxburst(struct sock *sk,  	int assoc_id = 0;  	if (optlen == sizeof(int)) { -		pr_warn("Use of int in max_burst socket option deprecated\n"); -		pr_warn("Use struct sctp_assoc_value instead\n"); +		pr_warn_ratelimited(DEPRECATED +				    "%s (pid %d) " +				    "Use of int in max_burst socket option deprecated.\n" +				    "Use struct sctp_assoc_value instead\n", +				    current->comm, task_pid_nr(current));  		if (copy_from_user(&val, optval, optlen))  			return -EFAULT;  	} else if (optlen == sizeof(struct sctp_assoc_value)) { @@ -3273,10 +3322,10 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,  				      char __user *optval,  				      unsigned int optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_authchunk val; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (optlen != sizeof(struct sctp_authchunk)) @@ -3293,7 +3342,7 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,  	}  	/* add this chunk id to the endpoint */ -	return sctp_auth_ep_add_chunkid(sctp_sk(sk)->ep, val.sauth_chunk); +	return sctp_auth_ep_add_chunkid(ep, val.sauth_chunk);  }  /* @@ -3306,18 +3355,18 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,  				      char __user *optval,  				      unsigned int optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_hmacalgo *hmacs;  	u32 idents;  	int err; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (optlen < sizeof(struct sctp_hmacalgo))  		return -EINVAL; -	hmacs= memdup_user(optval, optlen); +	hmacs = memdup_user(optval, optlen);  	if (IS_ERR(hmacs))  		return PTR_ERR(hmacs); @@ -3328,7 +3377,7 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,  		goto out;  	} -	err = sctp_auth_ep_set_hmacs(sctp_sk(sk)->ep, hmacs); +	err = sctp_auth_ep_set_hmacs(ep, hmacs);  out:  	kfree(hmacs);  	return err; @@ -3344,18 +3393,18 @@ static int sctp_setsockopt_auth_key(struct sock *sk,  				    char __user *optval,  				    unsigned int optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_authkey *authkey;  	struct sctp_association *asoc;  	int ret; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (optlen <= sizeof(struct sctp_authkey))  		return -EINVAL; -	authkey= memdup_user(optval, optlen); +	authkey = memdup_user(optval, optlen);  	if (IS_ERR(authkey))  		return PTR_ERR(authkey); @@ -3370,7 +3419,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk,  		goto out;  	} -	ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey); +	ret = sctp_auth_set_key(ep, asoc, authkey);  out:  	kzfree(authkey);  	return ret; @@ -3386,11 +3435,11 @@ static int sctp_setsockopt_active_key(struct sock *sk,  				      char __user *optval,  				      unsigned int optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_authkeyid val;  	struct sctp_association *asoc; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (optlen != sizeof(struct sctp_authkeyid)) @@ -3402,8 +3451,7 @@ static int sctp_setsockopt_active_key(struct sock *sk,  	if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))  		return -EINVAL; -	return sctp_auth_set_active_key(sctp_sk(sk)->ep, asoc, -					val.scact_keynumber); +	return sctp_auth_set_active_key(ep, asoc, val.scact_keynumber);  }  /* @@ -3415,11 +3463,11 @@ static int sctp_setsockopt_del_key(struct sock *sk,  				   char __user *optval,  				   unsigned int optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_authkeyid val;  	struct sctp_association *asoc; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (optlen != sizeof(struct sctp_authkeyid)) @@ -3431,8 +3479,7 @@ static int sctp_setsockopt_del_key(struct sock *sk,  	if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))  		return -EINVAL; -	return sctp_auth_del_key_id(sctp_sk(sk)->ep, asoc, -				    val.scact_keynumber); +	return sctp_auth_del_key_id(ep, asoc, val.scact_keynumber);  } @@ -3565,7 +3612,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,  		goto out_nounlock;  	} -	sctp_lock_sock(sk); +	lock_sock(sk);  	switch (optname) {  	case SCTP_SOCKOPT_BINDX_ADD: @@ -3683,7 +3730,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,  		break;  	} -	sctp_release_sock(sk); +	release_sock(sk);  out_nounlock:  	return retval; @@ -3711,7 +3758,7 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr,  	int err = 0;  	struct sctp_af *af; -	sctp_lock_sock(sk); +	lock_sock(sk);  	pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,  		 addr, addr_len); @@ -3727,7 +3774,7 @@ static int sctp_connect(struct sock *sk, struct sockaddr *addr,  		err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);  	} -	sctp_release_sock(sk); +	release_sock(sk);  	return err;  } @@ -3753,7 +3800,7 @@ static struct sock *sctp_accept(struct sock *sk, int flags, int *err)  	long timeo;  	int error = 0; -	sctp_lock_sock(sk); +	lock_sock(sk);  	sp = sctp_sk(sk);  	ep = sp->ep; @@ -3791,7 +3838,7 @@ static struct sock *sctp_accept(struct sock *sk, int flags, int *err)  	sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP);  out: -	sctp_release_sock(sk); +	release_sock(sk);  	*err = error;  	return newsk;  } @@ -3801,7 +3848,7 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)  {  	int rc = -ENOTCONN; -	sctp_lock_sock(sk); +	lock_sock(sk);  	/*  	 * SEQPACKET-style sockets in LISTENING state are valid, for @@ -3831,7 +3878,7 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)  		break;  	}  out: -	sctp_release_sock(sk); +	release_sock(sk);  	return rc;  } @@ -3909,7 +3956,7 @@ static int sctp_init_sock(struct sock *sk)  	 */  	sp->hbinterval  = net->sctp.hb_interval;  	sp->pathmaxrxt  = net->sctp.max_retrans_path; -	sp->pathmtu     = 0; // allow default discovery +	sp->pathmtu     = 0; /* allow default discovery */  	sp->sackdelay   = net->sctp.sack_timeout;  	sp->sackfreq	= 2;  	sp->param_flags = SPP_HB_ENABLE | @@ -4452,7 +4499,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,  	/* If an address other than INADDR_ANY is specified, and  	 * no transport is found, then the request is invalid.  	 */ -	if (!sctp_is_any(sk, ( union sctp_addr *)¶ms.spp_address)) { +	if (!sctp_is_any(sk, (union sctp_addr *)¶ms.spp_address)) {  		trans = sctp_addr_id2transport(sk, ¶ms.spp_address,  					       params.spp_assoc_id);  		if (!trans) { @@ -4558,12 +4605,15 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,  		if (copy_from_user(¶ms, optval, len))  			return -EFAULT;  	} else if (len == sizeof(struct sctp_assoc_value)) { -		pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n"); -		pr_warn("Use struct sctp_sack_info instead\n"); +		pr_warn_ratelimited(DEPRECATED +				    "%s (pid %d) " +				    "Use of struct sctp_assoc_value in delayed_ack socket option.\n" +				    "Use struct sctp_sack_info instead\n", +				    current->comm, task_pid_nr(current));  		if (copy_from_user(¶ms, optval, len))  			return -EFAULT;  	} else -		return - EINVAL; +		return -EINVAL;  	/* Get association, if sack_assoc_id != 0 and the socket is a one  	 * to many style socket, and an association was not found, then @@ -4653,8 +4703,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,  	if (!asoc)  		return -EINVAL; -	to = optval + offsetof(struct sctp_getaddrs,addrs); -	space_left = len - offsetof(struct sctp_getaddrs,addrs); +	to = optval + offsetof(struct sctp_getaddrs, addrs); +	space_left = len - offsetof(struct sctp_getaddrs, addrs);  	list_for_each_entry(from, &asoc->peer.transport_addr_list,  				transports) { @@ -4714,7 +4764,7 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,  		memcpy(to, &temp, addrlen);  		to += addrlen; -		cnt ++; +		cnt++;  		space_left -= addrlen;  		*bytes_copied += addrlen;  	} @@ -4763,8 +4813,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,  		bp = &asoc->base.bind_addr;  	} -	to = optval + offsetof(struct sctp_getaddrs,addrs); -	space_left = len - offsetof(struct sctp_getaddrs,addrs); +	to = optval + offsetof(struct sctp_getaddrs, addrs); +	space_left = len - offsetof(struct sctp_getaddrs, addrs);  	addrs = kmalloc(space_left, GFP_KERNEL);  	if (!addrs) @@ -4803,7 +4853,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,  		memcpy(buf, &temp, addrlen);  		buf += addrlen;  		bytes_copied += addrlen; -		cnt ++; +		cnt++;  		space_left -= addrlen;  	} @@ -5075,7 +5125,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len,  		assocparams.sasoc_cookie_life = ktime_to_ms(asoc->cookie_life);  		list_for_each(pos, &asoc->peer.transport_addr_list) { -			cnt ++; +			cnt++;  		}  		assocparams.sasoc_number_peer_destinations = cnt; @@ -5203,8 +5253,11 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,  	struct sctp_association *asoc;  	if (len == sizeof(int)) { -		pr_warn("Use of int in maxseg socket option deprecated\n"); -		pr_warn("Use struct sctp_assoc_value instead\n"); +		pr_warn_ratelimited(DEPRECATED +				    "%s (pid %d) " +				    "Use of int in maxseg socket option.\n" +				    "Use struct sctp_assoc_value instead\n", +				    current->comm, task_pid_nr(current));  		params.assoc_id = 0;  	} else if (len >= sizeof(struct sctp_assoc_value)) {  		len = sizeof(struct sctp_assoc_value); @@ -5295,8 +5348,11 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,  	struct sctp_association *asoc;  	if (len == sizeof(int)) { -		pr_warn("Use of int in max_burst socket option deprecated\n"); -		pr_warn("Use struct sctp_assoc_value instead\n"); +		pr_warn_ratelimited(DEPRECATED +				    "%s (pid %d) " +				    "Use of int in max_burst socket option.\n" +				    "Use struct sctp_assoc_value instead\n", +				    current->comm, task_pid_nr(current));  		params.assoc_id = 0;  	} else if (len >= sizeof(struct sctp_assoc_value)) {  		len = sizeof(struct sctp_assoc_value); @@ -5330,16 +5386,16 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,  static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,  				    char __user *optval, int __user *optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_hmacalgo  __user *p = (void __user *)optval;  	struct sctp_hmac_algo_param *hmacs;  	__u16 data_len = 0;  	u32 num_idents; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES; -	hmacs = sctp_sk(sk)->ep->auth_hmacs_list; +	hmacs = ep->auth_hmacs_list;  	data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t);  	if (len < sizeof(struct sctp_hmacalgo) + data_len) @@ -5360,11 +5416,11 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,  static int sctp_getsockopt_active_key(struct sock *sk, int len,  				    char __user *optval, int __user *optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_authkeyid val;  	struct sctp_association *asoc; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (len < sizeof(struct sctp_authkeyid)) @@ -5379,7 +5435,7 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,  	if (asoc)  		val.scact_keynumber = asoc->active_key_id;  	else -		val.scact_keynumber = sctp_sk(sk)->ep->active_key_id; +		val.scact_keynumber = ep->active_key_id;  	len = sizeof(struct sctp_authkeyid);  	if (put_user(len, optlen)) @@ -5393,7 +5449,7 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,  static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,  				    char __user *optval, int __user *optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_authchunks __user *p = (void __user *)optval;  	struct sctp_authchunks val;  	struct sctp_association *asoc; @@ -5401,7 +5457,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,  	u32    num_chunks = 0;  	char __user *to; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (len < sizeof(struct sctp_authchunks)) @@ -5428,7 +5484,8 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,  		return -EFAULT;  num:  	len = sizeof(struct sctp_authchunks) + num_chunks; -	if (put_user(len, optlen)) return -EFAULT; +	if (put_user(len, optlen)) +		return -EFAULT;  	if (put_user(num_chunks, &p->gauth_number_of_chunks))  		return -EFAULT;  	return 0; @@ -5437,7 +5494,7 @@ num:  static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,  				    char __user *optval, int __user *optlen)  { -	struct net *net = sock_net(sk); +	struct sctp_endpoint *ep = sctp_sk(sk)->ep;  	struct sctp_authchunks __user *p = (void __user *)optval;  	struct sctp_authchunks val;  	struct sctp_association *asoc; @@ -5445,7 +5502,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,  	u32    num_chunks = 0;  	char __user *to; -	if (!net->sctp.auth_enable) +	if (!ep->auth_enable)  		return -EACCES;  	if (len < sizeof(struct sctp_authchunks)) @@ -5460,9 +5517,9 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,  		return -EINVAL;  	if (asoc) -		ch = (struct sctp_chunks_param*)asoc->c.auth_chunks; +		ch = (struct sctp_chunks_param *)asoc->c.auth_chunks;  	else -		ch = sctp_sk(sk)->ep->auth_chunk_list; +		ch = ep->auth_chunk_list;  	if (!ch)  		goto num; @@ -5719,7 +5776,7 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,  	if (get_user(len, optlen))  		return -EFAULT; -	sctp_lock_sock(sk); +	lock_sock(sk);  	switch (optname) {  	case SCTP_STATUS: @@ -5843,7 +5900,7 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,  		break;  	} -	sctp_release_sock(sk); +	release_sock(sk);  	return retval;  } @@ -5883,33 +5940,34 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)  	pr_debug("%s: begins, snum:%d\n", __func__, snum); -	sctp_local_bh_disable(); +	local_bh_disable();  	if (snum == 0) {  		/* Search for an available port. */  		int low, high, remaining, index;  		unsigned int rover; +		struct net *net = sock_net(sk); -		inet_get_local_port_range(&low, &high); +		inet_get_local_port_range(net, &low, &high);  		remaining = (high - low) + 1; -		rover = net_random() % remaining + low; +		rover = prandom_u32() % remaining + low;  		do {  			rover++;  			if ((rover < low) || (rover > high))  				rover = low; -			if (inet_is_reserved_local_port(rover)) +			if (inet_is_local_reserved_port(net, rover))  				continue;  			index = sctp_phashfn(sock_net(sk), rover);  			head = &sctp_port_hashtable[index]; -			sctp_spin_lock(&head->lock); +			spin_lock(&head->lock);  			sctp_for_each_hentry(pp, &head->chain)  				if ((pp->port == rover) &&  				    net_eq(sock_net(sk), pp->net))  					goto next;  			break;  		next: -			sctp_spin_unlock(&head->lock); +			spin_unlock(&head->lock);  		} while (--remaining > 0);  		/* Exhausted local port range during search? */ @@ -5930,7 +5988,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)  		 * port iterator, pp being NULL.  		 */  		head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)]; -		sctp_spin_lock(&head->lock); +		spin_lock(&head->lock);  		sctp_for_each_hentry(pp, &head->chain) {  			if ((pp->port == snum) && net_eq(pp->net, sock_net(sk)))  				goto pp_found; @@ -6014,10 +6072,10 @@ success:  	ret = 0;  fail_unlock: -	sctp_spin_unlock(&head->lock); +	spin_unlock(&head->lock);  fail: -	sctp_local_bh_enable(); +	local_bh_enable();  	return ret;  } @@ -6109,7 +6167,7 @@ int sctp_inet_listen(struct socket *sock, int backlog)  	if (unlikely(backlog < 0))  		return err; -	sctp_lock_sock(sk); +	lock_sock(sk);  	/* Peeled-off sockets are not allowed to listen().  */  	if (sctp_style(sk, UDP_HIGH_BANDWIDTH)) @@ -6142,7 +6200,7 @@ int sctp_inet_listen(struct socket *sock, int backlog)  	err = 0;  out: -	sctp_release_sock(sk); +	release_sock(sk);  	return err;  } @@ -6251,20 +6309,20 @@ static inline void __sctp_put_port(struct sock *sk)  						  inet_sk(sk)->inet_num)];  	struct sctp_bind_bucket *pp; -	sctp_spin_lock(&head->lock); +	spin_lock(&head->lock);  	pp = sctp_sk(sk)->bind_hash;  	__sk_del_bind_node(sk);  	sctp_sk(sk)->bind_hash = NULL;  	inet_sk(sk)->inet_num = 0;  	sctp_bucket_destroy(pp); -	sctp_spin_unlock(&head->lock); +	spin_unlock(&head->lock);  }  void sctp_put_port(struct sock *sk)  { -	sctp_local_bh_disable(); +	local_bh_disable();  	__sctp_put_port(sk); -	sctp_local_bh_enable(); +	local_bh_enable();  }  /* @@ -6402,7 +6460,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs)   * Note: This function is the same function as in core/datagram.c   * with a few modifications to make lksctp work.   */ -static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) +static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p)  {  	int error;  	DEFINE_WAIT(wait); @@ -6439,9 +6497,9 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)  	 * does not fit in the user's buffer, but this seems to be the  	 * only way to honor MSG_DONTWAIT realistically.  	 */ -	sctp_release_sock(sk); +	release_sock(sk);  	*timeo_p = schedule_timeout(*timeo_p); -	sctp_lock_sock(sk); +	lock_sock(sk);  ready:  	finish_wait(sk_sleep(sk), &wait); @@ -6501,6 +6559,10 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,  		if (sk->sk_shutdown & RCV_SHUTDOWN)  			break; +		if (sk_can_busy_loop(sk) && +		    sk_busy_loop(sk, noblock)) +			continue; +  		/* User doesn't want to wait.  */  		error = -EAGAIN;  		if (!timeo) @@ -6541,6 +6603,46 @@ static void __sctp_write_space(struct sctp_association *asoc)  	}  } +static void sctp_wake_up_waiters(struct sock *sk, +				 struct sctp_association *asoc) +{ +	struct sctp_association *tmp = asoc; + +	/* We do accounting for the sndbuf space per association, +	 * so we only need to wake our own association. +	 */ +	if (asoc->ep->sndbuf_policy) +		return __sctp_write_space(asoc); + +	/* If association goes down and is just flushing its +	 * outq, then just normally notify others. +	 */ +	if (asoc->base.dead) +		return sctp_write_space(sk); + +	/* Accounting for the sndbuf space is per socket, so we +	 * need to wake up others, try to be fair and in case of +	 * other associations, let them have a go first instead +	 * of just doing a sctp_write_space() call. +	 * +	 * Note that we reach sctp_wake_up_waiters() only when +	 * associations free up queued chunks, thus we are under +	 * lock and the list of associations on a socket is +	 * guaranteed not to change. +	 */ +	for (tmp = list_next_entry(tmp, asocs); 1; +	     tmp = list_next_entry(tmp, asocs)) { +		/* Manually skip the head element. */ +		if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs)) +			continue; +		/* Wake up association. */ +		__sctp_write_space(tmp); +		/* We've reached the end. */ +		if (tmp == asoc) +			break; +	} +} +  /* Do accounting for the sndbuf space.   * Decrement the used sndbuf space of the corresponding association by the   * data size which was just transmitted(freed). @@ -6568,7 +6670,7 @@ static void sctp_wfree(struct sk_buff *skb)  	sk_mem_uncharge(sk, skb->truesize);  	sock_wfree(skb); -	__sctp_write_space(asoc); +	sctp_wake_up_waiters(sk, asoc);  	sctp_association_put(asoc);  } @@ -6624,10 +6726,10 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,  		/* Let another process have a go.  Since we are going  		 * to sleep anyway.  		 */ -		sctp_release_sock(sk); +		release_sock(sk);  		current_timeo = schedule_timeout(current_timeo);  		BUG_ON(sk != asoc->base.sk); -		sctp_lock_sock(sk); +		lock_sock(sk);  		*timeo_p = current_timeo;  	} @@ -6653,7 +6755,7 @@ do_nonblock:  	goto out;  } -void sctp_data_ready(struct sock *sk, int len) +void sctp_data_ready(struct sock *sk)  {  	struct socket_wq *wq; @@ -6732,9 +6834,9 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)  		/* Let another process have a go.  Since we are going  		 * to sleep anyway.  		 */ -		sctp_release_sock(sk); +		release_sock(sk);  		current_timeo = schedule_timeout(current_timeo); -		sctp_lock_sock(sk); +		lock_sock(sk);  		*timeo_p = current_timeo;  	} @@ -6777,9 +6879,9 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)  					  TASK_INTERRUPTIBLE);  		if (list_empty(&ep->asocs)) { -			sctp_release_sock(sk); +			release_sock(sk);  			timeo = schedule_timeout(timeo); -			sctp_lock_sock(sk); +			lock_sock(sk);  		}  		err = -EINVAL; @@ -6812,9 +6914,9 @@ static void sctp_wait_for_close(struct sock *sk, long timeout)  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);  		if (list_empty(&sctp_sk(sk)->ep->asocs))  			break; -		sctp_release_sock(sk); +		release_sock(sk);  		timeout = schedule_timeout(timeout); -		sctp_lock_sock(sk); +		lock_sock(sk);  	} while (!signal_pending(current) && timeout);  	finish_wait(sk_sleep(sk), &wait); @@ -6844,7 +6946,8 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,  	newsk->sk_type = sk->sk_type;  	newsk->sk_bound_dev_if = sk->sk_bound_dev_if;  	newsk->sk_flags = sk->sk_flags; -	newsk->sk_no_check = sk->sk_no_check; +	newsk->sk_no_check_tx = sk->sk_no_check_tx; +	newsk->sk_no_check_rx = sk->sk_no_check_rx;  	newsk->sk_reuse = sk->sk_reuse;  	newsk->sk_shutdown = sk->sk_shutdown; @@ -6915,14 +7018,14 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,  	/* Hook this new socket in to the bind_hash list. */  	head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk),  						 inet_sk(oldsk)->inet_num)]; -	sctp_local_bh_disable(); -	sctp_spin_lock(&head->lock); +	local_bh_disable(); +	spin_lock(&head->lock);  	pp = sctp_sk(oldsk)->bind_hash;  	sk_add_bind_node(newsk, &pp->owner);  	sctp_sk(newsk)->bind_hash = pp;  	inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num; -	sctp_spin_unlock(&head->lock); -	sctp_local_bh_enable(); +	spin_unlock(&head->lock); +	local_bh_enable();  	/* Copy the bind_addr list from the original endpoint to the new  	 * endpoint so that we can handle restarts properly @@ -7011,7 +7114,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,  		newsk->sk_shutdown |= RCV_SHUTDOWN;  	newsk->sk_state = SCTP_SS_ESTABLISHED; -	sctp_release_sock(newsk); +	release_sock(newsk);  }  | 
