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 "bundling.h"
45 #include "messages.h"
46 #include "recvctrl.h"
47 #include "reltransfer.h"
48 #include "errorhandler.h"
49 #include "streamengine.h"
50 #include "distribution.h"
51
52 #include <stdio.h>
53
54 #define TOTAL_SIZE(buf) ((buf)->ctrl_position+(buf)->sack_position+(buf)->data_position- 2*sizeof(SCTP_common_header))
55
56
57
rbu_scanPDU(guchar * pdu,guint len)58 unsigned int rbu_scanPDU(guchar * pdu, guint len)
59 {
60 gushort processed_len = 0;
61 gushort chunk_len = 0;
62 unsigned int result = 0;
63 guchar *current_position;
64 guint pad_bytes;
65 SCTP_simple_chunk *chunk;
66
67 current_position = pdu; /* points to the first chunk in this pdu */
68
69 while (processed_len < len) {
70
71 event_logii(VERBOSE, "rbu_scanPDU : len==%u, processed_len == %u", len, processed_len);
72
73 chunk = (SCTP_simple_chunk *) current_position;
74 chunk_len = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
75
76 if (chunk_len < 4 || chunk_len + processed_len > len) return result;
77
78 if (chunk->chunk_header.chunk_id <= 30) {
79 result = result | (1 << chunk->chunk_header.chunk_id);
80 event_logii(VERBOSE, "rbu_scanPDU : Chunk type==%u, result == %x", chunk->chunk_header.chunk_id, result);
81 } else {
82 result = result | (1 << 31);
83 event_logii(VERBOSE, "rbu_scanPDU : Chunk type==%u setting bit 31 --> result == %x", chunk->chunk_header.chunk_id, result);
84 }
85 processed_len += chunk_len;
86 pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
87 processed_len += pad_bytes;
88 chunk_len = (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) + pad_bytes * sizeof(unsigned char));
89
90 if (chunk_len < 4 || chunk_len + processed_len > len) return result;
91 current_position += chunk_len;
92
93 }
94 return result;
95 }
96
rbu_datagramContains(gushort chunk_type,unsigned int chunkArray)97 gboolean rbu_datagramContains(gushort chunk_type, unsigned int chunkArray)
98 {
99 unsigned int val = 0;
100
101 if (chunk_type >= 31) {
102 val = (1 << 31);
103 if ((val & chunkArray) == 0) return FALSE;
104 else return TRUE; /* meaning: it could be true */
105 }
106
107 val = (1 << chunk_type);
108 if ((val & chunkArray) != 0) return TRUE;
109 else return FALSE;
110
111 }
112
113
rbu_scanInitChunkForParameter(guchar * chunk,gushort paramType)114 guchar* rbu_scanInitChunkForParameter(guchar * chunk, gushort paramType)
115 {
116 gushort processed_len;
117 guint len = 0, parameterLength = 0;
118 guchar *current_position;
119 guint pad_bytes;
120 SCTP_init *initChunk;
121 SCTP_vlparam_header* vlp;
122
123 initChunk = (SCTP_init *) chunk;
124
125 if (initChunk->chunk_header.chunk_id != CHUNK_INIT &&
126 initChunk->chunk_header.chunk_id != CHUNK_INIT_ACK) {
127 return FALSE;
128 }
129 len = ntohs(initChunk->chunk_header.chunk_length);
130 current_position = initChunk->variableParams;
131 processed_len = (sizeof(SCTP_chunk_header)+sizeof(SCTP_init_fixed));
132
133 while (processed_len < len) {
134 event_logii(INTERNAL_EVENT_0,
135 "rbu_scanInitChunkForParameter : len==%u, processed_len == %u", len, processed_len);
136 vlp = (SCTP_vlparam_header*) current_position;
137 parameterLength = ntohs(vlp->param_length);
138
139 if (parameterLength < 4 || parameterLength + processed_len > len) return NULL;
140
141 if (ntohs(vlp->param_type) == paramType) {
142 return current_position;
143 }
144 processed_len += parameterLength;
145 pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
146 processed_len += pad_bytes;
147 current_position += (parameterLength + pad_bytes * sizeof(unsigned char));
148 }
149 return NULL;
150
151 }
152
153
154 /*
155 * rbu_findChunk: looks for chunk_type in a newly received datagram
156 *
157 * All chunks within the datagram are looked at, until one is found
158 * that equals the parameter chunk_type.
159 * @param datagram pointer to the newly received data
160 * @param len stop after this many bytes
161 * @param chunk_type chunk type to look for
162 * @return pointer to first chunk of chunk_type in SCTP datagram, else NULL
163 */
rbu_findChunk(guchar * datagram,guint len,gushort chunk_type)164 guchar* rbu_findChunk(guchar * datagram, guint len, gushort chunk_type)
165 {
166 gushort processed_len = 0, chunk_len = 0;
167 guchar *current_position;
168 guint pad_bytes;
169 SCTP_simple_chunk *chunk;
170
171 current_position = datagram; /* points to the first chunk in this pdu */
172 while (processed_len < len) {
173
174 event_logii(INTERNAL_EVENT_0,
175 "rbu_findChunk : len==%u, processed_len == %u", len, processed_len);
176
177 chunk = (SCTP_simple_chunk *) current_position;
178 if (chunk->chunk_header.chunk_id == chunk_type)
179 return current_position;
180 else {
181 chunk_len = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
182 if (chunk_len < 4 || chunk_len + processed_len > len) return NULL;
183
184 processed_len += CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
185 pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
186 processed_len += pad_bytes;
187 chunk_len = (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) + pad_bytes * sizeof(unsigned char));
188 if (chunk_len < 4 || chunk_len + processed_len > len) return NULL;
189 current_position += chunk_len;
190 }
191 }
192 return NULL;
193 }
194
195 /*
196 * rbu_findAddress: looks for address type parameters in INIT or INIT-ACKs
197 * All parameters within the chunk are looked at, and the n-th supported address is
198 * copied into the provided buffer pointed to by the foundAddress parameter.
199 * If there are less than n addresses, an appropriate error is
200 * returned. n should be at least 1, of course.
201 * @param chunk pointer to an INIT or INIT ACK chunk
202 * @param n get the n-th address
203 * @param foundAddress pointer to a buffer where an address, if found, will be copied
204 * @return -1 for parameter problem, 0 for success (i.e. address found), 1 if there are not
205 * that many addresses in the chunk.
206 */
rbu_findAddress(guchar * chunk,guint n,union sockunion * foundAddress,int supportedAddressTypes)207 gint rbu_findAddress(guchar * chunk, guint n, union sockunion* foundAddress, int supportedAddressTypes)
208 {
209 gushort processed_len;
210 guint len = 0, parameterLength = 0;
211 guchar *current_position;
212 guint pad_bytes;
213 SCTP_init *initChunk;
214 SCTP_vlparam_header* vlp;
215 SCTP_ip_address * address;
216 unsigned int foundAddressNumber = 0;
217
218 initChunk = (SCTP_init *) chunk;
219 if (foundAddress == NULL || n < 1 || n > SCTP_MAX_NUM_ADDRESSES)
220 return -1;
221 if (initChunk->chunk_header.chunk_id != CHUNK_INIT &&
222 initChunk->chunk_header.chunk_id != CHUNK_INIT_ACK) {
223 return -1;
224 }
225 len = ntohs(initChunk->chunk_header.chunk_length);
226 current_position = initChunk->variableParams;
227 processed_len = (sizeof(SCTP_chunk_header)+sizeof(SCTP_init_fixed));
228
229 while (processed_len < len) {
230 event_logii(INTERNAL_EVENT_0,
231 "rbu_findAddress : len==%u, processed_len == %u", len, processed_len);
232 vlp = (SCTP_vlparam_header*) current_position;
233 parameterLength = ntohs(vlp->param_length);
234
235 if (parameterLength < 4 || parameterLength + processed_len > len) return -1;
236
237 if (ntohs(vlp->param_type) == VLPARAM_IPV4_ADDRESS &&
238 supportedAddressTypes & SUPPORT_ADDRESS_TYPE_IPV4) {
239 /* discard invalid addresses */
240 foundAddressNumber++;
241 if (foundAddressNumber == n) {
242 address = (SCTP_ip_address *)current_position;
243 /* copy the address over to the user buffer */
244 foundAddress->sa.sa_family = AF_INET;
245 foundAddress->sin.sin_port = 0;
246 foundAddress->sin.sin_addr.s_addr = address->dest_addr.sctp_ipv4;
247 return 0;
248 }
249 #ifdef HAVE_IPV6
250 } else if (ntohs(vlp->param_type) == VLPARAM_IPV6_ADDRESS &&
251 supportedAddressTypes & SUPPORT_ADDRESS_TYPE_IPV6) {
252 /* discard invalid addresses */
253 foundAddressNumber++;
254 if (foundAddressNumber == n) {
255 address = (SCTP_ip_address *)current_position;
256 /* copy the address over to the user buffer */
257 foundAddress->sa.sa_family = AF_INET6;
258 foundAddress->sin6.sin6_port = htons(0);
259 foundAddress->sin6.sin6_flowinfo = htonl(0);
260 #ifdef HAVE_SIN6_SCOPE_ID
261 foundAddress->sin6.sin6_scope_id = htonl(0);
262 #endif
263 memcpy(foundAddress->sin6.sin6_addr.s6_addr,
264 address->dest_addr.sctp_ipv6, sizeof(struct in6_addr));
265
266 return 0;
267 }
268 #endif
269 }
270 processed_len += parameterLength;
271 pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
272 processed_len += pad_bytes;
273 current_position += (parameterLength + pad_bytes * sizeof(unsigned char));
274 }
275 return 1;
276 }
277
278 /**
279 * looks for Error chunk_type in a newly received datagram
280 * that contains a special error cause code
281 *
282 * All chunks within the datagram are lookes at, until one is found
283 * that equals the parameter chunk_type.
284 * @param datagram pointer to the newly received data
285 * @param len stop after this many bytes
286 * @param error_cause error cause code to look for
287 * @return true is chunk_type exists in SCTP datagram, false if it is not in there
288 */
rbu_scanDatagramForError(guchar * datagram,guint len,gushort error_cause)289 gboolean rbu_scanDatagramForError(guchar * datagram, guint len, gushort error_cause)
290 {
291 gushort processed_len = 0, param_length = 0, chunk_length = 0;
292 gushort err_len = 0;
293
294 guchar *current_position;
295 guint pad_bytes;
296 SCTP_simple_chunk *chunk;
297 SCTP_staleCookieError *err_chunk;
298
299
300 current_position = datagram; /* points to the first chunk in this pdu */
301 while (processed_len < len) {
302
303 event_logii(VERBOSE,
304 "rbu_scanDatagramForError : len==%u, processed_len == %u", len, processed_len);
305
306 chunk = (SCTP_simple_chunk *) current_position;
307 chunk_length = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
308 if (chunk_length < 4 || chunk_length + processed_len > len) return FALSE;
309
310 if (chunk->chunk_header.chunk_id == CHUNK_ERROR) {
311
312 if (chunk_length < 4 || chunk_length + processed_len > len) return FALSE;
313
314 event_log(INTERNAL_EVENT_0, "rbu_scanDatagramForError : Error Chunk Found");
315 /* now search for error parameter that fits */
316 while (err_len < chunk_length - sizeof(SCTP_chunk_header)) {
317 err_chunk = (SCTP_staleCookieError *) &(chunk->simple_chunk_data[err_len]);
318 if (ntohs(err_chunk->vlparam_header.param_type) == error_cause) {
319 event_logi(VERBOSE,
320 "rbu_scanDatagramForError : Error Cause %u found -> Returning TRUE",
321 error_cause);
322 return TRUE;
323 }
324 param_length = ntohs(err_chunk->vlparam_header.param_length);
325 if (param_length < 4 || param_length + err_len > len) return FALSE;
326
327 err_len += param_length;
328 while ((err_len % 4) != 0)
329 err_len++;
330 }
331 }
332
333 processed_len += chunk_length;
334 pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
335 processed_len += pad_bytes;
336 chunk_length = (CHUNKP_LENGTH((SCTP_chunk_header *) chunk) + pad_bytes * sizeof(unsigned char));
337 if (chunk_length < 4 || chunk_length + processed_len > len) return FALSE;
338 current_position += chunk_length;
339 }
340 event_logi(VERBOSE,
341 "rbu_scanDatagramForError : Error Cause %u NOT found -> Returning FALSE",
342 error_cause);
343 return FALSE;
344 }
345
346
347 /**
348 * Disassembles chunks from a received datagram
349 *
350 * FIXME : data chunks may only be parsed after control chunks.....
351 *
352 * All chunks within the datagram are dispatched and sent to the appropriate
353 * module, i.e.: control chunks are sent to sctp_control/pathmanagement,
354 * SACK chunks to reliable_transfer, and data_chunks to RX_control.
355 * Those modules must get a pointer to the start of a chunk and
356 * information about its size (without padding).
357 * @param address_index index of address on which this data arrived
358 * @param datagram pointer to first chunk of the newly received data
359 * @param len length of payload (i.e. len of the concatenation of chunks)
360 */
rbu_rcvDatagram(guint address_index,guchar * datagram,guint len)361 gint rbu_rcvDatagram(guint address_index, guchar * datagram, guint len)
362 {
363 /* sctp common header header has been verified */
364 /* tag (if association is established) and CRC is okay */
365 /* get first chunk-id and length, pass pointers & len on to relevant module :
366 - CHUNK_INIT, CHUNK_INIT_ACK,CHUNK_ABORT, CHUNK_SHUTDOWN,CHUNK_SHUTDOWN_ACK
367 CHUNK_COOKIE_ECHO,CHUNK_COOKIE_ACK go to SCTP_CONTROL (change of association state)
368 - CHUNK_HBREQ, CHUNK_HBACK go to PATH_MAN instance
369 - CHUNK_SACK goes to RELIABLE_TRANSFER
370 - CHUNK_ERROR probably to SCTP_CONTROL as well (at least there !)
371 - CHUNK_DATA goes to RX_CONTROL
372 */
373 guchar *current_position;
374 gushort processed_len = 0, chunk_len;
375 gushort pad_bytes;
376 SCTP_simple_chunk *chunk;
377 gboolean data_chunk_received = FALSE;
378
379 int association_state = STATE_OK;
380 gboolean send_it = FALSE;
381
382 bu_lock_sender();
383
384 current_position = datagram; /* points to the first chunk in this pdu */
385 event_log(INTERNAL_EVENT_0, "Entered rbu_rcvDatagram()...... ");
386 /* CHECKME : beim Empfangen leerer Chunks tritt im Bundling eine Endlosschleife auf ??? */
387 while (processed_len < len) {
388
389 chunk = (SCTP_simple_chunk *) current_position;
390 chunk_len = CHUNKP_LENGTH((SCTP_chunk_header *) chunk);
391 event_logiiii(INTERNAL_EVENT_0,
392 "rbu_rcvDatagram(address=%u) : len==%u, processed_len = %u, chunk_len=%u",
393 address_index, len, processed_len, chunk_len);
394 if ((processed_len+chunk_len) > len || chunk_len < 4) {
395 error_logiii(ERROR_MINOR, "Faulty chunklen=%u, total len=%u,processed_len=%u --> dropping packet !",
396 chunk_len,len,processed_len);
397 /* if the association has already been removed, we cannot unlock it anymore */
398 bu_unlock_sender(&address_index);
399 return 1;
400 }
401 /*
402 * TODO : Add return values to the chunk-functions, where they can indicate what
403 * to do with the rest of the datagram (i.e. DISCARD after stale COOKIE_ECHO
404 * with tie tags that do not match the current ones)
405 */
406 switch (chunk->chunk_header.chunk_id) {
407 case CHUNK_DATA:
408 event_log(INTERNAL_EVENT_0, "******************* Bundling received DATA chunk");
409 rxc_data_chunk_rx((SCTP_data_chunk*) chunk, address_index);
410 data_chunk_received = TRUE;
411 break;
412 case CHUNK_INIT:
413 event_log(INTERNAL_EVENT_0, "******************* Bundling received INIT chunk");
414 association_state = sctlr_init((SCTP_init *) chunk);
415 break;
416 case CHUNK_INIT_ACK:
417 event_log(INTERNAL_EVENT_0, "******************* Bundling received INIT ACK chunk");
418 association_state = sctlr_initAck((SCTP_init *) chunk);
419 break;
420 case CHUNK_SACK:
421 event_log(INTERNAL_EVENT_0, "******************* Bundling received SACK chunk");
422 rtx_process_sack(address_index, chunk, len);
423 break;
424 case CHUNK_HBREQ:
425 event_log(INTERNAL_EVENT_0, "******************* Bundling received HB_REQ chunk");
426 pm_heartbeat((SCTP_heartbeat *) chunk, address_index);
427 break;
428 case CHUNK_HBACK:
429 event_log(INTERNAL_EVENT_0, "******************* Bundling received HB_ACK chunk");
430 pm_heartbeatAck((SCTP_heartbeat *) chunk);
431 break;
432 case CHUNK_ABORT:
433 event_log(INTERNAL_EVENT_0, "******************* Bundling received ABORT chunk");
434 association_state = sctlr_abort();
435 break;
436 case CHUNK_SHUTDOWN:
437 event_log(INTERNAL_EVENT_0, "******************* Bundling received SHUTDOWN chunk");
438 association_state = sctlr_shutdown((SCTP_simple_chunk *) chunk);
439 break;
440 case CHUNK_SHUTDOWN_ACK:
441 event_log(INTERNAL_EVENT_0, "******************* Bundling received SHUTDOWN ACK chunk");
442 association_state = sctlr_shutdownAck();
443 break;
444 case CHUNK_ERROR:
445 event_log(INTERNAL_EVENT_0, "Error Chunk");
446 eh_recv_chunk(chunk);
447 break;
448 case CHUNK_COOKIE_ECHO:
449 event_log(INTERNAL_EVENT_0, "******************* Bundling received COOKIE ECHO chunk");
450 sctlr_cookie_echo((SCTP_cookie_echo *) chunk);
451 break;
452 case CHUNK_COOKIE_ACK:
453 event_log(INTERNAL_EVENT_0, "******************* Bundling received COOKIE ACK chunk");
454 sctlr_cookieAck((SCTP_simple_chunk *) chunk);
455 break;
456 /* case CHUNK_ECNE:
457 case CHUNK_CWR:
458 event_logi(INTERNAL_EVENT_0,
459 "Chunktype %u not Supported Yet !!!!!!!!", chunk->chunk_header.chunk_id);
460 break;*/
461 case CHUNK_SHUTDOWN_COMPLETE:
462 event_log(INTERNAL_EVENT_0, "******************* Bundling received SHUTDOWN_COMPLETE chunk");
463 association_state = sctlr_shutdownComplete();
464 break;
465 case CHUNK_FORWARD_TSN:
466 if (mdi_supportsPRSCTP() == TRUE) {
467 event_log(INTERNAL_EVENT_0, "******************* Bundling received FORWARD_TSN chunk");
468 rxc_process_forward_tsn((SCTP_simple_chunk *) chunk);
469 break;
470 } else
471 continue;
472 /* case CHUNK_ASCONF: */
473 /* check that ASCONF chunks are standalone chunks, not bundled with any other
474 chunks. Else ignore the ASCONF chunk (but not the others) */
475 /* event_log(INTERNAL_EVENT_0, "Bundling received ASCONF chunk");
476 asc_recv_asconf_chunk((SCTP_simple_chunk *) chunk);
477 break;
478 case CHUNK_ASCONF_ACK:
479 event_log(INTERNAL_EVENT_0, "Bundling received ASCONF_ACK chunk");
480 asc_recv_asconf_ack((SCTP_simple_chunk *) chunk);
481 break; */
482 default:
483 /* 00 - Stop processing this SCTP packet and discard it, do not process
484 any further chunks within it.
485 01 - Stop processing this SCTP packet and discard it, do not process
486 any further chunks within it, and report the unrecognized
487 parameter in an 'Unrecognized Parameter Type' (in either an
488 ERROR or in the INIT ACK).
489 10 - Skip this chunk and continue processing.
490 11 - Skip this chunk and continue processing, but report in an ERROR
491 Chunk using the 'Unrecognized Chunk Type' cause of error. */
492 if ((chunk->chunk_header.chunk_id & 0xC0) == 0x0) { /* 00 */
493 processed_len = len;
494 event_logi(EXTERNAL_EVENT_X, "00: Unknown chunktype %u in rbundling.c", chunk->chunk_header.chunk_id);
495 } else if ((chunk->chunk_header.chunk_id & 0xC0) == 0x40) { /* 01 */
496 processed_len = len;
497 eh_send_unrecognized_chunktype((unsigned char*)chunk,chunk_len);
498 event_logi(EXTERNAL_EVENT_X, "01: Unknown chunktype %u in rbundling.c",chunk->chunk_header.chunk_id);
499 } else if ((chunk->chunk_header.chunk_id & 0xC0) == 0x80) { /* 10 */
500 /* nothing */
501 event_logi(EXTERNAL_EVENT_X, "10: Unknown chunktype %u in rbundling.c",chunk->chunk_header.chunk_id);
502 } else if ((chunk->chunk_header.chunk_id & 0xC0) == 0xC0) { /* 11 */
503 event_logi(EXTERNAL_EVENT_X, "11: Unknown chunktype %u in rbundling.c", chunk->chunk_header.chunk_id);
504 eh_send_unrecognized_chunktype((unsigned char*)chunk,chunk_len);
505 }
506 break;
507 }
508
509 processed_len += chunk_len;
510 pad_bytes = ((processed_len % 4) == 0) ? 0 : (4 - processed_len % 4);
511 processed_len += pad_bytes;
512 current_position += (chunk_len + pad_bytes) * sizeof(unsigned char);
513
514 if (association_state != STATE_OK) processed_len = len;
515
516 event_logiiii(VVERBOSE, "processed_len=%u, pad_bytes=%u, current_position=%u, chunk_len=%u",
517 processed_len, pad_bytes, current_position,chunk_len);
518 }
519
520 if (association_state != STATE_STOP_PARSING_REMOVED) {
521
522 if (data_chunk_received == TRUE) {
523 /* update SACK structure and start SACK timer */
524 rxc_all_chunks_processed(TRUE);
525 } else {
526 /* update SACK structure and datagram counter */
527 rxc_all_chunks_processed(FALSE);
528 }
529 /* optionally also add a SACK chunk, at least for every second datagram
530 * see section 6.2, second paragraph
531 */
532 if (data_chunk_received == TRUE){
533 send_it = rxc_create_sack(&address_index, FALSE);
534 se_doNotifications();
535 if (send_it==TRUE) bu_sendAllChunks(&address_index);
536 }
537 /* if the association has already been removed, we cannot unlock it anymore */
538 bu_unlock_sender(&address_index);
539 }
540
541 return 0;
542
543 }
544
545
546