aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/options.c')
-rw-r--r--net/dccp/options.c65
1 files changed, 63 insertions, 2 deletions
diff --git a/net/dccp/options.c b/net/dccp/options.c
index cd3061813009..5adeeed5e0d2 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -340,6 +340,7 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time)
340 return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; 340 return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
341} 341}
342 342
343/* FIXME: This function is currently not used anywhere */
343int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time) 344int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time)
344{ 345{
345 const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); 346 const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
@@ -424,6 +425,67 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
424 return 0; 425 return 0;
425} 426}
426 427
428static 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 const u16 buflen = dccp_ackvec_buflen(av);
433 /* 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);
435 u16 len = buflen + 2 * nr_opts;
436 u8 i, nonce = 0;
437 const unsigned char *tail, *from;
438 unsigned char *to;
439
440 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
441 return -1;
442
443 DCCP_SKB_CB(skb)->dccpd_opt_len += len;
444
445 to = skb_push(skb, len);
446 len = buflen;
447 from = av->av_buf + av->av_buf_head;
448 tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
449
450 for (i = 0; i < nr_opts; ++i) {
451 int copylen = len;
452
453 if (len > DCCP_SINGLE_OPT_MAXLEN)
454 copylen = DCCP_SINGLE_OPT_MAXLEN;
455
456 /*
457 * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via
458 * its type; ack_nonce is the sum of all individual buf_nonce's.
459 */
460 nonce ^= av->av_buf_nonce[i];
461
462 *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i];
463 *to++ = copylen + 2;
464
465 /* Check if buf_head wraps */
466 if (from + copylen > tail) {
467 const u16 tailsize = tail - from;
468
469 memcpy(to, from, tailsize);
470 to += tailsize;
471 len -= tailsize;
472 copylen -= tailsize;
473 from = av->av_buf;
474 }
475
476 memcpy(to, from, copylen);
477 from += copylen;
478 to += copylen;
479 len -= copylen;
480 }
481 /*
482 * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340.
483 */
484 if (dccp_ackvec_update_records(av, DCCP_SKB_CB(skb)->dccpd_seq, nonce))
485 return -ENOBUFS;
486 return 0;
487}
488
427/** 489/**
428 * dccp_insert_option_mandatory - Mandatory option (5.8.2) 490 * dccp_insert_option_mandatory - Mandatory option (5.8.2)
429 * Note that since we are using skb_push, this function needs to be called 491 * Note that since we are using skb_push, this function needs to be called
@@ -519,8 +581,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
519 if (dccp_insert_option_timestamp(skb)) 581 if (dccp_insert_option_timestamp(skb))
520 return -1; 582 return -1;
521 583
522 } else if (dp->dccps_hc_rx_ackvec != NULL && 584 } else if (dccp_ackvec_pending(sk) &&
523 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
524 dccp_insert_option_ackvec(sk, skb)) { 585 dccp_insert_option_ackvec(sk, skb)) {
525 return -1; 586 return -1;
526 } 587 }