aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/feat.c
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-11-12 03:48:44 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-12 03:48:44 -0500
commit9eca0a47dee201a73967026985b5f0a79a46bd36 (patch)
treebeb39fbd3c28865705d7409aa35fd59914257da9 /net/dccp/feat.c
parentd90ebcbfa7f5a8b4e20518c9f94c5c4e4cd3c2e5 (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> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r--net/dccp/feat.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index f79fb5e33f5e..4c4144147325 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -400,6 +400,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
400 400
401EXPORT_SYMBOL_GPL(dccp_feat_change); 401EXPORT_SYMBOL_GPL(dccp_feat_change);
402 402
403/*
404 * Tracking features whose value depend on the choice of CCID
405 *
406 * This is designed with an extension in mind so that a list walk could be done
407 * before activating any features. However, the existing framework was found to
408 * work satisfactorily up until now, the automatic verification is left open.
409 * When adding new CCIDs, add a corresponding dependency table here.
410 */
411static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
412{
413 static const struct ccid_dependency ccid2_dependencies[2][2] = {
414 /*
415 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
416 * feature and Send Ack Vector is an RX feature, `is_local'
417 * needs to be reversed.
418 */
419 { /* Dependencies of the receiver-side (remote) CCID2 */
420 {
421 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
422 .is_local = true,
423 .is_mandatory = true,
424 .val = 1
425 },
426 { 0, 0, 0, 0 }
427 },
428 { /* Dependencies of the sender-side (local) CCID2 */
429 {
430 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
431 .is_local = false,
432 .is_mandatory = true,
433 .val = 1
434 },
435 { 0, 0, 0, 0 }
436 }
437 };
438 static const struct ccid_dependency ccid3_dependencies[2][5] = {
439 { /*
440 * Dependencies of the receiver-side CCID3
441 */
442 { /* locally disable Ack Vectors */
443 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
444 .is_local = true,
445 .is_mandatory = false,
446 .val = 0
447 },
448 { /* see below why Send Loss Event Rate is on */
449 .dependent_feat = DCCPF_SEND_LEV_RATE,
450 .is_local = true,
451 .is_mandatory = true,
452 .val = 1
453 },
454 { /* NDP Count is needed as per RFC 4342, 6.1.1 */
455 .dependent_feat = DCCPF_SEND_NDP_COUNT,
456 .is_local = false,
457 .is_mandatory = true,
458 .val = 1
459 },
460 { 0, 0, 0, 0 },
461 },
462 { /*
463 * CCID3 at the TX side: we request that the HC-receiver
464 * will not send Ack Vectors (they will be ignored, so
465 * Mandatory is not set); we enable Send Loss Event Rate
466 * (Mandatory since the implementation does not support
467 * the Loss Intervals option of RFC 4342, 8.6).
468 * The last two options are for peer's information only.
469 */
470 {
471 .dependent_feat = DCCPF_SEND_ACK_VECTOR,
472 .is_local = false,
473 .is_mandatory = false,
474 .val = 0
475 },
476 {
477 .dependent_feat = DCCPF_SEND_LEV_RATE,
478 .is_local = false,
479 .is_mandatory = true,
480 .val = 1
481 },
482 { /* this CCID does not support Ack Ratio */
483 .dependent_feat = DCCPF_ACK_RATIO,
484 .is_local = true,
485 .is_mandatory = false,
486 .val = 0
487 },
488 { /* tell receiver we are sending NDP counts */
489 .dependent_feat = DCCPF_SEND_NDP_COUNT,
490 .is_local = true,
491 .is_mandatory = false,
492 .val = 1
493 },
494 { 0, 0, 0, 0 }
495 }
496 };
497 switch (ccid) {
498 case DCCPC_CCID2:
499 return ccid2_dependencies[is_local];
500 case DCCPC_CCID3:
501 return ccid3_dependencies[is_local];
502 default:
503 return NULL;
504 }
505}
506
507/**
508 * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
509 * @fn: feature-negotiation list to update
510 * @id: CCID number to track
511 * @is_local: whether TX CCID (1) or RX CCID (0) is meant
512 * This function needs to be called after registering all other features.
513 */
514static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
515{
516 const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
517 int i, rc = (table == NULL);
518
519 for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
520 if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
521 rc = __feat_register_sp(fn, table[i].dependent_feat,
522 table[i].is_local,
523 table[i].is_mandatory,
524 &table[i].val, 1);
525 else
526 rc = __feat_register_nn(fn, table[i].dependent_feat,
527 table[i].is_mandatory,
528 table[i].val);
529 return rc;
530}
531
532/**
533 * dccp_feat_finalise_settings - Finalise settings before starting negotiation
534 * @dp: client or listening socket (settings will be inherited)
535 * This is called after all registrations (socket initialisation, sysctls, and
536 * sockopt calls), and before sending the first packet containing Change options
537 * (ie. client-Request or server-Response), to ensure internal consistency.
538 */
539int dccp_feat_finalise_settings(struct dccp_sock *dp)
540{
541 struct list_head *fn = &dp->dccps_featneg;
542 struct dccp_feat_entry *entry;
543 int i = 2, ccids[2] = { -1, -1 };
544
545 /*
546 * Propagating CCIDs:
547 * 1) not useful to propagate CCID settings if this host advertises more
548 * than one CCID: the choice of CCID may still change - if this is
549 * the client, or if this is the server and the client sends
550 * singleton CCID values.
551 * 2) since is that propagate_ccid changes the list, we defer changing
552 * the sorted list until after the traversal.
553 */
554 list_for_each_entry(entry, fn, node)
555 if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
556 ccids[entry->is_local] = entry->val.sp.vec[0];
557 while (i--)
558 if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
559 return -1;
560 return 0;
561}
562
403static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) 563static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
404{ 564{
405 struct dccp_sock *dp = dccp_sk(sk); 565 struct dccp_sock *dp = dccp_sk(sk);