diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-11-12 03:42:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-12 03:42:58 -0500 |
commit | f74e91b6cca5889e667193c7e794186db73c2000 (patch) | |
tree | 10f6a612d97b3ab5ba4ecd75b6decb669f178d76 | |
parent | 6bb3ce25d05f2990c8a19adaf427531430267c1f (diff) |
dccp: Limit feature negotiation to connection setup phase
This patch limits feature (capability) negotation to the connection setup phase:
1. Although it is theoretically possible to perform feature negotiation at any
time (and RFC 4340 supports this), in practice this is prohibitively complex,
as it requires to put traffic on hold for each new negotiation.
2. As a byproduct of restricting feature negotiation to connection setup, the
feature-negotiation retransmit timer is no longer required. This part is now
mapped onto the protocol-level retransmission.
Details indicating why timers are no longer needed can be found on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
implementation_notes.html
This patch disables anytime negotiation, subsequent patches work out full
feature negotiation support for connection setup.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/dccp/feat.c | 19 | ||||
-rw-r--r-- | net/dccp/options.c | 18 | ||||
-rw-r--r-- | net/dccp/timer.c | 12 |
3 files changed, 8 insertions, 41 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 069d8ffe4c6f..0e789e2e0aa9 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -6,6 +6,8 @@ | |||
6 | * | 6 | * |
7 | * ASSUMPTIONS | 7 | * ASSUMPTIONS |
8 | * ----------- | 8 | * ----------- |
9 | * o Feature negotiation is coordinated with connection setup (as in TCP), wild | ||
10 | * changes of parameters of an established connection are not supported. | ||
9 | * o All currently known SP features have 1-byte quantities. If in the future | 11 | * o All currently known SP features have 1-byte quantities. If in the future |
10 | * extensions of RFCs 4340..42 define features with item lengths larger than | 12 | * extensions of RFCs 4340..42 define features with item lengths larger than |
11 | * one byte, a feature-specific extension of the code will be required. | 13 | * one byte, a feature-specific extension of the code will be required. |
@@ -542,6 +544,9 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | |||
542 | { | 544 | { |
543 | int rc; | 545 | int rc; |
544 | 546 | ||
547 | /* Ignore Change requests other than during connection setup */ | ||
548 | if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) | ||
549 | return 0; | ||
545 | dccp_feat_debug(type, feature, *val); | 550 | dccp_feat_debug(type, feature, *val); |
546 | 551 | ||
547 | /* figure out if it's SP or NN feature */ | 552 | /* figure out if it's SP or NN feature */ |
@@ -591,6 +596,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
591 | int found = 0; | 596 | int found = 0; |
592 | int all_confirmed = 1; | 597 | int all_confirmed = 1; |
593 | 598 | ||
599 | /* Ignore Confirm options other than during connection setup */ | ||
600 | if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING) | ||
601 | return 0; | ||
594 | dccp_feat_debug(type, feature, *val); | 602 | dccp_feat_debug(type, feature, *val); |
595 | 603 | ||
596 | /* locate our change request */ | 604 | /* locate our change request */ |
@@ -625,17 +633,6 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | |||
625 | all_confirmed = 0; | 633 | all_confirmed = 0; |
626 | } | 634 | } |
627 | 635 | ||
628 | /* fix re-transmit timer */ | ||
629 | /* XXX gotta make sure that no option negotiation occurs during | ||
630 | * connection shutdown. Consider that the CLOSEREQ is sent and timer is | ||
631 | * on. if all options are confirmed it might kill timer which should | ||
632 | * remain alive until close is received. | ||
633 | */ | ||
634 | if (all_confirmed) { | ||
635 | dccp_pr_debug("clear feat negotiation timer %p\n", sk); | ||
636 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); | ||
637 | } | ||
638 | |||
639 | if (!found) | 636 | if (!found) |
640 | dccp_pr_debug("%s(%d, ...) never requested\n", | 637 | dccp_pr_debug("%s(%d, ...) never requested\n", |
641 | dccp_feat_typename(type), feature); | 638 | dccp_feat_typename(type), feature); |
diff --git a/net/dccp/options.c b/net/dccp/options.c index 0809b63cb055..67a171a1268c 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, | |||
489 | 489 | ||
490 | static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) | 490 | static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) |
491 | { | 491 | { |
492 | struct dccp_sock *dp = dccp_sk(sk); | ||
493 | struct dccp_minisock *dmsk = dccp_msk(sk); | 492 | struct dccp_minisock *dmsk = dccp_msk(sk); |
494 | struct dccp_opt_pend *opt, *next; | 493 | struct dccp_opt_pend *opt, *next; |
495 | int change = 0; | 494 | int change = 0; |
@@ -530,23 +529,6 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) | |||
530 | } | 529 | } |
531 | } | 530 | } |
532 | 531 | ||
533 | /* Retransmit timer. | ||
534 | * If this is the master listening sock, we don't set a timer on it. It | ||
535 | * should be fine because if the dude doesn't receive our RESPONSE | ||
536 | * [which will contain the CHANGE] he will send another REQUEST which | ||
537 | * will "retrnasmit" the change. | ||
538 | */ | ||
539 | if (change && dp->dccps_role != DCCP_ROLE_LISTEN) { | ||
540 | dccp_pr_debug("reset feat negotiation timer %p\n", sk); | ||
541 | |||
542 | /* XXX don't reset the timer on re-transmissions. I.e. reset it | ||
543 | * only when sending new stuff i guess. Currently the timer | ||
544 | * never backs off because on re-transmission it just resets it! | ||
545 | */ | ||
546 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | ||
547 | inet_csk(sk)->icsk_rto, DCCP_RTO_MAX); | ||
548 | } | ||
549 | |||
550 | return 0; | 532 | return 0; |
551 | } | 533 | } |
552 | 534 | ||
diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 54b3c7e9e016..162d1e683c39 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c | |||
@@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk) | |||
87 | { | 87 | { |
88 | struct inet_connection_sock *icsk = inet_csk(sk); | 88 | struct inet_connection_sock *icsk = inet_csk(sk); |
89 | 89 | ||
90 | /* retransmit timer is used for feature negotiation throughout | ||
91 | * connection. In this case, no packet is re-transmitted, but rather an | ||
92 | * ack is generated and pending changes are placed into its options. | ||
93 | */ | ||
94 | if (sk->sk_send_head == NULL) { | ||
95 | dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk); | ||
96 | if (sk->sk_state == DCCP_OPEN) | ||
97 | dccp_send_ack(sk); | ||
98 | goto backoff; | ||
99 | } | ||
100 | |||
101 | /* | 90 | /* |
102 | * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was | 91 | * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was |
103 | * sent, no need to retransmit, this sock is dead. | 92 | * sent, no need to retransmit, this sock is dead. |
@@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk) | |||
126 | return; | 115 | return; |
127 | } | 116 | } |
128 | 117 | ||
129 | backoff: | ||
130 | icsk->icsk_backoff++; | 118 | icsk->icsk_backoff++; |
131 | 119 | ||
132 | icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); | 120 | icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); |