aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/dccp.h2
-rw-r--r--net/dccp/options.c24
-rw-r--r--net/dccp/output.c15
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