diff options
Diffstat (limited to 'net/dccp/proto.c')
| -rw-r--r-- | net/dccp/proto.c | 53 | 
1 files changed, 40 insertions, 13 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 3090fc40eeb..c6b4362bb1d 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -470,6 +470,42 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,  	return 0;  } +static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx) +{ +	u8 *list, len; +	int i, rc; + +	if (cscov < 0 || cscov > 15) +		return -EINVAL; +	/* +	 * Populate a list of permissible values, in the range cscov...15. This +	 * is necessary since feature negotiation of single values only works if +	 * both sides incidentally choose the same value. Since the list starts +	 * lowest-value first, negotiation will pick the smallest shared value. +	 */ +	if (cscov == 0) +		return 0; +	len = 16 - cscov; + +	list = kmalloc(len, GFP_KERNEL); +	if (list == NULL) +		return -ENOBUFS; + +	for (i = 0; i < len; i++) +		list[i] = cscov++; + +	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len); + +	if (rc == 0) { +		if (rx) +			dccp_sk(sk)->dccps_pcrlen = cscov; +		else +			dccp_sk(sk)->dccps_pcslen = cscov; +	} +	kfree(list); +	return rc; +} +  static int do_dccp_setsockopt(struct sock *sk, int level, int optname,  		char __user *optval, int optlen)  { @@ -502,20 +538,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,  		else  			dp->dccps_server_timewait = (val != 0);  		break; -	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */ -		if (val < 0 || val > 15) -			err = -EINVAL; -		else -			dp->dccps_pcslen = val; +	case DCCP_SOCKOPT_SEND_CSCOV: +		err = dccp_setsockopt_cscov(sk, val, false);  		break; -	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */ -		if (val < 0 || val > 15) -			err = -EINVAL; -		else { -			dp->dccps_pcrlen = val; -			/* FIXME: add feature negotiation, -			 * ChangeL(MinimumChecksumCoverage, val) */ -		} +	case DCCP_SOCKOPT_RECV_CSCOV: +		err = dccp_setsockopt_cscov(sk, val, true);  		break;  	default:  		err = -ENOPROTOOPT;  |