diff options
Diffstat (limited to 'net/dccp/options.c')
-rw-r--r-- | net/dccp/options.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/net/dccp/options.c b/net/dccp/options.c index 5adeeed5e0d2..f06ffcfc8d71 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -54,7 +54,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
54 | struct dccp_sock *dp = dccp_sk(sk); | 54 | struct dccp_sock *dp = dccp_sk(sk); |
55 | const struct dccp_hdr *dh = dccp_hdr(skb); | 55 | const struct dccp_hdr *dh = dccp_hdr(skb); |
56 | const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; | 56 | const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; |
57 | u64 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; | ||
58 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); | 57 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); |
59 | unsigned char *opt_ptr = options; | 58 | unsigned char *opt_ptr = options; |
60 | const unsigned char *opt_end = (unsigned char *)dh + | 59 | const unsigned char *opt_end = (unsigned char *)dh + |
@@ -129,14 +128,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
129 | if (rc) | 128 | if (rc) |
130 | goto out_featneg_failed; | 129 | goto out_featneg_failed; |
131 | break; | 130 | break; |
132 | case DCCPO_ACK_VECTOR_0: | ||
133 | case DCCPO_ACK_VECTOR_1: | ||
134 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
135 | break; | ||
136 | if (dp->dccps_hc_rx_ackvec != NULL && | ||
137 | dccp_ackvec_parse(sk, skb, &ackno, opt, value, len)) | ||
138 | goto out_invalid_option; | ||
139 | break; | ||
140 | case DCCPO_TIMESTAMP: | 131 | case DCCPO_TIMESTAMP: |
141 | if (len != 4) | 132 | if (len != 4) |
142 | goto out_invalid_option; | 133 | goto out_invalid_option; |
@@ -226,6 +217,16 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
226 | pkt_type, opt, value, len)) | 217 | pkt_type, opt, value, len)) |
227 | goto out_invalid_option; | 218 | goto out_invalid_option; |
228 | break; | 219 | break; |
220 | case DCCPO_ACK_VECTOR_0: | ||
221 | case DCCPO_ACK_VECTOR_1: | ||
222 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
223 | break; | ||
224 | /* | ||
225 | * Ack vectors are processed by the TX CCID if it is | ||
226 | * interested. The RX CCID need not parse Ack Vectors, | ||
227 | * since it is only interested in clearing old state. | ||
228 | * Fall through. | ||
229 | */ | ||
229 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: | 230 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: |
230 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, | 231 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, |
231 | pkt_type, opt, value, len)) | 232 | pkt_type, opt, value, len)) |
@@ -429,6 +430,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
429 | { | 430 | { |
430 | struct dccp_sock *dp = dccp_sk(sk); | 431 | struct dccp_sock *dp = dccp_sk(sk); |
431 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | 432 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; |
433 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
432 | const u16 buflen = dccp_ackvec_buflen(av); | 434 | const u16 buflen = dccp_ackvec_buflen(av); |
433 | /* Figure out how many options do we need to represent the ackvec */ | 435 | /* Figure out how many options do we need to represent the ackvec */ |
434 | const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); | 436 | const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); |
@@ -437,10 +439,25 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
437 | const unsigned char *tail, *from; | 439 | const unsigned char *tail, *from; |
438 | unsigned char *to; | 440 | unsigned char *to; |
439 | 441 | ||
440 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | 442 | if (dcb->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { |
443 | DCCP_WARN("Lacking space for %u bytes on %s packet\n", len, | ||
444 | dccp_packet_name(dcb->dccpd_type)); | ||
441 | return -1; | 445 | return -1; |
442 | 446 | } | |
443 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 447 | /* |
448 | * Since Ack Vectors are variable-length, we can not always predict | ||
449 | * their size. To catch exception cases where the space is running out | ||
450 | * on the skb, a separate Sync is scheduled to carry the Ack Vector. | ||
451 | */ | ||
452 | if (len > DCCPAV_MIN_OPTLEN && | ||
453 | len + dcb->dccpd_opt_len + skb->len > dp->dccps_mss_cache) { | ||
454 | DCCP_WARN("No space left for Ack Vector (%u) on skb (%u+%u), " | ||
455 | "MPS=%u ==> reduce payload size?\n", len, skb->len, | ||
456 | dcb->dccpd_opt_len, dp->dccps_mss_cache); | ||
457 | dp->dccps_sync_scheduled = 1; | ||
458 | return 0; | ||
459 | } | ||
460 | dcb->dccpd_opt_len += len; | ||
444 | 461 | ||
445 | to = skb_push(skb, len); | 462 | to = skb_push(skb, len); |
446 | len = buflen; | 463 | len = buflen; |
@@ -481,7 +498,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
481 | /* | 498 | /* |
482 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. | 499 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. |
483 | */ | 500 | */ |
484 | if (dccp_ackvec_update_records(av, DCCP_SKB_CB(skb)->dccpd_seq, nonce)) | 501 | if (dccp_ackvec_update_records(av, dcb->dccpd_seq, nonce)) |
485 | return -ENOBUFS; | 502 | return -ENOBUFS; |
486 | return 0; | 503 | return 0; |
487 | } | 504 | } |