aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:27 -0400
commit093e1f46cf162913d05e1d4eeb01baa3e297b683 (patch)
tree4a66ebf581924936bc7850122cb6bdad1cd5383c /net/dccp
parent71bb49596bbf4e5a3328e1704d18604e822ba181 (diff)
dccp: Resolve dependencies of features on choice of CCID
This provides a missing link in the code chain, as several features implicitly depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector feature, but also Ack Ratio and Send Loss Event Rate (also taken care of). For Send Ack Vector, the situation is as follows: * since CCID2 mandates the use of Ack Vectors, there is no point in allowing endpoints which use CCID2 to disable Ack Vector features such a connection; * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4); * for all other CCIDs, the use of (Send) Ack Vector is optional and thus negotiable. However, this implies that the code negotiating the use of Ack Vectors also supports it (i.e. is able to supply and to either parse or ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack Vector support), the use of Ack Vectors is here disabled, with a comment in the source code. An analogous consideration arises for the Send Loss Event Rate feature, since the CCID-3 implementation does not support the loss interval options of RFC 4342. To make such use explicit, corresponding feature-negotiation options are inserted which signal the use of the loss event rate option, as it is used by the CCID3 code. Lastly, the values of the Ack Ratio feature are matched to the choice of CCID. The patch implements this as a function which is called after the user has made all other registrations for changing default values of features. The table is variable-length, the reserved (and hence for feature-negotiation invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0' is used to mark the end of the table. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Diffstat (limited to 'net/dccp')
-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