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 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 #include "sctp.h" /* ULP-interface definitions */
49 #include "distribution.h" /* SCTP-internal interfaces to message distribution */
50 #include "adaptation.h" /* interfaces to adaptation layer */
51 #include "bundling.h" /* interfaces to bundling */
52 #include "SCTP-control.h" /* interfaces to SCTP-control */
53 #include "auxiliary.h"
54 #include "streamengine.h" /* interfaces to streamengine */
55 #include "flowcontrol.h" /* interfaces to flowcontrol */
56 #include "recvctrl.h" /* interfaces to receive-controller */
57 #include "chunkHandler.h"
58
59 #include <sys/types.h>
60 #include <errno.h>
61 #ifdef WIN32
62 #include <winsock2.h>
63 #else
64 #include <arpa/inet.h> /* for inet_ntoa() under both SOLARIS/LINUX */
65 #endif
66
67 #ifndef IN_EXPERIMENTAL
68 #define IN_EXPERIMENTAL(a) ((((int) (a)) & 0xf0000000) == 0xf0000000)
69 #endif
70
71 #ifndef IN_BADCLASS
72 #define IN_BADCLASS(a) IN_EXPERIMENTAL((a))
73 #endif
74
75
76 /*------------------------ Default Definitions --------------------------------------------------*/
77 static int myRWND = 0x7FFF;
78 static union sockunion *myAddressList = NULL;
79 static unsigned int myNumberOfAddresses = 0;
80 static gboolean sendAbortForOOTB = TRUE;
81 static int checksumAlgorithm = SCTP_CHECKSUM_ALGORITHM_CRC32C;
82 static gboolean librarySupportsPRSCTP = TRUE;
83 static gboolean supportADDIP = FALSE;
84 /*------------------------Structure Definitions --------------------------------------------------*/
85
86 /**
87 * This struct stores data of SCTP-instances.
88 * Each SCTP-instances is related to one port and to
89 * one SCTP adaption-layer. This may change soon !
90 */
91 typedef struct SCTPINSTANCE
92 {
93 /*@{ */
94 /** The name of this SCTP-instance, used as key. */
95 unsigned short sctpInstanceName;
96 /** The local port of this instance, or zero for don't cares.
97 Once assigned this should not be changed ! */
98 unsigned short localPort;
99 guint16 noOfLocalAddresses;
100 union sockunion *localAddressList;
101 unsigned char* localAddressStrings;
102 gboolean has_INADDR_ANY_set;
103 gboolean has_IN6ADDR_ANY_set;
104 gboolean uses_IPv4;
105 gboolean uses_IPv6;
106 /** set of callback functions that were registered by the ULP */
107 SCTP_ulpCallbacks ULPcallbackFunctions;
108 /** maximum number of incoming streams that this instance will take */
109 unsigned short noOfInStreams;
110 /** maximum number of outgoingng streams that this instance will take */
111 unsigned short noOfOutStreams;
112 /** here follow default parameters for instance initialization */
113 unsigned int default_rtoInitial;
114 unsigned int default_validCookieLife;
115 unsigned int default_assocMaxRetransmits;
116 unsigned int default_pathMaxRetransmits;
117 unsigned int default_maxInitRetransmits;
118 unsigned int default_myRwnd;
119 unsigned int default_delay;
120 unsigned char default_ipTos;
121 unsigned int default_rtoMin;
122 unsigned int default_rtoMax;
123 unsigned int default_maxSendQueue;
124 unsigned int default_maxRecvQueue;
125 unsigned int default_maxBurst;
126 unsigned int supportedAddressTypes;
127 gboolean supportsPRSCTP;
128 gboolean supportsADDIP;
129 /*@}*/
130 }
131 SCTP_instance;
132
133
134 /**
135 * This struct contains all data of an association. As far as other modules must know elements
136 * of this struct, read functions are provided. No other module has write access to this structure.
137 */
138 typedef struct ASSOCIATION
139 {
140 /*@{*/
141 /** The current ID of this association,
142 it is used as a key to find a association in the list,
143 and never changes in the live of the association */
144 unsigned int assocId;
145 /** The local tag of this association. */
146 unsigned int tagLocal;
147 /** The tag of remote side of this association */
148 unsigned int tagRemote;
149 /** Pointer to the SCTP-instance this association
150 belongs to. It is equal to the wellknown port
151 number of the ULP that uses this instance. */
152 SCTP_instance* sctpInstance;
153 /** the local port number of this association. */
154 unsigned short localPort;
155 /** the remote port number of this association. */
156 unsigned short remotePort;
157 /** number of destination networks (paths) */
158 short noOfNetworks;
159 /** array of destination addresses */
160 union sockunion *destinationAddresses;
161 /** number of own addresses */
162 unsigned int noOfLocalAddresses;
163 /** array of local addresses */
164 union sockunion *localAddresses;
165 /** pointer to flowcontrol structure */
166 void *flowControl;
167 /** pointer to reliable-transfer structure */
168 void *reliableTransfer;
169 /** pointer to receive-control structure */
170 void *rx_control;
171 /** pointer to stream structure */
172 void *streamengine;
173 /** pointer to pathmanagement structure */
174 void *pathMan;
175 /** pointer to bundling structure */
176 void *bundling;
177 /** pointer to SCTP-control */
178 void *sctp_control;
179 /** marks an association for deletion */
180 boolean deleted;
181 /** transparent pointer to some upper layer data */
182 void * ulp_dataptr;
183 /** IP TOS value per association */
184 unsigned char ipTos;
185 unsigned int supportedAddressTypes;
186 unsigned int maxSendQueue;
187 unsigned int maxRecvQueue;
188 gboolean had_INADDR_ANY_set;
189 gboolean had_IN6ADDR_ANY_set;
190 /* do I support the SCTP extensions ? */
191 gboolean supportsPRSCTP;
192 gboolean supportsADDIP;
193 /* and these values for our peer */
194 gboolean peerSupportsPRSCTP;
195 gboolean peerSupportsADDIP;
196 /*@}*/
197 } Association;
198
199
200 /******************** Declarations ****************************************************************/
201 static gboolean sctpLibraryInitialized = FALSE;
202 /*
203 Keyed list of SCTP-instances with the instanceName as key
204 */
205 /**
206 * Keyed list of associations with the association-ID as key
207 */
208 static GList* AssociationList = NULL;
209
210 /**
211 * Whenever an external event (ULP-call, socket-event or timer-event) this variable must
212 * contain the addressed sctp instance.
213 * This pointer must be reset to null after the event has been handled.
214 */
215 static SCTP_instance *sctpInstance;
216
217 /**
218 * Keyed list of SCTP instances with the instance name as key
219 */
220 static GList* InstanceList = NULL;
221 static unsigned int ipv4_users = 0;
222 #ifdef HAVE_IPV6
223 static unsigned int ipv6_users = 0;
224 #endif
225 /**
226 * Whenever an external event (ULP-call, socket-event or timer-event) this variable must
227 * contain the addressed association.
228 * Read functions for 'global data' read data from the association pointed to by this pointer.
229 * This pointer must be reset to null after the event has been handled.
230 */
231 static Association *currentAssociation;
232 static Association tmpAssoc;
233 static union sockunion tmpAddress;
234
235
236 /* If firstSCTP_instance is true, a seed is generated by
237 use of (current time). After the first SCTP-instance was created, firstSCTP_instance
238 is set to false.
239 */
240 static unsigned short lastSCTP_instanceName = 1;
241 /*
242 AssociationIDs are counted up, and if a new one is needed, they are checked for wraps
243 */
244 static unsigned int nextAssocId = 1;
245
246 /**
247 initAck is sent to this address
248 In this case, SCTP-control reads this address on reception of the cookie echo
249 (which consequently also does not contain an addresslist) to initialize the new association.
250 */
251 static union sockunion *lastFromAddress;
252 static union sockunion *lastDestAddress;
253
254 static short lastFromPath;
255 static unsigned short lastFromPort;
256 static unsigned short lastDestPort;
257 static unsigned int lastInitiateTag;
258
259 /**
260 Descriptor of socket used by all associations and SCTP-instances.
261 */
262 static gint sctp_socket;
263
264 #ifdef HAVE_IPV6
265 static gint ipv6_sctp_socket;
266 #endif
267
268 /* port management array */
269 static unsigned char portsSeized[0x10000];
270 static unsigned int numberOfSeizedPorts;
271
272
273 /* ---------------------- Internal Function Prototypes ------------------------------------------- */
274 unsigned short mdi_getUnusedInstanceName(void);
275
276
277 /* ------------------------- Function Implementations --------------------------------------------- */
278
279 /*------------------- Internal Functions ---------------------------------------------------------*/
280
281 #define CHECK_LIBRARY if(sctpLibraryInitialized == FALSE) return SCTP_LIBRARY_NOT_INITIALIZED
282 #define ZERO_CHECK_LIBRARY if(sctpLibraryInitialized == FALSE) return 0
283
284 #ifdef LIBRARY_DEBUG
285 #define ENTER_LIBRARY(fname) printf("Entering sctplib (%s)\n", fname); fflush(stdout);
286 #define LEAVE_LIBRARY(fname) printf("Leaving sctplib (%s)\n", fname); fflush(stdout);
287 #define ENTER_CALLBACK(fname) printf("Entering callback (%s)\n", fname); fflush(stdout);
288 #define LEAVE_CALLBACK(fname) printf("Leaving callback (%s)\n", fname); fflush(stdout);
289 #else
290 #define ENTER_LIBRARY(fname)
291 #define LEAVE_LIBRARY(fname)
292 #define ENTER_CALLBACK(fname)
293 #define LEAVE_CALLBACK(fname)
294 #endif
295 /*------------------- Internal LIST Functions ----------------------------------------------------*/
296
297
298
299 /*
300 * return 1 or -1 if instances have different port,
301 * return 0 if same ports and one address is in set of second instances addresses
302 */
CheckForAddressInInstance(gconstpointer a,gconstpointer b)303 gint CheckForAddressInInstance(gconstpointer a, gconstpointer b)
304 {
305 int acount,bcount;
306 gboolean found;
307 SCTP_instance* ai = (SCTP_instance*)a;
308 SCTP_instance* bi = (SCTP_instance*)b;
309
310 event_logii(VVERBOSE, "DEBUG: CheckForAddressInInstance, comparing instance a port %u, instance b port %u",
311 ai->localPort, bi->localPort);
312
313 if (ai->localPort < bi->localPort) return -1;
314 else if (ai->localPort > bi->localPort) return 1;
315
316 else {
317 /* one has IN(6)ADDR_ANY : return equal ! */
318 if (ai->has_IN6ADDR_ANY_set && bi->has_IN6ADDR_ANY_set) return 0;
319 if (ai->has_INADDR_ANY_set && bi->has_INADDR_ANY_set) return 0;
320 if (ai->has_INADDR_ANY_set && bi->has_IN6ADDR_ANY_set) return 0;
321 if (ai->has_IN6ADDR_ANY_set && bi->has_INADDR_ANY_set) return 0;
322 if ((ai->has_IN6ADDR_ANY_set || ai->has_INADDR_ANY_set) &&
323 !(bi->has_IN6ADDR_ANY_set || bi->has_INADDR_ANY_set)) return 0;
324 if (!(ai->has_IN6ADDR_ANY_set || ai->has_INADDR_ANY_set) &&
325 (bi->has_IN6ADDR_ANY_set || bi->has_INADDR_ANY_set)) return 0;
326 /* both do not have an INADDR_ANY : use code below */
327 found = FALSE;
328 for (acount = 0; acount < ai->noOfLocalAddresses; acount++) {
329 for (bcount = 0; bcount < bi->noOfLocalAddresses; bcount++) {
330 /* if addresses are equal: set found TRUE and break; */
331 if (adl_equal_address
332 ( &(ai->localAddressList[acount]), &(bi->localAddressList[bcount])) == TRUE) found = TRUE;
333
334 event_logiii(VVERBOSE, "DEBUG: CheckForAddressInInstance, acount %u, bcount %u, found = %s",
335 acount, bcount, (found==TRUE)?"TRUE":"FALSE");
336
337 if (found == TRUE) break;
338 }
339 if (found == TRUE) break;
340 }
341 /* if address was not found, it is not in this instance */
342 if (found == FALSE) return -1; /* to continue search */
343 }
344 return 0;
345
346 }
347
348
CompareInstanceNames(gconstpointer a,gconstpointer b)349 gint CompareInstanceNames(gconstpointer a, gconstpointer b)
350 {
351 if ((((SCTP_instance*)a)->sctpInstanceName) < ((SCTP_instance*)b)->sctpInstanceName) return -1;
352 else if ((((SCTP_instance*)a)->sctpInstanceName) > ((SCTP_instance*)b)->sctpInstanceName) return 1;
353 else return 0;
354 }
355
356
357 /**
358 * Retrieve instance.
359 *
360 * @param instance_name Instance name.
361 * @return SCTP_instance or NULL if not found.
362 */
retrieveInstance(unsigned short instance_name)363 SCTP_instance* retrieveInstance(unsigned short instance_name)
364 {
365 SCTP_instance* instance;
366 SCTP_instance temporary;
367 GList* result = NULL;
368
369 event_logi(INTERNAL_EVENT_0, "retrieving instance %u from list", instance_name);
370
371 temporary.sctpInstanceName = instance_name;
372 result = g_list_find_custom(InstanceList, &temporary, &CompareInstanceNames);
373 if (result != NULL) {
374 instance = (SCTP_instance*)result->data;
375 }
376 else {
377 event_logi(INTERNAL_EVENT_0, "instance %u not in list", instance_name);
378 instance = NULL;
379 }
380
381 return(instance);
382 }
383
384
385 /**
386 * compareAssociationIDs compares the association ID's of two associations and returns 0
387 * if they are equal. This is a call back function called by List Functions whenever two
388 * association need to be compared.
389 * @param a pointer to association struct 1
390 * @param b pointer to association struct 2
391 * @return 0 if a->assocId equals b->assocId, 1 if bigger, -1 if smaller
392 */
compareAssociationIDs(gconstpointer a,gconstpointer b)393 gint compareAssociationIDs(gconstpointer a, gconstpointer b)
394 {
395 /* two associations are equal if there local tags (in this implementation also used as
396 association ID) are equal. */
397 if (((Association*)a)->assocId == ((Association*)b)->assocId)
398 return 0;
399 else if (((Association*)a)->assocId < ((Association*)b)->assocId)
400 return -1;
401 else
402 return 1;
403 }
404
405
406
407 /**
408 * equalAssociations compares two associations and returns 0 if they are equal. In contrast to
409 * function compareAssociationIDs, equal here means the two associations belong to the same
410 * SCTP-instance and have at least one destinationaddress in common.
411 * This is a call back function called by GList-functions whenever two association need to be compared.
412 * @param i1 association data 1
413 * @param i2 association data 2
414 * @return 0 if il1 and il2 are equal according to above definition, 1 else
415 */
equalAssociations(gconstpointer a,gconstpointer b)416 gint equalAssociations(gconstpointer a, gconstpointer b)
417 {
418 int i,j;
419
420 event_logii(VVERBOSE, "equalAssociations: checking assoc A[id=%d] and assoc B[id=%d]",
421 ((Association*)a)->assocId,((Association*)b)->assocId);
422
423 /* two associations are equal if their remote and local ports are equal and at least
424 one of their remote addresses are equal. This is like in TCP, where a connection
425 is identified by the transport address, i.e. the IP-address and port of the peer. */
426
427 if ( (((Association *)a)->remotePort == ((Association *)b)->remotePort) &&
428 (((Association *)a)->localPort == ((Association *)b)->localPort) ){
429 for (i = 0; i < ((Association *)a)->noOfNetworks; i++)
430 for (j = 0; j < ((Association *)b)->noOfNetworks; j++) {
431 event_logii(VVERBOSE, "equalAssociations: checking address A[%d] address B[%d]",i,j);
432 if (adl_equal_address
433 (&(((Association *)a)->destinationAddresses[i]),
434 &(((Association *)b)->destinationAddresses[j])) == TRUE) {
435 if ( (((Association *)b)->deleted == FALSE) && (((Association *)a)->deleted == FALSE)) {
436 event_log(VVERBOSE, "equalAssociations: found TWO equal assocs !");
437 return 0;
438 } else {
439 event_log(VVERBOSE, "equalAssociations: found NO equal assocs !");
440 return 1;
441 }
442 }
443 }
444 event_log(VVERBOSE, "equalAssociations: found NO equal assocs !");
445 return 1;
446 }
447 event_log(VVERBOSE, "equalAssociations: found NO equal assocs !");
448 return 1;
449 }
450
451
452 /**
453 * retrieveAssociation retrieves a association from the list using the id as key.
454 * Returns NULL also if the association is marked "deleted" !
455 * @param assocID association ID
456 * @return pointer to the retrieved association, or NULL
457 */
retrieveAssociation(unsigned int assocID)458 Association *retrieveAssociation(unsigned int assocID)
459 {
460 Association *assoc;
461 Association *assocFindP;
462 GList* result = NULL;
463
464 event_logi(INTERNAL_EVENT_0, "retrieving association %08x from list", assocID);
465
466 tmpAssoc.assocId = assocID;
467 tmpAssoc.deleted = FALSE;
468 assocFindP = &tmpAssoc;
469 assoc = NULL;
470
471 result = g_list_find_custom(AssociationList, assocFindP, &compareAssociationIDs);
472 if (result != NULL) {
473
474 assoc = (Association *)result->data;
475
476 if (assoc->deleted) {
477 assoc = NULL;
478 }
479 } else {
480 event_logi(INTERNAL_EVENT_0, "association %08x not in list", assocID);
481 assoc = NULL;
482 }
483 return assoc;
484 }
485
486 /**
487 * retrieveAssociationForced retrieves an association from the list using
488 * assoc id as key. Returns also associations marked "deleted" !
489 * @param assocID association ID
490 * @return pointer to the retrieved association, or NULL
491 */
retrieveAssociationForced(unsigned int assocID)492 Association *retrieveAssociationForced(unsigned int assocID)
493 {
494 Association *assoc;
495 Association *assocFindP;
496 GList* result = NULL;
497
498 event_logi(INTERNAL_EVENT_0, "forced retrieval of association %08x from list", assocID);
499
500 tmpAssoc.assocId = assocID;
501 assocFindP = &tmpAssoc;
502 assoc = NULL;
503 result = g_list_find_custom(AssociationList, assocFindP, &compareAssociationIDs);
504 if (result != NULL) {
505 assoc = (Association *)result->data;
506 } else {
507 event_logi(INTERNAL_EVENT_0, "association %08x not in list", assocID);
508 assoc = NULL;
509 }
510 return assoc;
511 }
512
513
514 /**
515 * retrieveAssociation retrieves a association from the list using the transport address as key.
516 * Returns NULL also if the association is marked "deleted" !
517 * CHECKME : Must return NULL, if no Address-Port combination does not occur in ANY existing assoc.
518 * If it occurs in one of these -> return it
519 *
520 * @param fromAddress address from which data arrived
521 * @param fromPort SCTP port from which data arrived
522 * @return pointer to the retrieved association, or NULL
523 */
retrieveAssociationByTransportAddress(union sockunion * fromAddress,unsigned short fromPort,unsigned short toPort)524 Association *retrieveAssociationByTransportAddress(union sockunion * fromAddress,
525 unsigned short fromPort,
526 unsigned short toPort)
527 {
528
529 Association *assocr;
530 Association *assocp;
531 GList* result = NULL;
532
533 tmpAssoc.noOfNetworks = 1;
534 tmpAssoc.destinationAddresses = &tmpAddress;
535
536 switch (sockunion_family(fromAddress)) {
537 case AF_INET:
538 event_logi(INTERNAL_EVENT_0,
539 "Looking for IPv4 Address %x (in NBO)", sock2ip(fromAddress));
540 tmpAssoc.destinationAddresses[0].sa.sa_family = AF_INET;
541 tmpAssoc.destinationAddresses[0].sin.sin_addr.s_addr = sock2ip(fromAddress);
542 tmpAssoc.remotePort = fromPort;
543 tmpAssoc.localPort = toPort;
544 tmpAssoc.deleted = FALSE;
545 break;
546 #ifdef HAVE_IPV6
547 case AF_INET6:
548 tmpAssoc.destinationAddresses[0].sa.sa_family = AF_INET6;
549 memcpy(&(tmpAssoc.destinationAddresses[0].sin6.sin6_addr.s6_addr),
550 (sock2ip6(fromAddress)), sizeof(struct in6_addr));
551 event_logi(INTERNAL_EVENT_0, "Looking for IPv6 Address %x, check NTOHX() ! ",
552 tmpAssoc.destinationAddresses[0].sin6.sin6_addr.s6_addr);
553 tmpAssoc.remotePort = fromPort;
554 tmpAssoc.localPort = toPort;
555 tmpAssoc.deleted = FALSE;
556 break;
557 #endif
558 default:
559 error_logi(ERROR_FATAL,
560 "Unsupported Address Type %d in retrieveAssociationByTransportAddress()",
561 sockunion_family(fromAddress));
562 break;
563
564 }
565
566 assocp = &tmpAssoc;
567
568 event_log(INTERNAL_EVENT_0, "retrieving association by transport address from list");
569
570 result = g_list_find_custom(AssociationList, assocp, equalAssociations);
571
572 if (result != NULL){
573 assocr = (Association *)result->data;
574 if (assocr->deleted) {
575 event_logi(VERBOSE, "Found assoc that should be deleted, with id %u",assocr->assocId);
576 assocr= NULL;
577 }
578 if (assocr != NULL)
579 event_logi(VERBOSE, "Found valid assoc assoc with id %u",assocr->assocId);
580 return assocr;
581 } else {
582 event_log(INTERNAL_EVENT_0, "association indexed by transport address not in list");
583 }
584 return NULL;
585 }
586
587
588
589 /**
590 * checkForExistingAssociations checks wether a given association is already in the list using
591 * the equality condition given by function equalAssociations.
592 * TODO : this must still be implemented. Where is it used ??????????????
593 *
594 * @param assoc_new the association to be compared with the association in the list.
595 * @return 1 if was association found, else 0
596 */
checkForExistingAssociations(Association * assoc_new)597 static short checkForExistingAssociations(Association * assoc_new)
598 {
599 GList* result = NULL;
600
601 if (AssociationList == NULL) {
602 event_logi(VERBOSE, "checkForExistingAssociations(new_assoc = %u) AssocList not set",
603 assoc_new->assocId);
604
605 return 0;
606 }
607
608 result = g_list_find_custom(AssociationList, assoc_new, equalAssociations);
609
610 if (result) /* then one of addresses of assoc A was in set of addresses of B */
611 return 1;
612 else
613 return 0;
614 }
615
616
617
618 /*------------------- Internal port management Functions -----------------------------------------*/
619
620 /**
621 * allocatePort Allocate a given port.
622 * @return Allocated port or 0 if port is occupied.
623 */
allocatePort(unsigned short port)624 static unsigned short allocatePort(unsigned short port)
625 {
626 if(portsSeized[port] == 0) {
627 portsSeized[port] = 1;
628 numberOfSeizedPorts++;
629 return(port);
630 }
631 return(0);
632 }
633
634
635 /**
636 * seizePort return a free port number.
637 * @return free port.
638 */
seizePort(void)639 static unsigned short seizePort(void)
640 {
641 unsigned short seizePort = 0;
642
643 /* problem: no more available ports ?! */
644 if (numberOfSeizedPorts >= 0xFBFF)
645 return 0x0000;
646
647 seizePort = (unsigned short)(adl_random() % 0xFFFF);
648
649 while (portsSeized[seizePort] || seizePort < 0x0400) {
650 seizePort = (unsigned short)(adl_random() % 0xFFFF);
651 }
652
653 numberOfSeizedPorts++;
654 portsSeized[seizePort] = 1;
655
656 return seizePort;
657 }
658
659
660 /**
661 * releasePort frees a previously used port.
662 * @param portSeized port that is to be freed.
663 */
releasePort(unsigned short portSeized)664 static void releasePort(unsigned short portSeized)
665 {
666 if (portsSeized[portSeized] == 0 || portSeized == 0){
667 error_log(ERROR_MINOR, "Warning: release of port that is not seized");
668 return;
669 }
670
671 numberOfSeizedPorts--;
672 portsSeized[portSeized] = 0;
673 }
674
675
676
677 /*------------------- Other Internal Functions ---------------------------------------------------*/
678
679 /**
680 * deleteAssociation removes the association from the list of associations, frees all data allocated
681 * for it and <calls moduleprefix>_delete*(...) function at all modules.
682 * @param assoc pointer to the association to be deleted.
683 */
mdi_removeAssociationData(Association * assoc)684 static void mdi_removeAssociationData(Association * assoc)
685 {
686 if (assoc != NULL) {
687 event_logi(INTERNAL_EVENT_0, "Deleting association %08x ", assoc->assocId);
688
689 /* free module data */
690 if (assoc->tagRemote != 0) {
691 /* association init was already completed */
692 if(assoc->flowControl) {
693 fc_delete_flowcontrol(assoc->flowControl);
694 assoc->flowControl = NULL;
695 }
696 if(assoc->reliableTransfer) {
697 rtx_delete_reltransfer(assoc->reliableTransfer);
698 assoc->reliableTransfer = NULL;
699 }
700 if(assoc->rx_control) {
701 rxc_delete_recvctrl(assoc->rx_control);
702 assoc->rx_control = NULL;
703 }
704 if(assoc->streamengine) {
705 se_delete_stream_engine(assoc->streamengine);
706 assoc->streamengine = NULL;
707 }
708 }
709
710 pm_deletePathman(assoc->pathMan);
711 bu_delete(assoc->bundling);
712 sci_deleteSCTP_control(assoc->sctp_control);
713
714 assoc->pathMan = NULL;
715 assoc->bundling = NULL;
716 assoc->sctp_control = NULL;
717
718 /* free association data */
719 free(assoc->destinationAddresses);
720 free(assoc->localAddresses);
721 assoc->destinationAddresses = NULL;
722 assoc->localAddresses = NULL;
723 free(assoc);
724 } else {
725 error_log(ERROR_MAJOR, "mdi_removeAssociationData: association does not exist");
726 }
727
728 return;
729
730 } /* end: mdi_deleteAssociation */
731
732
733 /*
734 * after sctpInstance and currentAssociation have been set for an
735 * incoming packet, this function will return, if a packet may be processed
736 * or if it is not destined for this instance
737 */
mdi_destination_address_okay(union sockunion * dest_addr)738 boolean mdi_destination_address_okay(union sockunion * dest_addr)
739 {
740 unsigned int i;
741 gboolean found = FALSE;
742 gboolean any_set = FALSE;
743
744 /* this case will be specially treated after the call to mdi_destination_address_okay() */
745 if (sctpInstance == NULL && currentAssociation == NULL) return TRUE;
746
747 /*
748 if (sctpInstance == NULL && currentAssociation == NULL) return FALSE;
749 */
750 if (currentAssociation != NULL) {
751 /* search through the _association_ list */
752 /* and accept or decline */
753 for (i=0; i< currentAssociation->noOfLocalAddresses; i++) {
754 event_logii(VVERBOSE, "mdi_destination_address_okay: Checking addresses Dest %x, local %x",
755 sock2ip(dest_addr), sock2ip(&(currentAssociation->localAddresses[i])));
756 if(adl_equal_address(dest_addr, &(currentAssociation->localAddresses[i])) == TRUE) {
757 found = TRUE;
758 break;
759 }
760 }
761 return found;
762 } else {
763 /* check whether _instance_ has INADDR_ANY */
764 if (sctpInstance->has_INADDR_ANY_set == TRUE) {
765 any_set = TRUE;
766 /* if so, accept */
767 switch(sockunion_family(dest_addr)) {
768 case AF_INET:
769 return TRUE;
770 break;
771 #ifdef HAVE_IPV6
772 case AF_INET6:
773 return FALSE;
774 break;
775 #endif
776 default:
777 break;
778
779 }
780 }
781 if (sctpInstance->has_IN6ADDR_ANY_set == TRUE) {
782 any_set = TRUE;
783 /* if so, accept */
784 switch(sockunion_family(dest_addr)) {
785 case AF_INET:
786 return TRUE;
787 break;
788 #ifdef HAVE_IPV6
789 case AF_INET6:
790 return TRUE;
791 break;
792 #endif
793 default:
794 break;
795
796 }
797 }
798 if (any_set == TRUE) return FALSE;
799 /* if not, search through the list */
800 for (i=0; i< sctpInstance->noOfLocalAddresses; i++) {
801 if(adl_equal_address(dest_addr, &(sctpInstance->localAddressList[i])) == TRUE) {
802 found = TRUE;
803 break;
804 }
805 }
806 /* and accept or decline */
807 }
808 return found;
809 }
810
811
812 /*------------------- Functions called by the Unix-Interface -------------------------------------*/
813 void
mdi_dummy_callback(gint socket_fd,unsigned char * buffer,int bufferLength,unsigned char * hoststring,unsigned short fromAddressLength)814 mdi_dummy_callback(gint socket_fd,
815 unsigned char *buffer,
816 int bufferLength,
817 unsigned char *hoststring,
818 unsigned short fromAddressLength)
819 {
820 error_log(ERROR_FATAL, "DUMMY CALLBACK should never be EXECUTED !");
821 }
822
823
824 /**
825 * mdi_receiveMessage is the callback function of the SCTP-message distribution.
826 * It is called by the Unix-interface module when a new datagramm is received.
827 * This function also performs OOTB handling, tag verification etc.
828 * (see also RFC 4960, section 8.5.1.B) and sends data to the bundling module of
829 * the right association
830 *
831 * @param socket_fd the socket file discriptor
832 * @param buffer pointer to arrived datagram
833 * @param bufferlength length of datagramm
834 * @param fromAddress source address of DG
835 * @param portnum bogus port number
836 */
837 void
mdi_receiveMessage(gint socket_fd,unsigned char * buffer,int bufferLength,union sockunion * source_addr,union sockunion * dest_addr)838 mdi_receiveMessage(gint socket_fd,
839 unsigned char *buffer,
840 int bufferLength,
841 union sockunion * source_addr,
842 union sockunion * dest_addr)
843 {
844 SCTP_message *message;
845 SCTP_init_fixed *initChunk = NULL;
846 guchar* initPtr = NULL;
847 guchar source_addr_string[SCTP_MAX_IP_LEN];
848 guchar dest_addr_string[SCTP_MAX_IP_LEN];
849 SCTP_vlparam_header* vlptr = NULL;
850
851 union sockunion alternateFromAddress;
852 int i = 0;
853 unsigned int len, state, chunkArray = 0;
854 boolean sourceAddressExists = FALSE;
855 boolean sendAbort = FALSE;
856 boolean discard = FALSE;
857 unsigned int addressType = 0;
858 int retval = 0, supportedAddressTypes = 0;
859
860 boolean initFound = FALSE, cookieEchoFound = FALSE, abortFound = FALSE;
861
862 short shutdownCompleteCID;
863 short abortCID;
864
865 SCTP_instance temporary;
866 GList* result = NULL;
867
868 /* FIXME: check this out, if it works at all :-D */
869 lastFromAddress = source_addr;
870 lastDestAddress = dest_addr;
871
872 lastFromPath = 0;
873
874 message = (SCTP_message *) buffer;
875
876 if (!validate_datagram(buffer, bufferLength)) {
877 event_log(INTERNAL_EVENT_0, "received corrupted datagramm");
878 lastFromAddress = NULL;
879 lastDestAddress = NULL;
880 return;
881 }
882
883 len = bufferLength - sizeof(SCTP_common_header);
884
885 /* save from address for response if a remote address is not available otherwise.
886 For instance initAck or cookieAck. */
887 lastFromPort = ntohs(message->common_header.src_port);
888 lastDestPort = ntohs(message->common_header.dest_port);
889
890 if (lastFromPort == 0 || lastDestPort == 0) {
891 error_log(ERROR_MINOR, "received DG with invalid (i.e. 0) ports");
892 lastFromAddress = NULL;
893 lastDestAddress = NULL;
894 lastFromPort = 0;
895 lastDestPort = 0;
896 return;
897 }
898
899 if (sockunion_family(dest_addr) == AF_INET) {
900 addressType = SUPPORT_ADDRESS_TYPE_IPV4;
901 event_log(VERBOSE, "mdi_receiveMessage: checking for correct IPV4 addresses");
902 if (IN_CLASSD(ntohl(dest_addr->sin.sin_addr.s_addr))) discard = TRUE;
903 if (IN_EXPERIMENTAL(ntohl(dest_addr->sin.sin_addr.s_addr))) discard = TRUE;
904 if (IN_BADCLASS(ntohl(dest_addr->sin.sin_addr.s_addr))) discard = TRUE;
905 if (INADDR_ANY == ntohl(dest_addr->sin.sin_addr.s_addr)) discard = TRUE;
906 if (INADDR_BROADCAST == ntohl(dest_addr->sin.sin_addr.s_addr)) discard = TRUE;
907
908 if (IN_CLASSD(ntohl(source_addr->sin.sin_addr.s_addr))) discard = TRUE;
909 if (IN_EXPERIMENTAL(ntohl(source_addr->sin.sin_addr.s_addr))) discard = TRUE;
910 if (IN_BADCLASS(ntohl(source_addr->sin.sin_addr.s_addr))) discard = TRUE;
911 if (INADDR_ANY == ntohl(source_addr->sin.sin_addr.s_addr)) discard = TRUE;
912 if (INADDR_BROADCAST == ntohl(source_addr->sin.sin_addr.s_addr)) discard = TRUE;
913
914 /* if ((INADDR_LOOPBACK != ntohl(source_addr->sin.sin_addr.s_addr)) &&
915 (source_addr->sin.sin_addr.s_addr == dest_addr->sin.sin_addr.s_addr)) discard = TRUE;
916 */
917
918 } else
919 #ifdef HAVE_IPV6
920 if (sockunion_family(dest_addr) == AF_INET6) {
921 addressType = SUPPORT_ADDRESS_TYPE_IPV6;
922 event_log(VERBOSE, "mdi_receiveMessage: checking for correct IPV6 addresses");
923 #if defined (LINUX)
924 if (IN6_IS_ADDR_UNSPECIFIED(&(dest_addr->sin6.sin6_addr.s6_addr))) discard = TRUE;
925 if (IN6_IS_ADDR_MULTICAST(&(dest_addr->sin6.sin6_addr.s6_addr))) discard = TRUE;
926 /* if (IN6_IS_ADDR_V4COMPAT(&(dest_addr->sin6.sin6_addr.s6_addr))) discard = TRUE; */
927
928 if (IN6_IS_ADDR_UNSPECIFIED(&(source_addr->sin6.sin6_addr.s6_addr))) discard = TRUE;
929 if (IN6_IS_ADDR_MULTICAST(&(source_addr->sin6.sin6_addr.s6_addr))) discard = TRUE;
930 /* if (IN6_IS_ADDR_V4COMPAT(&(source_addr->sin6.sin6_addr.s6_addr))) discard = TRUE; */
931 /*
932 if ((!IN6_IS_ADDR_LOOPBACK(&(source_addr->sin6.sin6_addr.s6_addr))) &&
933 IN6_ARE_ADDR_EQUAL(&(source_addr->sin6.sin6_addr.s6_addr),
934 &(dest_addr->sin6.sin6_addr.s6_addr))) discard = TRUE;
935 */
936 #else
937 if (IN6_IS_ADDR_UNSPECIFIED(&(dest_addr->sin6.sin6_addr))) discard = TRUE;
938 if (IN6_IS_ADDR_MULTICAST(&(dest_addr->sin6.sin6_addr))) discard = TRUE;
939 /* if (IN6_IS_ADDR_V4COMPAT(&(dest_addr->sin6.sin6_addr))) discard = TRUE; */
940
941 if (IN6_IS_ADDR_UNSPECIFIED(&(source_addr->sin6.sin6_addr))) discard = TRUE;
942 if (IN6_IS_ADDR_MULTICAST(&(source_addr->sin6.sin6_addr))) discard = TRUE;
943 /* if (IN6_IS_ADDR_V4COMPAT(&(source_addr->sin6.sin6_addr))) discard = TRUE; */
944 /*
945 if ((!IN6_IS_ADDR_LOOPBACK(&(source_addr->sin6.sin6_addr))) &&
946 IN6_ARE_ADDR_EQUAL(&(source_addr->sin6.sin6_addr),
947 &(dest_addr->sin6.sin6_addr))) discard = TRUE;
948 */
949 #endif
950 } else
951 #endif
952 {
953 error_log(ERROR_FATAL, "mdi_receiveMessage: Unsupported AddressType Received !");
954 discard = TRUE;
955 }
956 adl_sockunion2str(source_addr, source_addr_string, SCTP_MAX_IP_LEN);
957 adl_sockunion2str(dest_addr, dest_addr_string, SCTP_MAX_IP_LEN);
958
959 event_logiiiii(EXTERNAL_EVENT,
960 "mdi_receiveMessage : len %d, sourceaddress : %s, src_port %u,dest: %s, dest_port %u",
961 bufferLength, source_addr_string, lastFromPort, dest_addr_string,lastDestPort);
962
963 if (discard == TRUE) {
964 lastFromAddress = NULL;
965 lastDestAddress = NULL;
966 lastFromPort = 0;
967 lastDestPort = 0;
968 sctpInstance = NULL;
969 currentAssociation = NULL;
970 event_logi(INTERNAL_EVENT_0, "mdi_receiveMessage: discarding packet for incorrect address %s",
971 dest_addr_string);
972 return;
973 }
974
975
976 /* Retrieve association from list */
977 currentAssociation = retrieveAssociationByTransportAddress(lastFromAddress, lastFromPort,lastDestPort);
978
979 if (currentAssociation != NULL) {
980 /* meaning we MUST have an instance with no fixed port */
981 sctpInstance = currentAssociation->sctpInstance;
982 supportedAddressTypes = 0;
983 } else {
984 /* OK - if this packet is for a server, we will find an SCTP instance, that shall
985 handle it (i.e. we have the SCTP instance's localPort set and it matches the
986 packet's destination port */
987 temporary.localPort = lastDestPort;
988 temporary.noOfLocalAddresses = 1;
989 temporary.has_INADDR_ANY_set = FALSE;
990 temporary.has_IN6ADDR_ANY_set = FALSE;
991 temporary.localAddressList = dest_addr;
992 temporary.supportedAddressTypes = addressType;
993
994 result = g_list_find_custom(InstanceList, &temporary, &CheckForAddressInInstance);
995
996 if (result == NULL) {
997 event_logi(VERBOSE, "Couldn't find SCTP Instance for Port %u and Address in List !",lastDestPort);
998 /* may be an an association that is a client (with instance port 0) */
999 sctpInstance = NULL;
1000 #ifdef HAVE_IPV6
1001 supportedAddressTypes = SUPPORT_ADDRESS_TYPE_IPV6 | SUPPORT_ADDRESS_TYPE_IPV4;
1002 #else
1003 supportedAddressTypes = SUPPORT_ADDRESS_TYPE_IPV4;
1004 #endif
1005 } else {
1006 sctpInstance = (SCTP_instance*)result->data;
1007 supportedAddressTypes = sctpInstance->supportedAddressTypes;
1008 event_logii(VERBOSE, "Found an SCTP Instance for Port %u and Address in the list, types: %d !",
1009 lastDestPort, supportedAddressTypes);
1010 }
1011 }
1012
1013 if (mdi_destination_address_okay(dest_addr) == FALSE) {
1014 event_log(VERBOSE, "mdi_receiveMsg: this packet is not for me, DISCARDING !!!");
1015 lastFromAddress = NULL;
1016 lastDestAddress = NULL;
1017 lastFromPort = 0;
1018 lastDestPort = 0;
1019 sctpInstance = NULL;
1020 currentAssociation = NULL;
1021 return;
1022 }
1023
1024 lastInitiateTag = ntohl(message->common_header.verification_tag);
1025
1026 chunkArray = rbu_scanPDU(message->sctp_pdu, len);
1027
1028
1029
1030 if (currentAssociation == NULL) {
1031 if ((initPtr = rbu_findChunk(message->sctp_pdu, len, CHUNK_INIT)) != NULL) {
1032 event_log(VERBOSE, "mdi_receiveMsg: Looking for source address in INIT CHUNK");
1033 retval = 0; i = 1;
1034 do {
1035 retval = rbu_findAddress(initPtr, i, &alternateFromAddress, supportedAddressTypes);
1036 if (retval == 0) {
1037 currentAssociation = retrieveAssociationByTransportAddress(&alternateFromAddress,
1038 lastFromPort,lastDestPort);
1039 }
1040 i++;
1041 } while (currentAssociation == NULL && retval == 0);
1042 }
1043 if ((initPtr = rbu_findChunk(message->sctp_pdu, len, CHUNK_INIT_ACK)) != NULL) {
1044 event_log(VERBOSE, "mdi_receiveMsg: Looking for source address in INIT_ACK CHUNK");
1045 retval = 0; i = 1;
1046 do {
1047 retval = rbu_findAddress(initPtr, i, &alternateFromAddress, supportedAddressTypes);
1048 if (retval == 0) {
1049 currentAssociation = retrieveAssociationByTransportAddress(&alternateFromAddress,
1050 lastFromPort,lastDestPort);
1051 }
1052 i++;
1053 } while (currentAssociation == NULL && retval == 0);
1054 }
1055 if (currentAssociation != NULL) {
1056 event_log(VERBOSE, "mdi_receiveMsg: found association from INIT (ACK) CHUNK");
1057 sourceAddressExists = TRUE;
1058 } else {
1059 event_log(VERBOSE, "mdi_receiveMsg: found NO association from INIT (ACK) CHUNK");
1060 }
1061 }
1062
1063 /* check whether chunk is illegal or not (see section 3.1 of RFC 4960) */
1064 if ( ((rbu_datagramContains(CHUNK_INIT, chunkArray) == TRUE) && (chunkArray != (1 << CHUNK_INIT))) ||
1065 ((rbu_datagramContains(CHUNK_INIT_ACK, chunkArray) == TRUE) && (chunkArray != (1 << CHUNK_INIT_ACK))) ||
1066 ((rbu_datagramContains(CHUNK_SHUTDOWN_COMPLETE, chunkArray) == TRUE) && (chunkArray != (1 << CHUNK_SHUTDOWN_COMPLETE)))
1067 ){
1068
1069 error_log(ERROR_MINOR, "mdi_receiveMsg: discarding illegal packet....... :-)");
1070
1071 /* silently discard */
1072 lastFromAddress = NULL;
1073 lastDestAddress = NULL;
1074 lastFromPort = 0;
1075 lastDestPort = 0;
1076 sctpInstance = NULL;
1077 currentAssociation = NULL;
1078 return;
1079 }
1080
1081 /* check if sctp-message belongs to an existing association */
1082 if (currentAssociation == NULL) {
1083 event_log(VVERBOSE, "mdi_receiveMsg: currentAssociation==NULL, start scanning !");
1084 /* This is not very elegant, but....only used when assoc is being build up, so :-D */
1085 if (rbu_datagramContains(CHUNK_ABORT, chunkArray) == TRUE) {
1086 event_log(INTERNAL_EVENT_0, "mdi_receiveMsg: Found ABORT chunk, discarding it !");
1087 lastFromAddress = NULL;
1088 lastDestAddress = NULL;
1089 lastFromPort = 0;
1090 lastDestPort = 0;
1091 sctpInstance = NULL;
1092 currentAssociation = NULL;
1093 return;
1094 }
1095 if (rbu_datagramContains(CHUNK_SHUTDOWN_ACK, chunkArray) == TRUE) {
1096 event_log(INTERNAL_EVENT_0,
1097 "mdi_receiveMsg: Found SHUTDOWN_ACK chunk, send SHUTDOWN_COMPLETE !");
1098 /* section 8.4.5 : return SHUTDOWN_COMPLETE with peers veri-tag and T-Bit set */
1099 shutdownCompleteCID = ch_makeSimpleChunk(CHUNK_SHUTDOWN_COMPLETE, FLAG_NO_TCB);
1100 bu_put_Ctrl_Chunk(ch_chunkString(shutdownCompleteCID), NULL);
1101 bu_unlock_sender(NULL);
1102 /* should send it to last address */
1103 bu_sendAllChunks(NULL);
1104 /* free abort chunk */
1105 ch_deleteChunk(shutdownCompleteCID);
1106
1107 /* send an ABORT with peers veri-tag, set T-Bit */
1108 event_log(VERBOSE, "mdi_receiveMsg: sending CHUNK_SHUTDOWN_COMPLETE ");
1109 lastFromPort = 0;
1110 lastDestPort = 0;
1111 lastDestAddress = NULL;
1112 lastFromAddress = NULL;
1113 sctpInstance = NULL;
1114 currentAssociation = NULL;
1115 return;
1116 }
1117 if (rbu_datagramContains(CHUNK_SHUTDOWN_COMPLETE, chunkArray) == TRUE) {
1118 event_log(INTERNAL_EVENT_0,
1119 "mdi_receiveMsg: Found SHUTDOWN_COMPLETE chunk, discarding it !");
1120 lastFromPort = 0;
1121 lastDestPort = 0;
1122 lastDestAddress = NULL;
1123 lastFromAddress = NULL;
1124 sctpInstance = NULL;
1125 currentAssociation = NULL;
1126 return;
1127 }
1128 if (rbu_datagramContains(CHUNK_COOKIE_ACK, chunkArray) == TRUE) {
1129 event_log(INTERNAL_EVENT_0, "mdi_receiveMsg: Found COOKIE_ACK chunk, discarding it !");
1130 lastFromPort = 0;
1131 lastDestPort = 0;
1132 lastDestAddress = NULL;
1133 lastFromAddress = NULL;
1134 sctpInstance = NULL;
1135 currentAssociation = NULL;
1136 return;
1137 }
1138
1139 /* section 8.4.7) : Discard the datagram, if it contains a STALE-COOKIE ERROR */
1140 if (rbu_scanDatagramForError(message->sctp_pdu, len, ECC_STALE_COOKIE_ERROR) == TRUE) {
1141 event_log(INTERNAL_EVENT_0,
1142 "mdi_receiveMsg: Found STALE COOKIE ERROR, discarding packet !");
1143 lastFromPort = 0;
1144 lastDestPort = 0;
1145 lastDestAddress = NULL;
1146 lastFromAddress = NULL;
1147 sctpInstance = NULL;
1148 currentAssociation = NULL;
1149 return;
1150 }
1151
1152 if ((initPtr = rbu_findChunk(message->sctp_pdu, len, CHUNK_INIT)) != NULL) {
1153 if (sctpInstance != NULL) {
1154 if (lastDestPort != sctpInstance->localPort || sctpInstance->localPort == 0) {
1155 /* destination port is not the listening port of this this SCTP-instance. */
1156 event_log(INTERNAL_EVENT_0,
1157 "mdi_receiveMsg: got INIT Message, but dest. port does not fit -> ABORT");
1158 sendAbort = TRUE;
1159 /* as per section 5.1 :
1160 If an endpoint receives an INIT, INIT ACK, or COOKIE ECHO chunk but
1161 decides not to establish the new association due to missing mandatory
1162 parameters in the received INIT or INIT ACK, invalid parameter values,
1163 or lack of local resources, it MUST respond with an ABORT chunk */
1164 } else {
1165 event_log(INTERNAL_EVENT_0, "mdi_receiveMsg: INIT Message - processing it !");
1166 }
1167 initChunk = ((SCTP_init_fixed *) & ((SCTP_init *) message->sctp_pdu)->init_fixed);
1168 lastInitiateTag = ntohl(initChunk->init_tag);
1169 event_logi(VERBOSE, "setting lastInitiateTag to %x ", lastInitiateTag);
1170
1171 if ((vlptr = (SCTP_vlparam_header*)rbu_scanInitChunkForParameter(initPtr, VLPARAM_HOST_NAME_ADDR)) != NULL) {
1172 sendAbort = TRUE;
1173 }
1174
1175 } else { /* we do not have an instance up listening on that port-> ABORT him */
1176 event_log(INTERNAL_EVENT_0,
1177 "mdi_receiveMsg: got INIT Message, but no instance found -> IGNORE");
1178
1179 sendAbort = TRUE;
1180 initChunk = ((SCTP_init_fixed *) & ((SCTP_init *) message->sctp_pdu)->init_fixed);
1181 lastInitiateTag = ntohl(initChunk->init_tag);
1182 event_logi(VERBOSE, "setting lastInitiateTag to %x ", lastInitiateTag);
1183 }
1184
1185 } else if (rbu_datagramContains(CHUNK_COOKIE_ECHO, chunkArray) == TRUE) {
1186 if (sctpInstance != NULL) {
1187 if (lastDestPort != sctpInstance->localPort || sctpInstance->localPort == 0) {
1188 /* destination port is not the listening port of this this SCTP-instance. */
1189 event_log(INTERNAL_EVENT_0,
1190 "mdi_receiveMsg: COOKIE_ECHO ignored, dest. port does not fit");
1191 sendAbort = TRUE;
1192 } else {
1193 event_log(INTERNAL_EVENT_0,
1194 "mdi_receiveMsg: COOKIE_ECHO Message - processing it !");
1195 }
1196 } else { /* sctpInstance == NULL */
1197 event_log(INTERNAL_EVENT_0,
1198 "mdi_receiveMsg: got COOKIE ECHO Message, but no instance found -> IGNORE");
1199 lastFromPort = 0;
1200 lastDestPort = 0;
1201 lastDestAddress = NULL;
1202 lastFromAddress = NULL;
1203 sctpInstance = NULL;
1204 currentAssociation = NULL;
1205 return;
1206 }
1207 } else {
1208 /* section 8.4.8) send an ABORT with peers veri-tag, set T-Bit */
1209 event_log(INTERNAL_EVENT_0,
1210 "mdi_receiveMsg: send ABORT -> message ignored (OOTB - see section 8.4.8) ");
1211 sendAbort = TRUE;
1212 }
1213
1214
1215 } else { /* i.e. if(currentAssociation != NULL) */
1216
1217 /* If the association exists, both ports of the message must be equal to the ports
1218 of the association and the source address must be in the addresslist of the peer
1219 of this association */
1220 /* check src- and dest-port and source address */
1221 if (lastFromPort != currentAssociation->remotePort || lastDestPort != currentAssociation->localPort) {
1222 error_logiiii(ERROR_FATAL,
1223 "port mismatch in received DG (lastFromPort=%u, assoc->remotePort=%u, lastDestPort=%u, assoc->localPort=%u ", lastFromPort, currentAssociation->remotePort, lastDestPort, currentAssociation->localPort);
1224 currentAssociation = NULL;
1225 sctpInstance = NULL;
1226 lastFromAddress = NULL;
1227 lastDestAddress = NULL;
1228 lastFromPort = 0;
1229 lastDestPort = 0;
1230 return;
1231 }
1232
1233 if (sctpInstance == NULL) {
1234 sctpInstance = currentAssociation->sctpInstance;
1235 if (sctpInstance == NULL) {
1236 error_log(ERROR_FATAL, "We have an Association, but no Instance, FIXME !");
1237 }
1238 }
1239
1240 /* check if source address is in address list of this association.
1241 tbd: check the draft if this is correct. */
1242 if (sourceAddressExists == FALSE) {
1243 for (i = 0; i < currentAssociation->noOfNetworks; i++) {
1244 if (adl_equal_address
1245 (&(currentAssociation->destinationAddresses[i]), lastFromAddress) == TRUE) {
1246 sourceAddressExists = TRUE;
1247 break;
1248 }
1249 }
1250 }
1251
1252 if (!sourceAddressExists) {
1253 error_log(ERROR_MINOR,
1254 "source address of received DG is not in the destination addresslist");
1255 currentAssociation = NULL;
1256 sctpInstance = NULL;
1257 lastFromPort = 0;
1258 lastDestPort = 0;
1259 lastDestAddress = NULL;
1260 lastFromAddress = NULL;
1261 return;
1262 }
1263
1264 if (sourceAddressExists) lastFromPath = i;
1265
1266 /* check for verification tag rules --> see section 8.5 */
1267 if ((initPtr = rbu_findChunk(message->sctp_pdu, len, CHUNK_INIT)) != NULL) {
1268 /* check that there is ONLY init */
1269 initFound = TRUE;
1270 if (lastInitiateTag != 0) {
1271 currentAssociation = NULL;
1272 sctpInstance = NULL;
1273 lastFromPort = 0;
1274 lastDestPort = 0;
1275 lastDestAddress = NULL;
1276 lastFromAddress = NULL;
1277 event_log(VERBOSE, "mdi_receiveMsg: scan found INIT, lastInitiateTag!=0, returning");
1278 return;
1279 }
1280 initChunk = ((SCTP_init_fixed *) & ((SCTP_init *) message->sctp_pdu)->init_fixed);
1281 /* make sure, if you send an ABORT later on (i.e. when peer requests 0 streams),
1282 * you pick the right tag */
1283 lastInitiateTag = ntohl(initChunk->init_tag);
1284 event_logi(VVERBOSE, "Got an INIT CHUNK with initiation-tag %u", lastInitiateTag);
1285
1286 if ((vlptr = (SCTP_vlparam_header*)rbu_scanInitChunkForParameter(initPtr, VLPARAM_HOST_NAME_ADDR)) != NULL) {
1287 sendAbort = TRUE;
1288 }
1289 }
1290 if (rbu_datagramContains(CHUNK_ABORT, chunkArray) == TRUE) {
1291 /* accept my-tag or peers tag, else drop packet */
1292 if ((lastInitiateTag != currentAssociation->tagLocal &&
1293 lastInitiateTag != currentAssociation->tagRemote) || initFound == TRUE) {
1294 currentAssociation = NULL;
1295 sctpInstance = NULL;
1296 lastFromPort = 0;
1297 lastDestPort = 0;
1298 lastDestAddress = NULL;
1299 lastFromAddress = NULL;
1300 return;
1301 }
1302 abortFound = TRUE;
1303 }
1304 if (rbu_datagramContains(CHUNK_SHUTDOWN_COMPLETE, chunkArray) == TRUE) {
1305 /* accept my-tag or peers tag, else drop packet */
1306 /* TODO : make sure that if it is the peer's tag also T-Bit is set */
1307 if ((lastInitiateTag != currentAssociation->tagLocal &&
1308 lastInitiateTag != currentAssociation->tagRemote) || initFound == TRUE) {
1309 currentAssociation = NULL;
1310 sctpInstance = NULL;
1311 lastFromPort = 0;
1312 lastDestPort = 0;
1313 lastDestAddress = NULL;
1314 lastFromAddress = NULL;
1315 return;
1316 }
1317 }
1318 if (rbu_datagramContains(CHUNK_SHUTDOWN_ACK, chunkArray) == TRUE) {
1319 if (initFound == TRUE) {
1320 currentAssociation = NULL;
1321 sctpInstance = NULL;
1322 lastFromPort = 0;
1323 lastDestPort = 0;
1324 lastDestAddress = NULL;
1325 lastFromAddress = NULL;
1326 return;
1327 }
1328 state = sci_getState();
1329 if (state == COOKIE_ECHOED || state == COOKIE_WAIT) {
1330 /* see also section 8.5.E.) treat this like OOTB packet */
1331 event_logi(EXTERNAL_EVENT,
1332 "mdi_receive_message: shutdownAck in state %u, send SHUTDOWN_COMPLETE ! ",
1333 state);
1334 shutdownCompleteCID = ch_makeSimpleChunk(CHUNK_SHUTDOWN_COMPLETE, FLAG_NO_TCB);
1335 bu_put_Ctrl_Chunk(ch_chunkString(shutdownCompleteCID),NULL);
1336 bu_sendAllChunks(NULL);
1337 ch_deleteChunk(shutdownCompleteCID);
1338 currentAssociation = NULL;
1339 sctpInstance = NULL;
1340 lastFromPort = 0;
1341 lastDestPort = 0;
1342 lastDestAddress = NULL;
1343 lastFromAddress = NULL;
1344 return;
1345 }
1346 }
1347 if (rbu_datagramContains(CHUNK_COOKIE_ECHO, chunkArray) == TRUE) {
1348 cookieEchoFound = TRUE;
1349 }
1350
1351 if ((initPtr = rbu_findChunk(message->sctp_pdu, len, CHUNK_INIT_ACK)) != NULL) {
1352
1353 if ((vlptr = (SCTP_vlparam_header*)rbu_scanInitChunkForParameter(initPtr, VLPARAM_HOST_NAME_ADDR)) != NULL) {
1354 /* actually, this does not make sense...anyway: kill assoc, and notify user */
1355 scu_abort(ECC_UNRECOGNIZED_PARAMS, ntohs(vlptr->param_length), (guchar*)vlptr);
1356 currentAssociation = NULL;
1357 sctpInstance = NULL;
1358 lastFromPort = 0;
1359 lastDestPort = 0;
1360 lastDestAddress = NULL;
1361 lastFromAddress = NULL;
1362 return;
1363 }
1364 }
1365
1366 if (!cookieEchoFound && !initFound && !abortFound && lastInitiateTag != currentAssociation->tagLocal) {
1367 event_logii(EXTERNAL_EVENT,
1368 "Tag mismatch in receive DG, received Tag = %u, local Tag = %u -> discarding",
1369 lastInitiateTag, currentAssociation->tagLocal);
1370 currentAssociation = NULL;
1371 sctpInstance = NULL;
1372 lastFromPort = 0;
1373 lastDestPort = 0;
1374 lastDestAddress = NULL;
1375 lastFromAddress = NULL;
1376 return;
1377
1378 }
1379
1380 }
1381
1382 if (sendAbort == TRUE) {
1383 if (sendAbortForOOTB == FALSE) {
1384 event_log(VERBOSE, "mdi_receiveMsg: sendAbortForOOTB==FALSE -> Discarding MESSAGE: not sending ABORT");
1385 lastFromAddress = NULL;
1386 lastDestAddress = NULL;
1387 lastFromPort = 0;
1388 lastDestPort = 0;
1389 currentAssociation = NULL;
1390 sctpInstance = NULL;
1391 /* and discard that packet */
1392 return;
1393 }
1394 /* make and send abort message */
1395 if (currentAssociation == NULL) {
1396 abortCID = ch_makeSimpleChunk(CHUNK_ABORT, FLAG_NO_TCB);
1397 } else {
1398 abortCID = ch_makeSimpleChunk(CHUNK_ABORT, FLAG_NONE);
1399 }
1400 bu_put_Ctrl_Chunk(ch_chunkString(abortCID),NULL);
1401 /* should send it to last address */
1402 bu_unlock_sender(NULL);
1403 bu_sendAllChunks(NULL);
1404 /* free abort chunk */
1405 ch_deleteChunk(abortCID);
1406 /* send an ABORT with peers veri-tag, set T-Bit */
1407 event_log(VERBOSE, "mdi_receiveMsg: sending ABORT with T-Bit");
1408 lastFromAddress = NULL;
1409 lastDestAddress = NULL;
1410 lastFromPort = 0;
1411 lastDestPort = 0;
1412 currentAssociation = NULL;
1413 sctpInstance = NULL;
1414 /* and discard that packet */
1415 return;
1416 }
1417
1418 /* forward DG to bundling */
1419 rbu_rcvDatagram(lastFromPath, message->sctp_pdu, bufferLength - sizeof(SCTP_common_header));
1420
1421 lastInitiateTag = 0;
1422 currentAssociation = NULL;
1423 sctpInstance = NULL;
1424 lastDestAddress = NULL;
1425 lastFromAddress = NULL;
1426 lastFromPath = -1; /* only valid for functions called via mdi_receiveMessage */
1427
1428 } /* end: mdi_receiveMessage */
1429
1430
1431
1432
1433 /*------------------- Functions called by the ULP ------------------------------------------------*/
1434 /*------------------- Prototypes are defined in sctp.h -------------------------------------------*/
1435
1436
1437 /**
1438 * Function returns coded library version as result. This unsigned integer
1439 * contains the major version in the upper 16 bits, and the minor version in
1440 * the lower 16 bits.
1441 * @return library version, or 0 (i.e. zero) as error !
1442 */
sctp_getLibraryVersion(void)1443 unsigned int sctp_getLibraryVersion(void)
1444 {
1445 return (unsigned int)(SCTP_MAJOR_VERSION << 16 | SCTP_MINOR_VERSION);
1446 }
1447
1448 /**
1449 * Function that needs to be called in advance to all library calls.
1450 * It initializes all file descriptors etc. and sets up some variables
1451 * @return 0 for success, 1 for adaptation level error, -9 for already called
1452 * (i.e. the function has already been called), -2 for insufficient rights.
1453 */
sctp_initLibrary(void)1454 int sctp_initLibrary(void)
1455 {
1456 int i, result, sfd = -1, maxMTU=0;
1457 /* initialize the output of event/error-log functions */
1458 ENTER_LIBRARY("sctp_initLibrary");
1459 if (sctpLibraryInitialized == TRUE) {
1460 LEAVE_LIBRARY("sctp_initLibrary");
1461 return SCTP_LIBRARY_ALREADY_INITIALIZED;
1462 }
1463 read_tracelevels();
1464
1465 #if defined(HAVE_GETEUID)
1466 /* check privileges. Must be root or setuid-root for now ! */
1467 if (geteuid() != 0) {
1468 error_log(ERROR_MAJOR, "You must be root to use the SCTPLIB-functions (or make your program SETUID-root !).");
1469 LEAVE_LIBRARY("sctp_initLibrary");
1470 return SCTP_INSUFFICIENT_PRIVILEGES;
1471 }
1472 #endif
1473
1474
1475 event_log(EXTERNAL_EVENT, "sctp_initLibrary called");
1476 result = adl_init_adaptation_layer(&myRWND);
1477
1478 if (result != 0) {
1479 LEAVE_LIBRARY("sctp_initLibrary");
1480 return SCTP_SPECIFIC_FUNCTION_ERROR;
1481 }
1482
1483 /* Create list for associations - old, used to be here - now removed ! */
1484
1485 /* initialize ports seized -- see comments above !!! */
1486 for (i = 0; i < 0x10000; i++) portsSeized[i] = 0;
1487 numberOfSeizedPorts = 0x00000000;
1488
1489 /* initialize bundling, i.e. the common buffer for sending chunks when no association
1490 exists. */
1491 bu_init_bundling();
1492
1493 /* this block is to be executed only once for the lifetime of sctp-software */
1494 key_operation(KEY_INIT);
1495
1496 /* we might need to replace this socket !*/
1497 sfd = adl_get_sctpv4_socket();
1498
1499 if (adl_gatherLocalAddresses(&myAddressList, (int *)&myNumberOfAddresses,sfd,TRUE,&maxMTU,flag_Default) == FALSE) {
1500 LEAVE_LIBRARY("sctp_initLibrary");
1501 return SCTP_SPECIFIC_FUNCTION_ERROR;
1502 }
1503
1504 sctpLibraryInitialized = TRUE;
1505 LEAVE_LIBRARY("sctp_initLibrary");
1506 return SCTP_SUCCESS;
1507 }
1508
1509
mdi_updateMyAddressList(void)1510 int mdi_updateMyAddressList(void)
1511 {
1512 int sfd;
1513 int maxMTU;
1514
1515 /* we might need to replace this socket !*/
1516 sfd = adl_get_sctpv4_socket();
1517 free(myAddressList);
1518
1519 if (adl_gatherLocalAddresses(&myAddressList, (int *)&myNumberOfAddresses,sfd,TRUE,&maxMTU,flag_Default) == FALSE) {
1520 return SCTP_SPECIFIC_FUNCTION_ERROR;
1521 }
1522
1523 return SCTP_SUCCESS;
1524 }
1525
mdi_addressListContainsLocalhost(unsigned int noOfAddresses,union sockunion * addressList)1526 gboolean mdi_addressListContainsLocalhost(unsigned int noOfAddresses,
1527 union sockunion* addressList)
1528 {
1529 gboolean result = FALSE;
1530 unsigned int counter;
1531 unsigned int ii;
1532 for (ii=0; ii< noOfAddresses; ii++) {
1533 switch(sockunion_family(&(addressList[ii]))) {
1534 case AF_INET:
1535 if (ntohl(sock2ip(&(addressList[ii]))) == INADDR_LOOPBACK) {
1536 event_logi(VVERBOSE, "Found IPv4 loopback address ! Num: %u", noOfAddresses);
1537 result = TRUE;
1538 }
1539 break;
1540 #ifdef HAVE_IPV6
1541 case AF_INET6:
1542 #if defined (LINUX)
1543 if ( IN6_IS_ADDR_LOOPBACK( sock2ip6(&(addressList[ii])))) {
1544 #else
1545 if ( IN6_IS_ADDR_LOOPBACK(&sock2ip6addr(&(addressList[ii]))) ) {
1546 #endif
1547 event_logi(VVERBOSE, "Found IPv6 loopback address ! Num: %u", noOfAddresses);
1548 result = TRUE;
1549 }
1550 break;
1551 #endif
1552 default:
1553 break;
1554 }
1555 if (sctpInstance) {
1556 if (sctpInstance->noOfLocalAddresses > 0){
1557 for (counter = 0; counter < sctpInstance->noOfLocalAddresses; counter++) {
1558 if (adl_equal_address(&(addressList[ii]), &(sctpInstance->localAddressList[counter])) == TRUE) result =
1559 TRUE; }
1560 } else {
1561 if (sctpInstance->has_INADDR_ANY_set) {
1562 for (counter = 0; counter < myNumberOfAddresses; counter++) {
1563 if (sockunion_family(&myAddressList[counter]) == AF_INET) {
1564 if (adl_equal_address(&(addressList[ii]), &(myAddressList[counter])) == TRUE) result = TRUE;
1565 }
1566 }
1567 }
1568 if (sctpInstance->has_IN6ADDR_ANY_set) {
1569 for (counter = 0; counter < myNumberOfAddresses; counter++) {
1570 if (adl_equal_address(&(addressList[ii]), &(myAddressList[counter])) == TRUE) result = TRUE;
1571 }
1572 }
1573 }
1574 }
1575 }
1576 event_logi(VVERBOSE, "Found loopback address returns %s", (result == TRUE)?"TRUE":"FALSE");
1577
1578 return result;
1579 }
1580
1581 gboolean mdi_checkForCorrectAddress(union sockunion* su)
1582 {
1583 gboolean found = FALSE;
1584 unsigned int counter;
1585
1586 /* make sure, if IN(6)ADDR_ANY is specified, it is the only specified address */
1587 switch(sockunion_family(su)) {
1588 case AF_INET:
1589 if (sock2ip(su) == INADDR_ANY) return FALSE;
1590 break;
1591 #ifdef HAVE_IPV6
1592 case AF_INET6:
1593 #if defined (LINUX)
1594 if (IN6_IS_ADDR_UNSPECIFIED(sock2ip6(su))) return FALSE;
1595 #else
1596 if (IN6_IS_ADDR_UNSPECIFIED(&sock2ip6addr(su))) return FALSE;
1597 #endif
1598 break;
1599 #endif
1600 default:
1601 return FALSE;
1602 break;
1603 }
1604
1605 for (counter = 0; counter < myNumberOfAddresses; counter++) {
1606 if (adl_equal_address(su, &(myAddressList[counter])) == TRUE) found = TRUE;
1607 }
1608 return found;
1609 }
1610
1611 /*
1612 static void printAssocList()
1613 {
1614 Association* assoc;
1615 GList* iterator;
1616 iterator = g_list_first(AssociationList);
1617 puts("AssocList:");
1618 while(iterator) {
1619 assoc = (Association *)iterator->data;
1620 printf(" #%d: I=%u, deleted=%d\n", assoc->assocId, assoc->sctpInstance->sctpInstanceName, assoc->deleted);
1621 iterator = g_list_next(iterator);
1622 }
1623 }
1624 */
1625
1626 /**
1627 * sctp_registerInstance is called to initialize one SCTP-instance.
1628 * Each Adaption-Layer of the ULP must create its own SCTP-instance, and
1629 * define and register appropriate callback functions.
1630 * An SCTP-instance may define an own port, or zero here ! Servers and clients
1631 * that care for their source port must chose a port, clients that do not really
1632 * care which source port they use, chose ZERO, and have the implementation chose
1633 * a free source port.
1634 *
1635 * @param port wellknown port of this sctp-instance
1636 * @param noOfLocalAddresses number of local addresses
1637 * @param localAddressList local address list (pointer to a string-array)
1638 * @param ULPcallbackFunctions call back functions for primitives passed from sctp to ULP
1639 * @return instance name of this SCTP-instance or 0 in case of errors, or error code
1640 */
1641 int
1642 sctp_registerInstance(unsigned short port,
1643 unsigned short noOfInStreams,
1644 unsigned short noOfOutStreams,
1645 unsigned int noOfLocalAddresses,
1646 unsigned char localAddressList[][SCTP_MAX_IP_LEN],
1647 SCTP_ulpCallbacks ULPcallbackFunctions)
1648 {
1649
1650 unsigned int i;
1651 int adl_rscb_code;
1652 union sockunion su;
1653 gboolean with_ipv4 = FALSE;
1654 unsigned short result;
1655 GList* list_result = NULL;
1656
1657 #ifdef HAVE_IPV6
1658 gboolean with_ipv6 = FALSE;
1659 #endif
1660 SCTP_instance *old_Instance = sctpInstance;
1661 Association *old_assoc = currentAssociation;
1662
1663 ENTER_LIBRARY("sctp_registerInstance");
1664 ZERO_CHECK_LIBRARY;
1665
1666 event_log(EXTERNAL_EVENT, "sctp_registerInstance called");
1667
1668 if ((noOfInStreams==0) || (noOfOutStreams == 0) ||
1669 (noOfLocalAddresses == 0) || (localAddressList == NULL)) {
1670 error_log(ERROR_MAJOR, "Parameter Problem in sctp_registerInstance - Error !");
1671 sctpInstance = old_Instance;
1672 currentAssociation = old_assoc;
1673 LEAVE_LIBRARY("sctp_registerInstance");
1674 return SCTP_PARAMETER_PROBLEM;
1675 }
1676
1677 if(port == 0) {
1678 port = seizePort();
1679 }
1680 else {
1681 port = allocatePort(port);
1682 }
1683 if(port == 0) {
1684 sctpInstance = old_Instance;
1685 currentAssociation = old_assoc;
1686 error_log(ERROR_MAJOR, "User gave incorrect address !");
1687 LEAVE_LIBRARY("sctp_registerInstance");
1688 return SCTP_WRONG_ADDRESS;
1689 }
1690
1691
1692 for (i=0; i< noOfLocalAddresses; i++) {
1693 if (adl_str2sockunion((localAddressList[i]), &su) < 0) {
1694 error_logi(ERROR_MAJOR, "Address Error in sctp_registerInstance(%s)", (localAddressList[i]));
1695 releasePort(port);
1696 sctpInstance = old_Instance;
1697 currentAssociation = old_assoc;
1698 LEAVE_LIBRARY("sctp_registerInstance");
1699 return SCTP_PARAMETER_PROBLEM;
1700 } else {
1701 if (su.sa.sa_family == AF_INET) with_ipv4 = TRUE;
1702
1703 #ifdef HAVE_IPV6
1704 if (su.sa.sa_family == AF_INET6) with_ipv6 = TRUE;
1705 #endif
1706 }
1707 }
1708
1709 event_logi(VERBOSE, "sctp_registerInstance : with_ipv4 : %s ",(with_ipv4==TRUE)?"TRUE":"FALSE" );
1710 /* if not IPv6 callback must be registered too ! */
1711 #ifdef HAVE_IPV6
1712 event_logi(VERBOSE, "sctp_registerInstance : with_ipv6: %s ",(with_ipv6==TRUE)?"TRUE":"FALSE" );
1713 #endif
1714
1715 if ((with_ipv4 != TRUE)
1716 #ifdef HAVE_IPV6
1717 && (with_ipv6 != TRUE)
1718 #endif
1719 ) {
1720 error_log(ERROR_MAJOR, "No valid address in sctp_registerInstance()");
1721 releasePort(port);
1722 sctpInstance = old_Instance;
1723 currentAssociation = old_assoc;
1724 LEAVE_LIBRARY("sctp_registerInstance");
1725 return SCTP_PARAMETER_PROBLEM;
1726 }
1727
1728 i = mdi_updateMyAddressList();
1729 if (i != SCTP_SUCCESS) {
1730 error_log(ERROR_MAJOR, "Could not update my local addresses...");
1731 releasePort(port);
1732 sctpInstance = old_Instance;
1733 currentAssociation = old_assoc;
1734 LEAVE_LIBRARY("sctp_registerInstance");
1735 return SCTP_UNSPECIFIED_ERROR;
1736 }
1737
1738 sctpInstance = (SCTP_instance *) malloc(sizeof(SCTP_instance));
1739 if (!sctpInstance) {
1740 error_log_sys(ERROR_MAJOR, (short)errno);
1741 releasePort(port);
1742 sctpInstance = old_Instance;
1743 currentAssociation = old_assoc;
1744 LEAVE_LIBRARY("sctp_registerInstance");
1745 return SCTP_OUT_OF_RESOURCES;
1746 }
1747
1748 sctpInstance->localPort = port;
1749 sctpInstance->noOfInStreams = noOfInStreams;
1750 sctpInstance->noOfOutStreams = noOfOutStreams;
1751 sctpInstance->has_INADDR_ANY_set = FALSE;
1752 sctpInstance->has_IN6ADDR_ANY_set = FALSE;
1753 sctpInstance->uses_IPv4 = FALSE;
1754 sctpInstance->uses_IPv6 = TRUE;
1755 sctpInstance->supportsPRSCTP = librarySupportsPRSCTP;
1756 sctpInstance->supportsADDIP = supportADDIP;
1757
1758
1759 if (noOfLocalAddresses == 1) {
1760 adl_str2sockunion((localAddressList[0]), &su);
1761 switch(sockunion_family(&su)) {
1762 case AF_INET:
1763 if (sock2ip(&su) == INADDR_ANY){
1764 sctpInstance->has_INADDR_ANY_set = TRUE;
1765 with_ipv4 = TRUE;
1766 }
1767 break;
1768 #ifdef HAVE_IPV6
1769 case AF_INET6:
1770 #if defined (LINUX)
1771 if (IN6_IS_ADDR_UNSPECIFIED(sock2ip6(&su))) {
1772 #else
1773 if (IN6_IS_ADDR_UNSPECIFIED(&sock2ip6addr(&su))) {
1774 #endif
1775 with_ipv4 = TRUE;
1776 with_ipv6 = TRUE;
1777 sctpInstance->has_IN6ADDR_ANY_set = TRUE;
1778 }
1779 break;
1780 #endif
1781 default:
1782 releasePort(port);
1783 free(sctpInstance);
1784 sctpInstance = old_Instance;
1785 currentAssociation = old_assoc;
1786 error_log(ERROR_MAJOR, "Program Error -> Returning error !");
1787 LEAVE_LIBRARY("sctp_registerInstance");
1788 return SCTP_PARAMETER_PROBLEM;
1789 break;
1790 }
1791 }
1792
1793 sctpInstance->supportedAddressTypes = 0;
1794 if (with_ipv4) sctpInstance->supportedAddressTypes |= SUPPORT_ADDRESS_TYPE_IPV4;
1795 #ifdef HAVE_IPV6
1796 if (with_ipv6) sctpInstance->supportedAddressTypes |= SUPPORT_ADDRESS_TYPE_IPV6;
1797 #endif
1798
1799 if (sctpInstance->has_INADDR_ANY_set == FALSE && sctpInstance->has_IN6ADDR_ANY_set == FALSE) {
1800
1801 sctpInstance->localAddressList =
1802 (union sockunion *) malloc(noOfLocalAddresses * sizeof(union sockunion));
1803 for (i=0; i< noOfLocalAddresses; i++) {
1804 adl_str2sockunion(localAddressList[i], &(sctpInstance->localAddressList[i]));
1805 if (mdi_checkForCorrectAddress(&(sctpInstance->localAddressList[i])) == FALSE){
1806 releasePort(port);
1807 free (sctpInstance->localAddressList);
1808 free(sctpInstance);
1809 sctpInstance = old_Instance;
1810 currentAssociation = old_assoc;
1811 error_log(ERROR_MAJOR, "User gave incorrect address !");
1812 LEAVE_LIBRARY("sctp_registerInstance");
1813 return SCTP_WRONG_ADDRESS;
1814 }
1815 }
1816
1817 sctpInstance->noOfLocalAddresses = noOfLocalAddresses;
1818 } else {
1819 sctpInstance->localAddressList = NULL;
1820 sctpInstance->noOfLocalAddresses = 0;
1821 }
1822
1823
1824 list_result = g_list_find_custom(InstanceList, sctpInstance, &CheckForAddressInInstance);
1825
1826 if (list_result) {
1827 releasePort(port);
1828 free(sctpInstance->localAddressList);
1829 free(sctpInstance);
1830 sctpInstance = old_Instance;
1831 currentAssociation = old_assoc;
1832 error_log(ERROR_MAJOR, "Instance already existed ! Returning error !");
1833 LEAVE_LIBRARY("sctp_registerInstance");
1834 return 0;
1835 }
1836
1837 #ifdef HAVE_IPV6
1838 if (with_ipv6 && ipv6_sctp_socket==0) {
1839 ipv6_sctp_socket = adl_get_sctpv6_socket();
1840 if (!ipv6_sctp_socket)
1841 error_log(ERROR_FATAL, "IPv6 socket creation failed");
1842 /*
1843 * here some operating system specialties may kick in (i.e. opening only ONE
1844 * socket MIGHT be enough, provided IPv6 socket implicitly reveives IPv4 packets, too
1845 */
1846 adl_rscb_code = adl_register_socket_cb(ipv6_sctp_socket,&mdi_dummy_callback);
1847 if (!adl_rscb_code)
1848 error_log(ERROR_FATAL, "register ipv6 socket call back function failed");
1849 }
1850 if (with_ipv6 == TRUE) {
1851 ipv6_users++;
1852 sctpInstance->uses_IPv6 = TRUE;
1853 } else {
1854 sctpInstance->uses_IPv6 = FALSE;
1855 }
1856 #endif
1857 if (with_ipv4 && sctp_socket==0) {
1858 sctp_socket = adl_get_sctpv4_socket();
1859 if (!sctp_socket)
1860 error_log(ERROR_FATAL, "IPv4 socket creation failed");
1861
1862 adl_rscb_code = adl_register_socket_cb(sctp_socket,&mdi_dummy_callback);
1863 if (!adl_rscb_code)
1864 error_log(ERROR_FATAL, "registration of IPv4 socket call back function failed");
1865 }
1866 if (with_ipv4 == TRUE) {
1867 ipv4_users++;
1868 sctpInstance->uses_IPv4 = TRUE;
1869 } else {
1870 sctpInstance->uses_IPv4 = FALSE;
1871 }
1872
1873
1874 sctpInstance->sctpInstanceName = mdi_getUnusedInstanceName();
1875 if(sctpInstance->sctpInstanceName == 0) {
1876 releasePort(port);
1877 sctpInstance = old_Instance;
1878 currentAssociation = old_assoc;
1879 LEAVE_LIBRARY("sctp_registerInstance");
1880 return SCTP_OUT_OF_RESOURCES;
1881 }
1882
1883 sctpInstance->ULPcallbackFunctions = ULPcallbackFunctions;
1884
1885 sctpInstance->default_rtoInitial = RTO_INITIAL;
1886 sctpInstance->default_validCookieLife = VALID_COOKIE_LIFE_TIME;
1887 sctpInstance->default_assocMaxRetransmits = ASSOCIATION_MAX_RETRANS;
1888 sctpInstance->default_pathMaxRetransmits = MAX_PATH_RETRANSMITS ;
1889 sctpInstance->default_maxInitRetransmits = MAX_INIT_RETRANSMITS;
1890 /* using the static variable defined after initialization of the adaptation layer */
1891 sctpInstance->default_myRwnd = myRWND/2;
1892 sctpInstance->default_delay = SACK_DELAY;
1893 sctpInstance->default_ipTos = IPTOS_DEFAULT;
1894 sctpInstance->default_rtoMin = RTO_MIN;
1895 sctpInstance->default_rtoMax = RTO_MAX;
1896 sctpInstance->default_maxSendQueue = DEFAULT_MAX_SENDQUEUE;
1897 sctpInstance->default_maxRecvQueue = DEFAULT_MAX_RECVQUEUE;
1898 sctpInstance->default_maxBurst = DEFAULT_MAX_BURST;
1899
1900 InstanceList = g_list_insert_sorted(InstanceList, sctpInstance, &CompareInstanceNames);
1901
1902 result = sctpInstance->sctpInstanceName;
1903
1904 sctpInstance = old_Instance;
1905 currentAssociation = old_assoc;
1906 LEAVE_LIBRARY("sctp_registerInstance");
1907 return (int)result;
1908
1909 } /* end: sctp_registerInstance */
1910
1911
1912
1913 int sctp_unregisterInstance(unsigned short instance_name)
1914 {
1915 /* Look through the instance list, and delete instance, when
1916 found, else return error. */
1917 Association* assoc;
1918 GList* assocIterator = NULL;
1919 SCTP_instance temporary;
1920 SCTP_instance* instance;
1921 guint32 fds;
1922 GList* result = NULL;
1923 gboolean with_ipv4=FALSE;
1924 #ifdef HAVE_IPV6
1925 gboolean with_ipv6=FALSE;
1926 #endif
1927
1928 ENTER_LIBRARY("sctp_unregisterInstance");
1929
1930 CHECK_LIBRARY;
1931
1932 event_logi(INTERNAL_EVENT_0, "Removing SCTP Instance %u from list", instance_name);
1933
1934 temporary.sctpInstanceName = instance_name;
1935 result = g_list_find_custom(InstanceList, &temporary, &CompareInstanceNames);
1936 if (result != NULL) {
1937 instance = (SCTP_instance*)result->data;
1938 with_ipv4 = instance->uses_IPv4;
1939 #ifdef HAVE_IPV6
1940 with_ipv6 = instance->uses_IPv6;
1941 #endif
1942 event_logi(INTERNAL_EVENT_0, "sctp_unregisterInstance: SCTP Instance %u found !!!", instance_name);
1943 #ifdef HAVE_IPV6
1944 event_logi(VERBOSE, "sctp_unregisterInstance : with_ipv6: %s ",(with_ipv6==TRUE)?"TRUE":"FALSE" );
1945 if (with_ipv6 == TRUE) ipv6_users--;
1946 event_logi(VERBOSE, "sctp_unregisterInstance : ipv6_users: %u ",ipv6_users);
1947 #endif
1948 if (with_ipv4 == TRUE) ipv4_users--;
1949 event_logi(VERBOSE, "sctp_unregisterInstance : with_ipv4: %s ",(with_ipv4==TRUE)?"TRUE":"FALSE" );
1950 event_logi(VERBOSE, "sctp_unregisterInstance : ipv4_users: %u ",ipv4_users);
1951
1952 assocIterator = g_list_first(AssociationList);
1953 while(assocIterator) {
1954 assoc = (Association*)assocIterator->data;
1955 if(assoc->sctpInstance == instance) {
1956 event_logi(ERROR_MINOR, "sctp_unregisterInstance : instance still used by assoc %u !!!",
1957 assoc->assocId);
1958 return SCTP_INSTANCE_IN_USE;
1959 }
1960 assocIterator = g_list_next(assocIterator);
1961 }
1962
1963 if (sctp_socket != 0 && ipv4_users == 0) {
1964 fds = adl_remove_poll_fd(sctp_socket);
1965 event_logi(VVERBOSE, "sctp_unregisterInstance : Removed IPv4 cb, registered FDs: %u ",fds);
1966 /* if there are no ipv4_users, deregister callback for ipv4-socket, if it was registered ! */
1967 sctp_socket = 0;
1968 }
1969
1970 #ifdef HAVE_IPV6
1971 if (ipv6_sctp_socket != 0 && ipv6_users == 0) {
1972 fds = adl_remove_poll_fd(ipv6_sctp_socket);
1973 /* if there are no ipv6_users, deregister callback for ipv6-socket, if it was registered ! */
1974 event_logi(VVERBOSE, "sctp_unregisterInstance : Removed IPv4 cb, registered FDs: %u ",fds);
1975 ipv6_sctp_socket = 0;
1976 }
1977 #endif
1978
1979 if (instance->has_INADDR_ANY_set == FALSE) {
1980 event_log(VVERBOSE, "sctp_unregisterInstance : INADDR_ANY == FALSE");
1981 }
1982 if (instance->has_INADDR_ANY_set == TRUE) {
1983 event_log(VVERBOSE, "sctp_unregisterInstance : INADDR_ANY == TRUE");
1984 }
1985 #ifdef HAVE_IPV6
1986 if (instance->has_IN6ADDR_ANY_set == FALSE)
1987 event_log(VVERBOSE, "sctp_unregisterInstance : IN6ADDR_ANY == FALSE");
1988 #endif
1989 if (instance->noOfLocalAddresses > 0) {
1990 free(instance->localAddressList);
1991 }
1992 event_log(VVERBOSE, "sctp_unregisterInstance : freeing instance ");
1993 releasePort(instance->localPort);
1994 free(instance);
1995 InstanceList = g_list_remove(InstanceList, result->data);
1996 LEAVE_LIBRARY("sctp_unregisterInstance");
1997 return SCTP_SUCCESS;
1998 } else {
1999 event_logi(INTERNAL_EVENT_0, "SCTP Instance %u not in list", instance_name);
2000 }
2001 LEAVE_LIBRARY("sctp_unregisterInstance");
2002 return SCTP_INSTANCE_NOT_FOUND;
2003
2004 }
2005
2006
2007 /**
2008 * This function should be called AFTER an association has indicated a
2009 * COMMUNICATION_LOST or a SHUTDOWN_COMPLETE, and the upper layer has
2010 * retrieved all data it is interested in (possibly using the currently
2011 * not implemented functions sctp_receive_unsent() or sctp_receive_unacked())
2012 * it really removes all data belonging to the association, and removes the
2013 * association instance from the list, on explicit upper layer instruction !
2014 * @param associationID the association ID of the assoc that shall be removed
2015 * @return error_code 0 for success, 1 if assoc is already gone, -1 if assocs
2016 * deleted flag is not set (then assoc should be in a state different from CLOSED)
2017 */
2018 int sctp_deleteAssociation(unsigned int associationID)
2019 {
2020 Association *assocFindP;
2021 GList* result = NULL;
2022
2023 ENTER_LIBRARY("sctp_deleteAssociation");
2024
2025 CHECK_LIBRARY;
2026
2027 event_logi(INTERNAL_EVENT_0, "sctp_deleteAssociation: getting assoc %08x from list", associationID);
2028
2029 tmpAssoc.assocId = associationID;
2030 tmpAssoc.deleted = FALSE;
2031 assocFindP = &tmpAssoc;
2032 currentAssociation = NULL;
2033
2034 result = g_list_find_custom(AssociationList, assocFindP, &compareAssociationIDs);
2035 if (result != NULL) {
2036 currentAssociation = (Association *)result->data;
2037 if (!currentAssociation->deleted) {
2038 currentAssociation = NULL;
2039 error_log(ERROR_MAJOR, "Deleted-Flag not set, returning from sctp_deleteAssociation !");
2040 LEAVE_LIBRARY("sctp_deleteAssociation");
2041 return SCTP_SPECIFIC_FUNCTION_ERROR;
2042 }
2043 /* remove the association from the list */
2044 AssociationList = g_list_remove(AssociationList, currentAssociation);
2045 event_log(INTERNAL_EVENT_0, "sctp_deleteAssociation: Deleted Association from list");
2046 /* free all association data */
2047 mdi_removeAssociationData(currentAssociation);
2048 currentAssociation = NULL;
2049 LEAVE_LIBRARY("sctp_deleteAssociation");
2050 return SCTP_SUCCESS;
2051 } else {
2052 event_logi(INTERNAL_EVENT_0, "association %08x not in list", associationID);
2053 LEAVE_LIBRARY("sctp_deleteAssociation");
2054 return SCTP_ASSOC_NOT_FOUND;
2055 }
2056 /* should not be reached */
2057 LEAVE_LIBRARY("sctp_deleteAssociation");
2058 return SCTP_SUCCESS;
2059 }
2060
2061
2062 /**
2063 * This function is called to setup an association.
2064 * The ULP must specify the SCTP-instance to which this association belongs to.
2065 * @param SCTP_InstanceName the SCTP instance this association belongs to.
2066 * if the local port of this SCTP instance is zero, we will get a port num,
2067 else we will use the one from the SCTP instance !
2068 * @param noOfOutStreams number of output streams the ULP would like to have
2069 * @param destinationAddress destination address
2070 * @param destinationPort destination port
2071 * @param ulp_data pointer to an ULP data structure, will be passed with callbacks !
2072 * @return association ID of this association, 0 in case of failures
2073 */
2074 unsigned int sctp_associatex(unsigned int SCTP_InstanceName,
2075 unsigned short noOfOutStreams,
2076 unsigned char destinationAddresses[SCTP_MAX_NUM_ADDRESSES][SCTP_MAX_IP_LEN],
2077 unsigned int noOfDestinationAddresses,
2078 unsigned int maxSimultaneousInits,
2079 unsigned short destinationPort,
2080 void* ulp_data)
2081
2082 {
2083 unsigned int assocID, count;
2084 unsigned short zlocalPort;
2085 union sockunion dest_su[SCTP_MAX_NUM_ADDRESSES];
2086 gboolean withPRSCTP;
2087 AddressScopingFlags filterFlags = flag_Default;
2088 SCTP_instance temporary;
2089 GList* result = NULL;
2090
2091 SCTP_instance *old_Instance = sctpInstance;
2092 Association *old_assoc = currentAssociation;
2093
2094 ENTER_LIBRARY("sctp_associatex");
2095
2096 ZERO_CHECK_LIBRARY;
2097
2098 if (destinationPort == 0) {
2099 error_log(ERROR_MAJOR, "sctp_associate: destination port is zero....this is not allowed");
2100 sctpInstance = old_Instance;
2101 currentAssociation = old_assoc;
2102 LEAVE_LIBRARY("sctp_associate");
2103 return 0;
2104 }
2105
2106 for (count = 0; count < noOfDestinationAddresses; count++) {
2107 if (adl_str2sockunion(destinationAddresses[count], &dest_su[count]) < 0) {
2108 error_log(ERROR_MAJOR, "sctp_associate: destination adress not good !");
2109 sctpInstance = old_Instance;
2110 currentAssociation = old_assoc;
2111 LEAVE_LIBRARY("sctp_associate");
2112 return 0;
2113 } else if(adl_filterInetAddress(&dest_su[count], filterFlags) == FALSE) {
2114 error_log(ERROR_MAJOR, "sctp_associate: destination adress not good !");
2115 sctpInstance = old_Instance;
2116 currentAssociation = old_assoc;
2117 LEAVE_LIBRARY("sctp_associate");
2118 return 0;
2119 }
2120 }
2121
2122 event_log(EXTERNAL_EVENT, "sctp_associatex called");
2123 event_logi(VERBOSE, "Looking for SCTP Instance %u in the list", SCTP_InstanceName);
2124
2125 temporary.sctpInstanceName = SCTP_InstanceName;
2126 result = g_list_find_custom(InstanceList, &temporary, &CompareInstanceNames);
2127 if (result == NULL) {
2128 error_log(ERROR_MAJOR, "sctp_associate: SCTP instance not in the list !!!");
2129 sctpInstance = old_Instance;
2130 currentAssociation = old_assoc;
2131 LEAVE_LIBRARY("sctp_associate");
2132 return 0;
2133 }
2134 sctpInstance = (SCTP_instance*)result->data;
2135
2136 if (((SCTP_instance*)result->data)->localPort == 0)
2137 zlocalPort = seizePort();
2138 else
2139 zlocalPort = ((SCTP_instance*)result->data)->localPort;
2140
2141 event_logi(VERBOSE, "Chose local port %u for associate !", zlocalPort);
2142
2143 withPRSCTP = librarySupportsPRSCTP;
2144
2145 /* Create new association */
2146 if (mdi_newAssociation(sctpInstance,
2147 zlocalPort, /* local client port */
2148 destinationPort, /* remote server port */
2149 mdi_generateTag(),
2150 0,
2151 (short)noOfDestinationAddresses,
2152 dest_su)) {
2153 error_log(ERROR_MAJOR, "Creation of association failed");
2154 sctpInstance = old_Instance;
2155 currentAssociation = old_assoc;
2156 LEAVE_LIBRARY("sctp_associate");
2157 return 0;
2158 }
2159 currentAssociation->ulp_dataptr = ulp_data;
2160
2161 /* call associate at SCTP-control */
2162 scu_associate(noOfOutStreams,
2163 ((SCTP_instance*)result->data)->noOfInStreams,
2164 dest_su,
2165 noOfDestinationAddresses,
2166 withPRSCTP);
2167
2168 assocID = currentAssociation->assocId;
2169
2170 sctpInstance = old_Instance;
2171 currentAssociation = old_assoc;
2172 LEAVE_LIBRARY("sctp_associate");
2173 return assocID;
2174
2175 } /* end: sctp_associatex */
2176
2177
2178 unsigned int
2179 sctp_associate(unsigned int SCTP_InstanceName,
2180 unsigned short noOfOutStreams,
2181 unsigned char destinationAddress[SCTP_MAX_IP_LEN],
2182 unsigned short destinationPort,
2183 void* ulp_data)
2184 {
2185 unsigned char dAddress[1][SCTP_MAX_IP_LEN];
2186
2187 event_log(EXTERNAL_EVENT, "sctp_associate called");
2188 memcpy(dAddress, destinationAddress, SCTP_MAX_IP_LEN);
2189
2190 return sctp_associatex(SCTP_InstanceName,
2191 noOfOutStreams,
2192 dAddress,
2193 1,
2194 1,
2195 destinationPort,
2196 ulp_data);
2197
2198
2199 }
2200
2201 /**
2202 * sctp_shutdown initiates the shutdown of the specified association.
2203 * @param associationID the ID of the addressed association.
2204 * @return 0 for success, 1 for error (assoc. does not exist)
2205 */
2206 int sctp_shutdown(unsigned int associationID)
2207 {
2208 SCTP_instance *old_Instance = sctpInstance;
2209 Association *old_assoc = currentAssociation;
2210
2211 ENTER_LIBRARY("sctp_shutdown");
2212
2213 CHECK_LIBRARY;
2214
2215 /* Retrieve association from list */
2216 currentAssociation = retrieveAssociation(associationID);
2217
2218 if (currentAssociation != NULL) {
2219 sctpInstance = currentAssociation->sctpInstance;
2220 /* Forward shutdown to the addressed association */
2221 scu_shutdown();
2222 } else {
2223 event_log(VERBOSE, "sctp_shutdown: addressed association does not exist");
2224 sctpInstance = old_Instance;
2225 currentAssociation = old_assoc;
2226 LEAVE_LIBRARY("sctp_shutdown");
2227 return SCTP_ASSOC_NOT_FOUND;
2228 }
2229
2230 sctpInstance = old_Instance;
2231 currentAssociation = old_assoc;
2232 LEAVE_LIBRARY("sctp_shutdown");
2233 return SCTP_SUCCESS;
2234
2235 } /* end: sctp_shutdown */
2236
2237
2238
2239 /**
2240 * sctp_abort initiates the abort of the specified association.
2241 * @param associationID the ID of the addressed association.
2242 * @return 0 for success, 1 for error (assoc. does not exist)
2243 */
2244 int sctp_abort(unsigned int associationID)
2245 {
2246 SCTP_instance *old_Instance = sctpInstance;
2247 Association *old_assoc = currentAssociation;
2248 /* Retrieve association from list */
2249 ENTER_LIBRARY("sctp_abort");
2250
2251 CHECK_LIBRARY;
2252
2253 currentAssociation = retrieveAssociation(associationID);
2254
2255 if (currentAssociation != NULL) {
2256 sctpInstance = currentAssociation->sctpInstance;
2257 /* Forward shutdown to the addressed association */
2258 scu_abort(ECC_USER_INITIATED_ABORT, 0, NULL);
2259 } else {
2260 error_log(ERROR_MAJOR, "sctp_abort: addressed association does not exist");
2261 sctpInstance = old_Instance;
2262 currentAssociation = old_assoc;
2263 LEAVE_LIBRARY("sctp_abort");
2264 return SCTP_ASSOC_NOT_FOUND;
2265 }
2266
2267 sctpInstance = old_Instance;
2268 currentAssociation = old_assoc;
2269 LEAVE_LIBRARY("sctp_abort");
2270 return SCTP_SUCCESS;
2271
2272 } /* end: sctp_abort */
2273
2274
2275
2276 /**
2277 * sctp_send is used by the ULP to send data chunks.
2278 *
2279 * @param associationID the ID of the addressed association.
2280 * @param streamID identifies the stream on which the chunk is sent.
2281 * @param buffer chunk data.
2282 * @param length length of chunk data.
2283 * @param protocolId the payload protocol identifier
2284 * @param path_id index of destination address, if different from primary pat, negative for primary
2285 * @param context ULP context, i.e. a pointer that will may be retunred with certain callbacks.
2286 (in case of send errors).
2287 * @param lifetime maximum time of chunk in send queue in msecs, 0 for infinite
2288 * @param unorderedDelivery chunk is delivered to peer without resequencing, if true (==1), else ordered (==0).
2289 * @param dontBundle chunk must not be bundled with other data chunks.
2290 * boolean, 0==normal bundling, 1==do not bundle message
2291 * @return error code -1 for send error, 1 for association error, 0 if successful
2292 */
2293 int sctp_send_private(unsigned int associationID, unsigned short streamID,
2294 unsigned char *buffer, unsigned int length, unsigned int protocolId, short path_id,
2295 void* context, /* optional (=SCTP_NO_CONTEXT=NULL if none) */
2296 unsigned int lifetime, /* optional (zero -> infinite) */
2297 int unorderedDelivery, /* boolean, 0==ordered, 1==unordered */
2298 int dontBundle) /* boolean, 0==normal bundling, 1==do not bundle message */
2299 {
2300 int result = SCTP_SUCCESS;
2301 SCTP_instance *old_Instance = sctpInstance;
2302 Association *old_assoc = currentAssociation;
2303 ENTER_LIBRARY("sctp_send");
2304
2305 CHECK_LIBRARY;
2306
2307 /* Retrieve association from list */
2308 currentAssociation = retrieveAssociation(associationID);
2309
2310 if (currentAssociation != NULL) {
2311 sctpInstance = currentAssociation->sctpInstance;
2312
2313 if ((path_id >= -1) && (path_id < currentAssociation->noOfNetworks)) {
2314 event_log(INTERNAL_EVENT_1, "sctp_send: sending chunk");
2315 /* Forward chunk to the addressed association */
2316 result = se_ulpsend(streamID, buffer, length, protocolId, path_id,
2317 context, lifetime, unorderedDelivery, dontBundle);
2318 } else {
2319 error_logi(ERROR_MAJOR, "sctp_send: invalid destination address %d", path_id);
2320 sctpInstance = old_Instance;
2321 currentAssociation = old_assoc;
2322 LEAVE_LIBRARY("sctp_send");
2323 return SCTP_PARAMETER_PROBLEM;
2324 }
2325 } else {
2326 error_log(ERROR_MAJOR, "sctp_send: addressed association does not exist");
2327 result = SCTP_ASSOC_NOT_FOUND ;
2328 }
2329
2330 sctpInstance = old_Instance;
2331 currentAssociation = old_assoc;
2332 LEAVE_LIBRARY("sctp_send");
2333 return result;
2334 } /* end: sctp_send */
2335
2336
2337
2338 /**
2339 * sctp_setPrimary changes the primary path of an association.
2340 * @param associationID ID of assocation.
2341 * @param destAddressIndex index to the new primary path
2342 * @return error code
2343 */
2344 short sctp_setPrimary(unsigned int associationID, short path_id)
2345 {
2346 short rv;
2347 SCTP_instance *old_Instance = sctpInstance;
2348 Association *old_assoc = currentAssociation;
2349
2350 ENTER_LIBRARY("sctp_setPrimary");
2351
2352 CHECK_LIBRARY;
2353 /* Retrieve association from list */
2354 currentAssociation = retrieveAssociation(associationID);
2355
2356 if (currentAssociation != NULL) {
2357 if (sci_getState() != SCTP_ESTABLISHED) {
2358 LEAVE_LIBRARY("sctp_setPrimary");
2359 return SCTP_SPECIFIC_FUNCTION_ERROR;
2360 }
2361 sctpInstance = currentAssociation->sctpInstance;
2362 /* Forward shutdown to the addressed association */
2363 rv = pm_setPrimaryPath(path_id);
2364 } else {
2365 error_log(ERROR_MAJOR, "sctp_setPrimary: addressed association does not exist");
2366 rv = SCTP_ASSOC_NOT_FOUND;
2367 }
2368
2369 sctpInstance = old_Instance;
2370 currentAssociation = old_assoc;
2371 LEAVE_LIBRARY("sctp_setPrimary");
2372 return rv;
2373
2374 } /* end: sctp_setPrimary */
2375
2376 /**
2377 * sctp_receive is called in response to the dataArriveNotification to
2378 * get the received data.
2379 * The stream engine must copy the chunk data from a received SCTP datagram to
2380 * a new byte string, because the SCTP datagram is overwritten when the next datagram
2381 * is received and the lifetime of a chunk in the streamengine might outlast the
2382 * the reception of several SCTP datagrams.
2383 * For this reasons and to avoid repeated copying of byte strings, a pointer to
2384 * the byte string of chunkdata allocated by the streamengine is returned.
2385 * According to the standard, the chunkdata should be copied to to a buffer provided
2386 * by the ULP.
2387 * @param associationID ID of association.
2388 * @param streamID the stream on which the data chunk is received.
2389 * @param buffer pointer to where payload data of arrived chunk will be copied
2390 * @param length length of chunk data.
2391 * @return SCTP_SUCCESS if okay, 1==SCTP_SPECIFIC_FUNCTION_ERROR if there was no data
2392 */
2393 int sctp_receive(unsigned int associationID,
2394 unsigned short streamID,
2395 unsigned char *buffer,
2396 unsigned int *length,
2397 unsigned short *streamSN,
2398 unsigned int * tsn,
2399 unsigned int flags)
2400 {
2401 unsigned int addressIndex;
2402 return (sctp_receivefrom(associationID,streamID, buffer, length,
2403 streamSN, tsn, &addressIndex, flags));
2404
2405 }
2406
2407
2408 /**
2409 * sctp_receivefrom does the same thing as sctp_receive(), and additionally returns the
2410 * addressIndex, indicating where the chunks was received from.
2411 * @param associationID ID of association.
2412 * @param streamID the stream on which the data chunk is received.
2413 * @param buffer pointer to where payload data of arrived chunk will be copied
2414 * @param length length of chunk data.
2415 * @return SCTP_SUCCESS if okay, 1==SCTP_SPECIFIC_FUNCTION_ERROR if there was no data
2416 */
2417 int sctp_receivefrom(unsigned int associationID,
2418 unsigned short streamID,
2419 unsigned char *buffer,
2420 unsigned int *length,
2421 unsigned short *streamSN,
2422 unsigned int * tsn,
2423 unsigned int *addressIndex,
2424 unsigned int flags)
2425 {
2426 int result;
2427 SCTP_instance *old_Instance = sctpInstance;
2428 Association *old_assoc = currentAssociation;
2429
2430 ENTER_LIBRARY("sctp_receive");
2431
2432 CHECK_LIBRARY;
2433
2434 if (buffer == NULL) {
2435 LEAVE_LIBRARY("sctp_receive");
2436 return SCTP_PARAMETER_PROBLEM;
2437 }
2438 if (length == NULL) {
2439 LEAVE_LIBRARY("sctp_receive");
2440 return SCTP_PARAMETER_PROBLEM;
2441 }
2442 /* Retrieve association from list, as long as the data is not actually gone ! */
2443 currentAssociation = retrieveAssociationForced(associationID);
2444
2445 if (currentAssociation != NULL) {
2446 sctpInstance = currentAssociation->sctpInstance;
2447
2448 /* retrieve data from streamengine instance */
2449 result = se_ulpreceivefrom(buffer, length, streamID, streamSN, tsn, addressIndex, flags);
2450 } else {
2451 error_log(ERROR_MAJOR, "sctp_receive: addressed association does not exist");
2452 sctpInstance = old_Instance;
2453 currentAssociation = old_assoc;
2454 LEAVE_LIBRARY("sctp_receive");
2455 return SCTP_ASSOC_NOT_FOUND;
2456 }
2457 sctpInstance = old_Instance;
2458 currentAssociation = old_assoc;
2459 if (result == 0) {
2460 LEAVE_LIBRARY("sctp_receive");
2461 return SCTP_SUCCESS;
2462 }
2463 else if (result == 1) {
2464 LEAVE_LIBRARY("sctp_receive");
2465 return SCTP_PARAMETER_PROBLEM;
2466 }
2467 else if (result == SCTP_MODULE_NOT_FOUND) {
2468 LEAVE_LIBRARY("sctp_receive");
2469 return SCTP_MODULE_NOT_FOUND;
2470 }
2471 /* else result == 2, i.e. no data available */
2472 LEAVE_LIBRARY("sctp_receive");
2473 return SCTP_SPECIFIC_FUNCTION_ERROR;
2474 } /* end: sctp_receive */
2475
2476
2477
2478 /**
2479 * sctp_changeHeartBeat turns the hearbeat on a path of an association on or
2480 * off, or modifies the interval
2481 * @param associationID ID of assocation.
2482 * @param path_id index of the path where to do heartbeat
2483 * @param heartbeatON turn heartbeat on or off
2484 * @param timeIntervall heartbeat time intervall in milliseconds
2485 * @return error code, SCTP_LIBRARY_NOT_INITIALIZED, SCTP_SUCCESS, SCTP_PARAMETER_PROBLEM,
2486 * SCTP_MODULE_NOT_FOUND, SCTP_ASSOC_NOT_FOUND
2487 */
2488 int
2489 sctp_changeHeartBeat(unsigned int associationID,
2490 short path_id, gboolean heartbeatON, unsigned int timeIntervall)
2491 {
2492 int result;
2493 SCTP_instance *old_Instance = sctpInstance;
2494 Association *old_assoc = currentAssociation;
2495 ENTER_LIBRARY("sctp_changeHeartbeat");
2496
2497 CHECK_LIBRARY;
2498
2499 /* Retrieve association from list */
2500 currentAssociation = retrieveAssociation(associationID);
2501
2502 if (currentAssociation != NULL) {
2503 sctpInstance = currentAssociation->sctpInstance;
2504 /* Forward change HB to the addressed association */
2505 if (heartbeatON) {
2506 result = pm_enableHB(path_id, timeIntervall);
2507 event_logiii(VERBOSE,
2508 "Setting HB interval for address %d to %u msecs, result: %d !",
2509 path_id, timeIntervall, result);
2510 } else
2511 result = pm_disableHB(path_id);
2512 event_logii(VERBOSE,
2513 "Disabling HB for address %d, result: %d !",
2514 path_id, result);
2515 } else {
2516 error_log(ERROR_MAJOR, "sctp_changeHeartBeat: addressed association does not exist");
2517 result = SCTP_ASSOC_NOT_FOUND;
2518 }
2519 sctpInstance = old_Instance;
2520 currentAssociation = old_assoc;
2521 LEAVE_LIBRARY("sctp_changeHeartbeat");
2522 return result;
2523 } /* end: sctp_changeHeartBeat */
2524
2525
2526
2527 /**
2528 * sctp_requestHeartbeat sends a heartbeat to the given address of an association.
2529 * @param associationID ID of assocation.
2530 * @param path_id destination address to which the heartbeat is sent.
2531 * @return error code (SCTP_SUCCESS, SCTP_ASSOC_NOT_FOUND, SCTP_MODULE_NOT_FOUND, SCTP_LIBRARY_NOT_INITIALIZED,
2532 SCTP_UNSPECIFIED_ERROR)
2533 */
2534 int sctp_requestHeartbeat(unsigned int associationID, short path_id)
2535 {
2536 int result;
2537 SCTP_instance *old_Instance = sctpInstance;
2538 Association *old_assoc = currentAssociation;
2539
2540 ENTER_LIBRARY("sctp_requestHeartbeat");
2541
2542 CHECK_LIBRARY;
2543
2544 /* Retrieve association from list */
2545 currentAssociation = retrieveAssociation(associationID);
2546
2547 if (currentAssociation != NULL) {
2548 sctpInstance = currentAssociation->sctpInstance;
2549 result = pm_doHB(path_id);
2550 event_logi(VERBOSE, "Sending HB on user request to path ID: %u !",path_id);
2551 } else {
2552 error_log(ERROR_MAJOR, "sctp_requestHeartbeat: addressed association does not exist");
2553 result = SCTP_ASSOC_NOT_FOUND;
2554 }
2555 sctpInstance = old_Instance;
2556 currentAssociation = old_assoc;
2557 LEAVE_LIBRARY("sctp_requestHeartbeat");
2558 return result;
2559 } /* sctp_requestHeartbeat */
2560
2561 /**
2562 * sctp_getSrttReport returns a smoothed RTT value for a path to a given address
2563 * @param associationID ID of assocation.
2564 * @param destAddressIndex destination address where to get SRTT from
2565 * @return SRTT of the address in msecs, negative on error
2566 */
2567 int sctp_getSrttReport(unsigned int associationID, short path_id)
2568 {
2569 unsigned int srtt;
2570 SCTP_instance *old_Instance = sctpInstance;
2571 Association *old_assoc = currentAssociation;
2572
2573 ENTER_LIBRARY("sctp_getSrttReport");
2574
2575 CHECK_LIBRARY;
2576
2577 /* Retrieve association from list */
2578 currentAssociation = retrieveAssociation(associationID);
2579
2580 if (currentAssociation != NULL) {
2581 sctpInstance = currentAssociation->sctpInstance;
2582 srtt = pm_readSRTT(path_id);
2583 event_logiii(VERBOSE, "sctp_getSrttReport(asoc=%u, address=%d) result: %u !",
2584 associationID, path_id, srtt);
2585 sctpInstance = old_Instance;
2586 currentAssociation = old_assoc;
2587 if (srtt==0xffffffff) {
2588 LEAVE_LIBRARY("sctp_getSrttReport");
2589 return SCTP_PARAMETER_PROBLEM;
2590 } else {
2591 LEAVE_LIBRARY("sctp_getSrttReport");
2592 return (int)srtt;
2593 }
2594 } else {
2595 error_log(ERROR_MAJOR, "sctp_getSrttReport: addressed association does not exist");
2596 }
2597 sctpInstance = old_Instance;
2598 currentAssociation = old_assoc;
2599 LEAVE_LIBRARY("sctp_getSrttReport");
2600 return SCTP_ASSOC_NOT_FOUND;
2601
2602 }
2603
2604
2605 /**
2606 * sctp_setFailureThreshold is used to set the threshold for retransmissions on the given
2607 * address of an association. If the threshold is exeeded, the the destination address is
2608 * considered as unreachable.
2609 * @param associationID : ID of assocation.
2610 * @param destAddressIndex : destination address that gets a new failure threshold.
2611 * @param pathMaxRetransmissions : threshold for retransmissions.
2612 * @return
2613 */
2614 int
2615 sctp_setFailureThreshold(unsigned int associationID, unsigned short pathMaxRetransmissions)
2616 {
2617 guint16 result;
2618 SCTP_instance *old_Instance = sctpInstance;
2619 Association *old_assoc = currentAssociation;
2620
2621 ENTER_LIBRARY("sctp_setFailureThreshold");
2622
2623 CHECK_LIBRARY;
2624
2625 event_logii(VERBOSE, "sctp_setFailureThreshold: Association %u, pathMaxRetr. %u", associationID,
2626 pathMaxRetransmissions);
2627 currentAssociation = retrieveAssociation(associationID);
2628
2629 if (currentAssociation != NULL) {
2630 sctpInstance = currentAssociation->sctpInstance;
2631 pm_setMaxPathRetransmisions(pathMaxRetransmissions);
2632 result = SCTP_SUCCESS;
2633 } else {
2634 error_logi(ERROR_MAJOR, "sctp_setFailureThreshold : association %u does not exist", associationID);
2635 result = SCTP_ASSOC_NOT_FOUND;
2636 }
2637 sctpInstance = old_Instance;
2638 currentAssociation = old_assoc;
2639 LEAVE_LIBRARY("sctp_setFailureThreshold");
2640 return result;
2641
2642 } /* end: sctp_setFailureThreshold */
2643
2644
2645
2646 /**
2647 * sctp_getPathStatus : IP_TOS support is still missing !
2648 * Can be used to get path specific parameters in an existing association.
2649 *mdi_readLocalInStreams
2650 * @param associationID ID of assocation.
2651 * @param path_id path for which to get parameters
2652 * @param status pointer to new parameters
2653 * @return 0 for success, not zero for error
2654 */
2655 int sctp_getPathStatus(unsigned int associationID, short path_id, SCTP_PathStatus* status)
2656 {
2657 guint16 result;
2658 guint32 assocState;
2659 unsigned int totalBytesInFlight;
2660 SCTP_instance *old_Instance = sctpInstance;
2661 Association *old_assoc = currentAssociation;
2662
2663 ENTER_LIBRARY("sctp_getPathStatus");
2664
2665 CHECK_LIBRARY;
2666
2667 event_logii(VERBOSE, "sctp_getPathStatus: Association %u, Path %u", associationID, path_id);
2668
2669 if (status == NULL) {
2670 LEAVE_LIBRARY("sctp_getPathStatus");
2671 return SCTP_PARAMETER_PROBLEM;
2672 }
2673 currentAssociation = retrieveAssociation(associationID);
2674
2675 /* TODO: error handling for these two events should be separated - return two different errors */
2676 if (currentAssociation != NULL && path_id >= 0 && path_id< currentAssociation->noOfNetworks) {
2677 assocState = sci_getState();
2678 if (assocState < ESTABLISHED) {
2679 result = SCTP_ASSOC_NOT_FOUND;
2680 } else {
2681 sctpInstance = currentAssociation->sctpInstance;
2682 adl_sockunion2str(&(currentAssociation->destinationAddresses[path_id]),
2683 &(status->destinationAddress[0]), SCTP_MAX_IP_LEN);
2684 status->state = pm_readState(path_id);
2685 status->srtt = pm_readSRTT(path_id);
2686 status->rto = pm_readRTO(path_id);
2687 status->rttvar = pm_readRttVar(path_id);
2688 pm_getHBInterval(path_id, &(status->heartbeatIntervall));
2689 status->cwnd = fc_readCWND(path_id);
2690 status->cwnd2 = fc_readCWND2(path_id);
2691 status->partialBytesAcked = fc_readPBA(path_id);
2692 status->ssthresh = fc_readSsthresh(path_id);
2693 status->outstandingBytesPerAddress = rtx_get_obpa((unsigned int)path_id, &totalBytesInFlight);
2694 status->mtu = fc_readMTU(path_id);
2695 status->ipTos = currentAssociation->ipTos;
2696 result = SCTP_SUCCESS;
2697 }
2698 } else {
2699 error_logi(ERROR_MAJOR, "sctp_getPathStatus : association %u does not exist", associationID);
2700 result = SCTP_ASSOC_NOT_FOUND;
2701 }
2702 sctpInstance = old_Instance;
2703 currentAssociation = old_assoc;
2704 LEAVE_LIBRARY("sctp_getPathStatus");
2705 return result;
2706 }
2707
2708 /**
2709 * sctp_setPathStatus is currently NOT implemented !
2710 * Can be used to set path specific parameters in an existing association.
2711 *
2712 * @param associationID ID of assocation.
2713 * @param path_id path for which to set parameters
2714 * @param new_status pointer to new parameters
2715 * @return -1
2716 */
2717 int sctp_setPathStatus(unsigned int associationID, short path_id, SCTP_PathStatus* new_status)
2718 {
2719 CHECK_LIBRARY;
2720 ENTER_LIBRARY("sctp_setPathStatus");
2721
2722 error_log(ERROR_MAJOR, "sctp_setPathStatus : unimplemented function");
2723 LEAVE_LIBRARY("sctp_setPathStatus");
2724 return SCTP_UNSPECIFIED_ERROR;
2725 }
2726
2727
2728 /**
2729 * sctp_setAssocStatus allows for setting a number of association parameters.
2730 * _Not_ all values that the corresponding sctp_getAssocStatus-function returns
2731 * may be SET here !
2732 * Will set protocol parameters per SCTP association
2733 *
2734 * @param associationID ID of assocation.
2735 * @param new_status pointer to new parameters
2736 * @return -1
2737 */
2738 int sctp_setAssocStatus(unsigned int associationID, SCTP_AssociationStatus* new_status)
2739 {
2740 guint16 result;
2741 SCTP_instance *old_Instance = sctpInstance;
2742 Association *old_assoc = currentAssociation;
2743
2744 ENTER_LIBRARY("sctp_setAssocStatus");
2745
2746 CHECK_LIBRARY;
2747
2748 if (new_status == NULL) {
2749 LEAVE_LIBRARY("sctp_setAssocStatus");
2750 return SCTP_PARAMETER_PROBLEM;
2751 }
2752 currentAssociation = retrieveAssociation(associationID);
2753
2754 if (currentAssociation != NULL) {
2755 sctpInstance = currentAssociation->sctpInstance;
2756 event_logi(VERBOSE, "sctp_setAssocStatus: Association %u", associationID);
2757 if (pm_setPrimaryPath(new_status->primaryAddressIndex)) {
2758 error_logi(ERROR_MINOR, "pm_setPrimary(%u) returned error", new_status->primaryAddressIndex);
2759 sctpInstance = old_Instance;
2760 currentAssociation = old_assoc;
2761 LEAVE_LIBRARY("sctp_setAssocStatus");
2762 return SCTP_PARAMETER_PROBLEM;
2763 }
2764 if (pm_setRtoInitial(new_status->rtoInitial)) {
2765 error_logi(ERROR_MINOR, "pm_setRtoInitial(%u) returned error", new_status->rtoInitial);
2766 sctpInstance = old_Instance;
2767 currentAssociation = old_assoc;
2768 LEAVE_LIBRARY("sctp_setAssocStatus");
2769 return SCTP_PARAMETER_PROBLEM;
2770 }
2771 if (pm_setRtoMin(new_status->rtoMin)) {
2772 error_logi(ERROR_MINOR, "pm_setRtoMin(%u) returned error", new_status->rtoMin);
2773 sctpInstance = old_Instance;
2774 currentAssociation = old_assoc;
2775 LEAVE_LIBRARY("sctp_setAssocStatus");
2776 return SCTP_PARAMETER_PROBLEM;
2777 }
2778 if (pm_setRtoMax(new_status->rtoMax)) {
2779 error_logi(ERROR_MINOR, "pm_setRtoMax(%u) returned error", new_status->rtoMax);
2780 sctpInstance = old_Instance;
2781 currentAssociation = old_assoc;
2782 LEAVE_LIBRARY("sctp_setAssocStatus");
2783 return SCTP_PARAMETER_PROBLEM;
2784 }
2785 if(pm_setMaxPathRetransmisions(new_status->pathMaxRetransmits)) {
2786 error_logi(ERROR_MINOR, "pm_getMaxPathRetransmisions(%u) returned error", new_status->pathMaxRetransmits);
2787 sctpInstance = old_Instance;
2788 currentAssociation = old_assoc;
2789 LEAVE_LIBRARY("sctp_setAssocStatus");
2790 return SCTP_PARAMETER_PROBLEM;
2791 }
2792 sci_setCookieLifeTime(new_status->validCookieLife);
2793
2794 sci_setMaxAssocRetransmissions(new_status->assocMaxRetransmits);
2795 sci_setMaxInitRetransmissions(new_status->maxInitRetransmits);
2796
2797 rxc_set_local_receiver_window(new_status->myRwnd);
2798 rxc_set_sack_delay(new_status->delay);
2799 currentAssociation->ipTos = new_status->ipTos;
2800 result = fc_set_maxSendQueue(new_status->maxSendQueue);
2801
2802 result = SCTP_SUCCESS;
2803
2804 } else {
2805 error_logi(ERROR_MAJOR, "sctp_getAssocStatus : association %u does not exist", associationID);
2806 result = SCTP_ASSOC_NOT_FOUND;
2807 }
2808 sctpInstance = old_Instance;
2809 currentAssociation = old_assoc;
2810 LEAVE_LIBRARY("sctp_setAssocStatus");
2811 return result;
2812 } /* end: sctp_setAssocStatus */
2813
2814 /**
2815 * Will get the protocol parameters per SCTP association
2816 *
2817 * @param associationID ID of assocation.
2818 * @return pointer to a structure containing association parameters
2819 */
2820 int sctp_getAssocStatus(unsigned int associationID, SCTP_AssociationStatus* status)
2821 {
2822 guint16 result;
2823 SCTP_instance *old_Instance = sctpInstance;
2824 Association *old_assoc = currentAssociation;
2825
2826 ENTER_LIBRARY("sctp_getAssocStatus");
2827
2828 CHECK_LIBRARY;
2829
2830 if (status == NULL) {
2831 LEAVE_LIBRARY("sctp_getAssocStatus");
2832 return SCTP_PARAMETER_PROBLEM;
2833 }
2834 currentAssociation = retrieveAssociation(associationID);
2835
2836 if (currentAssociation != NULL) {
2837 sctpInstance = currentAssociation->sctpInstance;
2838 event_logi(VERBOSE, "sctp_getAssocStatus: Association %u", associationID);
2839 status->state = sci_getState();
2840 status->numberOfAddresses = currentAssociation->noOfNetworks;
2841 status->sourcePort =currentAssociation->localPort;
2842 status->destPort = currentAssociation->remotePort;
2843 status->primaryAddressIndex = pm_readPrimaryPath();
2844
2845 adl_sockunion2str(&(currentAssociation->destinationAddresses[status->primaryAddressIndex]),
2846 &(status->primaryDestinationAddress[0]),SCTP_MAX_IP_LEN);
2847
2848 se_readNumberOfStreams(&(status->inStreams), &(status->outStreams));
2849 status->currentReceiverWindowSize = rtx_read_remote_receiver_window();
2850 status->outstandingBytes = fc_readOutstandingBytes();
2851 status->noOfChunksInSendQueue = fc_readNumberOfQueuedChunks();
2852 status->noOfChunksInRetransmissionQueue = rtx_readNumberOfUnackedChunks();
2853 status->noOfChunksInReceptionQueue = se_numOfQueuedChunks();
2854 status->rtoInitial = pm_getRtoInitial();
2855 status->rtoMin = pm_getRtoMin();
2856 status->rtoMax = pm_getRtoMax();
2857 status->validCookieLife = sci_getCookieLifeTime();
2858 status->assocMaxRetransmits = sci_getMaxAssocRetransmissions();
2859 status->pathMaxRetransmits = pm_getMaxPathRetransmisions();
2860 status->maxInitRetransmits = sci_getMaxInitRetransmissions();
2861 status->myRwnd = rxc_get_local_receiver_window();
2862 status->delay = rxc_get_sack_delay();
2863 result = fc_get_maxSendQueue(&(status->maxSendQueue));
2864 status->maxRecvQueue = 0;
2865 status->ipTos = 0;
2866 result = SCTP_SUCCESS;
2867
2868 } else {
2869 error_logi(ERROR_MAJOR, "sctp_getAssocStatus : association %u does not exist", associationID);
2870 result = SCTP_ASSOC_NOT_FOUND;
2871 }
2872 sctpInstance = old_Instance;
2873 currentAssociation = old_assoc;
2874 LEAVE_LIBRARY("sctp_getAssocStatus");
2875 return result;
2876 } /* end: sctp_getAssocStatus */
2877
2878 /**
2879 * sctp_setAssocDefaults allows for setting a few association default parameters !
2880 * Will set protocol default parameters per given SCTP instance
2881 *
2882 * @param SCTP_InstanceName instance for which to set the parameters
2883 * @param params pointer to parameter data structure
2884 * @return -1
2885 */
2886 int sctp_setAssocDefaults(unsigned short SCTP_InstanceName, SCTP_InstanceParameters* params)
2887 {
2888 SCTP_instance temporary;
2889 SCTP_instance* instance;
2890 GList* result = NULL;
2891
2892 ENTER_LIBRARY("sctp_setAssocDefaults");
2893
2894 CHECK_LIBRARY;
2895
2896 event_logi(VERBOSE, "sctp_setInstanceParams: Instance %u", SCTP_InstanceName);
2897
2898 temporary.sctpInstanceName = SCTP_InstanceName;
2899 result = g_list_find_custom(InstanceList, &temporary, &CompareInstanceNames);
2900 if (result != NULL) {
2901 instance = (SCTP_instance*)result->data;
2902 } else {
2903 error_logi(ERROR_MINOR, "sctp_setAssocDefaults : Did not find Instance Number %u", SCTP_InstanceName);
2904 LEAVE_LIBRARY("sctp_setAssocDefaults");
2905 return SCTP_INSTANCE_NOT_FOUND;
2906 }
2907 if (params == NULL) {
2908 error_log(ERROR_MINOR, "sctp_setAssocDefaults : Passed NULL Pointer !");
2909 LEAVE_LIBRARY("sctp_setAssocDefaults");
2910 return SCTP_PARAMETER_PROBLEM;
2911 }
2912 instance->default_rtoInitial = params->rtoInitial;
2913 instance->default_rtoMin = params->rtoMin;
2914 instance->default_rtoMax = params->rtoMax;
2915 instance->default_validCookieLife = params->validCookieLife;
2916 instance->default_assocMaxRetransmits = params->assocMaxRetransmits;
2917 instance->default_pathMaxRetransmits = params->pathMaxRetransmits;
2918 instance->default_maxInitRetransmits = params->maxInitRetransmits;
2919 instance->default_myRwnd = params->myRwnd;
2920 instance->default_delay = params->delay;
2921 instance->default_ipTos = params->ipTos;
2922 instance->default_maxSendQueue = params->maxSendQueue;
2923 instance->default_maxRecvQueue = params->maxRecvQueue;
2924 instance->noOfInStreams = params->inStreams;
2925 instance->noOfOutStreams = params->outStreams;
2926 LEAVE_LIBRARY("sctp_setAssocDefaults");
2927 return SCTP_SUCCESS;
2928 } /* end: sctp_setInstanceParams */
2929
2930 /**
2931 * sctp_getInstanceParams returns a struct with default parameter values !
2932 * Will get protocol parameters per given SCTP instance
2933 *
2934 * @param SCTP_InstanceName instance for which to set the parameters
2935 * @param params pointer to parameter data
2936 * @return -1
2937 */
2938 int sctp_getAssocDefaults(unsigned short SCTP_InstanceName, SCTP_InstanceParameters* params)
2939 {
2940 SCTP_instance temporary;
2941 SCTP_instance* instance;
2942 unsigned int numOfAddresses=0, count=0;
2943
2944 GList* result = NULL;
2945
2946 ENTER_LIBRARY("sctp_getAssocDefaults");
2947
2948 CHECK_LIBRARY;
2949
2950 event_logi(VERBOSE, "sctp_getInstanceParams: Instance %u", SCTP_InstanceName);
2951
2952 temporary.sctpInstanceName = SCTP_InstanceName;
2953 result = g_list_find_custom(InstanceList, &temporary, &CompareInstanceNames);
2954 if (result != NULL) {
2955 instance = (SCTP_instance*)result->data;
2956 } else {
2957 error_logi(ERROR_MINOR, "sctp_getAssocDefaults : Did not find Instance Number %u", SCTP_InstanceName);
2958 LEAVE_LIBRARY("sctp_getAssocDefaults");
2959 return SCTP_INSTANCE_NOT_FOUND;
2960 }
2961 if (params == NULL) {
2962 error_log(ERROR_MINOR, "sctp_getAssocDefaults : Passed NULL Pointer !");
2963 LEAVE_LIBRARY("sctp_getAssocDefaults");
2964 return SCTP_PARAMETER_PROBLEM;
2965 }
2966 if (instance->noOfLocalAddresses > SCTP_MAX_NUM_ADDRESSES)
2967 numOfAddresses = SCTP_MAX_NUM_ADDRESSES;
2968 else numOfAddresses = instance->noOfLocalAddresses;
2969
2970 if (numOfAddresses == 0) {
2971 params->noOfLocalAddresses = myNumberOfAddresses;
2972 for (count = 0; count < myNumberOfAddresses; count++) {
2973 adl_sockunion2str(&(myAddressList[count]), params->localAddressList[count], SCTP_MAX_IP_LEN);
2974 }
2975 } else {
2976 params->noOfLocalAddresses = numOfAddresses;
2977 for (count = 0; count < numOfAddresses; count++) {
2978 adl_sockunion2str(&(instance->localAddressList[count]), params->localAddressList[count], SCTP_MAX_IP_LEN);
2979 }
2980 }
2981 params->rtoInitial = instance->default_rtoInitial;
2982 params->rtoMin = instance->default_rtoMin;
2983 params->rtoMax = instance->default_rtoMax;
2984 params->validCookieLife = instance->default_validCookieLife;
2985 params->assocMaxRetransmits = instance->default_assocMaxRetransmits;
2986 params->pathMaxRetransmits = instance->default_pathMaxRetransmits;
2987 params->maxInitRetransmits = instance->default_maxInitRetransmits;
2988 params->myRwnd = instance->default_myRwnd;
2989 params->delay = instance->default_delay ;
2990 params->ipTos = instance->default_ipTos ;
2991 params->maxSendQueue = instance->default_maxSendQueue;
2992 params->maxRecvQueue = instance->default_maxRecvQueue;
2993 params->inStreams = instance->noOfInStreams;
2994 params->outStreams = instance->noOfOutStreams;
2995
2996 LEAVE_LIBRARY("sctp_getAssocDefaults");
2997 return SCTP_SUCCESS;
2998 } /* end: sctp_getAssocDefaults */
2999
3000
3001 int sctp_setLibraryParameters(SCTP_LibraryParameters *params)
3002 {
3003 ENTER_LIBRARY("sctp_setLibraryParameters");
3004
3005 CHECK_LIBRARY;
3006 if (params == NULL) {
3007 LEAVE_LIBRARY("sctp_setLibraryParameters");
3008 return SCTP_PARAMETER_PROBLEM;
3009 }
3010
3011 event_logi(VERBOSE, "sctp_setLibraryParameters: Parameter sendAbortForOOTB is %s",
3012 (sendAbortForOOTB==TRUE)?"TRUE":"FALSE");
3013 if (params->sendOotbAborts == 0) {
3014 sendAbortForOOTB = FALSE;
3015 } else if (params->sendOotbAborts == 1) {
3016 sendAbortForOOTB = TRUE;
3017 } else {
3018 LEAVE_LIBRARY("sctp_setLibraryParameters");
3019 return SCTP_PARAMETER_PROBLEM;
3020 }
3021 if (params->checksumAlgorithm == SCTP_CHECKSUM_ALGORITHM_CRC32C ||
3022 params->checksumAlgorithm == SCTP_CHECKSUM_ALGORITHM_ADLER32) {
3023 if (checksumAlgorithm != params->checksumAlgorithm) {
3024 checksumAlgorithm = params->checksumAlgorithm;
3025 set_checksum_algorithm(checksumAlgorithm);
3026 } /* else nothing changes */
3027 } else {
3028 LEAVE_LIBRARY("sctp_setLibraryParameters");
3029 return SCTP_PARAMETER_PROBLEM;
3030 }
3031
3032 if (params->supportPRSCTP == 0) {
3033 librarySupportsPRSCTP = FALSE;
3034 } else if (params->supportPRSCTP == 1) {
3035 librarySupportsPRSCTP = TRUE;
3036 } else {
3037 LEAVE_LIBRARY("sctp_setLibraryParameters");
3038 return SCTP_PARAMETER_PROBLEM;
3039 }
3040 if (params->supportADDIP == 0) {
3041 supportADDIP = FALSE;
3042 } else if (params->supportADDIP == 1) {
3043 supportADDIP = TRUE;
3044 } else {
3045 LEAVE_LIBRARY("sctp_setLibraryParameters");
3046 return SCTP_PARAMETER_PROBLEM;
3047 }
3048
3049 event_logi(INTERNAL_EVENT_0, "sctp_setLibraryParameters: Set Parameter sendAbortForOOTB to %s",
3050 (sendAbortForOOTB==TRUE)?"TRUE":"FALSE");
3051 event_logi(INTERNAL_EVENT_0, "sctp_setLibraryParameters: Checksum Algorithm is now %s",
3052 (checksumAlgorithm==SCTP_CHECKSUM_ALGORITHM_CRC32C)?"CRC32C":"ADLER32");
3053 event_logi(INTERNAL_EVENT_0, "sctp_setLibraryParameters: Support of PRSCTP is now %s",
3054 (params->supportPRSCTP==TRUE)?"ENABLED":"DISABLED");
3055 event_logi(INTERNAL_EVENT_0, "sctp_setLibraryParameters: Support of ADDIP is now %s",
3056 (params->supportADDIP==TRUE)?"ENABLED":"DISABLED");
3057
3058 LEAVE_LIBRARY("sctp_setLibraryParameters");
3059 return SCTP_SUCCESS;
3060
3061 }
3062
3063 int sctp_getLibraryParameters(SCTP_LibraryParameters *params)
3064 {
3065 ENTER_LIBRARY("sctp_getLibraryParameters");
3066
3067 CHECK_LIBRARY;
3068 if (params == NULL) {
3069 LEAVE_LIBRARY("sctp_getLibraryParameters");
3070 return SCTP_PARAMETER_PROBLEM;
3071 }
3072
3073 event_logi(VERBOSE, "sctp_getLibraryParameters: Parameter sendAbortForOOTB is currently %s",
3074 (sendAbortForOOTB==TRUE)?"TRUE":"FALSE");
3075
3076 params->sendOotbAborts = sendAbortForOOTB;
3077 params->checksumAlgorithm = checksumAlgorithm;
3078 params->supportPRSCTP = (librarySupportsPRSCTP == TRUE) ? 1 : 0;
3079 params->supportADDIP = (supportADDIP == TRUE) ? 1 : 0;
3080 event_logi(INTERNAL_EVENT_0, "sctp_getLibraryParameters: Checksum Algorithm is currently %s",
3081 (checksumAlgorithm==SCTP_CHECKSUM_ALGORITHM_CRC32C)?"CRC32C":"ADLER32");
3082
3083 LEAVE_LIBRARY("sctp_getLibraryParameters");
3084 return SCTP_SUCCESS;
3085
3086 }
3087
3088 /**
3089 * sctp_receive_unsent returns messages that have not been sent before the termination of an association
3090 *
3091 * @param associationID ID of assocation.
3092 * @param buffer pointer to a buffer that the application needs to pass. Data is copied there.
3093 * @param length pointer to size of the buffer passed by application, contains actual length
3094 * of the copied chunk after the function call.
3095 * @param streamID pointer to the stream id, where data should have been sent
3096 * @param streamSN pointer to stream sequence number of the data chunk that was not sent
3097 * @param protocolID pointer to the protocol ID of the unsent chunk
3098 * @return number of unsent chunks still in the queue, else error code as SCTP_NO_CHUNKS_IN_QUEUE, or
3099 * SCTP_PARAMETER_PROBLEM, SCTP_WRONG_STATE, SCTP_ASSOC_NOT_FOUND, SCTP_LIBRARY_NOT_INITIALIZED
3100 */
3101 int sctp_receiveUnsent(unsigned int associationID, unsigned char *buffer, unsigned int *length,
3102 unsigned int *tsn, unsigned short *streamID, unsigned short *streamSN,
3103 unsigned int* protocolId, unsigned char* flags, void** context)
3104 {
3105 int result;
3106 SCTP_instance *old_Instance = sctpInstance;
3107 Association *old_assoc = currentAssociation;
3108
3109 ENTER_LIBRARY("sctp_receiveUnsent");
3110
3111 CHECK_LIBRARY;
3112
3113 if (buffer == NULL || length == NULL || tsn==NULL || streamID == NULL || streamSN == NULL || protocolId == NULL) {
3114 LEAVE_LIBRARY("sctp_receiveUnsent");
3115 return SCTP_PARAMETER_PROBLEM;
3116 }
3117 currentAssociation = retrieveAssociationForced(associationID);
3118
3119 if (currentAssociation != NULL) {
3120 if (currentAssociation->deleted == FALSE) {
3121 result = SCTP_WRONG_STATE;
3122 } else if (fc_readNumberOfUnsentChunks() == 0) {
3123 result = SCTP_NO_CHUNKS_IN_QUEUE;
3124 } else {
3125 result = fc_dequeueOldestUnsentChunk(buffer, length, tsn, streamID, streamSN, protocolId, flags,context);
3126 }
3127 } else {
3128 error_logi(ERROR_MAJOR, "sctp_receiveUnsent : association %u does not exist", associationID);
3129 result = SCTP_ASSOC_NOT_FOUND;
3130 }
3131 sctpInstance = old_Instance;
3132 currentAssociation = old_assoc;
3133 LEAVE_LIBRARY("sctp_receiveUnsent");
3134 return result;
3135
3136 }
3137
3138 /**
3139 * sctp_receive_unacked returns messages that were already put on the wire, but have not been
3140 * acknowledged by the peer before termination of the association
3141 *
3142 * @param associationID ID of assocation.
3143 * @param buffer pointer to a buffer that the application needs to pass. Data is copied there.
3144 * @param length pointer to size of the buffer passed by application, contains actual length
3145 * of the copied chunk after the function call.
3146 * @param streamID pointer to the stream id, where data should have been sent
3147 * @param streamSN pointer to stream sequence number of the data chunk that was not acked
3148 * @param protocolID pointer to the protocol ID of the unacked chunk
3149 * @return number of unacked chunks still in the queue, else SCTP_NO_CHUNKS_IN_QUEUE if no chunks there, else
3150 * appropriate error code: SCTP_PARAMETER_PROBLEM, SCTP_WRONG_STATE, SCTP_ASSOC_NOT_FOUND, SCTP_LIBRARY_NOT_INITIALIZED
3151 */
3152 int sctp_receiveUnacked(unsigned int associationID, unsigned char *buffer, unsigned int *length,
3153 unsigned int *tsn, unsigned short *streamID, unsigned short *streamSN,
3154 unsigned int* protocolId,unsigned char* flags, void** context)
3155 {
3156 int result;
3157 SCTP_instance *old_Instance = sctpInstance;
3158 Association *old_assoc = currentAssociation;
3159
3160 ENTER_LIBRARY("sctp_receiveUnacked");
3161
3162 CHECK_LIBRARY;
3163
3164 if (buffer == NULL || length == NULL || tsn==NULL || streamID == NULL || streamSN == NULL || protocolId == NULL) {
3165 LEAVE_LIBRARY("sctp_receiveUnacked");
3166 return SCTP_PARAMETER_PROBLEM;
3167 }
3168 currentAssociation = retrieveAssociationForced(associationID);
3169
3170 if (currentAssociation != NULL) {
3171 if (currentAssociation->deleted == FALSE) {
3172 result = SCTP_WRONG_STATE;
3173 } else if (rtx_readNumberOfUnackedChunks() == 0) {
3174 result = SCTP_NO_CHUNKS_IN_QUEUE;
3175 } else {
3176 result = rtx_dequeueOldestUnackedChunk(buffer, length, tsn, streamID, streamSN, protocolId, flags,context);
3177 }
3178 } else {
3179 error_logi(ERROR_MAJOR, "sctp_receiveUnacked : association %u does not exist", associationID);
3180 result = SCTP_ASSOC_NOT_FOUND;
3181 }
3182 sctpInstance = old_Instance;
3183 currentAssociation = old_assoc;
3184 LEAVE_LIBRARY("sctp_receiveUnacked");
3185 return result;
3186
3187
3188
3189 }
3190
3191
3192 /**
3193 * sctp_getPrimary returns the index of the current primary path
3194 * @param associationID ID of assocation.
3195 * @return the index of the current primary path, or -1 on error
3196 */
3197 short sctp_getPrimary(unsigned int associationID)
3198 {
3199 short primary;
3200 SCTP_instance *old_Instance = sctpInstance;
3201 Association *old_assoc = currentAssociation;
3202
3203 ENTER_LIBRARY("sctp_getPrimary");
3204
3205 CHECK_LIBRARY;
3206
3207 currentAssociation = retrieveAssociation(associationID);
3208
3209 if (currentAssociation != NULL) {
3210 sctpInstance = currentAssociation->sctpInstance;
3211 event_logi(VERBOSE, "sctp_getPrimary: Association %u", associationID);
3212 primary = pm_readPrimaryPath();
3213 }else{
3214 error_logi(ERROR_MAJOR, "sctp_getPrimary : association %u does not exist", associationID);
3215 primary = SCTP_ASSOC_NOT_FOUND;
3216 }
3217
3218 sctpInstance = old_Instance;
3219 currentAssociation = old_assoc;
3220 LEAVE_LIBRARY("sctp_getPrimary");
3221 return primary;
3222 }
3223
3224 int sctp_getInstanceID(unsigned int associationID, unsigned short* instanceID)
3225 {
3226 SCTP_instance *old_Instance = sctpInstance;
3227 Association *old_assoc = currentAssociation;
3228 int result=0;
3229
3230 ENTER_LIBRARY("sctp_getInstanceID");
3231
3232 CHECK_LIBRARY;
3233 if (instanceID == NULL) {
3234 LEAVE_LIBRARY("sctp_getInstanceID");
3235 return -1;
3236 }
3237 currentAssociation = retrieveAssociationForced(associationID);
3238
3239 if (currentAssociation != NULL) {
3240 sctpInstance = currentAssociation->sctpInstance;
3241 event_logii(VERBOSE, "sctp_getInstanceID: Association %u, Instance %u",
3242 associationID, sctpInstance->sctpInstanceName);
3243 (*instanceID) = sctpInstance->sctpInstanceName;
3244 }else{
3245 error_logi(ERROR_MINOR, "sctp_getInstanceID: association %u does not exist", associationID);
3246 result = 1;
3247 }
3248 sctpInstance = old_Instance;
3249 currentAssociation = old_assoc;
3250 LEAVE_LIBRARY("sctp_getInstanceID");
3251 return result;
3252 }
3253
3254 /* ----------------------------------------------------------------------------------------*/
3255 /* ------------------------------------ HELPER FUNCTIONS from adaptation ------------------*/
3256 /* ----------------------------------------------------------------------------------------*/
3257 #ifndef WIN32
3258 int sctp_registerUdpCallback(unsigned char me[],
3259 unsigned short my_port,
3260 sctp_socketCallback scf)
3261 {
3262 int result;
3263
3264 ENTER_LIBRARY("sctp_registerUdpCallback");
3265
3266 CHECK_LIBRARY;
3267 result = adl_registerUdpCallback(me,my_port,scf);
3268
3269 LEAVE_LIBRARY("sctp_registerUdpCallback");
3270 return result;
3271 }
3272
3273 int sctp_unregisterUdpCallback(int udp_sfd)
3274 {
3275 int result;
3276
3277 ENTER_LIBRARY("sctp_unregisterUdpCallback");
3278 CHECK_LIBRARY;
3279 result = adl_unregisterUdpCallback(udp_sfd);
3280 LEAVE_LIBRARY("sctp_unregisterUdpCallback");
3281 return result;
3282 }
3283
3284 int sctp_sendUdpData(int sfd, unsigned char* buf, int length,
3285 unsigned char destination[], unsigned short dest_port)
3286 {
3287 int result;
3288
3289 ENTER_LIBRARY("sctp_sendUdpData");
3290 CHECK_LIBRARY;
3291 result = adl_sendUdpData(sfd, buf, length, destination, dest_port);
3292 LEAVE_LIBRARY("sctp_sendUdpData");
3293 return result;
3294 }
3295 #endif
3296
3297 int sctp_registerStdinCallback(sctp_StdinCallback sdf, char* buffer, int length)
3298 {
3299 int result;
3300
3301 ENTER_LIBRARY("sctp_registerStdinCallback");
3302 CHECK_LIBRARY;
3303 result = adl_registerStdinCallback(sdf, buffer, length);
3304 LEAVE_LIBRARY("sctp_registerStdinCallback");
3305 return result;
3306 }
3307
3308 int sctp_unregisterStdinCallback()
3309 {
3310 int result;
3311
3312 ENTER_LIBRARY("sctp_unregisterStdinCallback");
3313 CHECK_LIBRARY;
3314 result = adl_unregisterStdinCallback();
3315 LEAVE_LIBRARY("sctp_registerStdinCallback");
3316 return result;
3317
3318 }
3319
3320 #ifndef WIN32
3321 int sctp_registerUserCallback(int fd, sctp_userCallback sdf, void* userData, short int eventMask)
3322 {
3323 int result;
3324
3325 ENTER_LIBRARY("sctp_registerUserCallback");
3326 CHECK_LIBRARY;
3327 result = adl_registerUserCallback(fd, sdf, userData, eventMask);
3328 LEAVE_LIBRARY("sctp_registerUserCallback");
3329 return result;
3330 }
3331
3332 int sctp_unregisterUserCallback(int fd)
3333 {
3334 int result;
3335
3336 ENTER_LIBRARY("sctp_unregisterUserCallback");
3337 CHECK_LIBRARY;
3338 result = adl_unregisterUserCallback(fd);
3339 LEAVE_LIBRARY("sctp_registerUserCallback");
3340 return result;
3341
3342 }
3343 #endif
3344
3345 unsigned int sctp_startTimer(unsigned int seconds , unsigned int microseconds,
3346 sctp_timerCallback timer_cb, void *param1, void *param2)
3347 {
3348 unsigned int result;
3349
3350 ENTER_LIBRARY("sctp_startTimer");
3351 CHECK_LIBRARY;
3352 result = adl_startMicroTimer(seconds, microseconds, timer_cb,TIMER_TYPE_USER, param1, param2);
3353 LEAVE_LIBRARY("sctp_startTimer");
3354 return result;
3355 }
3356
3357 int sctp_stopTimer(unsigned int tid)
3358 {
3359 int result;
3360
3361 ENTER_LIBRARY("sctp_stopTimer");
3362 CHECK_LIBRARY;
3363 result = adl_stopTimer(tid);
3364 LEAVE_LIBRARY("sctp_stopTimer");
3365 return result;
3366
3367 }
3368
3369 unsigned int sctp_restartTimer(unsigned int timer_id, unsigned int seconds, unsigned int microseconds)
3370 {
3371 int result;
3372
3373 ENTER_LIBRARY("sctp_restartTimer");
3374 CHECK_LIBRARY;
3375 result = adl_restartMicroTimer(timer_id, seconds, microseconds);
3376 LEAVE_LIBRARY("sctp_restartTimer");
3377 return result;
3378 }
3379
3380 int sctp_getEvents(void)
3381 {
3382 int result;
3383
3384 ENTER_LIBRARY("sctp_getEvents");
3385 CHECK_LIBRARY;
3386 result = adl_getEvents();
3387 LEAVE_LIBRARY("sctp_getEvents");
3388 return result;
3389 }
3390
3391 int sctp_eventLoop(void)
3392 {
3393 int result;
3394
3395 ENTER_LIBRARY("sctp_eventLoop");
3396 CHECK_LIBRARY;
3397 result = adl_eventLoop();
3398 LEAVE_LIBRARY("sctp_eventLoop");
3399 return result;
3400 }
3401
3402 int sctp_extendedEventLoop(void (*lock)(void* data), void (*unlock)(void* data), void* data)
3403 {
3404 int result;
3405
3406 ENTER_LIBRARY("sctp_extendedEventLoop");
3407 CHECK_LIBRARY;
3408 result = adl_extendedEventLoop(lock, unlock, data);
3409 LEAVE_LIBRARY("sctp_extendedEventLoop");
3410 return result;
3411 }
3412
3413
3414 #ifdef BAKEOFF
3415 int sctp_sendRawData(unsigned int associationID, short path_id,
3416 unsigned char *buffer, unsigned int length)
3417 {
3418 int result = 0;
3419 SCTP_instance *old_Instance = sctpInstance;
3420 Association *old_assoc = currentAssociation;
3421
3422 if (sctpLibraryInitialized == FALSE) return -1;
3423
3424
3425 /* Retrieve association from list */
3426 currentAssociation = retrieveAssociation(associationID);
3427
3428 if (currentAssociation != NULL) {
3429 sctpInstance = currentAssociation->sctpInstance;
3430 if (path_id >= 0) {
3431 if (path_id >= currentAssociation->noOfNetworks) {
3432 error_log(ERROR_MAJOR, "sctp_sendRawData: invalid destination address");
3433 sctpInstance = old_Instance;
3434 currentAssociation = old_assoc;
3435 return 1;
3436 }
3437 }
3438 event_logiii(INTERNAL_EVENT_1, "sctp_sendRawData(assoc:%u, path: %d): send %u bytes",associationID,
3439 path_id,length);
3440 /* Forward chunk to the addressed association */
3441 result = mdi_send_message((SCTP_message *) buffer, length, path_id);
3442
3443 } else {
3444 error_log(ERROR_MAJOR, "sctp_send: addressed association does not exist");
3445 result = 1;
3446 }
3447
3448 sctpInstance = old_Instance;
3449 currentAssociation = old_assoc;
3450 return result;
3451 } /* end: sctp_send */
3452 #endif
3453
3454 /*------------------- Functions called by the SCTP bundling --------------------------------------*/
3455
3456 /**
3457 * Used by bundling to send a SCTP-datagramm.
3458 *
3459 * Bundling passes a static pointer and leaves space for common header, so
3460 * we can fill that header in up front !
3461 * Before calling send_message at the adaption-layer, this function does:
3462 * \begin{itemize}
3463 * \item add the SCTP common header to the message
3464 * \item convert the SCTP message to a byte string
3465 * \item retrieve the socket-file descriptor of the SCTP-instance
3466 * \item retrieve the destination address
3467 * \item retrieve destination port ???
3468 * \end{itemize}
3469 *
3470 * @param SCTP_message SCTP message as a struct (i.e. common header and chunks)
3471 * @param length length of complete SCTP message.
3472 * @param destAddresIndex Index of address in the destination address list.
3473 * @return Errorcode (0 for good case: length bytes sent; 1 or -1 for error)
3474 */
3475 int mdi_send_message(SCTP_message * message, unsigned int length, short destAddressIndex)
3476 {
3477 union sockunion dest_su, *dest_ptr;
3478 SCTP_simple_chunk *chunk;
3479 unsigned char tos = 0;
3480 unsigned short dIdx;
3481 int txmit_len = 0;
3482 guchar hoststring[SCTP_MAX_IP_LEN];
3483
3484
3485 if (message == NULL) {
3486 error_log(ERROR_MINOR, "mdi_send_message: no message to send !!!");
3487 return 1;
3488 }
3489
3490 chunk = (SCTP_simple_chunk *) & message->sctp_pdu[0];
3491
3492 if (currentAssociation == NULL) {
3493 /* possible cases : initAck, no association exists yet, and OOTB packets
3494 use last from address as destination address */
3495
3496 if (lastFromAddress == NULL) {
3497 error_log(ERROR_MAJOR, "mdi_send_message: lastFromAddress does not exist for initAck");
3498 return 1;
3499 } else {
3500 /* only if the sctp-message received before contained an init-chunk */
3501 memcpy(&dest_su, lastFromAddress, sizeof(union sockunion));
3502 dest_ptr = &dest_su;
3503 message->common_header.verification_tag = htonl(lastInitiateTag);
3504 /* write invalid tag value to lastInitiateTag (reset it) */
3505 lastInitiateTag = 0;
3506 /* swap ports */
3507 message->common_header.src_port = htons(mdi_readLastDestPort());
3508 message->common_header.dest_port = htons(mdi_readLastFromPort());
3509 event_logiii(VVERBOSE,
3510 "mdi_send_message (I) : tag = %x, src_port = %u , dest_port = %u",
3511 lastInitiateTag, mdi_readLastDestPort(), mdi_readLastFromPort());
3512
3513 if (sctpInstance != NULL)
3514 tos = sctpInstance->default_ipTos;
3515 else
3516 tos = IPTOS_DEFAULT;
3517 }
3518 } else {
3519
3520 if (destAddressIndex < -1 || destAddressIndex >= currentAssociation->noOfNetworks) {
3521 error_log(ERROR_MAJOR, "mdi_send_message: invalid destination address");
3522 return 1;
3523 }
3524
3525 if (destAddressIndex != -1) {
3526 /* Use given destination address from current association */
3527 dest_ptr = &(currentAssociation->destinationAddresses[destAddressIndex]);
3528 } else { /* use last from address */
3529 if (lastFromAddress == NULL) {
3530 dIdx = pm_readPrimaryPath();
3531 event_logii(VVERBOSE, "mdi_send_message : sending to primary with index %u (with %u paths)",
3532 dIdx, currentAssociation->noOfNetworks);
3533
3534 if ((dIdx == 0xFFFF)|| (dIdx >= currentAssociation->noOfNetworks)) {
3535 error_log(ERROR_MAJOR, "mdi_send_message: could not get primary address");
3536 return 1;
3537 }
3538 dest_ptr = &(currentAssociation->destinationAddresses[dIdx]);
3539 } else {
3540 event_log(VVERBOSE, "mdi_send_message : last From Address was not NULL");
3541 memcpy(&dest_su, lastFromAddress, sizeof(union sockunion));
3542 dest_ptr = &dest_su;
3543 }
3544 }
3545
3546 if (isInitAckChunk(chunk)) {
3547 /* is true in case of an init-collision, normally when an initAck is sent
3548 no association exist and the last lastInitiateTag is used in the initAck. This
3549 is handled in the case above, where no association exists.
3550 Or when we respond to SHUTDOWN_ACK, see section 8.4.5)
3551 */
3552 if (lastInitiateTag == 0) {
3553 error_log(ERROR_MAJOR, "mdi_send_message: No verification tag");
3554 return 1;
3555 }
3556
3557 message->common_header.verification_tag = htonl(lastInitiateTag);
3558 } else {
3559 message->common_header.verification_tag = htonl(currentAssociation->tagRemote);
3560 }
3561
3562 message->common_header.src_port = htons(currentAssociation->localPort);
3563 message->common_header.dest_port = htons(currentAssociation->remotePort);
3564
3565 event_logiii(VVERBOSE,
3566 "mdi_send_message (II): tag = %x, src_port = %u , dest_port = %u",
3567 ntohl(message->common_header.verification_tag),
3568 currentAssociation->localPort, currentAssociation->remotePort);
3569 tos = currentAssociation->ipTos;
3570 }
3571
3572 /* calculate and insert checksum */
3573 aux_insert_checksum((unsigned char *) message, length);
3574
3575 switch (sockunion_family(dest_ptr)) {
3576 case AF_INET:
3577 txmit_len = adl_send_message(sctp_socket, message, length, dest_ptr, tos);
3578 break;
3579 #ifdef HAVE_IPV6
3580 case AF_INET6:
3581 txmit_len = adl_send_message(ipv6_sctp_socket, message, length, dest_ptr, tos);
3582 break;
3583 #endif
3584 default:
3585 error_log(ERROR_MAJOR, "mdi_send_message: Unsupported AF_TYPE");
3586 break;
3587 }
3588
3589 adl_sockunion2str(dest_ptr, hoststring, SCTP_MAX_IP_LEN);
3590 event_logiii(INTERNAL_EVENT_0, "sent SCTP message of %d bytes to %s, result was %d",
3591 length, hoststring, txmit_len);
3592
3593 return (txmit_len == (int)length) ? 0 : -1;
3594
3595 } /* end: mdi_send_message */
3596
3597
3598
3599 /*------------------- Functions called by the SCTP to forward primitives to ULP ------------------*/
3600
3601
3602 /**
3603 * indicates new data has arrived from peer (chapter 10.2.) destined for the ULP
3604 *
3605 * @param streamID received data belongs to this stream
3606 * @param length so many bytes have arrived (may be used to reserve space)
3607 * @param protoID the protocol ID of the arrived payload
3608 * @param unordered unordered flag (TRUE==1==unordered, FALSE==0==normal,numbered chunk)
3609 */
3610 void mdi_dataArriveNotif(unsigned short streamID, unsigned int length, unsigned short streamSN,
3611 unsigned int tsn, unsigned int protoID, unsigned int unordered)
3612 {
3613
3614 SCTP_instance *old_Instance = sctpInstance;
3615 Association *old_assoc = currentAssociation;
3616
3617 if (currentAssociation != NULL) {
3618
3619 event_logiiii(INTERNAL_EVENT_0, "mdi_dataArriveNotif(assoc %u, streamID %u, length %u, tsn %u)",
3620 currentAssociation->assocId, streamID, length, tsn);
3621 /* Forward dataArriveNotif to the ULP */
3622 if (sctpInstance->ULPcallbackFunctions.dataArriveNotif) {
3623 ENTER_CALLBACK("dataArriveNotif");
3624 sctpInstance->ULPcallbackFunctions.dataArriveNotif(currentAssociation->assocId,
3625 streamID,
3626 length,
3627 streamSN,
3628 tsn,
3629 protoID,
3630 unordered,
3631 currentAssociation->ulp_dataptr);
3632 LEAVE_CALLBACK("dataArriveNotif");
3633 }
3634 } else {
3635 error_log(ERROR_MAJOR, "mdi_dataArriveNotif: association not set");
3636 }
3637 sctpInstance = old_Instance;
3638 currentAssociation = old_assoc;
3639 } /* end: mdi_dataArriveNotif */
3640
3641
3642
3643 /**
3644 * indicates a change of network status (chapter 10.2.C). Calls the respective ULP callback function.
3645 * @param destinationAddress index to address that has changed
3646 * @param newState state to which indicated address has changed (PM_ACTIVE/PM_INACTIVE)
3647 */
3648 void mdi_networkStatusChangeNotif(short destinationAddress, unsigned short newState)
3649 {
3650 SCTP_instance *old_Instance = sctpInstance;
3651 Association *old_assoc = currentAssociation;
3652 if (currentAssociation != NULL) {
3653
3654 event_logiii(INTERNAL_EVENT_0, "mdi_networkStatusChangeNotif(assoc %u, path-id %d, state %u)",
3655 currentAssociation->assocId, destinationAddress,newState);
3656 if (sctpInstance->ULPcallbackFunctions.networkStatusChangeNotif) {
3657 ENTER_CALLBACK("networkStatusChangeNotif");
3658 sctpInstance->ULPcallbackFunctions.networkStatusChangeNotif(currentAssociation->assocId,
3659 destinationAddress, newState,
3660 currentAssociation->ulp_dataptr);
3661 LEAVE_CALLBACK("networkStatusChangeNotif");
3662 }
3663 } else {
3664 error_log(ERROR_MAJOR, "mdi_networkStatusChangeNotif: association not set");
3665 }
3666 sctpInstance = old_Instance;
3667 currentAssociation = old_assoc;
3668 } /* end: mdi_networkStatusChangeNotif */
3669
3670
3671
3672 /**
3673 * indicates a send failure (chapter 10.2.B). Calls the respective ULP callback function.
3674 * @param data pointer to the data that has not been sent
3675 * @param dataLength length of the data that has not been sent
3676 * @param context from sendChunk (CHECKME : may be obsolete ?)
3677 */
3678 void mdi_sendFailureNotif(unsigned char *data, unsigned int dataLength, unsigned int *context)
3679 {
3680 SCTP_instance *old_Instance = sctpInstance;
3681 Association *old_assoc = currentAssociation;
3682 if (currentAssociation != NULL) {
3683 if(sctpInstance->ULPcallbackFunctions.sendFailureNotif) {
3684 ENTER_CALLBACK("sendFailureNotif");
3685 sctpInstance->ULPcallbackFunctions.sendFailureNotif(currentAssociation->assocId,
3686 data, dataLength, context,
3687 currentAssociation->ulp_dataptr);
3688 LEAVE_CALLBACK("sendFailureNotif");
3689 }
3690 } else {
3691 error_log(ERROR_MAJOR, "mdi_sendFailureNotif: association not set");
3692 }
3693 sctpInstance = old_Instance;
3694 currentAssociation = old_assoc;
3695 } /* end: mdi_sendFailureNotif */
3696
3697
3698 /**
3699 * indicates that association has been gracefully shut down (chapter 10.2.H).
3700 * Calls the respective ULP callback function.
3701 */
3702 void mdi_peerShutdownReceivedNotif(void)
3703 {
3704 SCTP_instance *old_Instance = sctpInstance;
3705 Association *old_assoc = currentAssociation;
3706 if (currentAssociation != NULL) {
3707
3708 event_logi(INTERNAL_EVENT_0, "mdi_peerShutdownReceivedNotif(assoc %u)", currentAssociation->assocId);
3709 if(sctpInstance->ULPcallbackFunctions.peerShutdownReceivedNotif) {
3710 ENTER_CALLBACK("shutdownCompleteNotif");
3711 sctpInstance->ULPcallbackFunctions.peerShutdownReceivedNotif(currentAssociation->assocId,
3712 currentAssociation->ulp_dataptr);
3713 LEAVE_CALLBACK("peerShutdownReceivedNotif");
3714 }
3715 } else {
3716 error_log(ERROR_MAJOR, "mdi_peerShutdownReceivedNotif: association not set");
3717 }
3718 sctpInstance = old_Instance;
3719 currentAssociation = old_assoc;
3720 }
3721
3722
3723 /**
3724 * indicates that association has been gracefully shut down (chapter 10.2.H).
3725 * Calls the respective ULP callback function.
3726 */
3727 void mdi_shutdownCompleteNotif(void)
3728 {
3729 SCTP_instance *old_Instance = sctpInstance;
3730 Association *old_assoc = currentAssociation;
3731 if (currentAssociation != NULL) {
3732
3733 event_logi(INTERNAL_EVENT_0, "mdi_shutdownCompleteNotif(assoc %u)", currentAssociation->assocId);
3734 if(sctpInstance->ULPcallbackFunctions.shutdownCompleteNotif) {
3735 ENTER_CALLBACK("shutdownCompleteNotif");
3736 sctpInstance->ULPcallbackFunctions.shutdownCompleteNotif(currentAssociation->assocId,
3737 currentAssociation->ulp_dataptr);
3738 LEAVE_CALLBACK("shutdownCompleteNotif");
3739 }
3740 } else {
3741 error_log(ERROR_MAJOR, "mdi_shutdownCompleteNotif: association not set");
3742 }
3743 sctpInstance = old_Instance;
3744 currentAssociation = old_assoc;
3745 }
3746
3747
3748 /**
3749 * indicates that a restart has occured(chapter 10.2.G).
3750 * Calls the respective ULP callback function.
3751 */
3752 void mdi_restartNotif(void)
3753 {
3754 SCTP_instance *old_Instance = sctpInstance;
3755 Association *old_assoc = currentAssociation;
3756 if (currentAssociation != NULL) {
3757
3758 event_logi(INTERNAL_EVENT_0, "mdi_restartNotif(assoc %u)", currentAssociation->assocId);
3759
3760 if(sctpInstance->ULPcallbackFunctions.restartNotif) {
3761 ENTER_CALLBACK("restartNotif");
3762 sctpInstance->ULPcallbackFunctions.restartNotif(currentAssociation->assocId,
3763 currentAssociation->ulp_dataptr);
3764 LEAVE_CALLBACK("restartNotif");
3765 }
3766 } else {
3767 error_log(ERROR_MAJOR, "mdi_restartNotif: association not set");
3768 }
3769 sctpInstance = old_Instance;
3770 currentAssociation = old_assoc;
3771 }
3772
3773
3774
3775 /**
3776 * indicates that communication was lost to peer (chapter 10.2.E). Calls the respective ULP callback function.
3777 *
3778 * @param status type of event, that has caused the association to be terminated
3779 */
3780 void mdi_communicationLostNotif(unsigned short status)
3781 {
3782 SCTP_instance *old_Instance = sctpInstance;
3783 Association *old_assoc = currentAssociation;
3784
3785 if (currentAssociation != NULL) {
3786
3787 event_logii(INTERNAL_EVENT_0, "mdi_communicationLostNotif(assoc %u, status %u)",
3788 currentAssociation->assocId, status);
3789 if(sctpInstance->ULPcallbackFunctions.communicationLostNotif) {
3790 ENTER_CALLBACK("communicationLostNotif");
3791 sctpInstance->ULPcallbackFunctions.communicationLostNotif(currentAssociation->assocId,
3792 status,
3793 currentAssociation->ulp_dataptr);
3794 LEAVE_CALLBACK("communicationLostNotif");
3795 }
3796 } else {
3797 error_log(ERROR_MAJOR, "mdi_communicationLostNotif: association not set");
3798 }
3799 sctpInstance = old_Instance;
3800 currentAssociation = old_assoc;
3801 } /* end: mdi_communicationLostNotif */
3802
3803
3804
3805 /**
3806 * indicates that an association is established (chapter 10.2.D).
3807 *
3808 * @param status type of event that caused association to come up;
3809 * either SCTP_COMM_UP_RECEIVED_VALID_COOKIE, SCTP_COMM_UP_RECEIVED_COOKIE_ACK
3810 * or SCTP_COMM_UP_RECEIVED_COOKIE_RESTART
3811 */
3812 void mdi_communicationUpNotif(unsigned short status)
3813 {
3814 union sockunion lastAddress;
3815 int result, pathNum;
3816 short primaryPath;
3817 unsigned short noOfInStreams;
3818 unsigned short noOfOutStreams;
3819 SCTP_instance *old_Instance = sctpInstance;
3820 Association *old_assoc = currentAssociation;
3821
3822 if (currentAssociation != NULL) {
3823 /* Find primary path */
3824 result = mdi_readLastFromAddress(&lastAddress);
3825
3826 if (result != 1) {
3827
3828 for (primaryPath = 0; primaryPath < currentAssociation->noOfNetworks; primaryPath++) {
3829 if (adl_equal_address
3830 (&(currentAssociation->destinationAddresses[primaryPath]), &lastAddress)) {
3831 break;
3832 }
3833 }
3834 } else {
3835 primaryPath = 0;
3836 }
3837 if (primaryPath >= currentAssociation->noOfNetworks) primaryPath = 0;
3838
3839 /* set number of paths and primary path at pathmanegement and start heartbeat */
3840 pm_setPaths(currentAssociation->noOfNetworks, primaryPath);
3841
3842 se_readNumberOfStreams(&noOfInStreams, &noOfOutStreams);
3843
3844
3845 event_logiii(VERBOSE,
3846 "Distribution: COMM-UP, assocId: %u, status: %u, noOfNetworks: %u",
3847 currentAssociation->assocId, status, currentAssociation->noOfNetworks);
3848 event_logii(VERBOSE, "noOfInStreams: %u,noOfOutStreams %u", noOfInStreams, noOfOutStreams);
3849 /* FIXME (???) : retreive sctp-instance from list */
3850
3851 /* Forward mdi_communicationup Notification to the ULP */
3852 if(sctpInstance->ULPcallbackFunctions.communicationUpNotif) {
3853 ENTER_CALLBACK("communicationUpNotif");
3854 currentAssociation->ulp_dataptr = sctpInstance->ULPcallbackFunctions.communicationUpNotif(
3855 currentAssociation->assocId,
3856 status,
3857 currentAssociation->noOfNetworks,
3858 noOfInStreams, noOfOutStreams,
3859 currentAssociation->supportsPRSCTP,
3860 currentAssociation->ulp_dataptr);
3861 LEAVE_CALLBACK("communicationUpNotif");
3862 if (currentAssociation != NULL) {
3863 for (pathNum = 0; pathNum < currentAssociation->noOfNetworks; pathNum++) {
3864 if (pm_readState((short)pathNum) == PM_ACTIVE) {
3865 mdi_networkStatusChangeNotif((short)pathNum, PM_ACTIVE);
3866 }
3867 }
3868 }
3869 } else {
3870 currentAssociation->ulp_dataptr = NULL;
3871 }
3872 } else {
3873 error_log(ERROR_MAJOR, "mdi_communicationUpNotif: association not set");
3874 }
3875 sctpInstance = old_Instance;
3876 currentAssociation = old_assoc;
3877 } /* end: mdi_communicationLostNotif */
3878
3879
3880 /**
3881 * Function that notifies the ULP of a change in the queue status.
3882 * I.e. a limit may be exceeded, and therefore subsequent send-primitives will
3883 * fail, OR the queue length has dropped below a previously set queue length
3884 *
3885 * @param queueType i.e. an outbound queue, stream-engine queue, per stream queue (?)
3886 * @param queueId i.e. i.e. stream id for a per stream queue
3887 * @param queueLen in bytes or in messages, depending on the queue type
3888 */
3889 void mdi_queueStatusChangeNotif(int queueType, int queueId, int queueLen)
3890 {
3891 SCTP_instance *old_Instance = sctpInstance;
3892 Association *old_assoc = currentAssociation;
3893
3894 if (currentAssociation != NULL) {
3895
3896 event_logiiii(INTERNAL_EVENT_0, "mdi_queueStatusChangeNotif(assoc %u, queueType %d, queueId %d, len: %d)",
3897 currentAssociation->assocId, queueType,queueId,queueLen);
3898 if (sctpInstance->ULPcallbackFunctions.queueStatusChangeNotif) {
3899 ENTER_CALLBACK("queueStatusChangeNotif");
3900 sctpInstance->ULPcallbackFunctions.queueStatusChangeNotif(currentAssociation->assocId,
3901 queueType, queueId, queueLen,
3902 currentAssociation->ulp_dataptr);
3903 LEAVE_CALLBACK("queueStatusChangeNotif");
3904 }
3905 } else {
3906 error_log(ERROR_MAJOR, "mdi_queueuStatusChangeNotif: association not set");
3907 }
3908 sctpInstance = old_Instance;
3909 currentAssociation = old_assoc;
3910 } /* end: mdi_queueStatusChangeNotif */
3911
3912
3913 /*------------------- Functions called by the SCTP to get current association data----------------*/
3914
3915 /* When processing external events from outside the SCTP (socket events, timer events and
3916 function calls from the ULP), first the data of the addressed association are read
3917 from the list of associations and stored in a private but static datastructure.
3918 Elements of this association data can be read by the following functions.
3919 */
3920
3921
3922 /* The following functions return pointer to data of modules of the SCTP. As only these
3923 modules know the exact type of these data structures, so the returned pointer are
3924 of type void.
3925 */
3926
3927 /**
3928 * function to return a pointer to the flow control module of this association
3929 * @return pointer to the flow control data structure, null in case of error.
3930 */
3931 void *mdi_readFlowControl(void)
3932 {
3933 if (currentAssociation == NULL) {
3934 event_log(VVERBOSE, "mdi_readFlowControl: association not set");
3935 return NULL;
3936 } else {
3937 return currentAssociation->flowControl;
3938 }
3939 }
3940
3941
3942
3943 /**
3944 * function to return a pointer to the reliable transfer-module of this association
3945 * @return pointer to the reliable transfer data structure, null in case of error.
3946 */
3947 void *mdi_readReliableTransfer(void)
3948 {
3949 if (currentAssociation == NULL) {
3950 error_log(ERROR_MINOR, "mdi_readReliableTransfer: association not set");
3951 return NULL;
3952 } else {
3953 /* event_logii(VVERBOSE, "setting RelTransfer MemoryAddress %x, for association %u",
3954 currentAssociation->reliableTransfer, currentAssociation->assocId); */
3955 return currentAssociation->reliableTransfer;
3956 }
3957 }
3958
3959
3960
3961 /**
3962 * function to return a pointer to the receiver module of this association
3963 * @return pointer to the RX-control data structure, null in case of error.
3964 */
3965 void *mdi_readRX_control(void)
3966 {
3967 if (currentAssociation == NULL) {
3968 error_log(ERROR_MINOR, "mdi_readRX_control: association not set");
3969 return NULL;
3970 } else {
3971 return currentAssociation->rx_control;
3972 }
3973 }
3974
3975
3976
3977 /**
3978 * function to return a pointer to the stream-engine module of this association
3979 * @return pointer to the stream engine data structure, null in case of error.
3980 */
3981 void *mdi_readStreamEngine(void)
3982 {
3983 if (currentAssociation == NULL) {
3984 error_log(ERROR_MINOR, "mdi_readStreamEngine: association not set");
3985 return NULL;
3986 } else {
3987 event_logii(VVERBOSE, "setting StreamEngine MemoryAddress %x, for association %u",
3988 currentAssociation->streamengine, currentAssociation->assocId);
3989 return currentAssociation->streamengine;
3990 }
3991 }
3992
3993
3994
3995 /**
3996 * function to return a pointer to the path management module of this association
3997 * @return pointer to the pathmanagement data structure, null in case of error.
3998 */
3999 void *mdi_readPathMan(void)
4000 {
4001 if (currentAssociation == NULL) {
4002 error_log(ERROR_MINOR, "mdi_readPathMan: association not set");
4003 return NULL;
4004 } else {
4005 return currentAssociation->pathMan;
4006 }
4007 }
4008
4009
4010 /**
4011 * function to return a pointer to the bundling module of this association
4012 * @return pointer to the bundling data structure, null in case of error.
4013 */
4014 void *mdi_readBundling(void)
4015 {
4016 if (currentAssociation == NULL) {
4017 /*
4018 error_log(ERROR_MINOR, "mdi_readBundling: association not set");
4019 */
4020 return NULL;
4021 } else {
4022 return currentAssociation->bundling;
4023 }
4024 }
4025
4026
4027
4028 /**
4029 * function to return a pointer to the state machine controller of this association
4030 * @return pointer to the SCTP-control data structure, null in case of error.
4031 */
4032 void *mdi_readSCTP_control(void)
4033 {
4034 if (currentAssociation == NULL) {
4035 error_log(ERROR_MINOR, "mdi_readSCTP_control: association not set");
4036 return NULL;
4037 }
4038 return currentAssociation->sctp_control;
4039 }
4040
4041
4042 /**
4043 * function to read the association id of the current association
4044 * @return association-ID of the current association;
4045 * 0 means the association is not set (an error).
4046 */
4047 unsigned int mdi_readAssociationID(void)
4048 {
4049 if (currentAssociation == NULL) {
4050 error_log(ERROR_MINOR, "mdi_readAssociationID: association not set");
4051 return 0;
4052 } else {
4053 return currentAssociation->assocId;
4054 }
4055 }
4056
4057 /**
4058 * function to read the current local tag of the current association
4059 * @return association-ID of the current association;
4060 * 0 means the association is not set (an error).
4061 */
4062 unsigned int mdi_readLocalTag(void)
4063 {
4064 if (currentAssociation == NULL) {
4065 error_log(ERROR_MINOR, "mdi_readLocalTag: association not set");
4066 return 0;
4067 } else {
4068 return currentAssociation->tagLocal;
4069 }
4070 }
4071
4072
4073
4074 /**
4075 * function to read the tag that the peer within the current association uses
4076 * @return tag value of the peer within the current association;
4077 * CHECKME: can tag legally be 0 ?
4078 * 0 means the association is not set (an error).
4079 */
4080 unsigned int mdi_readTagRemote(void)
4081 {
4082 if (currentAssociation == NULL) {
4083 error_log(ERROR_MINOR, "mdi_readAssociationID: association not set");
4084 return 0;
4085 } else {
4086 return currentAssociation->tagRemote;
4087 }
4088 }
4089
4090 unsigned int mdi_getUnusedAssocId(void)
4091 {
4092 Association * tmp = NULL;
4093 unsigned int newId;
4094
4095 do {
4096 if(nextAssocId == 0) {
4097 nextAssocId++;
4098 }
4099 newId = nextAssocId;
4100 tmp = retrieveAssociation(newId);
4101 nextAssocId++;
4102 } while (tmp != NULL);
4103
4104 return newId;
4105 }
4106
4107 unsigned short mdi_getUnusedInstanceName(void)
4108 {
4109 SCTP_instance* tmp = NULL;
4110 unsigned short newId;
4111 unsigned int i;
4112
4113 for(i = 0;i < 65536;i++) {
4114 if(lastSCTP_instanceName == 0) {
4115 lastSCTP_instanceName++;
4116 }
4117 newId = lastSCTP_instanceName;
4118 tmp = retrieveInstance(newId);
4119 lastSCTP_instanceName++;
4120 if(tmp == NULL) {
4121 return(newId);
4122 }
4123 }
4124
4125 return(0);
4126 }
4127
4128 /**
4129 * generates a random tag value for a new association, but not 0
4130 * @return generates a random tag value for a new association, but not 0
4131 */
4132 unsigned int mdi_generateTag(void)
4133 {
4134 unsigned int tag;
4135
4136 while ((tag = adl_random()) == 0);
4137
4138 return tag;
4139 }
4140
4141
4142
4143 /**
4144 * generates a random tsn value for a new association (may also be 0)
4145 * @return generates a random tsn value for a new association (may also be 0)
4146 */
4147 unsigned int mdi_generateStartTSN(void)
4148 {
4149 return adl_random();
4150 }
4151
4152
4153
4154 /*------------- functions for the cookie mechanism --------------------------------------------*/
4155
4156 /**
4157 * sets the address from which the last datagramm was received (host byte order).
4158 * @returns 0 if successful, 1 if address could not be set !
4159 */
4160 int mdi_readLastFromAddress(union sockunion* fromAddress)
4161 {
4162 if (lastFromAddress == NULL) {
4163 error_log(ERROR_FATAL, "mdi_readLastFromAddress: no last from address");
4164 } else {
4165 memcpy(fromAddress, lastFromAddress, sizeof(union sockunion));
4166 return 0;
4167 }
4168 return 1;
4169 }
4170
4171 /**
4172 * sets the address from which the last datagramm was received (host byte order).
4173 * @returns 0 if successful, 1 if address could not be set !
4174 */
4175 int mdi_readLastDestAddress(union sockunion* destAddress)
4176 {
4177 if (lastDestAddress == NULL) {
4178 error_log(ERROR_MAJOR, "mdi_readLastDestAddress: no last dest address");
4179 } else {
4180 memcpy(destAddress, lastDestAddress, sizeof(union sockunion));
4181 return 0;
4182 }
4183 return 1;
4184 }
4185
4186
4187 /**
4188 * read the index of the path from which the last DG was received (-1 if no DG was received)
4189 * @return index of the path from which the last DG was received (-1 if no DG was received)
4190 */
4191 short mdi_readLastFromPath(void)
4192 {
4193 return lastFromPath;
4194 }
4195
4196 /**
4197 * read the port of the sender of the last received DG (host byte order)
4198 * @return the port of the sender of the last received DG (host byte order)
4199 */
4200 unsigned short mdi_readLastFromPort(void)
4201 {
4202 if (lastFromAddress == NULL) {
4203 error_log(ERROR_MINOR, "readLastFromPort: no last from address");
4204 return 0;
4205 } else {
4206 return lastFromPort;
4207 }
4208 }
4209
4210
4211 /**
4212 * read the port of the destination of the last received DG (host byte order)
4213 * @return the port of the destination of the last received DG (host byte order)
4214 */
4215 unsigned short mdi_readLastDestPort(void)
4216 {
4217 if (lastFromAddress == NULL) {
4218 error_log(ERROR_MINOR, "readLastDestPort: no last from address");
4219
4220 return 0;
4221 } else {
4222 return lastDestPort;
4223 }
4224 }
4225
4226 /* write the initiate tag of a-side to be used as verification tag for the initAck */
4227 void mdi_writeLastInitiateTag(unsigned int initiateTag)
4228 {
4229 lastInitiateTag = initiateTag;
4230 }
4231
4232 /* write the initiate tag of a-side to be used as verification tag for the initAck */
4233 unsigned int mdi_readLastInitiateTag(void)
4234 {
4235 return lastInitiateTag;
4236 }
4237
4238 /* rewrite the initiate tag of peer in case of a peer reset. */
4239 void mdi_rewriteTagRemote(unsigned int newInitiateTag)
4240 {
4241 if (currentAssociation == NULL) {
4242 error_log(ERROR_MINOR, "mdi_rewriteRemoteTag: association not set");
4243 } else {
4244 currentAssociation->tagRemote = newInitiateTag;
4245 }
4246 }
4247
4248 /* rewrite the initiate tag of peer in case of a peer reset. */
4249 void mdi_rewriteLocalTag(unsigned int newTag)
4250 {
4251 if (currentAssociation == NULL) {
4252 error_log(ERROR_MINOR, "mdi_rewriteLocalTag: association not set");
4253 } else {
4254 currentAssociation->tagLocal = newTag;
4255 }
4256 }
4257
4258
4259 /*------------- functions to write and read addresses --------------------------------------------*/
4260
4261 short mdi_getIndexForAddress(union sockunion* address)
4262 {
4263 short index = 0;
4264
4265 if (currentAssociation == NULL) {
4266 error_log(ERROR_MINOR, "mdi_getIndexForAddress: association not set");
4267 return -1;
4268 } else {
4269 if (currentAssociation->destinationAddresses == NULL) {
4270 error_log(ERROR_MINOR, "mdi_getIndexForAddress: addresses not set");
4271 return -1;
4272 }
4273 /* send cookie back to the address where we got it from */
4274 for (index = 0; index < currentAssociation->noOfNetworks; index++)
4275 if (adl_equal_address(&(currentAssociation->destinationAddresses[index]),address)) break;
4276 if (index == currentAssociation->noOfNetworks) /* not found */
4277 return -1;
4278
4279 }
4280 return index;
4281
4282 }
4283
4284 /**
4285 * copies destination addresses from the array passed as parameter to the current association
4286 * @param addresses array that will hold the destination addresses after returning
4287 * @param noOfAddresses number of addresses that the peer has (and sends along in init/initAck)
4288 */
4289 void mdi_writeDestinationAddresses(union sockunion addresses[MAX_NUM_ADDRESSES], int noOfAddresses)
4290 {
4291
4292 if (currentAssociation == NULL) {
4293 error_log(ERROR_MINOR, "mdi_writeDestinationAddresses: association not set");
4294 return;
4295 } else {
4296 if (currentAssociation->destinationAddresses != NULL) {
4297 free(currentAssociation->destinationAddresses);
4298 }
4299
4300 currentAssociation->destinationAddresses =
4301 (union sockunion *) malloc(noOfAddresses * sizeof(union sockunion));
4302
4303 if (currentAssociation->destinationAddresses == NULL)
4304 error_log(ERROR_FATAL, "mdi_writeDestinationAddresses: out of memory");
4305
4306 memcpy(currentAssociation->destinationAddresses, addresses,
4307 noOfAddresses * sizeof(union sockunion));
4308
4309 currentAssociation->noOfNetworks = noOfAddresses;
4310
4311 return;
4312 }
4313 }
4314
4315
4316 /**
4317 * Function that returns the number of incoming streams that this instance
4318 * is willing to handle !
4319 * @return maximum number of in-streams
4320 */
4321 unsigned short mdi_readLocalInStreams(void)
4322 {
4323 SCTP_instance temporary;
4324 GList* result = NULL;
4325
4326 if (currentAssociation == NULL) {
4327 /* retrieve SCTP-instance with last destination port */
4328 lastDestPort = mdi_readLastDestPort();
4329 event_logi(VERBOSE, "mdi_readLocalInStreams(): Searching for SCTP Instance with Port %u ", lastDestPort);
4330 temporary.supportedAddressTypes = 0;
4331 temporary.has_INADDR_ANY_set = FALSE;
4332 temporary.has_IN6ADDR_ANY_set = FALSE;
4333 temporary.localPort = lastDestPort;
4334 temporary.noOfLocalAddresses = 1;
4335 if (lastDestAddress)
4336 temporary.localAddressList = lastDestAddress;
4337 else
4338 error_log(ERROR_FATAL, "lastDestAddress NULL in mdi_readLocalInStreams() - FIXME !");
4339
4340 result = g_list_find_custom(InstanceList, &temporary, &CheckForAddressInInstance);
4341 if (result == NULL) {
4342 error_logi(ERROR_FATAL, "Could not find SCTP Instance for Port %u in List, FIXME !",lastDestPort);
4343 }
4344 sctpInstance = (SCTP_instance*)result->data;
4345 } else {
4346 /* retrieve SCTP-instance with SCTP-instance name in current association */
4347 temporary.sctpInstanceName = currentAssociation->sctpInstance->sctpInstanceName;
4348 event_logi(VERBOSE, "Searching for SCTP Instance with Name %u ", currentAssociation->sctpInstance->sctpInstanceName);
4349 result = g_list_find_custom(InstanceList, &temporary, &CompareInstanceNames);
4350 if (result == NULL) {
4351 error_logi(ERROR_FATAL, "Could not find SCTP Instance with name %u in List, FIXME !",
4352 currentAssociation->sctpInstance->sctpInstanceName);
4353 }
4354 sctpInstance = (SCTP_instance*)result->data;
4355 }
4356 return sctpInstance->noOfInStreams;
4357 }
4358
4359 /**
4360 * Function that returns the number of incoming streams that this instance
4361 * is willing to handle !
4362 * @return maximum number of in-streams
4363 */
4364 unsigned short mdi_readLocalOutStreams(void)
4365 {
4366 SCTP_instance temporary;
4367 GList* result = NULL;
4368
4369 if (currentAssociation == NULL) {
4370 /* retrieve SCTP-instance with last destination port */
4371 lastDestPort = mdi_readLastDestPort();
4372 event_logi(VERBOSE, "Searching for SCTP Instance with Port %u ", lastDestPort);
4373 temporary.supportedAddressTypes = 0;
4374 temporary.localPort = lastDestPort;
4375 temporary.has_INADDR_ANY_set = FALSE;
4376 temporary.has_IN6ADDR_ANY_set = FALSE;
4377 temporary.noOfLocalAddresses = 1;
4378 if (lastDestAddress)
4379 temporary.localAddressList = lastDestAddress;
4380 else
4381 error_log(ERROR_FATAL, "lastDestAddress NULL in mdi_readLocalInStreams() - FIXME !");
4382
4383 result = g_list_find_custom(InstanceList, &temporary, &CheckForAddressInInstance);
4384 if (result == NULL) {
4385 error_logi(ERROR_FATAL, "Could not find SCTP Instance for Port %u in List, FIXME !",lastDestPort);
4386 }
4387 sctpInstance = (SCTP_instance*)result->data;
4388 } else {
4389 /* retrieve SCTP-instance with SCTP-instance name in current association */
4390 temporary.sctpInstanceName = currentAssociation->sctpInstance->sctpInstanceName;
4391 event_logi(VERBOSE, "Searching for SCTP Instance with Name %u ", currentAssociation->sctpInstance->sctpInstanceName);
4392 result = g_list_find_custom(InstanceList, &temporary, &CompareInstanceNames);
4393 if (result == NULL) {
4394 error_logi(ERROR_FATAL, "Could not find SCTP Instance with name %u in List, FIXME !",
4395 currentAssociation->sctpInstance->sctpInstanceName);
4396 }
4397 sctpInstance = (SCTP_instance*)result->data;
4398 }
4399 return sctpInstance->noOfOutStreams;
4400 }
4401
4402
4403 /**
4404 * Copies local addresses of this instance into the array passed as parameter
4405 * CHECKME : does this function work in all circumstances ?
4406 * --> Under what conditions can we NOT find the SCTP instance ?
4407 *
4408 * @param addresses array that will hold the local host's addresses after returning
4409 * @param noOfAddresses number of addresses that local host/current association has
4410 */
4411 void mdi_readLocalAddresses(union sockunion laddresses[MAX_NUM_ADDRESSES],
4412 guint16 * noOfAddresses,
4413 union sockunion *peerAddress,
4414 unsigned int numPeerAddresses,
4415 unsigned int addressTypes,
4416 gboolean receivedFromPeer)
4417 {
4418
4419 unsigned int count = 0, tmp;
4420 AddressScopingFlags filterFlags = (AddressScopingFlags)0;
4421 gboolean localHostFound=FALSE, linkLocalFound = FALSE, siteLocalFound = FALSE;
4422
4423
4424 if ((currentAssociation == NULL) && (sctpInstance == NULL)) {
4425 error_log(ERROR_FATAL, "mdi_readLocalAddresses: neither assoc nor instance set - error !");
4426 *noOfAddresses = 0;
4427 return;
4428 }
4429 if (sctpInstance == NULL) {
4430 error_log(ERROR_MAJOR, "mdi_readLocalAddresses: instance not set - program error");
4431 sctpInstance = currentAssociation->sctpInstance;
4432 }
4433
4434 for (count = 0; count < numPeerAddresses; count++) {
4435 localHostFound |= mdi_addressListContainsLocalhost(1, &peerAddress[count]);
4436 linkLocalFound |= !( adl_filterInetAddress(&peerAddress[count], flag_HideLinkLocal));
4437 siteLocalFound |= !( adl_filterInetAddress(&peerAddress[count], flag_HideSiteLocal));
4438 }
4439
4440 /* if (receivedFromPeer == FALSE) I send an INIT with my addresses to the peer */
4441 if ((receivedFromPeer == FALSE) && (localHostFound == TRUE)) {
4442 /* if paddress == loopback then add my loopback */
4443 filterFlags = flag_Default;
4444 } else if ((receivedFromPeer == FALSE) && (localHostFound == FALSE)) {
4445 /* only add loopback, if sending to a loopback */
4446 filterFlags = (AddressScopingFlags)(flag_Default|flag_HideLoopback);
4447
4448 /* if (receivedFromPeer == TRUE) I got an INIT with addresses from the peer */
4449 } else if ((receivedFromPeer == TRUE) && (localHostFound == FALSE)) {
4450 /* this is from a normal address, get all except loopback */
4451 if (linkLocalFound) {
4452 filterFlags = (AddressScopingFlags)(flag_Default|flag_HideLoopback);
4453 } else if (siteLocalFound) {
4454 filterFlags = (AddressScopingFlags)(flag_Default| flag_HideLinkLocal|flag_HideLoopback);
4455 } else {
4456 filterFlags = (AddressScopingFlags)(flag_Default|flag_HideLocal);
4457 }
4458 } else /* if ((receivedFromPeer == TRUE) && (localHostFound == TRUE)) */ {
4459 /* this is from a loopback, get all loopbacks */
4460 filterFlags = flag_Default;
4461 }
4462
4463 count = 0;
4464
4465 if (sctpInstance->has_INADDR_ANY_set == TRUE) {
4466 for (tmp = 0; tmp < myNumberOfAddresses; tmp++) {
4467 switch(sockunion_family( &(myAddressList[tmp]))) {
4468 case AF_INET :
4469 if ((addressTypes & SUPPORT_ADDRESS_TYPE_IPV4) != 0) {
4470 if ( adl_filterInetAddress(&(myAddressList[tmp]), filterFlags) == TRUE) {
4471 memcpy(&(laddresses[count]), &(myAddressList[tmp]),sizeof(union sockunion));
4472 count++;
4473 }
4474 }
4475 break;
4476 default: break;
4477 }
4478 }
4479 event_logii(VERBOSE, "mdi_readLocalAddresses: found %u local addresses from INADDR_ANY (from %u)",
4480 count,myNumberOfAddresses ); } else if (sctpInstance->has_IN6ADDR_ANY_set == TRUE) {
4481 for (tmp = 0; tmp < myNumberOfAddresses; tmp++) {
4482 switch(sockunion_family( &(myAddressList[tmp]))) {
4483 case AF_INET :
4484 if ((addressTypes & SUPPORT_ADDRESS_TYPE_IPV4) != 0) {
4485 if ( adl_filterInetAddress(&(myAddressList[tmp]), filterFlags) == TRUE) {
4486 memcpy(&(laddresses[count]), &(myAddressList[tmp]),sizeof(union sockunion));
4487 count++;
4488 }
4489 }
4490 break;
4491 #ifdef HAVE_IPV6
4492 case AF_INET6 :
4493 if ((addressTypes & SUPPORT_ADDRESS_TYPE_IPV6) != 0) {
4494 if ( adl_filterInetAddress(&(myAddressList[tmp]), filterFlags) == TRUE) {
4495 memcpy(&(laddresses[count]), &(myAddressList[tmp]),sizeof(union sockunion));
4496 count++;
4497 }
4498 }
4499 break;
4500 #endif
4501 default: break;
4502 }
4503 }
4504 event_logii(VERBOSE, "mdi_readLocalAddresses: found %u local addresses from IN6ADDR_ANY (from %u)", count,
4505 myNumberOfAddresses);
4506 } else {
4507 for (tmp = 0; tmp < sctpInstance->noOfLocalAddresses; tmp++) {
4508 switch(sockunion_family( &(sctpInstance->localAddressList[tmp]))) {
4509 case AF_INET :
4510 if ((addressTypes & SUPPORT_ADDRESS_TYPE_IPV4) != 0) {
4511 if ( adl_filterInetAddress(&(sctpInstance->localAddressList[tmp]), filterFlags) == TRUE) {
4512 memcpy(&(laddresses[count]), &(sctpInstance->localAddressList[tmp]),
4513 sizeof(union sockunion));
4514 count++;
4515 }
4516 }
4517 break;
4518 #ifdef HAVE_IPV6
4519 case AF_INET6 :
4520 if ((addressTypes & SUPPORT_ADDRESS_TYPE_IPV6) != 0) {
4521 if ( adl_filterInetAddress(&(sctpInstance->localAddressList[tmp]), filterFlags) == TRUE) {
4522 memcpy(&(laddresses[count]), &(sctpInstance->localAddressList[tmp]),
4523 sizeof(union sockunion));
4524 count++;
4525 }
4526 }
4527 break;
4528 #endif
4529 default: break;
4530 }
4531 }
4532 event_logii(VERBOSE, "mdi_readLocalAddresses: found %u local addresses from instance (from %u)", count,
4533 sctpInstance->noOfLocalAddresses);
4534 }
4535 event_logi(INTERNAL_EVENT_0, "mdi_readLocalAddresses() : returning %u addresses !",count);
4536 /*
4537 if (count == 0) abort();
4538 */
4539
4540 *noOfAddresses = count;
4541 }
4542
4543
4544
4545 gboolean mdi_supportsPRSCTP(void)
4546 {
4547 if (currentAssociation != NULL) {
4548 return (currentAssociation->supportsPRSCTP && currentAssociation->peerSupportsPRSCTP);
4549 }
4550 if (sctpInstance != NULL) {
4551 return sctpInstance->supportsPRSCTP;
4552 }
4553 return (librarySupportsPRSCTP);
4554 }
4555
4556 gboolean mdi_peerSupportsPRSCTP(void)
4557 {
4558 if (currentAssociation == NULL)
4559 return FALSE;
4560 return currentAssociation->peerSupportsPRSCTP;
4561 }
4562
4563
4564 int mdi_getDefaultRtoInitial(void* sctpInstance)
4565 {
4566 if (sctpInstance == NULL) return -1;
4567 else
4568 return ((SCTP_instance*)sctpInstance)->default_rtoInitial;
4569 }
4570 int mdi_getDefaultValidCookieLife(void* sctpInstance)
4571 {
4572 if (sctpInstance == NULL) return -1;
4573 else
4574 return ((SCTP_instance*)sctpInstance)->default_validCookieLife;
4575 }
4576 int mdi_getDefaultAssocMaxRetransmits(void* sctpInstance)
4577 {
4578 if (sctpInstance == NULL) return -1;
4579 else
4580 return ((SCTP_instance*)sctpInstance)->default_assocMaxRetransmits;
4581 }
4582 int mdi_getDefaultPathMaxRetransmits(void* sctpInstance)
4583 {
4584 if (sctpInstance == NULL) return -1;
4585 else
4586 return ((SCTP_instance*)sctpInstance)->default_pathMaxRetransmits;
4587 }
4588 int mdi_getDefaultMaxInitRetransmits(void* sctpInstance)
4589 {
4590 if (sctpInstance == NULL) return -1;
4591 else
4592 return ((SCTP_instance*)sctpInstance)->default_maxInitRetransmits;
4593 }
4594 int mdi_getDefaultMyRwnd()
4595 {
4596 if (sctpInstance == NULL) return -1;
4597 else {
4598 event_logi(VVERBOSE, " mdi_getDefaultMyRwnd is %u", sctpInstance->default_myRwnd);
4599 return ((SCTP_instance*)sctpInstance)->default_myRwnd;
4600 }
4601 }
4602 int mdi_getDefaultRtoMin(void* sctpInstance)
4603 {
4604 if (sctpInstance == NULL) return -1;
4605 else
4606 return ((SCTP_instance*)sctpInstance)->default_rtoMin;
4607 }
4608
4609 int mdi_getDefaultRtoMax(void* sctpInstance)
4610 {
4611 if (sctpInstance == NULL) return -1;
4612 else
4613 return ((SCTP_instance*)sctpInstance)->default_rtoMax;
4614 }
4615
4616 int mdi_getDefaultMaxBurst(void)
4617 {
4618 if (sctpInstance == NULL) return DEFAULT_MAX_BURST;
4619 else if (currentAssociation == NULL) return DEFAULT_MAX_BURST;
4620 else
4621 return (currentAssociation->sctpInstance->default_maxBurst);
4622 }
4623
4624 int mdi_getDefaultDelay(void* sctpInstance)
4625 {
4626 if (sctpInstance == NULL) return -1;
4627 else
4628 return ((SCTP_instance*)sctpInstance)->default_delay;
4629 }
4630
4631 int mdi_getDefaultIpTos(void* sctpInstance)
4632 {
4633 if (sctpInstance == NULL) return -1;
4634 else
4635 return ((SCTP_instance*)sctpInstance)->default_ipTos;
4636 }
4637 int mdi_getDefaultMaxSendQueue(void* sctpInstance)
4638 {
4639 if (sctpInstance == NULL) return -1;
4640 else
4641 return ((SCTP_instance*)sctpInstance)->default_maxSendQueue;
4642 }
4643 int mdi_getDefaultMaxRecvQueue(void* sctpInstance)
4644 {
4645 if (sctpInstance == NULL) return -1;
4646 else
4647 return ((SCTP_instance*)sctpInstance)->default_maxRecvQueue;
4648 }
4649
4650 unsigned int mdi_getSupportedAddressTypes(void)
4651 {
4652 if (sctpInstance == NULL) return -1;
4653 else
4654 return sctpInstance->supportedAddressTypes;
4655 }
4656
4657 /*------------- functions to set and clear the association data ----------------------------------*/
4658
4659 /**
4660 * Each module within SCTP that has timers implements its own timer call back
4661 * functions. These are registered at the adaption layer when a timer is started
4662 * and called directly at the module when the timer expires.
4663 * setAssociationData allows SCTP-modules with timers to retrieve the data of the
4664 * addressed association from the list of associations.
4665 * For this purpose the association-ID must be included in one of the
4666 * parameters of the start_timer function of the adaption-layer.
4667 *
4668 * @param associationID the ID of the association
4669 * @return 0 if successful, 1 if the association does not exist in the list
4670 */
4671 unsigned short mdi_setAssociationData(unsigned int associationID)
4672 {
4673 if (currentAssociation != NULL)
4674 error_log(ERROR_MINOR, "mdi_setAssociationData: previous assoc not cleared");
4675
4676 /* retrieve association from list */
4677 currentAssociation = retrieveAssociation(associationID);
4678 if (currentAssociation == NULL) {
4679 error_log(ERROR_MINOR, "mdi_setAssociationData: association does not exist");
4680 return 1;
4681 }
4682 sctpInstance = currentAssociation->sctpInstance;
4683 return 0;
4684 }
4685
4686
4687
4688 /**
4689 * Clear the global association data.
4690 * This function must be called after the association retrieved from the list
4691 * with setAssociationData is no longer needed. This is the case after a time
4692 * event has been handled.
4693 *
4694 * @param associationID the ID of the association
4695 * @return 0 if successful, 1 if association data has not been set, 2 wrong associationID
4696 */
4697 unsigned short mdi_clearAssociationData(void)
4698 {
4699 currentAssociation = NULL;
4700 sctpInstance = NULL;
4701 return 0;
4702 }
4703
4704
4705 /*------------------- Functions to create and delete associations --------------------------------*/
4706
4707 /**
4708 * This function allocates memory for a new association.
4709 * For the active side of an association, this function is called when ULP calls Associate
4710 * For the passive side this function is called when a valid cookie message is received.
4711 * It also creates all the modules path management, bundling and SCTP-control.
4712 * The rest of the modules are created with mdi_initAssociation.
4713 * The created association is put into the list of associations.
4714 *
4715 * @param SCTP_InstanceName identifier for an SCTP instance (if there are more)
4716 * @param local_port src port (which this association listens to)
4717 * @param remote_port destination port (peers source port)
4718 * @param tagLocal randomly generated tag belonging to this association
4719 * @param primaryDestinitionAddress index of the primary address
4720 * @param noOfDestinationAddresses number of addresses the peer has
4721 * @param destinationAddressList pointer to the array of peer's addresses
4722 * @return 0 for success, else 1 for failure
4723 */
4724 unsigned short
4725 mdi_newAssociation(void* sInstance,
4726 unsigned short local_port,
4727 unsigned short remote_port,
4728 unsigned int tagLocal,
4729 short primaryDestinitionAddress,
4730 short noOfDestinationAddresses,
4731 union sockunion *destinationAddressList)
4732 {
4733 SCTP_instance* instance = NULL;
4734 unsigned int ii;
4735 int result;
4736
4737 if (sInstance == NULL) {
4738 if (sctpInstance == NULL) {
4739 error_logi(ERROR_FATAL, "SCTP Instance for Port %u were all NULL, call sctp_registerInstance FIRST !",local_port);
4740 return 1;
4741 } else {
4742 instance = sctpInstance;
4743 }
4744 } else {
4745 instance = (SCTP_instance*)sInstance;
4746 }
4747
4748 if (!instance) error_log(ERROR_MAJOR, "instance is NULL ! Segfault !");
4749
4750 event_logiiiii(VERBOSE," mdi_newAssociation: Instance: %u, local port %u, rem.port: %u, local tag: %u, primary: %d",
4751 instance->sctpInstanceName, local_port, remote_port, tagLocal, primaryDestinitionAddress);
4752
4753
4754 /* Do plausi checks on the addresses. */
4755 if (noOfDestinationAddresses <= 0 || destinationAddressList == NULL) {
4756 error_log(ERROR_MAJOR, "No destination address suppllied for new association");
4757 return 1;
4758
4759 } else if (primaryDestinitionAddress < 0
4760 || primaryDestinitionAddress >= noOfDestinationAddresses) {
4761 error_log(ERROR_MAJOR, "Invalid primary destination address for new association");
4762 return 1;
4763 }
4764
4765 if (currentAssociation) {
4766 error_log(ERROR_MINOR, "current association not cleared");
4767 }
4768
4769 currentAssociation = (Association *) malloc(sizeof(Association));
4770
4771 if (!currentAssociation) {
4772 error_log_sys(ERROR_FATAL, (short)errno);
4773 return 1;
4774 }
4775
4776 currentAssociation->sctpInstance = instance;
4777 currentAssociation->localPort = local_port;
4778 currentAssociation->remotePort = remote_port;
4779 currentAssociation->tagLocal = tagLocal;
4780 currentAssociation->assocId = mdi_getUnusedAssocId();
4781 currentAssociation->tagRemote = 0;
4782 currentAssociation->deleted = FALSE;
4783
4784 currentAssociation->ulp_dataptr = NULL;
4785 currentAssociation->ipTos = instance->default_ipTos;
4786 currentAssociation->maxSendQueue = instance->default_maxSendQueue;
4787
4788 result = mdi_updateMyAddressList();
4789 if (result != SCTP_SUCCESS) {
4790 error_log(ERROR_MAJOR, "Could not update my address list. Unable to initiate new association.");
4791 return 1;
4792 }
4793
4794 if (instance->has_IN6ADDR_ANY_set) {
4795 /* get ALL addresses */
4796 currentAssociation->noOfLocalAddresses = myNumberOfAddresses;
4797 currentAssociation->localAddresses =
4798 (union sockunion *) calloc(myNumberOfAddresses, sizeof(union sockunion));
4799 memcpy(currentAssociation->localAddresses, myAddressList,
4800 myNumberOfAddresses* sizeof(union sockunion));
4801 event_logi(VERBOSE," mdi_newAssociation: Assoc has has_IN6ADDR_ANY_set, and %d addresses",myNumberOfAddresses);
4802 } else if (instance->has_INADDR_ANY_set) {
4803 /* get all IPv4 addresses */
4804 currentAssociation->noOfLocalAddresses = 0;
4805 for (ii = 0; ii < myNumberOfAddresses; ii++) {
4806 if (sockunion_family(&(myAddressList[ii])) == AF_INET) {
4807 currentAssociation->noOfLocalAddresses++;
4808 }
4809 }
4810 currentAssociation->localAddresses =
4811 (union sockunion *) calloc(currentAssociation->noOfLocalAddresses, sizeof(union sockunion));
4812 currentAssociation->noOfLocalAddresses = 0;
4813 for (ii = 0; ii < myNumberOfAddresses; ii++) {
4814 if (sockunion_family(&(myAddressList[ii])) == AF_INET) {
4815 memcpy(&(currentAssociation->localAddresses[currentAssociation->noOfLocalAddresses]),
4816 &(myAddressList[ii]),sizeof(union sockunion));
4817 currentAssociation->noOfLocalAddresses++;
4818 }
4819 }
4820 event_logi(VERBOSE," mdi_newAssociation: Assoc has has_INADDR_ANY_set, and %d addresses",currentAssociation->noOfLocalAddresses);
4821 } else { /* get all specified addresses */
4822 currentAssociation->noOfLocalAddresses = instance->noOfLocalAddresses;
4823 currentAssociation->localAddresses =
4824 (union sockunion *) malloc(instance->noOfLocalAddresses * sizeof(union sockunion));
4825 memcpy(currentAssociation->localAddresses, instance->localAddressList,
4826 instance->noOfLocalAddresses * sizeof(union sockunion));
4827
4828 }
4829
4830 currentAssociation->had_IN6ADDR_ANY_set = instance->has_IN6ADDR_ANY_set;
4831 currentAssociation->had_INADDR_ANY_set = instance->has_INADDR_ANY_set;
4832
4833 currentAssociation->noOfNetworks = noOfDestinationAddresses;
4834 currentAssociation->destinationAddresses =
4835 (union sockunion *) malloc(noOfDestinationAddresses * sizeof(union sockunion));
4836 memcpy(currentAssociation->destinationAddresses, destinationAddressList,
4837 noOfDestinationAddresses * sizeof(union sockunion));
4838
4839 /* check if newly created association already exists. */
4840 if (checkForExistingAssociations(currentAssociation) == 1) {
4841 error_log(ERROR_MAJOR, "tried to establish an existing association");
4842 /* FIXME : also free bundling, pathmanagement,sctp_control */
4843 free(currentAssociation->localAddresses);
4844 free(currentAssociation->destinationAddresses);
4845 free(currentAssociation);
4846 currentAssociation = NULL;
4847 return 1;
4848 }
4849
4850 /* initialize pointer to other modules of SCTP */
4851 currentAssociation->flowControl = NULL;
4852 currentAssociation->reliableTransfer = NULL;
4853 currentAssociation->rx_control = NULL;
4854 currentAssociation->streamengine = NULL;
4855
4856 /* only pathman, bundling and sctp-control are created at this point, the rest is created
4857 with mdi_initAssociation */
4858 currentAssociation->bundling = bu_new();
4859 currentAssociation->pathMan = pm_newPathman(noOfDestinationAddresses,
4860 primaryDestinitionAddress, instance);
4861 currentAssociation->sctp_control = sci_newSCTP_control(instance);
4862
4863 currentAssociation->supportsPRSCTP = instance->supportsPRSCTP;
4864 currentAssociation->peerSupportsPRSCTP = instance->supportsPRSCTP;
4865
4866 currentAssociation->supportsADDIP = FALSE;
4867 currentAssociation->peerSupportsADDIP = FALSE;
4868
4869
4870 event_logii(INTERNAL_EVENT_1, "new Association created ID=%08x, local tag=%08x",
4871 currentAssociation->assocId, currentAssociation->tagLocal);
4872
4873 /* Enter association into list */
4874 event_logi(INTERNAL_EVENT_0, "entering association %08x into list", currentAssociation->assocId);
4875
4876 AssociationList = g_list_insert_sorted(AssociationList,currentAssociation, &compareAssociationIDs);
4877
4878 return 0;
4879 } /* end: mdi_newAssociation */
4880
4881
4882 /**
4883 * This is the second function needed to fully create and initialize an association (after
4884 * mdi_newAssociation()) THe association is created in two steps because data become available
4885 * at the a-side in two steps
4886 * \begin{enumerate}
4887 * \item associate
4888 * \item init acknowledgement
4889 * \end{enumerate}
4890 * At the z-side, with the cookie message all data is available at once. So mdi_newAssociation
4891 * and mdi_initAssociation must be called when the initAck with valid Cookie is received.
4892 *
4893 * @param remoteSideReceiverWindow rwnd size that the peer allowed in this association
4894 * @param noOfInStreams number of incoming (receive) streams after negotiation
4895 * @param noOfOutStreams number of outgoing (send) streams after negotiation
4896 * @param remoteInitialTSN initial TSN of the peer
4897 * @param tagRemote tag of the peer
4898 * @param localInitialTSN my initial TSN, needed for initializing my flow control
4899 * @return 0 for success, else 1 for error
4900 */
4901 unsigned short
4902 mdi_initAssociation(unsigned int remoteSideReceiverWindow,
4903 unsigned short noOfInStreams,
4904 unsigned short noOfOutStreams,
4905 unsigned int remoteInitialTSN,
4906 unsigned int tagRemote, unsigned int localInitialTSN,
4907 gboolean assocSupportsPRSCTP, gboolean assocSupportsADDIP)
4908 {
4909 gboolean withPRSCTP;
4910
4911 if (!currentAssociation) {
4912 error_log(ERROR_MAJOR,
4913 "mdi_initAssociation: current association does not exist, can not initialize");
4914 return 1;
4915 }
4916
4917 /* if mdi_initAssociation has already be called, delete modules and make new ones
4918 with possibly new data. Multiple calls of of mdi_initAssociation can occur on the
4919 a-side in the case of stale cookie errors. */
4920 if (currentAssociation->tagRemote != 0) {
4921 event_log(INTERNAL_EVENT_1,
4922 "Deleting Modules in mdi_initAssociation() -- then recreating them !!!!");
4923 /* association init was already completed */
4924 fc_delete_flowcontrol(currentAssociation->flowControl);
4925 rtx_delete_reltransfer(currentAssociation->reliableTransfer);
4926 rxc_delete_recvctrl(currentAssociation->rx_control);
4927 se_delete_stream_engine(currentAssociation->streamengine);
4928 }
4929
4930 /* TODO : check number of input and output streams (although that should be fixed now) */
4931
4932 currentAssociation->tagRemote = tagRemote;
4933
4934 withPRSCTP = assocSupportsPRSCTP && currentAssociation->supportsPRSCTP;
4935 currentAssociation->peerSupportsPRSCTP = withPRSCTP;
4936 currentAssociation->supportsPRSCTP = withPRSCTP;
4937
4938 currentAssociation->reliableTransfer =
4939 (void *) rtx_new_reltransfer(currentAssociation->noOfNetworks, localInitialTSN);
4940 currentAssociation->flowControl =
4941 (void *) fc_new_flowcontrol(remoteSideReceiverWindow, localInitialTSN,
4942 currentAssociation->noOfNetworks, currentAssociation->maxSendQueue);
4943
4944 currentAssociation->rx_control = (void *) rxc_new_recvctrl(remoteInitialTSN,currentAssociation->noOfNetworks,
4945 currentAssociation->sctpInstance);
4946 currentAssociation->streamengine = (void *) se_new_stream_engine(noOfInStreams,
4947 noOfOutStreams,
4948 withPRSCTP);
4949
4950 event_logii(INTERNAL_EVENT_1, "second step of association initialisation performed ID=%08x, local tag=%08x",
4951 currentAssociation->assocId, currentAssociation->tagLocal);
4952
4953 return 0;
4954
4955 } /* end: mdi_initAssociation */
4956
4957
4958 unsigned short
4959 mdi_restartAssociation(unsigned short noOfInStreams,
4960 unsigned short noOfOutStreams,
4961 unsigned int new_rwnd,
4962 unsigned int remoteInitialTSN,
4963 unsigned int localInitialTSN,
4964 short noOfPaths,
4965 short primaryAddress,
4966 union sockunion *destinationAddressList,
4967 gboolean assocSupportsPRSCTP, gboolean assocSupportsADDIP)
4968 {
4969 int result;
4970 gboolean withPRSCTP;
4971
4972 if (!currentAssociation) {
4973 error_log(ERROR_MAJOR, "mdi_restartAssociation: current association is NULL !");
4974 return 1;
4975 }
4976 if (!sctpInstance) {
4977 error_log(ERROR_MAJOR, "mdi_restartAssociation: sctpInstance is NULL !");
4978 return 1;
4979 }
4980 if (noOfPaths > currentAssociation->noOfNetworks) {
4981 error_log(ERROR_MAJOR, "mdi_restartAssociation tries to increase number of paths !");
4982 /* discard silently */
4983 return -1;
4984 }
4985 event_logiiii(INTERNAL_EVENT_0, "ASSOCIATION RESTART: in streams: %u, out streams: %u, rwnd: %u, paths: %u",
4986 noOfInStreams,noOfOutStreams,new_rwnd,noOfPaths);
4987 event_logii(INTERNAL_EVENT_0, "ASSOCIATION RESTART: remote initial TSN: %u, local initial TSN",
4988 remoteInitialTSN, localInitialTSN);
4989
4990 currentAssociation->reliableTransfer = rtx_restart_reliable_transfer(currentAssociation->reliableTransfer,
4991 noOfPaths, localInitialTSN);
4992 fc_restart(new_rwnd, localInitialTSN, currentAssociation->maxSendQueue);
4993 rxc_restart_receivecontrol(mdi_getDefaultMyRwnd(), remoteInitialTSN);
4994
4995 withPRSCTP = assocSupportsPRSCTP && currentAssociation->supportsPRSCTP;
4996 currentAssociation->peerSupportsPRSCTP = withPRSCTP;
4997 currentAssociation->supportsPRSCTP = withPRSCTP;
4998
4999 if(currentAssociation->streamengine) {
5000 se_delete_stream_engine(currentAssociation->streamengine);
5001 }
5002 else {
5003 error_log(ERROR_MAJOR, "mdi_restartAssociation: currentAssociation->streamengine is NULL !");
5004 }
5005 currentAssociation->streamengine = (void *) se_new_stream_engine(noOfInStreams,
5006 noOfOutStreams,withPRSCTP);
5007
5008 if(currentAssociation->pathMan) {
5009 pm_deletePathman(currentAssociation->pathMan);
5010 currentAssociation->pathMan = NULL;
5011 }
5012 else {
5013 error_log(ERROR_MAJOR, "mdi_restartAssociation: currentAssociation->pathMan is NULL !");
5014 }
5015
5016 /* frees old address-list before assigning new one */
5017 mdi_writeDestinationAddresses(destinationAddressList, noOfPaths);
5018
5019 currentAssociation->pathMan = pm_newPathman(noOfPaths, primaryAddress, sctpInstance);
5020
5021 if (!currentAssociation->pathMan) {
5022 error_log(ERROR_FATAL, "Error 1 in RESTART --> Fix implementation");
5023 return -1;
5024 }
5025
5026 event_logii(VERBOSE, "ASSOCIATION RESTART: calling pm_setPaths(%u, %u)",noOfPaths,primaryAddress);
5027
5028 result = pm_setPaths(noOfPaths,primaryAddress);
5029 if (result != 0) {
5030 error_log(ERROR_FATAL, "Error 2 in RESTART --> Fix implementation");
5031 return -1;
5032 }
5033
5034 return 0;
5035 }
5036
5037
5038 /**
5039 * mdi_deleteCurrentAssociation deletes the current association.
5040 *
5041 * The association will not be deleted at once, but is only marked for deletion. This is done in
5042 * this way to allow other modules to finish their current activities. To prevent them to start
5043 * new activities, the currentAssociation pointer is set to NULL.
5044 */
5045 void mdi_deleteCurrentAssociation(void)
5046 {
5047 short pathID;
5048
5049 if (currentAssociation != NULL) {
5050 if (currentAssociation->tagRemote != 0) {
5051 /* stop timers */
5052 for (pathID = 0; pathID < currentAssociation->noOfNetworks; pathID++)
5053 pm_disableHB(pathID);
5054
5055 fc_stop_timers();
5056 rxc_stop_sack_timer();
5057 /* stop SCTP control timers */
5058 }
5059
5060 /* mark association as deleted, it will be deleted when retrieveAssociation(..) encounters
5061 a "deleted" association. */
5062 currentAssociation->deleted = TRUE;
5063 event_logi(INTERNAL_EVENT_1, "association ID=%08x marked for deletion", currentAssociation->assocId);
5064 } else {
5065 error_log(ERROR_MAJOR,
5066 "mdi_deleteAssociation: current association does not exist, can not delete");
5067 }
5068 }
5069
5070
5071 #ifdef TD_DEBUG
5072 #undef calloc
5073 #undef malloc
5074 #undef free
5075 void* calloc(size_t nmemb, size_t size);
5076 void* malloc(size_t size);
5077 void free(void* p);
5078
5079 void* my_calloc(size_t nmemb, size_t size)
5080 {
5081 void* ptr = my_malloc(nmemb * size);
5082 if(ptr) {
5083 memset(ptr, 0, nmemb * size);
5084 }
5085 return(ptr);
5086 }
5087
5088 void* my_malloc(size_t size)
5089 {
5090 size_t* ptr = malloc(size + sizeof(size_t));
5091 if(ptr) {
5092 memset(ptr, 0xef, size + sizeof(size_t));
5093 ptr[0] = size + sizeof(size_t);
5094 return((void*)&ptr[1]);
5095 }
5096 return(NULL);
5097 }
5098
5099 void my_free(void* p)
5100 {
5101 size_t* ptr;
5102 size_t l;
5103 if(p != NULL) {
5104 ptr = &((size_t*)p)[-1];
5105 l = ptr[0];
5106 memset(ptr, 0xba, l);
5107 free(ptr);
5108 }
5109 }
5110 #endif
5111