diff options
Diffstat (limited to 'net/dccp/options.c')
-rw-r--r-- | net/dccp/options.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/net/dccp/options.c b/net/dccp/options.c index 799c6f4547cd..f4ff0a308269 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -425,6 +425,66 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp, | |||
425 | return 0; | 425 | return 0; |
426 | } | 426 | } |
427 | 427 | ||
428 | static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | ||
429 | { | ||
430 | struct dccp_sock *dp = dccp_sk(sk); | ||
431 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | ||
432 | /* Figure out how many options do we need to represent the ackvec */ | ||
433 | const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN); | ||
434 | u16 len = av->av_vec_len + 2 * nr_opts; | ||
435 | u8 i, nonce = 0; | ||
436 | const unsigned char *tail, *from; | ||
437 | unsigned char *to; | ||
438 | |||
439 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
440 | return -1; | ||
441 | |||
442 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | ||
443 | |||
444 | to = skb_push(skb, len); | ||
445 | len = av->av_vec_len; | ||
446 | from = av->av_buf + av->av_buf_head; | ||
447 | tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; | ||
448 | |||
449 | for (i = 0; i < nr_opts; ++i) { | ||
450 | int copylen = len; | ||
451 | |||
452 | if (len > DCCP_SINGLE_OPT_MAXLEN) | ||
453 | copylen = DCCP_SINGLE_OPT_MAXLEN; | ||
454 | |||
455 | /* | ||
456 | * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via | ||
457 | * its type; ack_nonce is the sum of all individual buf_nonce's. | ||
458 | */ | ||
459 | nonce ^= av->av_buf_nonce[i]; | ||
460 | |||
461 | *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i]; | ||
462 | *to++ = copylen + 2; | ||
463 | |||
464 | /* Check if buf_head wraps */ | ||
465 | if (from + copylen > tail) { | ||
466 | const u16 tailsize = tail - from; | ||
467 | |||
468 | memcpy(to, from, tailsize); | ||
469 | to += tailsize; | ||
470 | len -= tailsize; | ||
471 | copylen -= tailsize; | ||
472 | from = av->av_buf; | ||
473 | } | ||
474 | |||
475 | memcpy(to, from, copylen); | ||
476 | from += copylen; | ||
477 | to += copylen; | ||
478 | len -= copylen; | ||
479 | } | ||
480 | /* | ||
481 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. | ||
482 | */ | ||
483 | if (dccp_ackvec_update_records(av, DCCP_SKB_CB(skb)->dccpd_seq, nonce)) | ||
484 | return -ENOBUFS; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
428 | /** | 488 | /** |
429 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) | 489 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) |
430 | * Note that since we are using skb_push, this function needs to be called | 490 | * Note that since we are using skb_push, this function needs to be called |