aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/dccp.h4
-rw-r--r--net/dccp/proto.c53
2 files changed, 42 insertions, 15 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 6eaaca9b037a..5a5a89935dbc 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -527,8 +527,8 @@ struct dccp_sock {
527 __u32 dccps_timestamp_time; 527 __u32 dccps_timestamp_time;
528 __u16 dccps_l_ack_ratio; 528 __u16 dccps_l_ack_ratio;
529 __u16 dccps_r_ack_ratio; 529 __u16 dccps_r_ack_ratio;
530 __u16 dccps_pcslen; 530 __u8 dccps_pcslen:4;
531 __u16 dccps_pcrlen; 531 __u8 dccps_pcrlen:4;
532 __u64 dccps_ndp_count:48; 532 __u64 dccps_ndp_count:48;
533 unsigned long dccps_rate_last; 533 unsigned long dccps_rate_last;
534 struct dccp_minisock dccps_minisock; 534 struct dccp_minisock dccps_minisock;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 3090fc40eebd..c6b4362bb1d7 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,
470 return 0; 470 return 0;
471} 471}
472 472
473static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
474{
475 u8 *list, len;
476 int i, rc;
477
478 if (cscov < 0 || cscov > 15)
479 return -EINVAL;
480 /*
481 * Populate a list of permissible values, in the range cscov...15. This
482 * is necessary since feature negotiation of single values only works if
483 * both sides incidentally choose the same value. Since the list starts
484 * lowest-value first, negotiation will pick the smallest shared value.
485 */
486 if (cscov == 0)
487 return 0;
488 len = 16 - cscov;
489
490 list = kmalloc(len, GFP_KERNEL);
491 if (list == NULL)
492 return -ENOBUFS;
493
494 for (i = 0; i < len; i++)
495 list[i] = cscov++;
496
497 rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
498
499 if (rc == 0) {
500 if (rx)
501 dccp_sk(sk)->dccps_pcrlen = cscov;
502 else
503 dccp_sk(sk)->dccps_pcslen = cscov;
504 }
505 kfree(list);
506 return rc;
507}
508
473static int do_dccp_setsockopt(struct sock *sk, int level, int optname, 509static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
474 char __user *optval, int optlen) 510 char __user *optval, int optlen)
475{ 511{
@@ -502,20 +538,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
502 else 538 else
503 dp->dccps_server_timewait = (val != 0); 539 dp->dccps_server_timewait = (val != 0);
504 break; 540 break;
505 case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ 541 case DCCP_SOCKOPT_SEND_CSCOV:
506 if (val < 0 || val > 15) 542 err = dccp_setsockopt_cscov(sk, val, false);
507 err = -EINVAL;
508 else
509 dp->dccps_pcslen = val;
510 break; 543 break;
511 case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */ 544 case DCCP_SOCKOPT_RECV_CSCOV:
512 if (val < 0 || val > 15) 545 err = dccp_setsockopt_cscov(sk, val, true);
513 err = -EINVAL;
514 else {
515 dp->dccps_pcrlen = val;
516 /* FIXME: add feature negotiation,
517 * ChangeL(MinimumChecksumCoverage, val) */
518 }
519 break; 546 break;
520 default: 547 default:
521 err = -ENOPROTOOPT; 548 err = -ENOPROTOOPT;