dccp_tcplike.c revision 1.4 1 1.1 rjs /* $KAME: dccp_tcplike.c,v 1.19 2005/07/27 06:27:25 nishida Exp $ */
2 1.4 msaitoh /* $NetBSD: dccp_tcplike.c,v 1.4 2019/06/04 10:15:22 msaitoh Exp $ */
3 1.1 rjs
4 1.1 rjs /*
5 1.1 rjs * Copyright (c) 2003 Magnus Erixzon
6 1.1 rjs * All rights reserved.
7 1.1 rjs *
8 1.1 rjs * Redistribution and use in source and binary forms, with or without
9 1.1 rjs * modification, are permitted provided that the following conditions
10 1.1 rjs * are met:
11 1.1 rjs *
12 1.1 rjs * 1. Redistributions of source code must retain the above copyright
13 1.1 rjs * notice, this list of conditions and the following disclaimer.
14 1.1 rjs * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 rjs * notice, this list of conditions and the following disclaimer in the
16 1.1 rjs * documentation and/or other materials provided with the distribution.
17 1.1 rjs * 3. The name of the author may not be used to endorse or promote products
18 1.1 rjs * derived from this software without specific prior written permission.
19 1.1 rjs *
20 1.1 rjs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 1.1 rjs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 1.1 rjs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 1.1 rjs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 1.1 rjs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 1.1 rjs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 1.1 rjs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 1.1 rjs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 1.1 rjs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 1.1 rjs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 1.1 rjs */
31 1.1 rjs /*
32 1.1 rjs * TCP-like congestion control for DCCP
33 1.1 rjs */
34 1.1 rjs
35 1.1 rjs #include <sys/cdefs.h>
36 1.4 msaitoh __KERNEL_RCSID(0, "$NetBSD: dccp_tcplike.c,v 1.4 2019/06/04 10:15:22 msaitoh Exp $");
37 1.1 rjs
38 1.2 pooka #ifdef _KERNEL_OPT
39 1.1 rjs #include "opt_dccp.h"
40 1.2 pooka #endif
41 1.1 rjs
42 1.1 rjs #include <sys/param.h>
43 1.1 rjs #include <sys/systm.h>
44 1.1 rjs #include <sys/domain.h>
45 1.1 rjs #include <sys/kernel.h>
46 1.1 rjs #include <sys/lock.h>
47 1.1 rjs #include <sys/malloc.h>
48 1.1 rjs #include <sys/mbuf.h>
49 1.1 rjs #include <sys/proc.h>
50 1.1 rjs #include <sys/protosw.h>
51 1.1 rjs #include <sys/signalvar.h>
52 1.1 rjs #include <sys/socket.h>
53 1.1 rjs #include <sys/socketvar.h>
54 1.1 rjs #include <sys/mutex.h>
55 1.1 rjs #include <sys/sysctl.h>
56 1.1 rjs #include <sys/syslog.h>
57 1.1 rjs
58 1.1 rjs #include <net/if.h>
59 1.1 rjs
60 1.1 rjs #include <netinet/in.h>
61 1.1 rjs #include <netinet/in_systm.h>
62 1.1 rjs #include <netinet/ip.h>
63 1.1 rjs #include <netinet/in_pcb.h>
64 1.1 rjs #include <netinet/in_var.h>
65 1.1 rjs
66 1.1 rjs #include <netinet/ip_icmp.h>
67 1.1 rjs #include <netinet/icmp_var.h>
68 1.1 rjs #include <netinet/ip_var.h>
69 1.1 rjs
70 1.1 rjs #include <netinet/dccp.h>
71 1.1 rjs #include <netinet/dccp_var.h>
72 1.1 rjs #include <netinet/dccp_tcplike.h>
73 1.1 rjs
74 1.1 rjs #define TCPLIKE_DEBUG(args) dccp_log args
75 1.1 rjs #define MALLOC_DEBUG(args) log args
76 1.1 rjs #define CWND_DEBUG(args) dccp_log args
77 1.1 rjs #define ACKRATIO_DEBUG(args) dccp_log args
78 1.1 rjs #define LOSS_DEBUG(args) dccp_log args
79 1.1 rjs #define TIMEOUT_DEBUG(args) dccp_log args
80 1.1 rjs
81 1.1 rjs #if !defined(__FreeBSD__) || __FreeBSD_version < 500000
82 1.1 rjs #define INP_INFO_LOCK_INIT(x,y)
83 1.1 rjs #define INP_INFO_WLOCK(x)
84 1.1 rjs #define INP_INFO_WUNLOCK(x)
85 1.1 rjs #define INP_INFO_RLOCK(x)
86 1.1 rjs #define INP_INFO_RUNLOCK(x)
87 1.1 rjs #define INP_LOCK(x)
88 1.1 rjs #define INP_UNLOCK(x)
89 1.1 rjs #endif
90 1.1 rjs
91 1.1 rjs /* Sender side */
92 1.1 rjs
93 1.1 rjs void tcplike_rto_timeout(void *);
94 1.1 rjs void tcplike_rtt_sample(struct tcplike_send_ccb *, u_int16_t);
95 1.1 rjs void _add_to_cwndvector(struct tcplike_send_ccb *, u_int64_t);
96 1.1 rjs void _remove_from_cwndvector(struct tcplike_send_ccb *, u_int64_t);
97 1.1 rjs int _chop_cwndvector(struct tcplike_send_ccb *, u_int64_t);
98 1.1 rjs int _cwndvector_size(struct tcplike_send_ccb *);
99 1.1 rjs u_char _cwndvector_state(struct tcplike_send_ccb *, u_int64_t);
100 1.1 rjs
101 1.1 rjs void tcplike_send_term(void *);
102 1.1 rjs void tcplike_recv_term(void *);
103 1.1 rjs
104 1.1 rjs void _avlist_add(struct tcplike_recv_ccb *, u_int64_t, u_int64_t);
105 1.1 rjs u_int64_t _avlist_get(struct tcplike_recv_ccb *, u_int64_t);
106 1.1 rjs
107 1.1 rjs /* extern Ack Vector functions */
108 1.1 rjs extern void dccp_use_ackvector(struct dccpcb *);
109 1.1 rjs extern void dccp_update_ackvector(struct dccpcb *, u_int64_t);
110 1.1 rjs extern void dccp_increment_ackvector(struct dccpcb *, u_int64_t);
111 1.1 rjs extern u_int16_t dccp_generate_ackvector(struct dccpcb *, u_char *);
112 1.1 rjs extern u_char dccp_ackvector_state(struct dccpcb *, u_int32_t);
113 1.1 rjs
114 1.1 rjs extern int dccp_get_option(char *, int, int, char *, int);
115 1.1 rjs extern int dccp_remove_feature(struct dccpcb *, u_int8_t, u_int8_t);
116 1.1 rjs
117 1.1 rjs /*
118 1.1 rjs * RTO timer activated
119 1.1 rjs */
120 1.1 rjs void
121 1.1 rjs tcplike_rto_timeout(void *ccb)
122 1.1 rjs {
123 1.1 rjs struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
124 1.1 rjs /*struct inpcb *inp;*/
125 1.1 rjs int s;
126 1.1 rjs
127 1.1 rjs mutex_enter(&(cb->mutex));
128 1.1 rjs
129 1.1 rjs cb->ssthresh = cb->cwnd >>1;
130 1.1 rjs cb->cwnd = 1; /* allowing 1 packet to be sent */
131 1.1 rjs cb->outstanding = 0; /* is this correct? */
132 1.1 rjs cb->rto_timer_callout = 0;
133 1.1 rjs cb->rto = cb->rto << 1;
134 1.1 rjs TIMEOUT_DEBUG((LOG_INFO, "RTO Timeout. New RTO = %u\n", cb->rto));
135 1.1 rjs
136 1.1 rjs cb->sample_rtt = 0;
137 1.1 rjs
138 1.1 rjs cb->ack_last = 0;
139 1.1 rjs cb->ack_miss = 0;
140 1.1 rjs
141 1.1 rjs cb->rcvr_ackratio = 1; /* Constraint 2 & 3. We need ACKs asap */
142 1.1 rjs dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKRATIO);
143 1.1 rjs dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKRATIO,
144 1.1 rjs (char *) &cb->rcvr_ackratio, 1);
145 1.1 rjs cb->acked_in_win = 0;
146 1.1 rjs cb->acked_windows = 0;
147 1.1 rjs cb->oldcwnd_ts = cb->pcb->seq_snd;
148 1.1 rjs
149 1.1 rjs LOSS_DEBUG((LOG_INFO, "Timeout. CWND value: %u , OUTSTANDING value: %u\n",
150 1.1 rjs cb->cwnd, cb->outstanding));
151 1.1 rjs mutex_exit(&(cb->mutex));
152 1.1 rjs
153 1.1 rjs /* lock'n run dccp_output */
154 1.1 rjs s = splnet();
155 1.1 rjs INP_INFO_RLOCK(&dccpbinfo);
156 1.1 rjs /*inp = cb->pcb->d_inpcb;*/
157 1.1 rjs INP_LOCK(inp);
158 1.1 rjs INP_INFO_RUNLOCK(&dccpbinfo);
159 1.1 rjs
160 1.1 rjs dccp_output(cb->pcb, 1);
161 1.1 rjs
162 1.1 rjs INP_UNLOCK(inp);
163 1.1 rjs splx(s);
164 1.1 rjs }
165 1.1 rjs
166 1.1 rjs void tcplike_rtt_sample(struct tcplike_send_ccb *cb, u_int16_t sample)
167 1.1 rjs {
168 1.1 rjs u_int16_t err;
169 1.1 rjs
170 1.1 rjs if (cb->rtt == 0xffff) {
171 1.1 rjs /* hmmmmm. */
172 1.1 rjs cb->rtt = sample;
173 1.1 rjs cb->rto = cb->rtt << 1;
174 1.1 rjs return;
175 1.1 rjs }
176 1.1 rjs
177 1.1 rjs /* This is how the Linux implementation is doing it.. */
178 1.1 rjs if (sample >= cb->rtt) {
179 1.1 rjs err = sample - cb->rtt;
180 1.1 rjs cb->rtt = cb->rtt + (err >> 3);
181 1.1 rjs } else {
182 1.1 rjs err = cb->rtt - sample;
183 1.1 rjs cb->rtt = cb->rtt - (err >> 3);
184 1.1 rjs }
185 1.1 rjs cb->rtt_d = cb->rtt_d + ((err - cb->rtt_d) >> 2);
186 1.1 rjs if (cb->rtt < TCPLIKE_MIN_RTT)
187 1.1 rjs cb->rtt = TCPLIKE_MIN_RTT;
188 1.1 rjs cb->rto = cb->rtt + (cb->rtt_d << 2);
189 1.1 rjs
190 1.1 rjs
191 1.1 rjs /* 5 million ways to calculate RTT ...*/
192 1.1 rjs #if 0
193 1.1 rjs cb->srtt = ( 0.8 * cb->srtt ) + (0.2 * sample);
194 1.1 rjs if (cb->srtt < TCPLIKE_MIN_RTT)
195 1.1 rjs cb->srtt = TCPLIKE_MIN_RTT;
196 1.1 rjs cb->rto = cb->srtt << 1;
197 1.1 rjs #endif
198 1.1 rjs
199 1.1 rjs LOSS_DEBUG((LOG_INFO, "RTT Sample: %u , New RTO: %u\n", sample, cb->rto));
200 1.1 rjs }
201 1.1 rjs
202 1.1 rjs /* Functions declared in struct dccp_cc_sw */
203 1.1 rjs
204 1.1 rjs /*
205 1.1 rjs * Initialises the sender side
206 1.1 rjs * returns: pointer to a tfrc_send_ccb struct on success, otherwise 0
207 1.1 rjs */
208 1.1 rjs void *
209 1.1 rjs tcplike_send_init(struct dccpcb* pcb)
210 1.1 rjs {
211 1.1 rjs struct tcplike_send_ccb *cb;
212 1.1 rjs
213 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_init()\n"));
214 1.1 rjs
215 1.1 rjs cb = malloc(sizeof (struct tcplike_send_ccb), M_PCB, M_NOWAIT | M_ZERO);
216 1.1 rjs if (cb == 0) {
217 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Unable to allocate memory for tcplike_send_ccb!\n"));
218 1.1 rjs dccpstat.tcplikes_send_memerr++;
219 1.1 rjs return 0;
220 1.1 rjs }
221 1.1 rjs memset(cb, 0, sizeof (struct tcplike_send_ccb));
222 1.1 rjs
223 1.1 rjs /* init sender */
224 1.1 rjs cb->pcb = pcb;
225 1.1 rjs
226 1.1 rjs cb->cwnd = TCPLIKE_INITIAL_CWND;
227 1.1 rjs cb->ssthresh = 0xafff; /* lim-> infinity */
228 1.1 rjs cb->oldcwnd_ts = 0;
229 1.1 rjs cb->outstanding = 0;
230 1.1 rjs cb->rcvr_ackratio = 2; /* Ack Ratio */
231 1.1 rjs cb->acked_in_win = 0;
232 1.1 rjs cb->acked_windows = 0;
233 1.1 rjs
234 1.1 rjs CWND_DEBUG((LOG_INFO, "Init. CWND value: %u , OUTSTANDING value: %u\n",
235 1.1 rjs cb->cwnd, cb->outstanding));
236 1.1 rjs cb->rtt = 0xffff;
237 1.1 rjs cb->rto = TIMEOUT_UBOUND;
238 1.1 rjs callout_init(&cb->rto_timer, 0);
239 1.1 rjs callout_init(&cb->free_timer, 0);
240 1.1 rjs cb->rto_timer_callout = 0;
241 1.1 rjs cb->rtt_d = 0;
242 1.1 rjs cb->timestamp = 0;
243 1.1 rjs
244 1.1 rjs cb->sample_rtt = 1;
245 1.1 rjs
246 1.1 rjs cb->cv_size = TCPLIKE_INITIAL_CWNDVECTOR;
247 1.1 rjs /* 1 bit per entry */
248 1.1 rjs cb->cwndvector = malloc(cb->cv_size / 8, M_PCB, M_NOWAIT | M_ZERO);
249 1.1 rjs if (cb->cwndvector == NULL) {
250 1.1 rjs MALLOC_DEBUG((LOG_INFO, "Unable to allocate memory for cwndvector\n"));
251 1.1 rjs /* What to do now? */
252 1.1 rjs cb->cv_size = 0;
253 1.1 rjs dccpstat.tcplikes_send_memerr++;
254 1.1 rjs return 0;
255 1.1 rjs }
256 1.1 rjs memset(cb->cwndvector, 0, cb->cv_size / 8);
257 1.1 rjs cb->cv_hs = cb->cv_ts = 0;
258 1.1 rjs cb->cv_hp = cb->cwndvector;
259 1.1 rjs
260 1.1 rjs cb->ack_last = 0;
261 1.1 rjs cb->ack_miss = 0;
262 1.1 rjs
263 1.1 rjs mutex_init(&(cb->mutex), MUTEX_DEFAULT, IPL_SOFTNET);
264 1.1 rjs
265 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "TCPlike sender initialised!\n"));
266 1.1 rjs dccpstat.tcplikes_send_conn++;
267 1.1 rjs return cb;
268 1.1 rjs }
269 1.1 rjs
270 1.1 rjs void tcplike_send_term(void *ccb)
271 1.1 rjs {
272 1.1 rjs struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
273 1.1 rjs if (ccb == 0)
274 1.1 rjs return;
275 1.1 rjs
276 1.1 rjs mutex_destroy(&(cb->mutex));
277 1.1 rjs
278 1.1 rjs free(cb, M_PCB);
279 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "TCP-like sender is destroyed\n"));
280 1.1 rjs }
281 1.1 rjs
282 1.1 rjs /*
283 1.1 rjs * Free the sender side
284 1.1 rjs * args: ccb - ccb of sender
285 1.1 rjs */
286 1.1 rjs void
287 1.1 rjs tcplike_send_free(void *ccb)
288 1.1 rjs {
289 1.1 rjs struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
290 1.1 rjs
291 1.1 rjs LOSS_DEBUG((LOG_INFO, "Entering tcplike_send_free()\n"));
292 1.1 rjs
293 1.1 rjs if (ccb == 0)
294 1.1 rjs return;
295 1.1 rjs
296 1.1 rjs mutex_enter(&(cb->mutex));
297 1.1 rjs
298 1.1 rjs free(cb->cwndvector, M_PCB);
299 1.1 rjs cb->cv_hs = cb->cv_ts = 0;
300 1.1 rjs
301 1.1 rjs /* untimeout any active timer */
302 1.1 rjs if (cb->rto_timer_callout) {
303 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Untimeout RTO Timer\n"));
304 1.1 rjs callout_stop(&cb->rto_timer);
305 1.1 rjs cb->rto_timer_callout = 0;
306 1.1 rjs }
307 1.1 rjs
308 1.1 rjs mutex_exit(&(cb->mutex));
309 1.1 rjs
310 1.1 rjs callout_reset(&cb->free_timer, 10 * hz, tcplike_send_term, (void *)cb);
311 1.1 rjs }
312 1.1 rjs
313 1.1 rjs /*
314 1.1 rjs * Ask TCPlike wheter one can send a packet or not
315 1.1 rjs * args: ccb - ccb block for current connection
316 1.1 rjs * returns: 0 if ok, else <> 0.
317 1.1 rjs */
318 1.1 rjs int
319 1.1 rjs tcplike_send_packet(void *ccb, long datasize)
320 1.1 rjs {
321 1.1 rjs /* check if one can send here */
322 1.1 rjs struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
323 1.1 rjs long ticks;
324 1.1 rjs char feature[1];
325 1.1 rjs
326 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_packet()\n"));
327 1.1 rjs
328 1.1 rjs if (datasize == 0) {
329 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Sending pure ACK. Dont care about CC right now\n"));
330 1.1 rjs return 1;
331 1.1 rjs }
332 1.1 rjs
333 1.1 rjs mutex_enter(&(cb->mutex));
334 1.1 rjs
335 1.1 rjs if (cb->cwnd <= cb->outstanding) {
336 1.1 rjs /* May not send. trigger RTO */
337 1.1 rjs DCCP_DEBUG((LOG_INFO, "cwnd (%d) < outstanding (%d)\n", cb->cwnd, cb->outstanding));
338 1.1 rjs if (!cb->rto_timer_callout) {
339 1.1 rjs LOSS_DEBUG((LOG_INFO, "Trigger TCPlike RTO timeout timer. Ticks = %u\n", cb->rto));
340 1.1 rjs ticks = (long)cb->rto;
341 1.1 rjs callout_reset(&cb->rto_timer, ticks,
342 1.1 rjs tcplike_rto_timeout, (void *)cb);
343 1.1 rjs cb->rto_timer_callout = 1;
344 1.1 rjs }
345 1.1 rjs mutex_exit(&(cb->mutex));
346 1.1 rjs return 0;
347 1.1 rjs }
348 1.1 rjs
349 1.1 rjs /* We're allowed to send */
350 1.1 rjs
351 1.1 rjs feature[0] = 1;
352 1.1 rjs if (cb->pcb->remote_ackvector == 0) {
353 1.1 rjs ACK_DEBUG((LOG_INFO, "Adding Change(Use Ack Vector, 1) to outgoing packet\n"));
354 1.1 rjs dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKVECTOR);
355 1.1 rjs dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKVECTOR, feature, 1);
356 1.1 rjs }
357 1.1 rjs
358 1.1 rjs /* untimeout any active timer */
359 1.1 rjs if (cb->rto_timer_callout) {
360 1.1 rjs LOSS_DEBUG((LOG_INFO, "Untimeout RTO Timer\n"));
361 1.1 rjs callout_stop(&cb->rto_timer);
362 1.1 rjs cb->rto_timer_callout = 0;
363 1.1 rjs }
364 1.1 rjs
365 1.1 rjs if (!cb->sample_rtt) {
366 1.1 rjs struct timeval stamp;
367 1.1 rjs microtime(&stamp);
368 1.1 rjs cb->timestamp = ((stamp.tv_sec & 0x00000FFF) * 1000000) + stamp.tv_usec;
369 1.1 rjs dccp_add_option(cb->pcb, DCCP_OPT_TIMESTAMP, (char*) &(cb->timestamp), 4);
370 1.1 rjs /*LOSS_DEBUG((LOG_INFO, "Adding timestamp %u\n", cb->timestamp));*/
371 1.1 rjs cb->sample_rtt = 1;
372 1.1 rjs }
373 1.1 rjs
374 1.1 rjs mutex_exit(&(cb->mutex));
375 1.1 rjs return 1;
376 1.1 rjs
377 1.1 rjs }
378 1.1 rjs
379 1.1 rjs /*
380 1.1 rjs * Notify sender that a packet has been sent
381 1.1 rjs * args: ccb - ccb block for current connection
382 1.1 rjs * moreToSend - if there exists more packets to send
383 1.1 rjs */
384 1.1 rjs void
385 1.1 rjs tcplike_send_packet_sent(void *ccb, int moreToSend, long datasize)
386 1.1 rjs {
387 1.1 rjs struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
388 1.1 rjs
389 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_packet_sent(,%i,%i)\n",moreToSend,(int) datasize));
390 1.1 rjs
391 1.1 rjs if (datasize == 0) {
392 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Sent pure ACK. Dont care about cwnd-storing\n"));
393 1.1 rjs return;
394 1.1 rjs }
395 1.1 rjs
396 1.1 rjs mutex_enter(&(cb->mutex));
397 1.1 rjs
398 1.1 rjs cb->outstanding++;
399 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "SENT. cwnd: %d, outstanding: %d\n",cb->cwnd, cb->outstanding));
400 1.1 rjs
401 1.1 rjs /* stash the seqnr in cwndvector */
402 1.1 rjs /* Dont do this if we're only sending an ACK ! */
403 1.1 rjs _add_to_cwndvector(cb, cb->pcb->seq_snd);
404 1.1 rjs CWND_DEBUG((LOG_INFO, "Sent. CWND value: %u , OUTSTANDING value: %u\n",cb->cwnd, cb->outstanding));
405 1.1 rjs
406 1.1 rjs dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKRATIO);
407 1.1 rjs mutex_exit(&(cb->mutex));
408 1.1 rjs }
409 1.1 rjs
410 1.1 rjs /*
411 1.1 rjs * Notify that an ack package was received
412 1.1 rjs * args: ccb - ccb block for current connection
413 1.1 rjs */
414 1.1 rjs void
415 1.1 rjs tcplike_send_packet_recv(void *ccb, char *options, int optlen)
416 1.1 rjs {
417 1.1 rjs dccp_seq acknum, lastok;
418 1.1 rjs u_int16_t numlostpackets, avsize, i, prev_size;
419 1.1 rjs u_int8_t length, state, numokpackets, ackratiocnt;
420 1.1 rjs u_char av[10];
421 1.1 rjs struct tcplike_send_ccb *cb = (struct tcplike_send_ccb *) ccb;
422 1.1 rjs
423 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_send_ack_recv()\n"));
424 1.1 rjs mutex_enter(&(cb->mutex));
425 1.1 rjs
426 1.1 rjs if (dccp_get_option(options, optlen, DCCP_OPT_TIMESTAMP_ECHO, av,10) > 0) {
427 1.1 rjs u_int32_t echo, elapsed;
428 1.1 rjs
429 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Received TIMESTAMP ECHO\n"));
430 1.1 rjs bcopy(av, &echo, 4);
431 1.1 rjs bcopy(av + 4, &elapsed, 4);
432 1.1 rjs
433 1.1 rjs if (echo == cb->timestamp) {
434 1.1 rjs struct timeval time;
435 1.1 rjs u_int32_t c_stamp;
436 1.1 rjs u_int16_t diff;
437 1.1 rjs
438 1.1 rjs microtime(&time);
439 1.1 rjs c_stamp = ((time.tv_sec & 0x00000FFF) * 1000000) + time.tv_usec;
440 1.1 rjs
441 1.1 rjs diff = (u_int16_t) c_stamp - cb->timestamp - elapsed;
442 1.1 rjs diff = (u_int16_t)(diff / 1000);
443 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Got Timestamp Echo; Echo = %u, Elapsed = %u. DIFF = %u\n",
444 1.1 rjs echo, elapsed, diff));
445 1.1 rjs tcplike_rtt_sample(cb, diff);
446 1.1 rjs }
447 1.1 rjs }
448 1.1 rjs
449 1.1 rjs if (cb->pcb->ack_rcv == 0) {
450 1.1 rjs /* There was no Ack. There is no spoon */
451 1.1 rjs
452 1.1 rjs /* We'll clear the missingacks data here, since the other host
453 1.1 rjs * is also sending data.
454 1.1 rjs * I guess we could deal with this, using the NDP field in the
455 1.1 rjs * header. Let's stick a *TODO* mark here for now.
456 1.1 rjs * The missingacks mechanism will activate if other host goes to
457 1.1 rjs * only sending DCCP-Ack packets.
458 1.1 rjs */
459 1.1 rjs cb->ack_last = 0;
460 1.1 rjs cb->ack_miss = 0;
461 1.1 rjs ACKRATIO_DEBUG((LOG_INFO, "Clear Missing Acks state!\n"));
462 1.1 rjs mutex_exit(&(cb->mutex));
463 1.1 rjs return;
464 1.1 rjs }
465 1.1 rjs
466 1.1 rjs cb->sample_rtt = 0;
467 1.1 rjs
468 1.1 rjs /* check ackVector for lost packets. cmp with cv_list */
469 1.1 rjs avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR0, av,10);
470 1.1 rjs if (avsize == 0)
471 1.1 rjs avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR1, av,10);
472 1.1 rjs
473 1.1 rjs if (avsize > 0)
474 1.1 rjs dccpstat.tcplikes_send_ackrecv++;
475 1.1 rjs
476 1.1 rjs acknum = cb->pcb->ack_rcv;
477 1.1 rjs numlostpackets = 0;
478 1.1 rjs numokpackets = 0;
479 1.1 rjs lastok = 0;
480 1.1 rjs prev_size = _cwndvector_size(cb);
481 1.1 rjs
482 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Start removing from cwndvector %d\n", avsize));
483 1.1 rjs if (avsize == 0)
484 1.1 rjs _remove_from_cwndvector(cb, acknum);
485 1.1 rjs
486 1.1 rjs for (i=0; i < avsize; i++) {
487 1.1 rjs state = (av[i] & 0xc0) >> 6;
488 1.1 rjs length = (av[i] & 0x3f) +1;
489 1.1 rjs while (length > 0) {
490 1.1 rjs if (state == 0) {
491 1.1 rjs CWND_DEBUG((LOG_INFO, "Packet %llu was OK\n", acknum));
492 1.1 rjs numokpackets++;
493 1.1 rjs lastok = acknum;
494 1.1 rjs _remove_from_cwndvector(cb, acknum);
495 1.1 rjs } else {
496 1.1 rjs if (acknum > cb->oldcwnd_ts) {
497 1.1 rjs LOSS_DEBUG((LOG_INFO, "Packet %llu was lost %llu state %d\n", acknum, cb->oldcwnd_ts, state));
498 1.1 rjs numlostpackets++;
499 1.1 rjs dccpstat.tcplikes_send_reploss++;
500 1.1 rjs }
501 1.1 rjs }
502 1.1 rjs acknum--;
503 1.1 rjs length--;
504 1.1 rjs }
505 1.1 rjs }
506 1.1 rjs if (lastok)
507 1.1 rjs if (_chop_cwndvector(cb, lastok-TCPLIKE_NUMDUPACK)) {
508 1.1 rjs LOSS_DEBUG((LOG_INFO, "Packets were lost\n"));
509 1.1 rjs if (lastok-TCPLIKE_NUMDUPACK > cb->oldcwnd_ts) {
510 1.1 rjs numlostpackets++;
511 1.1 rjs dccpstat.tcplikes_send_assloss++;
512 1.1 rjs }
513 1.1 rjs }
514 1.1 rjs
515 1.1 rjs lastok = cb->cv_hs;
516 1.1 rjs while (_cwndvector_state(cb, lastok) == 0x00 && lastok < cb->cv_ts)
517 1.1 rjs lastok++;
518 1.1 rjs if (lastok != cb->cv_hs)
519 1.1 rjs _chop_cwndvector(cb, lastok);
520 1.1 rjs
521 1.1 rjs cb->outstanding = _cwndvector_size(cb);
522 1.1 rjs CWND_DEBUG((LOG_INFO, "Decrease outstanding. was = %u , now = %u\n", prev_size, cb->outstanding));
523 1.1 rjs if (prev_size == cb->outstanding) {
524 1.1 rjs /* Nothing dropped from cwndvector */
525 1.1 rjs mutex_exit(&(cb->mutex));
526 1.1 rjs return;
527 1.1 rjs }
528 1.1 rjs
529 1.1 rjs cb->acked_in_win += numokpackets;
530 1.1 rjs
531 1.1 rjs if (cb->cwnd < cb->ssthresh) {
532 1.1 rjs /* Slow start */
533 1.1 rjs
534 1.1 rjs if (numlostpackets > 0) {
535 1.1 rjs /* Packet loss */
536 1.1 rjs LOSS_DEBUG((LOG_INFO, "Packet Loss in Slow Start\n"));
537 1.1 rjs cb->cwnd = cb->cwnd>>1;
538 1.1 rjs if (cb->cwnd < 1)
539 1.1 rjs cb->cwnd = 1;
540 1.1 rjs cb->ssthresh = cb->cwnd;
541 1.1 rjs cb->acked_in_win = 0;
542 1.1 rjs cb->acked_windows = 0;
543 1.1 rjs cb->oldcwnd_ts = cb->pcb->seq_snd;
544 1.1 rjs
545 1.1 rjs } else {
546 1.1 rjs cb->cwnd++;
547 1.1 rjs }
548 1.1 rjs
549 1.1 rjs } else if (cb->cwnd >= cb->ssthresh) {
550 1.1 rjs
551 1.1 rjs if (numlostpackets > 0) {
552 1.1 rjs /* Packet loss */
553 1.1 rjs LOSS_DEBUG((LOG_INFO, "Packet Loss in action\n"));
554 1.1 rjs cb->cwnd = cb->cwnd>>1;
555 1.1 rjs if (cb->cwnd < 1)
556 1.1 rjs cb->cwnd = 1;
557 1.1 rjs cb->ssthresh = cb->cwnd;
558 1.1 rjs cb->acked_in_win = 0;
559 1.1 rjs cb->acked_windows = 0;
560 1.1 rjs cb->oldcwnd_ts = cb->pcb->seq_snd;
561 1.1 rjs
562 1.1 rjs } else if (cb->acked_in_win > cb->cwnd) {
563 1.1 rjs cb->cwnd++;
564 1.1 rjs }
565 1.1 rjs }
566 1.1 rjs
567 1.1 rjs /* Ok let's check if there are missing Ack packets */
568 1.1 rjs ACKRATIO_DEBUG((LOG_INFO, "Check Ack. seq_rcv: %u ,ack_last: %u ,ack_miss: %u\n",
569 1.1 rjs cb->pcb->seq_rcv, cb->ack_last, cb->ack_miss));
570 1.1 rjs
571 1.1 rjs if (cb->ack_last == 0) {
572 1.1 rjs /* First received ack (or first after Data packet). Yey */
573 1.1 rjs cb->ack_last = cb->pcb->seq_rcv;
574 1.1 rjs cb->ack_miss = 0;
575 1.1 rjs } else if (cb->pcb->seq_rcv == (cb->ack_last + 1)) {
576 1.1 rjs /* This is correct, non-congestion, in-order behaviour */
577 1.1 rjs cb->ack_last = cb->pcb->seq_rcv;
578 1.1 rjs
579 1.1 rjs } else if (cb->pcb->seq_rcv < (cb->ack_last + 1)) {
580 1.1 rjs /* Might be an Ack we've been missing */
581 1.1 rjs /* This code has a flaw; If we miss 2 Ack packets, we only care
582 1.1 rjs * about the older one. This means that the next-to-oldest one could
583 1.1 rjs * be lost without any action beeing taken.
584 1.1 rjs * Time will tell if that is going to be a Giant Problem(r)
585 1.1 rjs */
586 1.1 rjs if (cb->pcb->seq_rcv == cb->ack_miss) {
587 1.1 rjs /* Yea it was. great */
588 1.1 rjs cb->ack_miss = 0;
589 1.1 rjs }
590 1.1 rjs
591 1.1 rjs } else if (cb->pcb->seq_rcv > (cb->ack_last + 1)) {
592 1.1 rjs /* There is a jump in Ack seqnums.. */
593 1.1 rjs cb->ack_miss = cb->ack_last + 1;
594 1.1 rjs cb->ack_last = cb->pcb->seq_rcv;
595 1.1 rjs }
596 1.1 rjs
597 1.1 rjs if (cb->ack_miss && ((cb->ack_miss + TCPLIKE_NUMDUPACK) < cb->ack_last)) {
598 1.1 rjs /* Alert! Alert! Ack packets are MIA.
599 1.1 rjs * Decrease Ack Ratio
600 1.1 rjs */
601 1.1 rjs cb->rcvr_ackratio = cb->rcvr_ackratio<<1;
602 1.1 rjs if (cb->rcvr_ackratio > (cb->cwnd>>1)) {
603 1.1 rjs /* Constraint 2 */
604 1.1 rjs cb->rcvr_ackratio = cb->cwnd>>1;
605 1.1 rjs }
606 1.1 rjs if (cb->rcvr_ackratio == 0)
607 1.1 rjs cb->rcvr_ackratio = 1;
608 1.1 rjs ACKRATIO_DEBUG((LOG_INFO, "Increase Ack Ratio. Now = %u. (cwnd = %u)\n", cb->rcvr_ackratio, cb->cwnd));
609 1.1 rjs dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKRATIO);
610 1.1 rjs dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKRATIO,
611 1.1 rjs (char *) &cb->rcvr_ackratio, 1);
612 1.1 rjs
613 1.1 rjs cb->ack_miss = 0;
614 1.1 rjs cb->acked_windows = 0;
615 1.1 rjs cb->acked_in_win = 0;
616 1.1 rjs dccpstat.tcplikes_send_missack++;
617 1.1 rjs
618 1.1 rjs } else if (cb->acked_in_win > cb->cwnd) {
619 1.1 rjs cb->acked_in_win = 0;
620 1.1 rjs cb->acked_windows++;
621 1.1 rjs if (cb->rcvr_ackratio == 1) {
622 1.1 rjs /* Ack Ratio is 1. We cant decrease it more.. Lets wait for some
623 1.1 rjs * heavy congestion so we can increase it
624 1.1 rjs */
625 1.1 rjs cb->acked_windows = 0;
626 1.1 rjs }
627 1.1 rjs }
628 1.1 rjs
629 1.1 rjs if (cb->acked_windows >= 1) {
630 1.1 rjs ackratiocnt = (cb->cwnd / ((cb->rcvr_ackratio*cb->rcvr_ackratio) - cb->rcvr_ackratio));
631 1.1 rjs if (cb->acked_windows >= ackratiocnt) {
632 1.1 rjs if (cb->rcvr_ackratio > 2 && cb->cwnd >= 4) {
633 1.1 rjs /* Constraint 3 - AckRatio at least 2 for a cwnd >= 4 */
634 1.1 rjs cb->rcvr_ackratio--;
635 1.1 rjs ACKRATIO_DEBUG((LOG_INFO, "Decrease ackratio by 1, now: %u\n", cb->rcvr_ackratio));
636 1.1 rjs dccp_remove_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKRATIO);
637 1.1 rjs dccp_add_feature(cb->pcb, DCCP_OPT_CHANGE_R, DCCP_FEATURE_ACKRATIO,
638 1.1 rjs (char *) &cb->rcvr_ackratio, 1);
639 1.1 rjs }
640 1.1 rjs cb->acked_in_win = 0;
641 1.1 rjs cb->acked_windows = 0;
642 1.1 rjs }
643 1.1 rjs }
644 1.1 rjs
645 1.1 rjs CWND_DEBUG((LOG_INFO, "Recvd. CWND value: %u , OUTSTANDING value: %u\n",
646 1.1 rjs cb->cwnd, cb->outstanding));
647 1.1 rjs
648 1.1 rjs if (cb->cwnd > cb->outstanding && cb->rto_timer_callout) {
649 1.1 rjs LOSS_DEBUG((LOG_INFO, "Force DCCP_OUTPUT, CWND = %u Outstanding = %u\n",
650 1.1 rjs cb->cwnd, cb->outstanding));
651 1.1 rjs callout_stop(&cb->rto_timer);
652 1.1 rjs cb->rto_timer_callout = 0;
653 1.1 rjs
654 1.1 rjs mutex_exit(&(cb->mutex));
655 1.1 rjs dccp_output(cb->pcb, 1);
656 1.1 rjs return;
657 1.1 rjs }
658 1.1 rjs mutex_exit(&(cb->mutex));
659 1.1 rjs }
660 1.1 rjs
661 1.1 rjs int
662 1.1 rjs _cwndvector_size(struct tcplike_send_ccb *cb)
663 1.1 rjs {
664 1.1 rjs u_int64_t gap, offset, seqnr;
665 1.1 rjs u_int32_t cnt;
666 1.1 rjs u_char *t;
667 1.1 rjs
668 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Enter cwndvector_size\n"));
669 1.1 rjs cnt = 0;
670 1.1 rjs for (seqnr = cb->cv_hs; seqnr < cb->cv_ts; seqnr++) {
671 1.1 rjs gap = seqnr - cb->cv_hs;
672 1.1 rjs
673 1.1 rjs offset = gap % 8;
674 1.1 rjs t = cb->cv_hp + (gap/8);
675 1.1 rjs if (t >= (cb->cwndvector + (cb->cv_size/8)))
676 1.1 rjs t -= (cb->cv_size / 8); /* wrapped */
677 1.1 rjs
678 1.1 rjs if (((*t & (0x01 << offset)) >> offset) == 0x01)
679 1.1 rjs cnt++;
680 1.1 rjs }
681 1.1 rjs return cnt;
682 1.1 rjs }
683 1.1 rjs
684 1.1 rjs u_char
685 1.1 rjs _cwndvector_state(struct tcplike_send_ccb *cb, u_int64_t seqnr)
686 1.1 rjs {
687 1.1 rjs u_int64_t gap, offset;
688 1.1 rjs u_char *t;
689 1.1 rjs
690 1.1 rjs /* Check for wrapping */
691 1.1 rjs if (seqnr >= cb->cv_hs) {
692 1.1 rjs /* Not wrapped */
693 1.1 rjs gap = seqnr - cb->cv_hs;
694 1.1 rjs } else {
695 1.1 rjs /* Wrapped XXXXX */
696 1.1 rjs gap = seqnr + 0x1000000000000LL - cb->cv_hs; /* seq nr = 48 bits */
697 1.1 rjs }
698 1.1 rjs
699 1.1 rjs if (gap >= cb->cv_size) {
700 1.1 rjs /* gap is bigger than cwndvector size? baaad */
701 1.1 rjs return 0x01;
702 1.1 rjs }
703 1.1 rjs
704 1.1 rjs offset = gap % 8;
705 1.1 rjs t = cb->cv_hp + (gap/8);
706 1.1 rjs if (t >= (cb->cwndvector + (cb->cv_size/8)))
707 1.1 rjs t -= (cb->cv_size / 8); /* wrapped */
708 1.1 rjs
709 1.1 rjs return ((*t & (0x01 << offset)) >> offset);
710 1.1 rjs }
711 1.1 rjs
712 1.1 rjs void
713 1.1 rjs _add_to_cwndvector(struct tcplike_send_ccb *cb, u_int64_t seqnr)
714 1.1 rjs {
715 1.1 rjs u_int64_t offset, dc, gap;
716 1.1 rjs u_char *t, *n;
717 1.1 rjs
718 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Entering add_to_cwndvector\n"));
719 1.1 rjs
720 1.1 rjs if (cb->cv_hs == cb->cv_ts) {
721 1.1 rjs /* Empty cwndvector */
722 1.1 rjs cb->cv_hs = cb->cv_ts = seqnr;
723 1.1 rjs }
724 1.1 rjs
725 1.1 rjs /* Check for wrapping */
726 1.1 rjs if (seqnr >= cb->cv_hs) {
727 1.1 rjs /* Not wrapped */
728 1.1 rjs gap = seqnr - cb->cv_hs;
729 1.1 rjs } else {
730 1.1 rjs /* Wrapped */
731 1.1 rjs gap = seqnr + 0x1000000000000LL - cb->cv_hs; /* seq nr = 48 bits */
732 1.1 rjs }
733 1.1 rjs
734 1.1 rjs if (gap >= cb->cv_size) {
735 1.1 rjs /* gap is bigger than cwndvector size? baaad */
736 1.1 rjs /* maybe we should increase the cwndvector here */
737 1.1 rjs CWND_DEBUG((LOG_INFO, "add cwndvector error. gap: %d, cv_size: %d, seqnr: %d\n",
738 1.1 rjs gap, cb->cv_size, seqnr));
739 1.1 rjs dccpstat.tcplikes_send_badseq++;
740 1.1 rjs return;
741 1.1 rjs }
742 1.1 rjs
743 1.1 rjs offset = gap % 8; /* bit to mark */
744 1.1 rjs t = cb->cv_hp + (gap/8);
745 1.1 rjs if (t >= (cb->cwndvector + (cb->cv_size/8)))
746 1.1 rjs t -= (cb->cv_size / 8); /* cwndvector wrapped */
747 1.1 rjs
748 1.1 rjs *t = *t | (0x01 << offset); /* turn on bit */
749 1.1 rjs
750 1.1 rjs cb->cv_ts = seqnr+1;
751 1.1 rjs if (cb->cv_ts == 0x1000000000000LL)
752 1.1 rjs cb->cv_ts = 0;
753 1.1 rjs
754 1.1 rjs if (gap > (cb->cv_size - 128)) {
755 1.1 rjs MALLOC_DEBUG((LOG_INFO, "INCREASE cwndVECTOR\n"));
756 1.1 rjs n = malloc(cb->cv_size/4, M_PCB, M_NOWAIT); /* old size * 2 */
757 1.1 rjs if (n == NULL) {
758 1.1 rjs MALLOC_DEBUG((LOG_INFO, "Increase cwndvector FAILED\n"));
759 1.1 rjs dccpstat.tcplikes_send_memerr++;
760 1.1 rjs return;
761 1.1 rjs }
762 1.1 rjs memset (n+cb->cv_size/8,0x00,cb->cv_size/8); /* new half all missing */
763 1.1 rjs dc = (cb->cwndvector + (cb->cv_size/8)) - cb->cv_hp;
764 1.1 rjs memcpy (n,cb->cv_hp, dc); /* tail to end */
765 1.1 rjs memcpy (n+dc,cb->cwndvector,cb->cv_hp - cb->cwndvector); /* start to tail */
766 1.1 rjs cb->cv_size = cb->cv_size * 2; /* counted in items, so it';s a doubling */
767 1.1 rjs free (cb->cwndvector, M_PCB);
768 1.1 rjs cb->cv_hp = cb->cwndvector = n;
769 1.1 rjs }
770 1.1 rjs }
771 1.1 rjs
772 1.1 rjs void
773 1.1 rjs _remove_from_cwndvector(struct tcplike_send_ccb *cb, u_int64_t seqnr)
774 1.1 rjs {
775 1.1 rjs u_int64_t offset;
776 1.1 rjs int64_t gap;
777 1.1 rjs u_char *t;
778 1.1 rjs
779 1.1 rjs DCCP_DEBUG((LOG_INFO, "Entering remove_from_cwndvector\n"));
780 1.1 rjs
781 1.1 rjs if (cb->cv_hs == cb->cv_ts) {
782 1.1 rjs /* Empty cwndvector */
783 1.1 rjs return;
784 1.1 rjs }
785 1.1 rjs
786 1.1 rjs /* Check for wrapping */
787 1.1 rjs if (seqnr >= cb->cv_hs) {
788 1.1 rjs /* Not wrapped */
789 1.1 rjs gap = seqnr - cb->cv_hs;
790 1.1 rjs } else {
791 1.1 rjs /* Wrapped */
792 1.1 rjs gap = seqnr + 0x1000000000000LL - cb->cv_hs; /* seq nr = 48 bits */
793 1.1 rjs }
794 1.1 rjs
795 1.1 rjs if (gap >= cb->cv_size) {
796 1.1 rjs /* gap is bigger than cwndvector size. has already been chopped */
797 1.1 rjs return;
798 1.1 rjs }
799 1.1 rjs
800 1.1 rjs offset = gap % 8; /* hi or low 2 bits to mark */
801 1.1 rjs t = cb->cv_hp + (gap/8);
802 1.1 rjs if (t >= (cb->cwndvector + (cb->cv_size/8)))
803 1.1 rjs t -= (cb->cv_size / 8); /* cwndvector wrapped */
804 1.1 rjs
805 1.1 rjs *t = *t & (~(0x01 << offset)); /* turn off bits */
806 1.1 rjs }
807 1.1 rjs
808 1.1 rjs int
809 1.1 rjs _chop_cwndvector(struct tcplike_send_ccb *cb, u_int64_t seqnr)
810 1.1 rjs {
811 1.1 rjs int64_t gap, bytegap;
812 1.1 rjs u_char *t;
813 1.1 rjs
814 1.1 rjs CWND_DEBUG((LOG_INFO,"Chop cwndvector at: %u\n", seqnr));
815 1.1 rjs
816 1.1 rjs if (cb->cv_hs == cb->cv_ts)
817 1.1 rjs return 0;
818 1.1 rjs
819 1.1 rjs if (seqnr > cb->cv_hs) {
820 1.1 rjs gap = seqnr - cb->cv_hs;
821 1.1 rjs } else {
822 1.1 rjs /* We received obsolete information */
823 1.1 rjs return 0;
824 1.1 rjs }
825 1.1 rjs
826 1.1 rjs bytegap = gap/8;
827 1.1 rjs if (bytegap == 0)
828 1.1 rjs return 0;
829 1.1 rjs
830 1.1 rjs t = cb->cv_hp + bytegap;
831 1.1 rjs if (t >= (cb->cwndvector + (cb->cv_size/8)))
832 1.1 rjs t -= (cb->cv_size / 8); /* ackvector wrapped */
833 1.1 rjs cb->cv_hp = t;
834 1.1 rjs cb->cv_hs += bytegap*8;
835 1.1 rjs return 1;
836 1.1 rjs }
837 1.1 rjs
838 1.1 rjs
839 1.1 rjs /* Receiver side */
840 1.1 rjs
841 1.1 rjs
842 1.1 rjs /* Functions declared in struct dccp_cc_sw */
843 1.1 rjs
844 1.1 rjs /* Initialises the receiver side
845 1.1 rjs * returns: pointer to a tcplike_recv_ccb struct on success, otherwise 0
846 1.1 rjs */
847 1.1 rjs void *
848 1.1 rjs tcplike_recv_init(struct dccpcb *pcb)
849 1.1 rjs {
850 1.1 rjs struct tcplike_recv_ccb *ccb;
851 1.1 rjs
852 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_recv_init()\n"));
853 1.1 rjs
854 1.1 rjs ccb = malloc(sizeof (struct tcplike_recv_ccb), M_PCB, M_NOWAIT | M_ZERO);
855 1.1 rjs if (ccb == 0) {
856 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Unable to allocate memory for tcplike_recv_ccb!\n"));
857 1.1 rjs dccpstat.tcplikes_recv_memerr++;
858 1.1 rjs return 0;
859 1.1 rjs }
860 1.1 rjs
861 1.1 rjs memset(ccb, 0, sizeof (struct tcplike_recv_ccb));
862 1.1 rjs
863 1.1 rjs ccb->pcb = pcb;
864 1.1 rjs ccb->unacked = 0;
865 1.1 rjs ccb->pcb->ack_ratio = 2;
866 1.1 rjs
867 1.1 rjs ccb->pcb->remote_ackvector = 1;
868 1.1 rjs dccp_use_ackvector(ccb->pcb);
869 1.1 rjs
870 1.1 rjs callout_init(&ccb->free_timer, 0);
871 1.1 rjs
872 1.1 rjs mutex_init(&(ccb->mutex), MUTEX_DEFAULT, IPL_SOFTNET);
873 1.1 rjs
874 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "TCPlike receiver initialised!\n"));
875 1.1 rjs dccpstat.tcplikes_recv_conn++;
876 1.1 rjs return ccb;
877 1.1 rjs }
878 1.1 rjs
879 1.1 rjs void tcplike_recv_term(void *ccb)
880 1.1 rjs {
881 1.1 rjs struct tcplike_recv_ccb *cb = (struct tcplike_recv_ccb *) ccb;
882 1.1 rjs if (ccb == 0)
883 1.1 rjs return;
884 1.1 rjs
885 1.1 rjs mutex_destroy(&(cb->mutex));
886 1.1 rjs free(cb, M_PCB);
887 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "TCP-like receiver is destroyed\n"));
888 1.1 rjs }
889 1.1 rjs
890 1.1 rjs /* Free the receiver side
891 1.4 msaitoh * args: ccb - ccb of receiver
892 1.1 rjs */
893 1.1 rjs void
894 1.1 rjs tcplike_recv_free(void *ccb)
895 1.1 rjs {
896 1.1 rjs struct ack_list *a;
897 1.1 rjs struct tcplike_recv_ccb *cb = (struct tcplike_recv_ccb *) ccb;
898 1.1 rjs
899 1.1 rjs LOSS_DEBUG((LOG_INFO, "Entering tcplike_recv_free()\n"));
900 1.1 rjs
901 1.1 rjs if (ccb == 0)
902 1.1 rjs return;
903 1.1 rjs
904 1.1 rjs mutex_enter(&(cb->mutex));
905 1.1 rjs
906 1.1 rjs a = cb->av_list;
907 1.1 rjs while (a) {
908 1.1 rjs cb->av_list = a->next;
909 1.1 rjs free(a, M_TEMP);
910 1.1 rjs a = cb->av_list;
911 1.1 rjs }
912 1.1 rjs
913 1.1 rjs cb->pcb->av_size = 0;
914 1.1 rjs free(cb->pcb->ackvector, M_PCB);
915 1.1 rjs
916 1.1 rjs mutex_exit(&(cb->mutex));
917 1.1 rjs callout_reset(&cb->free_timer, 10 * hz, tcplike_recv_term, (void *)cb);
918 1.1 rjs }
919 1.1 rjs
920 1.1 rjs /*
921 1.1 rjs * Tell TCPlike that a packet has been received
922 1.1 rjs * args: ccb - ccb block for current connection
923 1.1 rjs */
924 1.1 rjs void
925 1.1 rjs tcplike_recv_packet_recv(void *ccb, char *options, int optlen)
926 1.1 rjs {
927 1.1 rjs struct tcplike_recv_ccb *cb = (struct tcplike_recv_ccb *) ccb;
928 1.1 rjs u_char ackvector[16];
929 1.1 rjs u_int16_t avsize;
930 1.1 rjs u_char av_rcv[10];
931 1.1 rjs
932 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "Entering tcplike_recv_packet()\n"));
933 1.1 rjs
934 1.1 rjs mutex_enter(&(cb->mutex));
935 1.1 rjs
936 1.1 rjs if (cb->pcb->type_rcv == DCCP_TYPE_DATA ||
937 1.1 rjs cb->pcb->type_rcv == DCCP_TYPE_DATAACK)
938 1.1 rjs dccpstat.tcplikes_recv_datarecv++;
939 1.1 rjs
940 1.1 rjs /* Grab Ack Vector 0 or 1 */
941 1.1 rjs avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR0, av_rcv,10);
942 1.1 rjs if (avsize == 0)
943 1.1 rjs avsize = dccp_get_option(options, optlen, DCCP_OPT_ACK_VECTOR1, av_rcv,10);
944 1.1 rjs
945 1.1 rjs /* We are only interested in acks-on-acks here.
946 1.1 rjs * The "real" ack handling is done be the sender */
947 1.1 rjs if (avsize == 0 && cb->pcb->ack_rcv) {
948 1.1 rjs u_int64_t ackthru;
949 1.1 rjs /* We got an Ack without an ackvector.
950 1.1 rjs * This would mean it's an ack on an ack.
951 1.1 rjs */
952 1.1 rjs ackthru = _avlist_get(cb, cb->pcb->ack_rcv);
953 1.1 rjs ACK_DEBUG((LOG_INFO, "GOT Ack without Ackvector; Ackthru: %u\n", ackthru));
954 1.1 rjs if (ackthru) {
955 1.1 rjs dccp_update_ackvector(cb->pcb, ackthru);
956 1.1 rjs dccpstat.tcplikes_recv_ackack++;
957 1.1 rjs }
958 1.1 rjs } else if (avsize > 0 && cb->pcb->ack_rcv) {
959 1.1 rjs /* We received an AckVector */
960 1.1 rjs u_int32_t acknum, ackthru;
961 1.1 rjs int i;
962 1.1 rjs ACK_DEBUG((LOG_INFO, "GOT Ack with Ackvector\n"));
963 1.1 rjs /* gotta loop through the ackvector */
964 1.1 rjs acknum = cb->pcb->ack_rcv;
965 1.1 rjs for (i=0; i<avsize; i++) {
966 1.1 rjs u_int8_t state, len;
967 1.1 rjs state = (av_rcv[i] & 0xc0) >> 6;
968 1.1 rjs len = (av_rcv[i] & 0x2f) + 1;
969 1.1 rjs if (state != 0) {
970 1.1 rjs /* Drops in ackvector! Will be noted and taken care of by the sender part */
971 1.1 rjs ACK_DEBUG((LOG_INFO, "Packets %u - %u are FUCKED\n",acknum-len, acknum));
972 1.1 rjs continue;
973 1.1 rjs }
974 1.1 rjs
975 1.1 rjs while (len>0) {
976 1.1 rjs ackthru = _avlist_get(cb, acknum);
977 1.1 rjs ACK_DEBUG((LOG_INFO, "Ackthru: %u\n", ackthru));
978 1.1 rjs if (ackthru) {
979 1.1 rjs dccp_update_ackvector(cb->pcb, ackthru);
980 1.1 rjs dccpstat.tcplikes_recv_ackack++;
981 1.1 rjs }
982 1.1 rjs acknum--;
983 1.1 rjs len--;
984 1.1 rjs }
985 1.1 rjs }
986 1.1 rjs }
987 1.1 rjs
988 1.1 rjs ACK_DEBUG((LOG_INFO, "Adding %llu to local ackvector\n", cb->pcb->seq_rcv));
989 1.1 rjs dccp_increment_ackvector(cb->pcb, cb->pcb->seq_rcv);
990 1.1 rjs cb->unacked++;
991 1.1 rjs
992 1.1 rjs if (cb->unacked >= cb->pcb->ack_ratio) {
993 1.1 rjs /* Time to send an Ack */
994 1.1 rjs
995 1.1 rjs avsize = dccp_generate_ackvector(cb->pcb, ackvector);
996 1.1 rjs TCPLIKE_DEBUG((LOG_INFO, "recv_packet avsize %d ackvector %d\n", avsize, ackvector));
997 1.1 rjs cb->unacked = 0;
998 1.1 rjs if (avsize > 0) {
999 1.1 rjs dccp_add_option(cb->pcb, DCCP_OPT_ACK_VECTOR0, ackvector, avsize);
1000 1.1 rjs cb->pcb->ack_snd = cb->pcb->seq_rcv;
1001 1.1 rjs _avlist_add(cb, cb->pcb->seq_snd+1, cb->pcb->ack_snd);
1002 1.1 rjs ACK_DEBUG((LOG_INFO, "Recvr: Sending Ack (%llu) w/ Ack Vector\n", cb->pcb->ack_snd));
1003 1.1 rjs dccpstat.tcplikes_recv_acksent++;
1004 1.1 rjs dccp_output(cb->pcb, 1);
1005 1.1 rjs }
1006 1.1 rjs }
1007 1.1 rjs mutex_exit(&(cb->mutex));
1008 1.1 rjs }
1009 1.1 rjs
1010 1.1 rjs void
1011 1.1 rjs _avlist_add(struct tcplike_recv_ccb *cb, u_int64_t localseq, u_int64_t ackthru)
1012 1.1 rjs {
1013 1.1 rjs struct ack_list *a;
1014 1.1 rjs ACK_DEBUG((LOG_INFO,"Adding localseq %u - ackthru %u to avlist\n", localseq, ackthru));
1015 1.1 rjs /*MALLOC_DEBUG((LOG_INFO, "New ack_list, %u\n", sizeof (struct ack_list)));*/
1016 1.1 rjs a = malloc(sizeof(struct ack_list), M_TEMP, M_NOWAIT);
1017 1.1 rjs if (a == NULL) {
1018 1.1 rjs MALLOC_DEBUG((LOG_INFO, "avlist_add: FAILED\n"));
1019 1.1 rjs dccpstat.tcplikes_recv_memerr++;
1020 1.1 rjs return;
1021 1.1 rjs }
1022 1.1 rjs memset(a, 0, sizeof(struct ack_list));
1023 1.1 rjs a->localseq = localseq;
1024 1.1 rjs a->ackthru = ackthru;
1025 1.1 rjs a->next = cb->av_list;
1026 1.1 rjs cb->av_list = a;
1027 1.1 rjs }
1028 1.1 rjs
1029 1.1 rjs /*
1030 1.1 rjs * Searches the av_list. if 'localseq' found, drop it from list and return
1031 1.1 rjs * ackthru
1032 1.1 rjs */
1033 1.1 rjs u_int64_t
1034 1.1 rjs _avlist_get(struct tcplike_recv_ccb *cb, u_int64_t localseq)
1035 1.1 rjs {
1036 1.1 rjs struct ack_list *a, *n, *p;
1037 1.1 rjs u_int64_t ackthru;
1038 1.1 rjs
1039 1.1 rjs ACK_DEBUG((LOG_INFO,"Getting localseq %u from avlist\n", localseq));
1040 1.1 rjs a = cb->av_list;
1041 1.1 rjs p = 0;
1042 1.1 rjs while (a) {
1043 1.1 rjs n = a->next;
1044 1.1 rjs if (a->localseq == localseq) {
1045 1.1 rjs if (p)
1046 1.1 rjs p->next = n;
1047 1.1 rjs else
1048 1.1 rjs cb->av_list = n;
1049 1.1 rjs ackthru = a->ackthru;
1050 1.1 rjs /*MALLOC_DEBUG((LOG_INFO, "Freeing element %u in ack_list\n", a->localseq));*/
1051 1.1 rjs free(a, M_TEMP);
1052 1.1 rjs return ackthru;
1053 1.1 rjs }
1054 1.1 rjs p = a;
1055 1.1 rjs a = n;
1056 1.1 rjs }
1057 1.1 rjs /* Not found. return 0 */
1058 1.1 rjs return 0;
1059 1.1 rjs }
1060 1.1 rjs
1061 1.1 rjs /*
1062 1.1 rjs int tcplike_option_recv(void);
1063 1.1 rjs */
1064