aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/dccp.h1
-rw-r--r--net/dccp/feat.c160
-rw-r--r--net/dccp/output.c4
-rw-r--r--net/dccp/proto.c3
4 files changed, 168 insertions, 0 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index dee4a90886d6..1881527bdcd7 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
442 inet_csk_ack_scheduled(sk); 442 inet_csk_ack_scheduled(sk);
443} 443}
444 444
445extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
445extern void dccp_feat_list_purge(struct list_head *fn_list); 446extern void dccp_feat_list_purge(struct list_head *fn_list);
446 447
447extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); 448extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 9399554878cc..ed9f50b1c34a 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -441,6 +441,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
441 441
442EXPORT_SYMBOL_GPL(dccp_feat_change); 442EXPORT_SYMBOL_GPL(dccp_feat_change);
443 443
444/*
445 * Tracking features whose value depend on the choice of CCID
446 *
447 * This is designed with an extension in mind so that a list walk could be done
448 * before activating any features. However, the existing framework was found to
449 * work satisfactorily up until now, the automatic verification is left open.
450 * When adding new CCIDs, add a corresponding dependency table here.
451 */
452static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
453{
454 static const struct ccid_dependency ccid2_dependencies[2][2] = {
455 /*
456 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
457 * feature and Send Ack Vector is an RX feature, `is_local'
458 * needs to be reversed.
459 */
460 { /* Dependencies of the receiver-side (remote) CCID2 */
461 {
462 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
463 .is_local = true,
464 .is_mandatory = true,
465 .val = 1
466 },
467 { 0, 0, 0, 0 }
468 },
469 { /* Dependencies of the sender-side (local) CCID2 */
470 {
471 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
472 .is_local = false,
473 .is_mandatory = true,
474 .val = 1
475 },
476 { 0, 0, 0, 0 }
477 }
478 };
479 static const struct ccid_dependency ccid3_dependencies[2][5] = {
480 { /*
481 * Dependencies of the receiver-side CCID3
482 */
483 { /* locally disable Ack Vectors */
484 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
485 .is_local = true,
486 .is_mandatory = false,
487 .val = 0
488 },
489 { /* see below why Send Loss Event Rate is on */
490 .dependent_feat = DCCPF_SEND_LEV_RATE,
491 .is_local = true,
492 .is_mandatory = true,
493 .val = 1
494 },
495 { /* NDP Count is needed as per RFC 4342, 6.1.1 */
496 .dependent_feat = DCCPF_SEND_NDP_COUNT,
497 .is_local = false,
498 .is_mandatory = true,
499 .val = 1
500 },
501 { 0, 0, 0, 0 },
502 },
503 { /*
504 * CCID3 at the TX side: we request that the HC-receiver
505 * will not send Ack Vectors (they will be ignored, so
506 * Mandatory is not set); we enable Send Loss Event Rate
507 * (Mandatory since the implementation does not support
508 * the Loss Intervals option of RFC 4342, 8.6).
509 * The last two options are for peer's information only.
510 */
511 {
512 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
513 .is_local = false,
514 .is_mandatory = false,
515 .val = 0
516 },
517 {
518 .dependent_feat = DCCPF_SEND_LEV_RATE,
519 .is_local = false,
520 .is_mandatory = true,
521 .val = 1
522 },
523 { /* this CCID does not support Ack Ratio */
524 .dependent_feat = DCCPF_ACK_RATIO,
525 .is_local = true,
526 .is_mandatory = false,
527 .val = 0
528 },
529 { /* tell receiver we are sending NDP counts */
530 .dependent_feat = DCCPF_SEND_NDP_COUNT,
531 .is_local = true,
532 .is_mandatory = false,
533 .val = 1
534 },
535 { 0, 0, 0, 0 }
536 }
537 };
538 switch (ccid) {
539 case DCCPC_CCID2:
540 return ccid2_dependencies[is_local];
541 case DCCPC_CCID3:
542 return ccid3_dependencies[is_local];
543 default:
544 return NULL;
545 }
546}
547
548/**
549 * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
550 * @fn: feature-negotiation list to update
551 * @id: CCID number to track
552 * @is_local: whether TX CCID (1) or RX CCID (0) is meant
553 * This function needs to be called after registering all other features.
554 */
555static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
556{
557 const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
558 int i, rc = (table == NULL);
559
560 for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
561 if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
562 rc = __feat_register_sp(fn, table[i].dependent_feat,
563 table[i].is_local,
564 table[i].is_mandatory,
565 &table[i].val, 1);
566 else
567 rc = __feat_register_nn(fn, table[i].dependent_feat,
568 table[i].is_mandatory,
569 table[i].val);
570 return rc;
571}
572
573/**
574 * dccp_feat_finalise_settings - Finalise settings before starting negotiation
575 * @dp: client or listening socket (settings will be inherited)
576 * This is called after all registrations (socket initialisation, sysctls, and
577 * sockopt calls), and before sending the first packet containing Change options
578 * (ie. client-Request or server-Response), to ensure internal consistency.
579 */
580int dccp_feat_finalise_settings(struct dccp_sock *dp)
581{
582 struct list_head *fn = &dp->dccps_featneg;
583 struct dccp_feat_entry *entry;
584 int i = 2, ccids[2] = { -1, -1 };
585
586 /*
587 * Propagating CCIDs:
588 * 1) not useful to propagate CCID settings if this host advertises more
589 * than one CCID: the choice of CCID may still change - if this is
590 * the client, or if this is the server and the client sends
591 * singleton CCID values.
592 * 2) since is that propagate_ccid changes the list, we defer changing
593 * the sorted list until after the traversal.
594 */
595 list_for_each_entry(entry, fn, node)
596 if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
597 ccids[entry->is_local] = entry->val.sp.vec[0];
598 while (i--)
599 if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
600 return -1;
601 return 0;
602}
603
444static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 604static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
445{ 605{
446 struct dccp_sock *dp = dccp_sk(sk); 606 struct dccp_sock *dp = dccp_sk(sk);
diff --git a/net/dccp/output.c b/net/dccp/output.c
index d06945c7d3df..dc96ecfbe6e8 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
469 struct sk_buff *skb; 469 struct sk_buff *skb;
470 struct inet_connection_sock *icsk = inet_csk(sk); 470 struct inet_connection_sock *icsk = inet_csk(sk);
471 471
472 /* do not connect if feature negotiation setup fails */
473 if (dccp_feat_finalise_settings(dccp_sk(sk)))
474 return -EPROTO;
475
472 dccp_connect_init(sk); 476 dccp_connect_init(sk);
473 477
474 skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation); 478 skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b4b10cbd8880..46cb3490d48e 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,6 +278,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
278 struct dccp_sock *dp = dccp_sk(sk); 278 struct dccp_sock *dp = dccp_sk(sk);
279 279
280 dp->dccps_role = DCCP_ROLE_LISTEN; 280 dp->dccps_role = DCCP_ROLE_LISTEN;
281 /* do not start to listen if feature negotiation setup fails */
282 if (dccp_feat_finalise_settings(dp))
283 return -EPROTO;
281 return inet_csk_listen_start(sk, backlog); 284 return inet_csk_listen_start(sk, backlog);
282} 285}
283 286