diff options
Diffstat (limited to 'net/dccp/options.c')
-rw-r--r-- | net/dccp/options.c | 100 |
1 files changed, 89 insertions, 11 deletions
diff --git a/net/dccp/options.c b/net/dccp/options.c index cd3061813009..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)) |
@@ -340,6 +341,7 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time) | |||
340 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; | 341 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; |
341 | } | 342 | } |
342 | 343 | ||
344 | /* FIXME: This function is currently not used anywhere */ | ||
343 | int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time) | 345 | int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time) |
344 | { | 346 | { |
345 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | 347 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); |
@@ -424,6 +426,83 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp, | |||
424 | return 0; | 426 | return 0; |
425 | } | 427 | } |
426 | 428 | ||
429 | static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | ||
430 | { | ||
431 | struct dccp_sock *dp = dccp_sk(sk); | ||
432 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | ||
433 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
434 | const u16 buflen = dccp_ackvec_buflen(av); | ||
435 | /* Figure out how many options do we need to represent the ackvec */ | ||
436 | const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); | ||
437 | u16 len = buflen + 2 * nr_opts; | ||
438 | u8 i, nonce = 0; | ||
439 | const unsigned char *tail, *from; | ||
440 | unsigned char *to; | ||
441 | |||
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)); | ||
445 | return -1; | ||
446 | } | ||
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; | ||
461 | |||
462 | to = skb_push(skb, len); | ||
463 | len = buflen; | ||
464 | from = av->av_buf + av->av_buf_head; | ||
465 | tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; | ||
466 | |||
467 | for (i = 0; i < nr_opts; ++i) { | ||
468 | int copylen = len; | ||
469 | |||
470 | if (len > DCCP_SINGLE_OPT_MAXLEN) | ||
471 | copylen = DCCP_SINGLE_OPT_MAXLEN; | ||
472 | |||
473 | /* | ||
474 | * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via | ||
475 | * its type; ack_nonce is the sum of all individual buf_nonce's. | ||
476 | */ | ||
477 | nonce ^= av->av_buf_nonce[i]; | ||
478 | |||
479 | *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i]; | ||
480 | *to++ = copylen + 2; | ||
481 | |||
482 | /* Check if buf_head wraps */ | ||
483 | if (from + copylen > tail) { | ||
484 | const u16 tailsize = tail - from; | ||
485 | |||
486 | memcpy(to, from, tailsize); | ||
487 | to += tailsize; | ||
488 | len -= tailsize; | ||
489 | copylen -= tailsize; | ||
490 | from = av->av_buf; | ||
491 | } | ||
492 | |||
493 | memcpy(to, from, copylen); | ||
494 | from += copylen; | ||
495 | to += copylen; | ||
496 | len -= copylen; | ||
497 | } | ||
498 | /* | ||
499 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. | ||
500 | */ | ||
501 | if (dccp_ackvec_update_records(av, dcb->dccpd_seq, nonce)) | ||
502 | return -ENOBUFS; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
427 | /** | 506 | /** |
428 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) | 507 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) |
429 | * Note that since we are using skb_push, this function needs to be called | 508 | * Note that since we are using skb_push, this function needs to be called |
@@ -519,8 +598,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | |||
519 | if (dccp_insert_option_timestamp(skb)) | 598 | if (dccp_insert_option_timestamp(skb)) |
520 | return -1; | 599 | return -1; |
521 | 600 | ||
522 | } else if (dp->dccps_hc_rx_ackvec != NULL && | 601 | } else if (dccp_ackvec_pending(sk) && |
523 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && | ||
524 | dccp_insert_option_ackvec(sk, skb)) { | 602 | dccp_insert_option_ackvec(sk, skb)) { |
525 | return -1; | 603 | return -1; |
526 | } | 604 | } |