aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ackvec.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ackvec.c')
-rw-r--r--net/dccp/ackvec.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 41d34d1babc1..bdf1bb7a82c0 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -68,10 +68,15 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
68{ 68{
69 struct dccp_sock *dp = dccp_sk(sk); 69 struct dccp_sock *dp = dccp_sk(sk);
70 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; 70 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
71 int len = av->dccpav_vec_len + 2; 71 /* Figure out how many options do we need to represent the ackvec */
72 const u16 nr_opts = (av->dccpav_vec_len +
73 DCCP_MAX_ACKVEC_OPT_LEN - 1) /
74 DCCP_MAX_ACKVEC_OPT_LEN;
75 u16 len = av->dccpav_vec_len + 2 * nr_opts, i;
72 struct timeval now; 76 struct timeval now;
73 u32 elapsed_time; 77 u32 elapsed_time;
74 unsigned char *to, *from; 78 const unsigned char *tail, *from;
79 unsigned char *to;
75 struct dccp_ackvec_record *avr; 80 struct dccp_ackvec_record *avr;
76 81
77 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) 82 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
@@ -90,24 +95,37 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
90 95
91 DCCP_SKB_CB(skb)->dccpd_opt_len += len; 96 DCCP_SKB_CB(skb)->dccpd_opt_len += len;
92 97
93 to = skb_push(skb, len); 98 to = skb_push(skb, len);
94 *to++ = DCCPO_ACK_VECTOR_0;
95 *to++ = len;
96
97 len = av->dccpav_vec_len; 99 len = av->dccpav_vec_len;
98 from = av->dccpav_buf + av->dccpav_buf_head; 100 from = av->dccpav_buf + av->dccpav_buf_head;
101 tail = av->dccpav_buf + DCCP_MAX_ACKVEC_LEN;
102
103 for (i = 0; i < nr_opts; ++i) {
104 int copylen = len;
105
106 if (len > DCCP_MAX_ACKVEC_OPT_LEN)
107 copylen = DCCP_MAX_ACKVEC_OPT_LEN;
99 108
100 /* Check if buf_head wraps */ 109 *to++ = DCCPO_ACK_VECTOR_0;
101 if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) { 110 *to++ = copylen + 2;
102 const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head; 111
112 /* Check if buf_head wraps */
113 if (from + copylen > tail) {
114 const u16 tailsize = tail - from;
115
116 memcpy(to, from, tailsize);
117 to += tailsize;
118 len -= tailsize;
119 copylen -= tailsize;
120 from = av->dccpav_buf;
121 }
103 122
104 memcpy(to, from, tailsize); 123 memcpy(to, from, copylen);
105 to += tailsize; 124 from += copylen;
106 len -= tailsize; 125 to += copylen;
107 from = av->dccpav_buf; 126 len -= copylen;
108 } 127 }
109 128
110 memcpy(to, from, len);
111 /* 129 /*
112 * From RFC 4340, A.2: 130 * From RFC 4340, A.2:
113 * 131 *