diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 85 | 
1 files changed, 83 insertions, 2 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6f0a9be50f50..72cc3ecf6516 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3758,6 +3758,39 @@ out:  	return retval;  } +static int sctp_setsockopt_reconfig_supported(struct sock *sk, +					      char __user *optval, +					      unsigned int optlen) +{ +	struct sctp_assoc_value params; +	struct sctp_association *asoc; +	int retval = -EINVAL; + +	if (optlen != sizeof(params)) +		goto out; + +	if (copy_from_user(¶ms, optval, optlen)) { +		retval = -EFAULT; +		goto out; +	} + +	asoc = sctp_id2assoc(sk, params.assoc_id); +	if (asoc) { +		asoc->reconf_enable = !!params.assoc_value; +	} else if (!params.assoc_id) { +		struct sctp_sock *sp = sctp_sk(sk); + +		sp->ep->reconf_enable = !!params.assoc_value; +	} else { +		goto out; +	} + +	retval = 0; + +out: +	return retval; +} +  static int sctp_setsockopt_enable_strreset(struct sock *sk,  					   char __user *optval,  					   unsigned int optlen) @@ -4038,6 +4071,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,  	case SCTP_DEFAULT_PRINFO:  		retval = sctp_setsockopt_default_prinfo(sk, optval, optlen);  		break; +	case SCTP_RECONFIG_SUPPORTED: +		retval = sctp_setsockopt_reconfig_supported(sk, optval, optlen); +		break;  	case SCTP_ENABLE_STREAM_RESET:  		retval = sctp_setsockopt_enable_strreset(sk, optval, optlen);  		break; @@ -4116,7 +4152,7 @@ static int sctp_disconnect(struct sock *sk, int flags)   * descriptor will be returned from accept() to represent the newly   * formed association.   */ -static struct sock *sctp_accept(struct sock *sk, int flags, int *err) +static struct sock *sctp_accept(struct sock *sk, int flags, int *err, bool kern)  {  	struct sctp_sock *sp;  	struct sctp_endpoint *ep; @@ -4151,7 +4187,7 @@ static struct sock *sctp_accept(struct sock *sk, int flags, int *err)  	 */  	asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); -	newsk = sp->pf->create_accept_sk(sk, asoc); +	newsk = sp->pf->create_accept_sk(sk, asoc, kern);  	if (!newsk) {  		error = -ENOMEM;  		goto out; @@ -6540,6 +6576,47 @@ out:  	return retval;  } +static int sctp_getsockopt_reconfig_supported(struct sock *sk, int len, +					      char __user *optval, +					      int __user *optlen) +{ +	struct sctp_assoc_value params; +	struct sctp_association *asoc; +	int retval = -EFAULT; + +	if (len < sizeof(params)) { +		retval = -EINVAL; +		goto out; +	} + +	len = sizeof(params); +	if (copy_from_user(¶ms, optval, len)) +		goto out; + +	asoc = sctp_id2assoc(sk, params.assoc_id); +	if (asoc) { +		params.assoc_value = asoc->reconf_enable; +	} else if (!params.assoc_id) { +		struct sctp_sock *sp = sctp_sk(sk); + +		params.assoc_value = sp->ep->reconf_enable; +	} else { +		retval = -EINVAL; +		goto out; +	} + +	if (put_user(len, optlen)) +		goto out; + +	if (copy_to_user(optval, ¶ms, len)) +		goto out; + +	retval = 0; + +out: +	return retval; +} +  static int sctp_getsockopt_enable_strreset(struct sock *sk, int len,  					   char __user *optval,  					   int __user *optlen) @@ -6748,6 +6825,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,  		retval = sctp_getsockopt_pr_assocstatus(sk, len, optval,  							optlen);  		break; +	case SCTP_RECONFIG_SUPPORTED: +		retval = sctp_getsockopt_reconfig_supported(sk, len, optval, +							    optlen); +		break;  	case SCTP_ENABLE_STREAM_RESET:  		retval = sctp_getsockopt_enable_strreset(sk, len, optval,  							 optlen);  | 
