mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	sctp: add SCTP_PR_SUPPORTED on sctp sockopt
According to section 4.5 of rfc7496, prsctp_enable should be per asoc. We will add prsctp_enable to both asoc and ep, and replace the places where it used net.sctp->prsctp_enable with asoc->prsctp_enable. ep->prsctp_enable will be initialized with net.sctp->prsctp_enable, and asoc->prsctp_enable will be initialized with ep->prsctp_enable. We can also modify it's value through sockopt SCTP_PR_SUPPORTED. Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									bac65c4b39
								
							
						
					
					
						commit
						28aa4c26fc
					
				
					 6 changed files with 93 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -1256,7 +1256,8 @@ struct sctp_endpoint {
 | 
			
		|||
	/* SCTP-AUTH: endpoint shared keys */
 | 
			
		||||
	struct list_head endpoint_shared_keys;
 | 
			
		||||
	__u16 active_key_id;
 | 
			
		||||
	__u8  auth_enable;
 | 
			
		||||
	__u8  auth_enable:1,
 | 
			
		||||
	      prsctp_enable:1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Recover the outter endpoint structure. */
 | 
			
		||||
| 
						 | 
				
			
			@ -1848,7 +1849,8 @@ struct sctp_association {
 | 
			
		|||
	__u16 active_key_id;
 | 
			
		||||
 | 
			
		||||
	__u8 need_ecne:1,	/* Need to send an ECNE Chunk? */
 | 
			
		||||
	     temp:1;		/* Is it a temporary association? */
 | 
			
		||||
	     temp:1,		/* Is it a temporary association? */
 | 
			
		||||
	     prsctp_enable:1;
 | 
			
		||||
 | 
			
		||||
	struct sctp_priv_assoc_stats stats;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,6 +112,7 @@ typedef __s32 sctp_assoc_t;
 | 
			
		|||
#define SCTP_SOCKOPT_CONNECTX	110		/* CONNECTX requests. */
 | 
			
		||||
#define SCTP_SOCKOPT_CONNECTX3	111	/* CONNECTX requests (updated) */
 | 
			
		||||
#define SCTP_GET_ASSOC_STATS	112	/* Read only */
 | 
			
		||||
#define SCTP_PR_SUPPORTED	113
 | 
			
		||||
 | 
			
		||||
/* These are bit fields for msghdr->msg_flags.  See section 5.1.  */
 | 
			
		||||
/* On user space Linux, these live in <bits/socket.h> as an enum.  */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -268,6 +268,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 | 
			
		|||
		goto fail_init;
 | 
			
		||||
 | 
			
		||||
	asoc->active_key_id = ep->active_key_id;
 | 
			
		||||
	asoc->prsctp_enable = ep->prsctp_enable;
 | 
			
		||||
 | 
			
		||||
	/* Save the hmacs and chunks list into this association */
 | 
			
		||||
	if (ep->auth_hmacs_list)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -163,6 +163,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
 | 
			
		|||
	 */
 | 
			
		||||
	ep->auth_hmacs_list = auth_hmacs;
 | 
			
		||||
	ep->auth_chunk_list = auth_chunks;
 | 
			
		||||
	ep->prsctp_enable = net->sctp.prsctp_enable;
 | 
			
		||||
 | 
			
		||||
	return ep;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -261,7 +261,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
 | 
			
		|||
	chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types));
 | 
			
		||||
	chunksize += sizeof(ecap_param);
 | 
			
		||||
 | 
			
		||||
	if (net->sctp.prsctp_enable)
 | 
			
		||||
	if (asoc->prsctp_enable)
 | 
			
		||||
		chunksize += sizeof(prsctp_param);
 | 
			
		||||
 | 
			
		||||
	/* ADDIP: Section 4.2.7:
 | 
			
		||||
| 
						 | 
				
			
			@ -355,7 +355,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
 | 
			
		|||
		sctp_addto_param(retval, num_ext, extensions);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (net->sctp.prsctp_enable)
 | 
			
		||||
	if (asoc->prsctp_enable)
 | 
			
		||||
		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 | 
			
		||||
 | 
			
		||||
	if (sp->adaptation_ind) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2024,7 +2024,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
 | 
			
		|||
	for (i = 0; i < num_ext; i++) {
 | 
			
		||||
		switch (param.ext->chunks[i]) {
 | 
			
		||||
		case SCTP_CID_FWD_TSN:
 | 
			
		||||
			if (net->sctp.prsctp_enable && !asoc->peer.prsctp_capable)
 | 
			
		||||
			if (asoc->prsctp_enable && !asoc->peer.prsctp_capable)
 | 
			
		||||
				asoc->peer.prsctp_capable = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case SCTP_CID_AUTH:
 | 
			
		||||
| 
						 | 
				
			
			@ -2169,7 +2169,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
 | 
			
		|||
		break;
 | 
			
		||||
 | 
			
		||||
	case SCTP_PARAM_FWD_TSN_SUPPORT:
 | 
			
		||||
		if (net->sctp.prsctp_enable)
 | 
			
		||||
		if (ep->prsctp_enable)
 | 
			
		||||
			break;
 | 
			
		||||
		goto fallthrough;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2653,7 +2653,7 @@ static int sctp_process_param(struct sctp_association *asoc,
 | 
			
		|||
		break;
 | 
			
		||||
 | 
			
		||||
	case SCTP_PARAM_FWD_TSN_SUPPORT:
 | 
			
		||||
		if (net->sctp.prsctp_enable) {
 | 
			
		||||
		if (asoc->prsctp_enable) {
 | 
			
		||||
			asoc->peer.prsctp_capable = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3661,6 +3661,39 @@ static int sctp_setsockopt_recvnxtinfo(struct sock *sk,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sctp_setsockopt_pr_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->prsctp_enable = !!params.assoc_value;
 | 
			
		||||
	} else if (!params.assoc_id) {
 | 
			
		||||
		struct sctp_sock *sp = sctp_sk(sk);
 | 
			
		||||
 | 
			
		||||
		sp->ep->prsctp_enable = !!params.assoc_value;
 | 
			
		||||
	} else {
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	retval = 0;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* API 6.2 setsockopt(), getsockopt()
 | 
			
		||||
 *
 | 
			
		||||
 * Applications use setsockopt() and getsockopt() to set or retrieve
 | 
			
		||||
| 
						 | 
				
			
			@ -3821,6 +3854,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
 | 
			
		|||
	case SCTP_RECVNXTINFO:
 | 
			
		||||
		retval = sctp_setsockopt_recvnxtinfo(sk, optval, optlen);
 | 
			
		||||
		break;
 | 
			
		||||
	case SCTP_PR_SUPPORTED:
 | 
			
		||||
		retval = sctp_setsockopt_pr_supported(sk, optval, optlen);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		retval = -ENOPROTOOPT;
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			@ -6166,6 +6202,47 @@ static int sctp_getsockopt_recvnxtinfo(struct sock *sk,	int len,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sctp_getsockopt_pr_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->prsctp_enable;
 | 
			
		||||
	} else if (!params.assoc_id) {
 | 
			
		||||
		struct sctp_sock *sp = sctp_sk(sk);
 | 
			
		||||
 | 
			
		||||
		params.assoc_value = sp->ep->prsctp_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(struct sock *sk, int level, int optname,
 | 
			
		||||
			   char __user *optval, int __user *optlen)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -6319,6 +6396,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
 | 
			
		|||
	case SCTP_RECVNXTINFO:
 | 
			
		||||
		retval = sctp_getsockopt_recvnxtinfo(sk, len, optval, optlen);
 | 
			
		||||
		break;
 | 
			
		||||
	case SCTP_PR_SUPPORTED:
 | 
			
		||||
		retval = sctp_getsockopt_pr_supported(sk, len, optval, optlen);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		retval = -ENOPROTOOPT;
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue