aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-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 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);
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 809d803d5006..92f3f6f2ef51 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