Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29450559 authored by Gerrit Renker's avatar Gerrit Renker Committed by David S. Miller
Browse files

dccp: Feature negotiation for minimum-checksum-coverage



This provides feature negotiation for server minimum checksum coverage
which so far has been missing.

Since sender/receiver coverage values range only from 0...15, their
type has also been reduced in size from u16 to u4.

Feature-negotiation options are now generated for both sender and receiver
coverage, i.e. when the peer has `forgotten' to enable partial coverage
then feature negotiation will automatically enable (negotiate) the partial
coverage value for this connection.

Signed-off-by: default avatarGerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: default avatarIan McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 49aebc66
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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;
+40 −13
Original line number Diff line number Diff line
@@ -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;