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