|
@@ -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;
|