diff options
author | David S. Miller <davem@davemloft.net> | 2011-08-01 20:37:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-08-01 20:37:22 -0400 |
commit | ebdcc94b4b03212a1f715c39526c9b9578bba0b0 (patch) | |
tree | 3e1a48cfdb1beb7a68a64502785fb5e07ddfad04 | |
parent | fc502ba0086f142639208f879e577e1b5a4eeb8e (diff) | |
parent | d96a9e8dd04cf5ab2782ca6192e395c5ca373f7d (diff) |
Merge branch 'dccp' of git://eden-feed.erg.abdn.ac.uk/net-next-2.6
-rw-r--r-- | net/dccp/ccids/ccid2.c | 84 | ||||
-rw-r--r-- | net/dccp/ccids/ccid2.h | 6 | ||||
-rw-r--r-- | net/dccp/dccp.h | 1 | ||||
-rw-r--r-- | net/dccp/feat.c | 202 | ||||
-rw-r--r-- | net/dccp/feat.h | 1 | ||||
-rw-r--r-- | net/dccp/proto.c | 1 |
6 files changed, 271 insertions, 24 deletions
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 0462040fc818..67164bb6ae4d 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c | |||
@@ -85,7 +85,6 @@ static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) | |||
85 | 85 | ||
86 | static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) | 86 | static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) |
87 | { | 87 | { |
88 | struct dccp_sock *dp = dccp_sk(sk); | ||
89 | u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->tx_cwnd, 2); | 88 | u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->tx_cwnd, 2); |
90 | 89 | ||
91 | /* | 90 | /* |
@@ -98,14 +97,33 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) | |||
98 | DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio); | 97 | DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio); |
99 | val = max_ratio; | 98 | val = max_ratio; |
100 | } | 99 | } |
101 | if (val > DCCPF_ACK_RATIO_MAX) | 100 | dccp_feat_signal_nn_change(sk, DCCPF_ACK_RATIO, |
102 | val = DCCPF_ACK_RATIO_MAX; | 101 | min_t(u32, val, DCCPF_ACK_RATIO_MAX)); |
102 | } | ||
103 | 103 | ||
104 | if (val == dp->dccps_l_ack_ratio) | 104 | static void ccid2_check_l_ack_ratio(struct sock *sk) |
105 | return; | 105 | { |
106 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); | ||
106 | 107 | ||
107 | ccid2_pr_debug("changing local ack ratio to %u\n", val); | 108 | /* |
108 | dp->dccps_l_ack_ratio = val; | 109 | * After a loss, idle period, application limited period, or RTO we |
110 | * need to check that the ack ratio is still less than the congestion | ||
111 | * window. Otherwise, we will send an entire congestion window of | ||
112 | * packets and got no response because we haven't sent ack ratio | ||
113 | * packets yet. | ||
114 | * If the ack ratio does need to be reduced, we reduce it to half of | ||
115 | * the congestion window (or 1 if that's zero) instead of to the | ||
116 | * congestion window. This prevents problems if one ack is lost. | ||
117 | */ | ||
118 | if (dccp_feat_nn_get(sk, DCCPF_ACK_RATIO) > hc->tx_cwnd) | ||
119 | ccid2_change_l_ack_ratio(sk, hc->tx_cwnd/2 ? : 1U); | ||
120 | } | ||
121 | |||
122 | static void ccid2_change_l_seq_window(struct sock *sk, u64 val) | ||
123 | { | ||
124 | dccp_feat_signal_nn_change(sk, DCCPF_SEQUENCE_WINDOW, | ||
125 | clamp_val(val, DCCPF_SEQ_WMIN, | ||
126 | DCCPF_SEQ_WMAX)); | ||
109 | } | 127 | } |
110 | 128 | ||
111 | static void ccid2_hc_tx_rto_expire(unsigned long data) | 129 | static void ccid2_hc_tx_rto_expire(unsigned long data) |
@@ -187,6 +205,8 @@ static void ccid2_cwnd_application_limited(struct sock *sk, const u32 now) | |||
187 | } | 205 | } |
188 | hc->tx_cwnd_used = 0; | 206 | hc->tx_cwnd_used = 0; |
189 | hc->tx_cwnd_stamp = now; | 207 | hc->tx_cwnd_stamp = now; |
208 | |||
209 | ccid2_check_l_ack_ratio(sk); | ||
190 | } | 210 | } |
191 | 211 | ||
192 | /* This borrows the code of tcp_cwnd_restart() */ | 212 | /* This borrows the code of tcp_cwnd_restart() */ |
@@ -205,6 +225,8 @@ static void ccid2_cwnd_restart(struct sock *sk, const u32 now) | |||
205 | 225 | ||
206 | hc->tx_cwnd_stamp = now; | 226 | hc->tx_cwnd_stamp = now; |
207 | hc->tx_cwnd_used = 0; | 227 | hc->tx_cwnd_used = 0; |
228 | |||
229 | ccid2_check_l_ack_ratio(sk); | ||
208 | } | 230 | } |
209 | 231 | ||
210 | static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) | 232 | static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) |
@@ -405,17 +427,37 @@ static void ccid2_new_ack(struct sock *sk, struct ccid2_seq *seqp, | |||
405 | unsigned int *maxincr) | 427 | unsigned int *maxincr) |
406 | { | 428 | { |
407 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); | 429 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); |
408 | 430 | struct dccp_sock *dp = dccp_sk(sk); | |
409 | if (hc->tx_cwnd < hc->tx_ssthresh) { | 431 | int r_seq_used = hc->tx_cwnd / dp->dccps_l_ack_ratio; |
410 | if (*maxincr > 0 && ++hc->tx_packets_acked == 2) { | 432 | |
433 | if (hc->tx_cwnd < dp->dccps_l_seq_win && | ||
434 | r_seq_used < dp->dccps_r_seq_win) { | ||
435 | if (hc->tx_cwnd < hc->tx_ssthresh) { | ||
436 | if (*maxincr > 0 && ++hc->tx_packets_acked >= 2) { | ||
437 | hc->tx_cwnd += 1; | ||
438 | *maxincr -= 1; | ||
439 | hc->tx_packets_acked = 0; | ||
440 | } | ||
441 | } else if (++hc->tx_packets_acked >= hc->tx_cwnd) { | ||
411 | hc->tx_cwnd += 1; | 442 | hc->tx_cwnd += 1; |
412 | *maxincr -= 1; | ||
413 | hc->tx_packets_acked = 0; | 443 | hc->tx_packets_acked = 0; |
414 | } | 444 | } |
415 | } else if (++hc->tx_packets_acked >= hc->tx_cwnd) { | ||
416 | hc->tx_cwnd += 1; | ||
417 | hc->tx_packets_acked = 0; | ||
418 | } | 445 | } |
446 | |||
447 | /* | ||
448 | * Adjust the local sequence window and the ack ratio to allow about | ||
449 | * 5 times the number of packets in the network (RFC 4340 7.5.2) | ||
450 | */ | ||
451 | if (r_seq_used * CCID2_WIN_CHANGE_FACTOR >= dp->dccps_r_seq_win) | ||
452 | ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio * 2); | ||
453 | else if (r_seq_used * CCID2_WIN_CHANGE_FACTOR < dp->dccps_r_seq_win/2) | ||
454 | ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio / 2 ? : 1U); | ||
455 | |||
456 | if (hc->tx_cwnd * CCID2_WIN_CHANGE_FACTOR >= dp->dccps_l_seq_win) | ||
457 | ccid2_change_l_seq_window(sk, dp->dccps_l_seq_win * 2); | ||
458 | else if (hc->tx_cwnd * CCID2_WIN_CHANGE_FACTOR < dp->dccps_l_seq_win/2) | ||
459 | ccid2_change_l_seq_window(sk, dp->dccps_l_seq_win / 2); | ||
460 | |||
419 | /* | 461 | /* |
420 | * FIXME: RTT is sampled several times per acknowledgment (for each | 462 | * FIXME: RTT is sampled several times per acknowledgment (for each |
421 | * entry in the Ack Vector), instead of once per Ack (as in TCP SACK). | 463 | * entry in the Ack Vector), instead of once per Ack (as in TCP SACK). |
@@ -441,9 +483,7 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp) | |||
441 | hc->tx_cwnd = hc->tx_cwnd / 2 ? : 1U; | 483 | hc->tx_cwnd = hc->tx_cwnd / 2 ? : 1U; |
442 | hc->tx_ssthresh = max(hc->tx_cwnd, 2U); | 484 | hc->tx_ssthresh = max(hc->tx_cwnd, 2U); |
443 | 485 | ||
444 | /* Avoid spurious timeouts resulting from Ack Ratio > cwnd */ | 486 | ccid2_check_l_ack_ratio(sk); |
445 | if (dccp_sk(sk)->dccps_l_ack_ratio > hc->tx_cwnd) | ||
446 | ccid2_change_l_ack_ratio(sk, hc->tx_cwnd); | ||
447 | } | 487 | } |
448 | 488 | ||
449 | static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type, | 489 | static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type, |
@@ -494,8 +534,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
494 | if (hc->tx_rpdupack >= NUMDUPACK) { | 534 | if (hc->tx_rpdupack >= NUMDUPACK) { |
495 | hc->tx_rpdupack = -1; /* XXX lame */ | 535 | hc->tx_rpdupack = -1; /* XXX lame */ |
496 | hc->tx_rpseq = 0; | 536 | hc->tx_rpseq = 0; |
497 | 537 | #ifdef __CCID2_COPES_GRACEFULLY_WITH_ACK_CONGESTION_CONTROL__ | |
538 | /* | ||
539 | * FIXME: Ack Congestion Control is broken; in | ||
540 | * the current state instabilities occurred with | ||
541 | * Ack Ratios greater than 1; causing hang-ups | ||
542 | * and long RTO timeouts. This needs to be fixed | ||
543 | * before opening up dynamic changes. -- gerrit | ||
544 | */ | ||
498 | ccid2_change_l_ack_ratio(sk, 2 * dp->dccps_l_ack_ratio); | 545 | ccid2_change_l_ack_ratio(sk, 2 * dp->dccps_l_ack_ratio); |
546 | #endif | ||
499 | } | 547 | } |
500 | } | 548 | } |
501 | } | 549 | } |
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index f585d330e1e5..18c97543e522 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h | |||
@@ -43,6 +43,12 @@ struct ccid2_seq { | |||
43 | #define CCID2_SEQBUF_LEN 1024 | 43 | #define CCID2_SEQBUF_LEN 1024 |
44 | #define CCID2_SEQBUF_MAX 128 | 44 | #define CCID2_SEQBUF_MAX 128 |
45 | 45 | ||
46 | /* | ||
47 | * Multiple of congestion window to keep the sequence window at | ||
48 | * (RFC 4340 7.5.2) | ||
49 | */ | ||
50 | #define CCID2_WIN_CHANGE_FACTOR 5 | ||
51 | |||
46 | /** | 52 | /** |
47 | * struct ccid2_hc_tx_sock - CCID2 TX half connection | 53 | * struct ccid2_hc_tx_sock - CCID2 TX half connection |
48 | * @tx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5 | 54 | * @tx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5 |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 5fdb07229017..583490aaf56f 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -474,6 +474,7 @@ static inline int dccp_ack_pending(const struct sock *sk) | |||
474 | return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk); | 474 | return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk); |
475 | } | 475 | } |
476 | 476 | ||
477 | extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val); | ||
477 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); | 478 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); |
478 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); | 479 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); |
479 | extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, | 480 | extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, |
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 568def952722..23cea0ee3101 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * ----------- | 12 | * ----------- |
13 | * o Feature negotiation is coordinated with connection setup (as in TCP), wild | 13 | * o Feature negotiation is coordinated with connection setup (as in TCP), wild |
14 | * changes of parameters of an established connection are not supported. | 14 | * changes of parameters of an established connection are not supported. |
15 | * o Changing non-negotiable (NN) values is supported in state OPEN/PARTOPEN. | ||
15 | * o All currently known SP features have 1-byte quantities. If in the future | 16 | * o All currently known SP features have 1-byte quantities. If in the future |
16 | * extensions of RFCs 4340..42 define features with item lengths larger than | 17 | * extensions of RFCs 4340..42 define features with item lengths larger than |
17 | * one byte, a feature-specific extension of the code will be required. | 18 | * one byte, a feature-specific extension of the code will be required. |
@@ -343,6 +344,20 @@ static int __dccp_feat_activate(struct sock *sk, const int idx, | |||
343 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); | 344 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); |
344 | } | 345 | } |
345 | 346 | ||
347 | /** | ||
348 | * dccp_feat_activate - Activate feature value on socket | ||
349 | * @sk: fully connected DCCP socket (after handshake is complete) | ||
350 | * @feat_num: feature to activate, one of %dccp_feature_numbers | ||
351 | * @local: whether local (1) or remote (0) @feat_num is meant | ||
352 | * @fval: the value (SP or NN) to activate, or NULL to use the default value | ||
353 | * For general use this function is preferable over __dccp_feat_activate(). | ||
354 | */ | ||
355 | static int dccp_feat_activate(struct sock *sk, u8 feat_num, bool local, | ||
356 | dccp_feat_val const *fval) | ||
357 | { | ||
358 | return __dccp_feat_activate(sk, dccp_feat_index(feat_num), local, fval); | ||
359 | } | ||
360 | |||
346 | /* Test for "Req'd" feature (RFC 4340, 6.4) */ | 361 | /* Test for "Req'd" feature (RFC 4340, 6.4) */ |
347 | static inline int dccp_feat_must_be_understood(u8 feat_num) | 362 | static inline int dccp_feat_must_be_understood(u8 feat_num) |
348 | { | 363 | { |
@@ -650,11 +665,22 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq, | |||
650 | return -1; | 665 | return -1; |
651 | if (pos->needs_mandatory && dccp_insert_option_mandatory(skb)) | 666 | if (pos->needs_mandatory && dccp_insert_option_mandatory(skb)) |
652 | return -1; | 667 | return -1; |
653 | /* | 668 | |
654 | * Enter CHANGING after transmitting the Change option (6.6.2). | 669 | if (skb->sk->sk_state == DCCP_OPEN && |
655 | */ | 670 | (opt == DCCPO_CONFIRM_R || opt == DCCPO_CONFIRM_L)) { |
656 | if (pos->state == FEAT_INITIALISING) | 671 | /* |
657 | pos->state = FEAT_CHANGING; | 672 | * Confirms don't get retransmitted (6.6.3) once the |
673 | * connection is in state OPEN | ||
674 | */ | ||
675 | dccp_feat_list_pop(pos); | ||
676 | } else { | ||
677 | /* | ||
678 | * Enter CHANGING after transmitting the Change | ||
679 | * option (6.6.2). | ||
680 | */ | ||
681 | if (pos->state == FEAT_INITIALISING) | ||
682 | pos->state = FEAT_CHANGING; | ||
683 | } | ||
658 | } | 684 | } |
659 | return 0; | 685 | return 0; |
660 | } | 686 | } |
@@ -730,6 +756,70 @@ int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, | |||
730 | 0, list, len); | 756 | 0, list, len); |
731 | } | 757 | } |
732 | 758 | ||
759 | /** | ||
760 | * dccp_feat_nn_get - Query current/pending value of NN feature | ||
761 | * @sk: DCCP socket of an established connection | ||
762 | * @feat: NN feature number from %dccp_feature_numbers | ||
763 | * For a known NN feature, returns value currently being negotiated, or | ||
764 | * current (confirmed) value if no negotiation is going on. | ||
765 | */ | ||
766 | u64 dccp_feat_nn_get(struct sock *sk, u8 feat) | ||
767 | { | ||
768 | if (dccp_feat_type(feat) == FEAT_NN) { | ||
769 | struct dccp_sock *dp = dccp_sk(sk); | ||
770 | struct dccp_feat_entry *entry; | ||
771 | |||
772 | entry = dccp_feat_list_lookup(&dp->dccps_featneg, feat, 1); | ||
773 | if (entry != NULL) | ||
774 | return entry->val.nn; | ||
775 | |||
776 | switch (feat) { | ||
777 | case DCCPF_ACK_RATIO: | ||
778 | return dp->dccps_l_ack_ratio; | ||
779 | case DCCPF_SEQUENCE_WINDOW: | ||
780 | return dp->dccps_l_seq_win; | ||
781 | } | ||
782 | } | ||
783 | DCCP_BUG("attempt to look up unsupported feature %u", feat); | ||
784 | return 0; | ||
785 | } | ||
786 | EXPORT_SYMBOL_GPL(dccp_feat_nn_get); | ||
787 | |||
788 | /** | ||
789 | * dccp_feat_signal_nn_change - Update NN values for an established connection | ||
790 | * @sk: DCCP socket of an established connection | ||
791 | * @feat: NN feature number from %dccp_feature_numbers | ||
792 | * @nn_val: the new value to use | ||
793 | * This function is used to communicate NN updates out-of-band. | ||
794 | */ | ||
795 | int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val) | ||
796 | { | ||
797 | struct list_head *fn = &dccp_sk(sk)->dccps_featneg; | ||
798 | dccp_feat_val fval = { .nn = nn_val }; | ||
799 | struct dccp_feat_entry *entry; | ||
800 | |||
801 | if (sk->sk_state != DCCP_OPEN && sk->sk_state != DCCP_PARTOPEN) | ||
802 | return 0; | ||
803 | |||
804 | if (dccp_feat_type(feat) != FEAT_NN || | ||
805 | !dccp_feat_is_valid_nn_val(feat, nn_val)) | ||
806 | return -EINVAL; | ||
807 | |||
808 | if (nn_val == dccp_feat_nn_get(sk, feat)) | ||
809 | return 0; /* already set or negotiation under way */ | ||
810 | |||
811 | entry = dccp_feat_list_lookup(fn, feat, 1); | ||
812 | if (entry != NULL) { | ||
813 | dccp_pr_debug("Clobbering existing NN entry %llu -> %llu\n", | ||
814 | (unsigned long long)entry->val.nn, | ||
815 | (unsigned long long)nn_val); | ||
816 | dccp_feat_list_pop(entry); | ||
817 | } | ||
818 | |||
819 | inet_csk_schedule_ack(sk); | ||
820 | return dccp_feat_push_change(fn, feat, 1, 0, &fval); | ||
821 | } | ||
822 | EXPORT_SYMBOL_GPL(dccp_feat_signal_nn_change); | ||
733 | 823 | ||
734 | /* | 824 | /* |
735 | * Tracking features whose value depend on the choice of CCID | 825 | * Tracking features whose value depend on the choice of CCID |
@@ -1187,6 +1277,100 @@ confirmation_failed: | |||
1187 | } | 1277 | } |
1188 | 1278 | ||
1189 | /** | 1279 | /** |
1280 | * dccp_feat_handle_nn_established - Fast-path reception of NN options | ||
1281 | * @sk: socket of an established DCCP connection | ||
1282 | * @mandatory: whether @opt was preceded by a Mandatory option | ||
1283 | * @opt: %DCCPO_CHANGE_L | %DCCPO_CONFIRM_R (NN only) | ||
1284 | * @feat: NN number, one of %dccp_feature_numbers | ||
1285 | * @val: NN value | ||
1286 | * @len: length of @val in bytes | ||
1287 | * This function combines the functionality of change_recv/confirm_recv, with | ||
1288 | * the following differences (reset codes are the same): | ||
1289 | * - cleanup after receiving the Confirm; | ||
1290 | * - values are directly activated after successful parsing; | ||
1291 | * - deliberately restricted to NN features. | ||
1292 | * The restriction to NN features is essential since SP features can have non- | ||
1293 | * predictable outcomes (depending on the remote configuration), and are inter- | ||
1294 | * dependent (CCIDs for instance cause further dependencies). | ||
1295 | */ | ||
1296 | static u8 dccp_feat_handle_nn_established(struct sock *sk, u8 mandatory, u8 opt, | ||
1297 | u8 feat, u8 *val, u8 len) | ||
1298 | { | ||
1299 | struct list_head *fn = &dccp_sk(sk)->dccps_featneg; | ||
1300 | const bool local = (opt == DCCPO_CONFIRM_R); | ||
1301 | struct dccp_feat_entry *entry; | ||
1302 | u8 type = dccp_feat_type(feat); | ||
1303 | dccp_feat_val fval; | ||
1304 | |||
1305 | dccp_feat_print_opt(opt, feat, val, len, mandatory); | ||
1306 | |||
1307 | /* Ignore non-mandatory unknown and non-NN features */ | ||
1308 | if (type == FEAT_UNKNOWN) { | ||
1309 | if (local && !mandatory) | ||
1310 | return 0; | ||
1311 | goto fast_path_unknown; | ||
1312 | } else if (type != FEAT_NN) { | ||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | /* | ||
1317 | * We don't accept empty Confirms, since in fast-path feature | ||
1318 | * negotiation the values are enabled immediately after sending | ||
1319 | * the Change option. | ||
1320 | * Empty Changes on the other hand are invalid (RFC 4340, 6.1). | ||
1321 | */ | ||
1322 | if (len == 0 || len > sizeof(fval.nn)) | ||
1323 | goto fast_path_unknown; | ||
1324 | |||
1325 | if (opt == DCCPO_CHANGE_L) { | ||
1326 | fval.nn = dccp_decode_value_var(val, len); | ||
1327 | if (!dccp_feat_is_valid_nn_val(feat, fval.nn)) | ||
1328 | goto fast_path_unknown; | ||
1329 | |||
1330 | if (dccp_feat_push_confirm(fn, feat, local, &fval) || | ||
1331 | dccp_feat_activate(sk, feat, local, &fval)) | ||
1332 | return DCCP_RESET_CODE_TOO_BUSY; | ||
1333 | |||
1334 | /* set the `Ack Pending' flag to piggyback a Confirm */ | ||
1335 | inet_csk_schedule_ack(sk); | ||
1336 | |||
1337 | } else if (opt == DCCPO_CONFIRM_R) { | ||
1338 | entry = dccp_feat_list_lookup(fn, feat, local); | ||
1339 | if (entry == NULL || entry->state != FEAT_CHANGING) | ||
1340 | return 0; | ||
1341 | |||
1342 | fval.nn = dccp_decode_value_var(val, len); | ||
1343 | /* | ||
1344 | * Just ignore a value that doesn't match our current value. | ||
1345 | * If the option changes twice within two RTTs, then at least | ||
1346 | * one CONFIRM will be received for the old value after a | ||
1347 | * new CHANGE was sent. | ||
1348 | */ | ||
1349 | if (fval.nn != entry->val.nn) | ||
1350 | return 0; | ||
1351 | |||
1352 | /* Only activate after receiving the Confirm option (6.6.1). */ | ||
1353 | dccp_feat_activate(sk, feat, local, &fval); | ||
1354 | |||
1355 | /* It has been confirmed - so remove the entry */ | ||
1356 | dccp_feat_list_pop(entry); | ||
1357 | |||
1358 | } else { | ||
1359 | DCCP_WARN("Received illegal option %u\n", opt); | ||
1360 | goto fast_path_failed; | ||
1361 | } | ||
1362 | return 0; | ||
1363 | |||
1364 | fast_path_unknown: | ||
1365 | if (!mandatory) | ||
1366 | return dccp_push_empty_confirm(fn, feat, local); | ||
1367 | |||
1368 | fast_path_failed: | ||
1369 | return mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR | ||
1370 | : DCCP_RESET_CODE_OPTION_ERROR; | ||
1371 | } | ||
1372 | |||
1373 | /** | ||
1190 | * dccp_feat_parse_options - Process Feature-Negotiation Options | 1374 | * dccp_feat_parse_options - Process Feature-Negotiation Options |
1191 | * @sk: for general use and used by the client during connection setup | 1375 | * @sk: for general use and used by the client during connection setup |
1192 | * @dreq: used by the server during connection setup | 1376 | * @dreq: used by the server during connection setup |
@@ -1221,6 +1405,14 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
1221 | return dccp_feat_confirm_recv(fn, mandatory, opt, feat, | 1405 | return dccp_feat_confirm_recv(fn, mandatory, opt, feat, |
1222 | val, len, server); | 1406 | val, len, server); |
1223 | } | 1407 | } |
1408 | break; | ||
1409 | /* | ||
1410 | * Support for exchanging NN options on an established connection. | ||
1411 | */ | ||
1412 | case DCCP_OPEN: | ||
1413 | case DCCP_PARTOPEN: | ||
1414 | return dccp_feat_handle_nn_established(sk, mandatory, opt, feat, | ||
1415 | val, len); | ||
1224 | } | 1416 | } |
1225 | return 0; /* ignore FN options in all other states */ | 1417 | return 0; /* ignore FN options in all other states */ |
1226 | } | 1418 | } |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index e56a4e5e634e..90b957d34d26 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -129,6 +129,7 @@ extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); | |||
129 | 129 | ||
130 | extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len); | 130 | extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len); |
131 | extern u64 dccp_decode_value_var(const u8 *bf, const u8 len); | 131 | extern u64 dccp_decode_value_var(const u8 *bf, const u8 len); |
132 | extern u64 dccp_feat_nn_get(struct sock *sk, u8 feat); | ||
132 | 133 | ||
133 | extern int dccp_insert_option_mandatory(struct sk_buff *skb); | 134 | extern int dccp_insert_option_mandatory(struct sk_buff *skb); |
134 | extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, | 135 | extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 152975d942d9..e742f90a6858 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -184,7 +184,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) | |||
184 | dp->dccps_rate_last = jiffies; | 184 | dp->dccps_rate_last = jiffies; |
185 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | 185 | dp->dccps_role = DCCP_ROLE_UNDEFINED; |
186 | dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; | 186 | dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; |
187 | dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; | ||
188 | dp->dccps_tx_qlen = sysctl_dccp_tx_qlen; | 187 | dp->dccps_tx_qlen = sysctl_dccp_tx_qlen; |
189 | 188 | ||
190 | dccp_init_xmit_timers(sk); | 189 | dccp_init_xmit_timers(sk); |