aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
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 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