1 /* $Id$
2 * --------------------------------------------------------------------------
3 *
4 * //===== //===== ===//=== //===// // // //===//
5 * // // // // // // // // //
6 * //====// // // //===// // // //===<<
7 * // // // // // // // //
8 * ======// //===== // // //===== // //===//
9 *
10 * -------------- An SCTP implementation according to RFC 4960 --------------
11 *
12 * Copyright (C) 2000 by Siemens AG, Munich, Germany.
13 * Copyright (C) 2001-2004 Andreas Jungmaier
14 * Copyright (C) 2004-2019 Thomas Dreibholz
15 *
16 * Acknowledgements:
17 * Realized in co-operation between Siemens AG and the University of
18 * Duisburg-Essen, Institute for Experimental Mathematics, Computer
19 * Networking Technology group.
20 * This work was partially funded by the Bundesministerium fuer Bildung und
21 * Forschung (BMBF) of the Federal Republic of Germany
22 * (Förderkennzeichen 01AK045).
23 * The authors alone are responsible for the contents.
24 *
25 * This library is free software: you can redistribute it and/or modify it
26 * under the terms of the GNU Lesser General Public License as published by
27 * the Free Software Foundation, either version 2.1 of the License, or
28 * (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public License
36 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37 *
38 * Contact: sctp-discussion@sctp.de
39 * dreibh@iem.uni-due.de
40 * tuexen@fh-muenster.de
41 * andreas.jungmaier@web.de
42 */
43
44 #include "recvctrl.h"
45 #include "adaptation.h"
46 #include "bundling.h"
47 #include "distribution.h"
48 #include "streamengine.h"
49 #include "SCTP-control.h"
50
51 #include <glib.h>
52 #include <string.h>
53
54 /**
55 * this struct contains all necessary data for creating SACKs from received data chunks
56 */
57 typedef struct rxc_buffer_struct
58 {
59 /*@{ */
60 /** */
61 void *sack_chunk;
62 /** */
63 GList *frag_list;
64 /** */
65 GList *dup_list;
66 /** cumulative TSN acked */
67 unsigned int ctsna;
68 /** store lowest tsn value for dups (!) */
69 unsigned int lowest;
70 /** stores highest tsn received so far, taking care of wraps
71 i.e. highest < lowest indicates a wrap */
72 unsigned int highest;
73 /** */
74 boolean contains_valid_sack;
75 /** */
76 boolean timer_running;
77 /** indicates whether a chunk was recvd that is truly new */
78 boolean new_chunk_received;
79 /** timer for delayed sacks */
80 TimerID sack_timer;
81 int datagrams_received;
82 /* either 1 (= sack each data chunk) or 2 (=sack every second chunk)*/
83 unsigned int sack_flag;
84 /** */
85 unsigned int last_address;
86 /** */
87 unsigned int my_association;
88 /** */
89 unsigned int my_rwnd;
90 /** delay for delayed ACK in msecs */
91 unsigned int delay;
92 /** number of dest addresses */
93 unsigned int num_of_addresses;
94 /*@} */
95 } rxc_buffer;
96
97
98 /**
99 * function creates and allocs new rxc_buffer structure.
100 * There is one such structure per established association
101 * @param remote_initial_TSN initial tsn of the peer
102 * @return pointer to the newly created structure
103 */
rxc_new_recvctrl(unsigned int remote_initial_TSN,unsigned int number_of_destination_addresses,void * sctpInstance)104 void *rxc_new_recvctrl(unsigned int remote_initial_TSN, unsigned int number_of_destination_addresses, void* sctpInstance)
105 {
106 rxc_buffer *tmp;
107 /*
108 unsigned int count;
109 */
110 tmp = (rxc_buffer*)malloc(sizeof(rxc_buffer));
111 if (!tmp) error_log(ERROR_FATAL, "Malloc failed");
112
113 tmp->frag_list = NULL;
114 tmp->dup_list = NULL;
115 tmp->num_of_addresses = number_of_destination_addresses;
116 tmp->sack_chunk = malloc(sizeof(SCTP_sack_chunk));
117 tmp->ctsna = remote_initial_TSN - 1; /* as per section 4.1 */
118 tmp->lowest = remote_initial_TSN - 1;
119 tmp->highest = remote_initial_TSN - 1;
120 tmp->contains_valid_sack = FALSE;
121 tmp->timer_running = FALSE;
122 tmp->datagrams_received = -1;
123 tmp->sack_flag = 2;
124 tmp->last_address = 0;
125 tmp->my_rwnd = mdi_getDefaultMyRwnd();
126 tmp->delay = mdi_getDefaultDelay(sctpInstance);
127 tmp->my_association = mdi_readAssociationID();
128 event_logi(VVERBOSE, "RecvControl : Association-ID== %d ", tmp->my_association);
129 if (tmp->my_association == 0)
130 error_log(ERROR_FATAL, "Association was not set, should be......");
131 return (tmp);
132 }
133
134 /**
135 * function deletes a rxc_buffer structure (when it is not needed anymore)
136 * @param rxc_instance pointer to a rxc_buffer, that was previously created
137 */
rxc_delete_recvctrl(void * rxc_instance)138 void rxc_delete_recvctrl(void *rxc_instance)
139 {
140 rxc_buffer *tmp;
141 tmp = (rxc_buffer *) rxc_instance;
142 event_log(INTERNAL_EVENT_0, "deleting receivecontrol");
143 free(tmp->sack_chunk);
144
145 if (tmp->timer_running == TRUE) {
146 sctp_stopTimer(tmp->sack_timer);
147 tmp->timer_running = FALSE;
148 }
149
150 g_list_foreach(tmp->frag_list, &free_list_element, NULL);
151 g_list_free(tmp->frag_list);
152 g_list_foreach(tmp->dup_list, &free_list_element, NULL);
153 g_list_free(tmp->dup_list);
154 free(tmp);
155 }
156
157
158 /**
159 * function to find out, whether a chunk is duplicate or not
160 * @param rbuf instance of rxc_buffer
161 * @param chunk_tsn tsn we just received
162 * @return the boolean response
163 */
rxc_chunk_is_duplicate(rxc_buffer * rbuf,unsigned int chunk_tsn)164 boolean rxc_chunk_is_duplicate(rxc_buffer * rbuf, unsigned int chunk_tsn)
165 {
166 unsigned int low = rbuf->lowest;
167 unsigned int hi = rbuf->highest;
168 unsigned int ctsna = rbuf->ctsna;
169 fragment32 *frag;
170 GList *temp = NULL;
171
172 /* Assume, lowest and highest have already been updated */
173 if (between(low, chunk_tsn, ctsna))
174 return TRUE;
175 if (!between(ctsna, chunk_tsn, hi))
176 return FALSE;
177
178 /* Now check, whether chunk_tsn is in the (sorted !) list of fragments */
179 if (rbuf->frag_list == NULL) /* no fragments ! */
180 return FALSE;
181
182 /* if we are still here, we need to check, whether chunk_tsn is between any fragment bounds */
183 temp = g_list_first(rbuf->frag_list);
184 while (temp != NULL) {
185 if (temp->data == NULL) {
186 error_log(ERROR_FATAL, "LIST ERROR rxc_chunk_is_duplicate(2)");
187 temp = g_list_next(temp);
188 continue;
189 }
190 frag = (fragment32*) temp->data;
191 if (between(frag->start_tsn, chunk_tsn, frag->stop_tsn))
192 return TRUE;
193 /* assuming an ordered list of fragments */
194 if (after(frag->stop_tsn, chunk_tsn))
195 return FALSE;
196 temp = g_list_next(temp);
197 }
198 /* never reached */
199 error_log(ERROR_MAJOR, "while loop went past end of list....should not have happened !");
200 return FALSE;
201 }
202
203 /**
204 * Helper function to do the correct update of rxc->lowest
205 * Function is only called, if that is necessary !
206 * @param rbuf instance of rxc_buffer
207 * @param chunk_tsn tsn we just received
208 * @return boolean indicating whether lowest was updated or not
209 */
rxc_update_lowest(rxc_buffer * rbuf,unsigned int chunk_tsn)210 boolean rxc_update_lowest(rxc_buffer * rbuf, unsigned int chunk_tsn)
211 {
212 unsigned int low = rbuf->lowest;
213 if (before(chunk_tsn, low)) {
214 rbuf->lowest = chunk_tsn;
215 /* and it must be a duplicate ! */
216 return TRUE;
217 } else
218 return FALSE /* no update of lowest */ ;
219 }
220
221 /**
222 * Helper function to do the correct update of rxc->highest
223 * Function is only called, if that is necessary !
224 * @param rbuf instance of rxc_buffer
225 * @param chunk_tsn tsn we just received
226 * @return boolean indicating whether highest was updated or not
227 */
rxc_update_highest(rxc_buffer * rbuf,unsigned int chunk_tsn)228 boolean rxc_update_highest(rxc_buffer * rbuf, unsigned int chunk_tsn)
229 {
230 unsigned int hi = rbuf->highest;
231 if (after(chunk_tsn, hi)) {
232 rbuf->highest = chunk_tsn;
233 return TRUE;
234 } else
235 return FALSE /* no update of highest */ ;
236 }
237
rxc_sort_duplicates(duplicate * one,duplicate * two)238 int rxc_sort_duplicates(duplicate * one, duplicate * two)
239 {
240 if (before(one->duplicate_tsn, two->duplicate_tsn)) {
241 return -1;
242 } else if (after(one->duplicate_tsn, two->duplicate_tsn)) {
243 return 1;
244 } else /* one==two */
245 return 0;
246 }
247
rxc_sort_fragments(fragment32 * one,fragment32 * two)248 int rxc_sort_fragments(fragment32 * one, fragment32 * two)
249 {
250 if (before(one->start_tsn, two->start_tsn) && before(one->stop_tsn, two->stop_tsn)) {
251 return -1;
252 } else if (after(one->start_tsn, two->start_tsn) && after(one->stop_tsn, two->stop_tsn)) {
253 return 1;
254 } else /* one==two */
255 return 0;
256 }
257
258
259 /**
260 * Helper function for inserting chunk_tsn in the list of duplicates
261 * @param rbuf instance of rxc_buffer
262 * @param chunk_tsn tsn we just received
263 */
rxc_update_duplicates(rxc_buffer * rbuf,unsigned int ch_tsn)264 void rxc_update_duplicates(rxc_buffer * rbuf, unsigned int ch_tsn)
265 {
266 duplicate* match;
267 GList* current = NULL;
268
269 current = g_list_first(rbuf->dup_list);
270 while (current != NULL) {
271 match = (duplicate*)current->data;
272 if (ch_tsn == match->duplicate_tsn) return;
273 current = g_list_next(current);
274 }
275 /* its new - add it to the list */
276 match = (duplicate*)malloc(sizeof(duplicate));
277 match->duplicate_tsn = ch_tsn;
278 rbuf->dup_list = g_list_insert_sorted(rbuf->dup_list, match, (GCompareFunc) rxc_sort_duplicates);
279
280 }
281
282
283
284 /**
285 * Helper function to do the correct update of rxc->ctsna
286 * @param rbuf instance of rxc_buffer
287 * @param chunk_tsn tsn we just received
288 */
rxc_bubbleup_ctsna(rxc_buffer * rbuf)289 void rxc_bubbleup_ctsna(rxc_buffer * rbuf)
290 {
291 fragment32 *frag;
292 GList *temp = NULL, *old = NULL;
293
294 event_log(INTERNAL_EVENT_0, "Entering rxc_bubbleup_ctsna... ");
295
296 if (rbuf->frag_list == NULL) return;
297
298 temp = g_list_first(rbuf->frag_list);
299
300 while (temp != NULL) {
301 frag = (fragment32*)temp->data;
302 if (frag != NULL){
303 if (rbuf->ctsna + 1 == frag->start_tsn) {
304 rbuf->ctsna = frag->stop_tsn;
305 old = temp;
306 temp = g_list_next(temp);
307 rbuf->frag_list = g_list_remove_link(rbuf->frag_list, old);
308 g_list_free_1(old); free(frag);
309 }
310 else
311 return;
312 } else {
313 error_log(ERROR_FATAL, "rxc_bubbleup_ctsna: fragment data was NULL !!!!!!! ");
314 return;
315 }
316 } /* end while */
317 }
318
rxc_update_fragments(rxc_buffer * rbuf,unsigned int ch_tsn)319 boolean rxc_update_fragments(rxc_buffer * rbuf, unsigned int ch_tsn)
320 {
321 unsigned int lo, hi, gapsize;
322 fragment32 *frag=NULL, *new_frag, * lo_frag;
323 GList *current = NULL, *tmp = NULL;
324
325 event_logi(INTERNAL_EVENT_0, "Entering rxc_update_fragments.tsn==%u.. ", ch_tsn);
326
327 lo = rbuf->ctsna + 1;
328
329 current = g_list_first(rbuf->frag_list);
330
331 while (current != NULL) {
332 frag = (fragment32*)current->data;
333
334 hi = frag->start_tsn - 1;
335 event_logiii(VVERBOSE, "while-loop: lo=%u, tsn=%u, hi=%u, \n", lo, ch_tsn, hi);
336
337 if (between(lo, ch_tsn, hi)) {
338 gapsize = hi - lo + 1;
339 if (gapsize > 1) {
340 event_logi(INTERNAL_EVENT_0, "Value of Gapsize (should be > 1 :) ", gapsize);
341 if (ch_tsn == hi) {
342 event_log(VVERBOSE, "ch_tsn==hi....");
343 frag->start_tsn = ch_tsn;
344 rbuf->new_chunk_received = TRUE;
345 return TRUE;
346 } else if (ch_tsn == lo) {
347 event_logii(VVERBOSE, "ch_tsn==lo==%u....rbuf->ctsna==%u....", lo, rbuf->ctsna);
348 if (ch_tsn == (rbuf->ctsna + 1)) {
349 rbuf->ctsna++;
350 rbuf->new_chunk_received = TRUE;
351 return TRUE;
352 }
353 current = g_list_previous(current);
354 if (current==NULL) {
355 error_log(ERROR_MAJOR, "Error in Fragment List HANDLING - check program");
356 return FALSE;
357 }
358 frag = (fragment32*)current->data;
359 frag->stop_tsn = ch_tsn;
360 rbuf->new_chunk_received = TRUE;
361 return TRUE;
362 } else { /* a fragment in between */
363 new_frag = (fragment32*)malloc(sizeof(fragment32));
364 new_frag->start_tsn = new_frag->stop_tsn = ch_tsn;
365 event_log(VVERBOSE, "Inserting new fragment....");
366 rbuf->frag_list = g_list_insert_sorted(rbuf->frag_list, new_frag, (GCompareFunc) rxc_sort_fragments);
367 rbuf->new_chunk_received = TRUE;
368 return FALSE;
369 }
370 } else { /*gapsize == 1 */
371 event_logi(INTERNAL_EVENT_0, "Value of Gapsize (should be 1 :) %u", gapsize);
372 /* delete fragment, return TRUE */
373 if (lo == rbuf->ctsna + 1) {
374 rbuf->ctsna = frag->stop_tsn;
375 rbuf->frag_list = g_list_remove_link(rbuf->frag_list, current);
376 g_list_free_1(current); free(frag);
377 rbuf->new_chunk_received = TRUE;
378 return TRUE;
379 } else {
380 tmp = current;
381 current = g_list_previous(current);
382 if (current == NULL) {
383 error_log(ERROR_MAJOR, "Error 2 in Fragment List HANDLING - check program");
384 return FALSE;
385 }
386 lo_frag = (fragment32*)current->data;
387 frag->start_tsn = lo_frag->start_tsn;
388 rbuf->frag_list = g_list_remove_link(rbuf->frag_list, current);
389 g_list_free_1(current); free(lo_frag);
390 current = tmp;
391 rbuf->new_chunk_received = TRUE;
392 return TRUE;
393 }
394 }
395 } else { /* ch_tsn is not in the gap between these two fragments */
396 lo = frag->stop_tsn + 1;
397 event_logi(VVERBOSE, "rxc_update_fragments: Setting lo to %u ", lo);
398 }
399 current = g_list_next(current);
400 }
401
402 /* (NULL LISTE) OR (End of Fragment List was passed) */
403 if (ch_tsn == lo) {
404 /* just increase ctsna, handle rest in separate update_ctsna() */
405 if (ch_tsn == rbuf->ctsna + 1) {
406 event_logi(VVERBOSE, "Updating rbuf->ctsna==%u", ch_tsn);
407 rbuf->ctsna = ch_tsn;
408 rbuf->new_chunk_received = TRUE;
409 return TRUE;
410 }
411 /* Update last fragment....increase stop_tsn by one */
412 current = g_list_last(rbuf->frag_list);
413 if (current == NULL) {
414 error_log(ERROR_MAJOR, "rxc_update_fragments: Went past end of List....");
415 return FALSE;
416 }
417 frag = (fragment32*)current->data;
418 frag->stop_tsn = frag->stop_tsn + 1;
419 rbuf->new_chunk_received = TRUE;
420
421 event_logiii(VVERBOSE, "Updating last fragment frag.start==%u, frag.stop==%u, tsn=%u",
422 frag->start_tsn, frag->stop_tsn, ch_tsn);
423 return FALSE;
424 } else { /* a new fragment altogether */
425 current = g_list_last(rbuf->frag_list);
426 new_frag = (fragment32*)malloc(sizeof(fragment32));
427 new_frag->start_tsn = ch_tsn;
428 new_frag->stop_tsn = ch_tsn;
429 rbuf->frag_list = g_list_append(rbuf->frag_list, new_frag);
430 event_logiii(VVERBOSE,
431 "Inserting new fragment at end...frag.start==%u,frag.stop==%u, tsn=%u",
432 new_frag->start_tsn, new_frag->stop_tsn, ch_tsn);
433 rbuf->new_chunk_received = TRUE;
434 return FALSE; /* no ctsna update necessary whatsoever */
435 }
436 }
437
438
439 /**
440 * For now this function treats only one incoming data chunk' tsn
441 * @param chunk the data chunk that was received by the bundling
442 */
rxc_data_chunk_rx(SCTP_data_chunk * se_chk,unsigned int ad_idx)443 int rxc_data_chunk_rx(SCTP_data_chunk * se_chk, unsigned int ad_idx)
444 {
445 rxc_buffer *rxc;
446 unsigned int chunk_tsn;
447 unsigned int chunk_len;
448 unsigned int assoc_state;
449 boolean result = FALSE;
450 int bytesQueued = 0;
451 unsigned current_rwnd = 0;
452
453 event_log(INTERNAL_EVENT_0, "Entering function rxc_data_chunk_rx");
454 rxc = (rxc_buffer *) mdi_readRX_control();
455 if (!rxc) {
456 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
457 return (-1);
458 }
459
460
461 /* resetting it */
462 rxc->new_chunk_received = FALSE;
463 rxc->last_address = ad_idx;
464
465 bytesQueued = se_getQueuedBytes();
466 if (bytesQueued < 0) bytesQueued = 0;
467 if ((unsigned int)bytesQueued > rxc->my_rwnd) {
468 current_rwnd = 0;
469 } else {
470 current_rwnd = rxc->my_rwnd - bytesQueued;
471 }
472
473 /* do SWS prevention */
474 if (current_rwnd > 0 && current_rwnd <= 2 * MAX_SCTP_PDU) current_rwnd = 1;
475
476 /*
477 * if any received data chunks have not been acked, sender
478 * should create a SACK and bundle it with the outbound data
479 */
480 rxc->contains_valid_sack = FALSE;
481
482 chunk_tsn = ntohl(se_chk->tsn);
483 chunk_len = ntohs(se_chk->chunk_length);
484 assoc_state = sci_getState();
485
486 if ( (after(chunk_tsn, rxc->highest) && current_rwnd == 0) ||
487 (assoc_state == SHUTDOWNRECEIVED) ||
488 (assoc_state == SHUTDOWNACKSENT) ) {
489 /* drop chunk, if either: our rwnd is 0, or we are already shutting down */
490 rxc->new_chunk_received = FALSE;
491 return 1;
492 }
493
494 /* TODO : Duplicates : see Note in section 6.2 : */
495 /* Note: When a datagram arrives with duplicate DATA chunk(s) and no new
496 DATA chunk(s), the receiver MUST immediately send a SACK with no
497 delay. Normally this will occur when the original SACK was lost, and
498 the peers RTO has expired. The duplicate TSN number(s) SHOULD be
499 reported in the SACK as duplicate.
500 */
501 event_logii(VERBOSE, "rxc_data_chunk_rx : chunk_tsn==%u, chunk_len=%u", chunk_tsn, chunk_len);
502 if (rxc_update_lowest(rxc, chunk_tsn) == TRUE) {
503 /* tsn is even lower than the lowest one received so far */
504 rxc_update_duplicates(rxc, chunk_tsn);
505 } else if (rxc_update_highest(rxc, chunk_tsn) == TRUE) {
506 rxc->new_chunk_received = TRUE;
507 result = rxc_update_fragments(rxc, chunk_tsn);
508 } else if (rxc_chunk_is_duplicate(rxc, chunk_tsn) == TRUE)
509 rxc_update_duplicates(rxc, chunk_tsn);
510 else
511 result = rxc_update_fragments(rxc, chunk_tsn);
512
513 if (result == TRUE) rxc_bubbleup_ctsna(rxc);
514
515 event_logi(VVERBOSE, "rxc_data_chunk_rx: after rxc_bubbleup_ctsna, rxc->ctsna=%u", rxc->ctsna);
516
517 if (rxc->new_chunk_received == TRUE) {
518 if(se_recvDataChunk(se_chk, chunk_len, ad_idx) == SCTP_SUCCESS) {
519 /* resetting it */
520 rxc->new_chunk_received = FALSE;
521 }
522 /* else: ABORT has been sent and the association (possibly) removed in callback! */
523 }
524 return 1;
525 }
526
527 /**
528 * Function triggered by flowcontrol, tells recvcontrol to
529 * send SACK to bundling using bu_put_SACK_Chunk() function.
530 * @return boolean to indicate, whether a SACK was generated, and should be sent !
531 */
rxc_create_sack(unsigned int * destination_address,boolean force_sack)532 boolean rxc_create_sack(unsigned int *destination_address, boolean force_sack)
533 {
534 rxc_buffer *rxc;
535 unsigned int num_of_frags;
536
537 event_logii(VVERBOSE,
538 "Entering rxc_create_sack(address==%u, force_sack==%s",
539 ((destination_address != NULL) ? *destination_address : 0),
540 ((force_sack == TRUE) ? "TRUE" : "FALSE"));
541
542 rxc = (rxc_buffer *) mdi_readRX_control();
543 if (!rxc) {
544 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
545 return FALSE;
546 }
547
548 if (rxc->contains_valid_sack == FALSE) {
549 event_log(INTERNAL_EVENT_0, "SACK structure was not updated (should have been)");
550 rxc_all_chunks_processed(FALSE);
551 }
552
553 num_of_frags = g_list_length(rxc->frag_list);
554
555 if (num_of_frags > 0)
556 rxc_send_sack_everytime();
557 else
558 rxc_send_sack_every_second_time();
559
560 /* send sacks along every second time, generally */
561 /* some timers may want to have a SACK anyway */
562 /* first sack is sent at once, since datagrams_received==-1 */
563 if (force_sack == TRUE) {
564 rxc->lowest = rxc->ctsna;
565 bu_put_SACK_Chunk((SCTP_sack_chunk*)rxc->sack_chunk, destination_address);
566 return TRUE;
567 } else {
568
569 /* in case we have not yet got any data, we will not want to send a SACK */
570 if (rxc->datagrams_received == -1)
571 return FALSE;
572
573 if (rxc->datagrams_received % rxc->sack_flag != 0) {
574 event_log(VVERBOSE, "Did not send SACK here - returning");
575 return FALSE;
576 }
577 rxc->lowest = rxc->ctsna;
578 bu_put_SACK_Chunk((SCTP_sack_chunk*)rxc->sack_chunk,destination_address);
579 return TRUE;
580 }
581 return FALSE;
582 }
583
584
585
586 /**
587 * the callback function when the sack timer goes off, and we must sack previously
588 * received data (e.g. after 200 msecs)
589 * Has three parameters as all timer callbacks
590 * @param tid id of the timer that has gone off
591 * @param assoc pointer to the association this event belongs to
592 * @param dummy pointer that is not used here
593 */
rxc_sack_timer_cb(TimerID tid,void * assoc,void * dummy)594 void rxc_sack_timer_cb(TimerID tid, void *assoc, void *dummy)
595 {
596 unsigned short res;
597
598 rxc_buffer *rxc;
599 event_log(INTERNAL_EVENT_1, "Timer Callback Function activated -> initiate sending of a SACK");
600 res = mdi_setAssociationData(*(unsigned int *) assoc);
601 if (res == 1)
602 error_log(ERROR_MAJOR, " association does not exist !");
603 if (res == 2) {
604 error_log(ERROR_MAJOR, "Association was not cleared..... !!!");
605 /* failure treatment ? */
606 }
607 /* all should be well now */
608 rxc = (rxc_buffer *) mdi_readRX_control();
609 if (!rxc) {
610 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
611 return;
612 }
613 rxc->timer_running = FALSE;
614 /* sending sack */
615 /* FIXME : maybe choose different address ??? */
616 rxc_create_sack(&rxc->last_address, TRUE);
617 bu_sendAllChunks(&rxc->last_address);
618
619 mdi_clearAssociationData();
620 return;
621 }
622
623 /**
624 * function called by bundling when a SACK is actually sent, to stop
625 * a possibly running timer
626 */
rxc_stop_sack_timer(void)627 void rxc_stop_sack_timer(void)
628 {
629 rxc_buffer *rxc;
630 int result;
631
632 rxc = (rxc_buffer *) mdi_readRX_control();
633 if (!rxc) {
634 error_log(ERROR_MINOR, "rxc_buffer instance not set !");
635 return;
636 }
637 /* also make sure you forget all the duplicates we received ! */
638 g_list_foreach(rxc->dup_list, &free_list_element, NULL);
639 g_list_free(rxc->dup_list);
640 rxc->dup_list = NULL;
641
642 if (rxc->timer_running == TRUE) {
643 result = sctp_stopTimer(rxc->sack_timer);
644 event_logi(INTERNAL_EVENT_0, "Stopped Timer, Result was %d", result);
645 rxc->timer_running = FALSE;
646 }
647 return;
648 }
649
rxc_sack_timer_is_running(void)650 boolean rxc_sack_timer_is_running(void)
651 {
652 rxc_buffer *rxc;
653 rxc = (rxc_buffer *) mdi_readRX_control();
654 if (!rxc) {
655 error_log(ERROR_MINOR, "rxc_buffer instance not set !");
656 return FALSE;
657 }
658 if (rxc->timer_running == TRUE) return TRUE;
659 return FALSE;
660 }
661
662 /**
663 * called by bundling, after new data has been processed (so we may start building a sack chunk)
664 * or by streamengine, when ULP has read some data, and we want to update the RWND.
665 */
rxc_all_chunks_processed(boolean new_data_received)666 void rxc_all_chunks_processed(boolean new_data_received)
667 {
668 /* now go and create SACK structure from the array */
669 rxc_buffer *rxc=NULL;
670 SCTP_sack_chunk *sack=NULL;
671 unsigned short num_of_frags, num_of_dups;
672 unsigned short len16, count, frag_start16, frag_stop16;
673 unsigned int pos;
674 duplicate *dptr=NULL, d;
675 fragment32 *f32=NULL;
676 fragment chunk_frag;
677 GList *temp=NULL;
678 int bytesQueued = 0;
679 unsigned current_rwnd = 0;
680
681 event_log(INTERNAL_EVENT_0, "Entering funtion rxc_all_chunks_processed ()");
682
683 rxc = (rxc_buffer *) mdi_readRX_control();
684 if (!rxc) {
685 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
686 return;
687 }
688
689 if (new_data_received == TRUE) rxc->datagrams_received++;
690
691 num_of_frags = g_list_length(rxc->frag_list);
692 num_of_dups = g_list_length(rxc->dup_list);
693
694 /* limit size of SACK to 80 bytes plus fixed size chunk and chunk header */
695 /* FIXME : Limit number of Fragments/Duplicates according to ->PATH MTU<- */
696 if (num_of_frags > 10) num_of_frags = 10;
697 if (num_of_dups > 10) num_of_dups = 10;
698
699 event_logii(VVERBOSE, "len of frag_list==%u, len of dup_list==%u", num_of_frags, num_of_dups);
700
701 bytesQueued = se_getQueuedBytes();
702 if (bytesQueued < 0) bytesQueued = 0;
703 if ((unsigned int)bytesQueued > rxc->my_rwnd) {
704 current_rwnd = 0;
705 } else {
706 current_rwnd = rxc->my_rwnd - bytesQueued;
707 }
708 /* do SWS prevention */
709 if (current_rwnd > 0 && current_rwnd <= 2 * MAX_SCTP_PDU) current_rwnd = 1;
710
711
712 sack = (SCTP_sack_chunk*)rxc->sack_chunk;
713 sack->chunk_header.chunk_id = CHUNK_SACK;
714 sack->chunk_header.chunk_flags = 0;
715 len16 = sizeof(SCTP_chunk_header) + (2 + num_of_dups) * sizeof(unsigned int) +
716 (2 * num_of_frags + 2) * sizeof(unsigned short);
717
718 sack->chunk_header.chunk_length = htons(len16);
719 sack->cumulative_tsn_ack = htonl(rxc->ctsna);
720 /* FIXME : deduct size of data still in queue, that is waiting to be picked up by an ULP */
721 sack->a_rwnd = htonl(current_rwnd);
722 sack->num_of_fragments = htons(num_of_frags);
723 sack->num_of_duplicates = htons(num_of_dups);
724 pos = 0L;
725
726 temp = g_list_first(rxc->frag_list); count = 0;
727 while ((temp != NULL) && (count < num_of_frags)) {
728
729 f32 = (fragment32*)temp->data;
730
731 event_logiii(VVERBOSE,"ctsna==%u, fragment.start==%u, fragment.stop==%u",
732 rxc->ctsna, f32->start_tsn, f32->stop_tsn);
733
734 if (((f32->start_tsn - rxc->ctsna) > 0xFFFF) || ((f32->stop_tsn - rxc->ctsna) > 0xFFFF)) {
735 error_log(ERROR_MINOR, "Fragment offset becomes too big");
736 break;
737 }
738 frag_start16 = (unsigned short) (f32->start_tsn - rxc->ctsna);
739 frag_stop16 = (unsigned short) (f32->stop_tsn - rxc->ctsna);
740 event_logii(VVERBOSE, "frag_start16==%u, frag_stop16==%u", frag_start16, frag_stop16);
741
742 chunk_frag.start = htons((unsigned short)(f32->start_tsn - rxc->ctsna));
743 chunk_frag.stop = htons((unsigned short)(f32->stop_tsn - rxc->ctsna));
744 event_logii(VVERBOSE, "chunk_frag.start=%u,chunk_frag.stop ==%u",
745 ntohs(chunk_frag.start), ntohs(chunk_frag.stop));
746 memcpy(&sack->fragments_and_dups[pos], &chunk_frag, sizeof(fragment));
747 pos += sizeof(fragment);
748 temp = g_list_next(temp); count++;
749 }
750
751 temp = g_list_first(rxc->dup_list); count = 0;
752 while ((temp != NULL) && (count < num_of_dups)) {
753 dptr = (duplicate*)temp->data;
754 if (dptr) d.duplicate_tsn = htonl(dptr->duplicate_tsn);
755 memcpy(&sack->fragments_and_dups[pos], &d, sizeof(duplicate));
756 pos += sizeof(duplicate);
757 temp = g_list_next(temp); count++;
758 }
759 /* start sack_timer set to 200 msecs */
760 if (rxc->timer_running != TRUE && new_data_received == TRUE) {
761 rxc->sack_timer = adl_startTimer(rxc->delay, &rxc_sack_timer_cb, TIMER_TYPE_SACK, &(rxc->my_association), NULL);
762 event_log(INTERNAL_EVENT_0, "Started SACK Timer !");
763 rxc->timer_running = TRUE;
764 }
765 rxc->contains_valid_sack = TRUE;
766 return;
767 }
768
769
770 /**
771 Function starts a SACK timer after data has been read by the ULP, and the
772 buffer is about to change...
773 */
rxc_start_sack_timer(unsigned int oldQueueLen)774 int rxc_start_sack_timer(unsigned int oldQueueLen)
775 {
776 rxc_buffer *rxc;
777 int bytesQueued = 0;
778
779 rxc = (rxc_buffer *) mdi_readRX_control();
780 if (!rxc) {
781 error_log(ERROR_MINOR, "rxc_buffer instance not set - returning 0");
782 return (-1);
783 }
784
785 bytesQueued = se_getQueuedBytes();
786 if (bytesQueued < 0) bytesQueued = 0;
787 /* no new data received, but we want updated SACK to be sent */
788 rxc_all_chunks_processed(FALSE);
789 if ((rxc->my_rwnd - oldQueueLen < 2 * MAX_SCTP_PDU) &&
790 (rxc->my_rwnd - bytesQueued >= 2 * MAX_SCTP_PDU)) {
791 /* send SACK at once */
792 rxc_create_sack(&rxc->last_address, TRUE);
793 bu_sendAllChunks(&rxc->last_address);
794 rxc_stop_sack_timer();
795 } else { /* normal application read, no need to rush things */
796 if (rxc->timer_running != TRUE) {
797 rxc->sack_timer = adl_startTimer(rxc->delay, &rxc_sack_timer_cb, TIMER_TYPE_SACK, &(rxc->my_association), NULL);
798 event_log(INTERNAL_EVENT_0, "Started SACK Timer !");
799 rxc->timer_running = TRUE;
800 }
801 }
802 return 0;
803 }
804
805
806 /**
807 @return my current receiver window (32 bit unsigned value)
808 */
rxc_get_local_receiver_window(void)809 unsigned int rxc_get_local_receiver_window(void)
810 {
811 rxc_buffer *rxc;
812 rxc = (rxc_buffer *) mdi_readRX_control();
813 if (!rxc) {
814 error_log(ERROR_MINOR, "rxc_buffer instance not set - returning 0");
815 return (0);
816 }
817 event_logi(VERBOSE, "function rxc_get_my_receiver_window() returns %u", rxc->my_rwnd);
818 return rxc->my_rwnd;
819 }
820
821
822 /**
823 @return my current sack delay in msecs
824 */
rxc_get_sack_delay(void)825 int rxc_get_sack_delay(void)
826 {
827 rxc_buffer *rxc;
828 rxc = (rxc_buffer *) mdi_readRX_control();
829 if (!rxc) {
830 error_log(ERROR_MINOR, "rxc_buffer instance not set - returning default");
831 return (-1);
832 }
833 event_logi(VERBOSE, "function rxc_get_sack_delay() returns %u", rxc->delay);
834 return ((int)rxc->delay);
835 }
836
837 /**
838 @return my current sack delay in msecs
839 */
rxc_set_sack_delay(unsigned int new_delay)840 int rxc_set_sack_delay(unsigned int new_delay)
841 {
842 rxc_buffer *rxc;
843 rxc = (rxc_buffer *) mdi_readRX_control();
844 if (!rxc) {
845 error_log(ERROR_MINOR, "rxc_buffer instance not set - returning default");
846 return (-1);
847 }
848 rxc->delay = new_delay;
849 event_logi(VERBOSE, "Setting new sack delay to %u msecs", rxc->delay);
850 return 0;
851 }
852
853 /**
854 Set the size of my receiver window. This needs to reflect buffer sizes.
855 Beware, this is really only a DUMMY function, too !
856 @param new local receiver window (32 bit unsigned value)
857 @return 0 on success, else -1 on failure
858 */
rxc_set_local_receiver_window(unsigned int new_window)859 int rxc_set_local_receiver_window(unsigned int new_window)
860 {
861 rxc_buffer *rxc;
862 rxc = (rxc_buffer *) mdi_readRX_control();
863 if (!rxc) {
864 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
865 return (-1);
866 }
867 event_logi(VERBOSE, "function rxc_set_my_receiver_window(%u)", new_window);
868 rxc->my_rwnd = new_window;
869 return 0;
870 }
871
872
873 /**
874 Get the number of the current cumulative TSN, that we may ack
875 @return my current ctsna (32 bit unsigned value)
876 */
rxc_read_cummulativeTSNacked(void)877 unsigned int rxc_read_cummulativeTSNacked(void)
878 {
879 rxc_buffer *rxc;
880
881 rxc = (rxc_buffer *) mdi_readRX_control();
882 if (!rxc) {
883 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
884 return (0);
885 }
886 return (rxc->ctsna);
887 }
888
889 /**
890 * Helper function called, when we have gap reports in incoming
891 * SACK chunks....
892 */
rxc_send_sack_everytime(void)893 void rxc_send_sack_everytime(void)
894 {
895 rxc_buffer *rxc;
896
897 rxc = (rxc_buffer *) mdi_readRX_control();
898 if (!rxc) {
899 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
900 return;
901 }
902 rxc->sack_flag = 1;
903 }
904
905 /**
906 * Helper function called, when we have no gap reports in incoming
907 * SACK chunks....
908 */
rxc_send_sack_every_second_time(void)909 void rxc_send_sack_every_second_time(void)
910 {
911 rxc_buffer *rxc;
912
913 rxc = (rxc_buffer *) mdi_readRX_control();
914 if (!rxc) {
915 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
916 return;
917 }
918 rxc->sack_flag = 2;
919
920 }
921
922
923 /**
924 function only called in a restart case.
925 Beware : this has been largely untested !
926 @param new_remote_TSN new tsn value of peer that has restarted
927 */
rxc_restart_receivecontrol(unsigned int my_rwnd,unsigned int new_remote_TSN)928 void rxc_restart_receivecontrol(unsigned int my_rwnd, unsigned int new_remote_TSN)
929 {
930 rxc_buffer *rxc;
931
932 rxc = (rxc_buffer *) mdi_readRX_control();
933 if (!rxc) {
934 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
935 return;
936 }
937 rxc_stop_sack_timer();
938 g_list_foreach(rxc->frag_list, &free_list_element, NULL);
939 g_list_free(rxc->frag_list);
940 rxc->ctsna = new_remote_TSN - 1;
941 rxc->lowest = new_remote_TSN - 1;
942 rxc->highest = new_remote_TSN - 1;
943 /* initialize and set up lists */
944
945 rxc->frag_list = NULL;
946 rxc->dup_list = NULL;
947 rxc->contains_valid_sack = FALSE;
948 rxc->timer_running = FALSE;
949 rxc->datagrams_received = -1;
950 rxc->sack_flag = 2;
951 rxc->last_address = 0;
952 rxc->my_rwnd = my_rwnd;
953 rxc->my_association = mdi_readAssociationID();
954 return;
955 }
956
957
rxc_process_forward_tsn(void * chunk)958 int rxc_process_forward_tsn(void* chunk)
959 {
960 rxc_buffer *rxc=NULL;
961 unsigned int fw_tsn;
962 unsigned int chunk_len;
963 unsigned int lo, hi;
964 fragment32 *frag=NULL;
965 GList *current = NULL;
966
967 SCTP_forward_tsn_chunk* chk = (SCTP_forward_tsn_chunk*)chunk;
968
969 fw_tsn = ntohl(chk->forward_tsn);
970 chunk_len = ntohs(chk->chunk_header.chunk_length);
971
972 event_logii(INTERNAL_EVENT_0, "rxc_process_forward_tsn: %u, len:%u",fw_tsn, chunk_len);
973 rxc = (rxc_buffer *) mdi_readRX_control();
974 if (!rxc) {
975 error_log(ERROR_MAJOR, "rxc_buffer instance not set !");
976 return (-1);
977 }
978 /* discard old FORWARD_TSN */
979 if (after(rxc->ctsna, fw_tsn) || fw_tsn==rxc->ctsna || mdi_supportsPRSCTP() == FALSE) {
980 event_logii(VERBOSE, "rxc_process_forward_tsn --> discard fw_tsn !! (fw_tsn %u <= ctsna %u)",fw_tsn, rxc->ctsna);
981 return 0;
982 }
983
984 current = g_list_first(rxc->frag_list);
985
986 /* -get first fragment
987 -case1: fw_tsn after hi: delete fragment, continue with next fragment;
988 -case2: fw_tsn between hi and lo-1:
989 delete fragment, set ctsna=hi, break;
990 -case3: fw_tsn before lo-1, set ctsna => fw_tsn, break;
991 */
992 while (current != NULL) {
993 frag = (fragment32*)current->data;
994 if (current != NULL && frag != NULL){
995 lo = frag->start_tsn;
996 hi = frag->stop_tsn;
997 if (before(fw_tsn, lo-1)) {
998 /* case3: fw_tsn before lo-1, set ctsna => fw_tsn, break; */
999 event_logi(VERBOSE, "process- case3: update ctsna to %u !",fw_tsn);
1000 rxc->ctsna = fw_tsn;
1001 break;
1002 } else if (between(lo-1, fw_tsn, hi)) {
1003 /* case2: fw_tsn between hi and lo-1: delete fragment, set ctsna=hi, break; */
1004 rxc->frag_list = g_list_remove_link(rxc->frag_list, current);
1005 g_list_free_1(current); free(frag);
1006 event_logi(VERBOSE, "process- case2: remove fragment and update ctsna to %u !",hi);
1007 rxc->ctsna = hi;
1008 break;
1009 } else if (after(fw_tsn, hi)) {
1010 /* case1: fw_tsn after hi: delete fragment, continue with next fragment; */
1011 rxc->frag_list = g_list_remove_link(rxc->frag_list, current);
1012 g_list_free_1(current); free(frag);
1013 event_logi(VERBOSE, "process- case1: remove fragment, and set ctsna => %u !",hi);
1014 rxc->ctsna = fw_tsn;
1015 } else {
1016 error_log(ERROR_FATAL, "rxc_process_forward_tsn: impossible conditon");
1017 abort();
1018 }
1019 }
1020 /* we are still here, take next fragment == first fragment */
1021 current = g_list_first(rxc->frag_list);
1022 }
1023 if (after(fw_tsn, rxc->ctsna)) {
1024 rxc->ctsna = fw_tsn;
1025 event_logi(VERBOSE, "rxc_process_forward_tsn: case4: set ctsna => %u !",fw_tsn);
1026 }
1027 se_deliver_unreliably(rxc->ctsna, chk);
1028
1029 rxc_all_chunks_processed(TRUE);
1030
1031 return 0;
1032 }
1033
1034