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