diff options
| -rw-r--r-- | include/linux/dccp.h | 4 | ||||
| -rw-r--r-- | net/dccp/proto.c | 53 | 
2 files changed, 42 insertions, 15 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 6eaaca9b037..5a5a89935db 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -527,8 +527,8 @@ struct dccp_sock {  	__u32				dccps_timestamp_time;  	__u16				dccps_l_ack_ratio;  	__u16				dccps_r_ack_ratio; -	__u16				dccps_pcslen; -	__u16				dccps_pcrlen; +	__u8				dccps_pcslen:4; +	__u8				dccps_pcrlen:4;  	__u64				dccps_ndp_count:48;  	unsigned long			dccps_rate_last;  	struct dccp_minisock		dccps_minisock; 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;  |