diff options
-rw-r--r-- | include/linux/dccp.h | 2 | ||||
-rw-r--r-- | net/dccp/options.c | 24 | ||||
-rw-r--r-- | net/dccp/output.c | 15 |
3 files changed, 37 insertions, 4 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 749f01ccd26e..eed52bcd35d0 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -462,6 +462,7 @@ struct dccp_ackvec; | |||
462 | * @dccps_hc_rx_insert_options - receiver wants to add options when acking | 462 | * @dccps_hc_rx_insert_options - receiver wants to add options when acking |
463 | * @dccps_hc_tx_insert_options - sender wants to add options when sending | 463 | * @dccps_hc_tx_insert_options - sender wants to add options when sending |
464 | * @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3) | 464 | * @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3) |
465 | * @dccps_sync_scheduled - flag which signals "send out-of-band message soon" | ||
465 | * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets | 466 | * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets |
466 | * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) | 467 | * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) |
467 | * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) | 468 | * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) |
@@ -503,6 +504,7 @@ struct dccp_sock { | |||
503 | __u8 dccps_hc_rx_insert_options:1; | 504 | __u8 dccps_hc_rx_insert_options:1; |
504 | __u8 dccps_hc_tx_insert_options:1; | 505 | __u8 dccps_hc_tx_insert_options:1; |
505 | __u8 dccps_server_timewait:1; | 506 | __u8 dccps_server_timewait:1; |
507 | __u8 dccps_sync_scheduled:1; | ||
506 | struct tasklet_struct dccps_xmitlet; | 508 | struct tasklet_struct dccps_xmitlet; |
507 | struct timer_list dccps_xmit_timer; | 509 | struct timer_list dccps_xmit_timer; |
508 | }; | 510 | }; |
diff --git a/net/dccp/options.c b/net/dccp/options.c index 7743df00f5b1..dabd6ee34d45 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -427,6 +427,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
427 | { | 427 | { |
428 | struct dccp_sock *dp = dccp_sk(sk); | 428 | struct dccp_sock *dp = dccp_sk(sk); |
429 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | 429 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; |
430 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
430 | const u16 buflen = dccp_ackvec_buflen(av); | 431 | const u16 buflen = dccp_ackvec_buflen(av); |
431 | /* Figure out how many options do we need to represent the ackvec */ | 432 | /* Figure out how many options do we need to represent the ackvec */ |
432 | const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); | 433 | const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); |
@@ -435,10 +436,25 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
435 | const unsigned char *tail, *from; | 436 | const unsigned char *tail, *from; |
436 | unsigned char *to; | 437 | unsigned char *to; |
437 | 438 | ||
438 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | 439 | if (dcb->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { |
440 | DCCP_WARN("Lacking space for %u bytes on %s packet\n", len, | ||
441 | dccp_packet_name(dcb->dccpd_type)); | ||
439 | return -1; | 442 | return -1; |
440 | 443 | } | |
441 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 444 | /* |
445 | * Since Ack Vectors are variable-length, we can not always predict | ||
446 | * their size. To catch exception cases where the space is running out | ||
447 | * on the skb, a separate Sync is scheduled to carry the Ack Vector. | ||
448 | */ | ||
449 | if (len > DCCPAV_MIN_OPTLEN && | ||
450 | len + dcb->dccpd_opt_len + skb->len > dp->dccps_mss_cache) { | ||
451 | DCCP_WARN("No space left for Ack Vector (%u) on skb (%u+%u), " | ||
452 | "MPS=%u ==> reduce payload size?\n", len, skb->len, | ||
453 | dcb->dccpd_opt_len, dp->dccps_mss_cache); | ||
454 | dp->dccps_sync_scheduled = 1; | ||
455 | return 0; | ||
456 | } | ||
457 | dcb->dccpd_opt_len += len; | ||
442 | 458 | ||
443 | to = skb_push(skb, len); | 459 | to = skb_push(skb, len); |
444 | len = buflen; | 460 | len = buflen; |
@@ -479,7 +495,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
479 | /* | 495 | /* |
480 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. | 496 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. |
481 | */ | 497 | */ |
482 | if (dccp_ackvec_update_records(av, DCCP_SKB_CB(skb)->dccpd_seq, nonce)) | 498 | if (dccp_ackvec_update_records(av, dcb->dccpd_seq, nonce)) |
483 | return -ENOBUFS; | 499 | return -ENOBUFS; |
484 | return 0; | 500 | return 0; |
485 | } | 501 | } |
diff --git a/net/dccp/output.c b/net/dccp/output.c index 45b91853f5ae..d96dd9d362ae 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -283,6 +283,15 @@ static void dccp_xmit_packet(struct sock *sk) | |||
283 | * any local drop will eventually be reported via receiver feedback. | 283 | * any local drop will eventually be reported via receiver feedback. |
284 | */ | 284 | */ |
285 | ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); | 285 | ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); |
286 | |||
287 | /* | ||
288 | * If the CCID needs to transfer additional header options out-of-band | ||
289 | * (e.g. Ack Vectors or feature-negotiation options), it activates this | ||
290 | * flag to schedule a Sync. The Sync will automatically incorporate all | ||
291 | * currently pending header options, thus clearing the backlog. | ||
292 | */ | ||
293 | if (dp->dccps_sync_scheduled) | ||
294 | dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC); | ||
286 | } | 295 | } |
287 | 296 | ||
288 | /** | 297 | /** |
@@ -636,6 +645,12 @@ void dccp_send_sync(struct sock *sk, const u64 ackno, | |||
636 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; | 645 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; |
637 | DCCP_SKB_CB(skb)->dccpd_ack_seq = ackno; | 646 | DCCP_SKB_CB(skb)->dccpd_ack_seq = ackno; |
638 | 647 | ||
648 | /* | ||
649 | * Clear the flag in case the Sync was scheduled for out-of-band data, | ||
650 | * such as carrying a long Ack Vector. | ||
651 | */ | ||
652 | dccp_sk(sk)->dccps_sync_scheduled = 0; | ||
653 | |||
639 | dccp_transmit_skb(sk, skb); | 654 | dccp_transmit_skb(sk, skb); |
640 | } | 655 | } |
641 | 656 | ||