]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/netinet/libalias/alias_sctp.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / netinet / libalias / alias_sctp.c
1 /*-
2  * Copyright (c) 2008
3  *      Swinburne University of Technology, Melbourne, Australia.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions
7  *  are met:
8  *  1. Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  *  THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND
15  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  *  SUCH DAMAGE.
25  */
26
27 /*
28  * Alias_sctp forms part of the libalias kernel module to handle 
29  * Network Address Translation (NAT) for the SCTP protocol.
30  *
31  *  This software was developed by David A. Hayes and Jason But
32  *
33  * The design is outlined in CAIA technical report number  080618A
34  * (D. Hayes and J. But, "Alias_sctp Version 0.1: SCTP NAT implementation in IPFW")
35  *
36  * Development is part of the CAIA SONATA project,
37  * proposed by Jason But and Grenville Armitage:
38  * http://caia.swin.edu.au/urp/sonata/
39  *
40  * 
41  * This project has been made possible in part by a grant from
42  * the Cisco University Research Program Fund at Community
43  * Foundation Silicon Valley.
44  *
45  */
46 /** @mainpage 
47  * Alias_sctp is part of the SONATA (http://caia.swin.edu.au/urp/sonata) project
48  * to develop and release a BSD licensed implementation of a Network Address
49  * Translation (NAT) module that supports the Stream Control Transmission
50  * Protocol (SCTP).
51  *
52  * Traditional address and port number look ups are inadequate for SCTP's
53  * operation due to both processing requirements and issues with multi-homing.
54  * Alias_sctp integrates with FreeBSD's ipfw/libalias NAT system.
55  *
56  * Version 0.2 features include:
57  * - Support for global multi-homing
58  * - Support for ASCONF modification from Internet Draft
59  *   (draft-stewart-behave-sctpnat-04, R. Stewart and M. Tuexen, "Stream control
60  *   transmission protocol (SCTP) network address translation," Jul. 2008) to
61  *   provide support for multi-homed privately addressed hosts
62  * - Support for forwarding of T-flagged packets
63  * - Generation and delivery of AbortM/ErrorM packets upon detection of NAT
64  *   collisions
65  * - Per-port forwarding rules
66  * - Dynamically controllable logging and statistics
67  * - Dynamic management of timers
68  * - Dynamic control of hash-table size
69  */
70
71 /* $FreeBSD$ */
72
73 #ifdef _KERNEL
74 #include <machine/stdarg.h>
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
78 #include <sys/module.h>
79 #include <sys/syslog.h>
80 #include <netinet/libalias/alias_sctp.h>
81 #include <netinet/libalias/alias.h>
82 #include <netinet/libalias/alias_local.h>
83 #include <netinet/sctp_crc32.h>
84 #include <machine/in_cksum.h>
85 #else
86 #include "alias_sctp.h"
87 #include <arpa/inet.h>
88 #include "alias.h"
89 #include "alias_local.h"
90 #include <machine/in_cksum.h>
91 #include <sys/libkern.h>
92 #endif //#ifdef _KERNEL
93
94 /* ----------------------------------------------------------------------
95  *                          FUNCTION PROTOTYPES
96  * ----------------------------------------------------------------------
97  */
98 /* Packet Parsing Functions */
99 static int sctp_PktParser(struct libalias *la, int direction, struct ip *pip,
100     struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc);
101 static int GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm,
102     uint32_t *l_vtag, uint32_t *g_vtag, int direction);
103 static int IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction);
104
105 static void AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction);
106 static int  Add_Global_Address_to_List(struct sctp_nat_assoc *assoc,  struct sctp_GlobalAddress *G_addr);
107 static void RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction);
108 static int IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction);
109
110 /* State Machine Functions */
111 static int ProcessSctpMsg(struct libalias *la, int direction, \
112     struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc);
113
114 static int ID_process(struct libalias *la, int direction,\
115     struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm);
116 static int INi_process(struct libalias *la, int direction,\
117     struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm);
118 static int INa_process(struct libalias *la, int direction,\
119     struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm);
120 static int UP_process(struct libalias *la, int direction,\
121     struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm);
122 static int CL_process(struct libalias *la, int direction,\
123     struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm);
124 static void TxAbortErrorM(struct libalias *la,  struct sctp_nat_msg *sm,\
125     struct sctp_nat_assoc *assoc, int sndrply, int direction);
126
127 /* Hash Table Functions */
128 static struct sctp_nat_assoc*
129 FindSctpLocal(struct libalias *la, struct in_addr l_addr, struct in_addr g_addr, uint32_t l_vtag, uint16_t l_port, uint16_t g_port);
130 static struct sctp_nat_assoc*
131 FindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match);
132 static struct sctp_nat_assoc*
133 FindSctpGlobalClash(struct libalias *la,  struct sctp_nat_assoc *Cassoc);
134 static struct sctp_nat_assoc*
135 FindSctpLocalT(struct libalias *la,  struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port);
136 static struct sctp_nat_assoc*
137 FindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port);
138
139 static int AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr);
140 static int AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc);
141 static void RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc);
142 static void freeGlobalAddressList(struct sctp_nat_assoc *assoc);
143
144 /* Timer Queue Functions */
145 static void sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc);
146 static void sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc);
147 static void sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp);
148 void sctp_CheckTimers(struct libalias *la);
149
150
151 /* Logging Functions */
152 static void logsctperror(char* errormsg, uint32_t vtag, int error, int direction);
153 static void logsctpparse(int direction, struct sctp_nat_msg *sm);
154 static void logsctpassoc(struct sctp_nat_assoc *assoc, char *s);
155 static void logTimerQ(struct libalias *la);
156 static void logSctpGlobal(struct libalias *la);
157 static void logSctpLocal(struct libalias *la);
158 #ifdef _KERNEL
159 static void SctpAliasLog(const char *format, ...);
160 #endif
161
162 /** @defgroup external External code changes and modifications
163  *
164  * Some changes have been made to files external to alias_sctp.(c|h). These
165  * changes are primarily due to code needing to call static functions within
166  * those files or to perform extra functionality that can only be performed
167  * within these files.
168  */
169 /** @ingroup external
170  * @brief Log current statistics for the libalias instance
171  *
172  * This function is defined in alias_db.c, since it calls static functions in
173  * this file
174  *
175  * Calls the higher level ShowAliasStats() in alias_db.c which logs all current
176  * statistics about the libalias instance - including SCTP statistics
177  * 
178  * @param la Pointer to the libalias instance
179  */
180 void SctpShowAliasStats(struct libalias *la);
181
182 #ifdef  _KERNEL
183
184 static MALLOC_DEFINE(M_SCTPNAT, "sctpnat", "sctp nat dbs");
185 /* Use kernel allocator. */
186 #ifdef _SYS_MALLOC_H_
187 #define sn_malloc(x)    malloc(x, M_SCTPNAT, M_NOWAIT|M_ZERO)
188 #define sn_calloc(n,x)  sn_malloc(x * n)
189 #define sn_free(x)      free(x, M_SCTPNAT)
190 #endif// #ifdef _SYS_MALLOC_H_
191
192 #else //#ifdef  _KERNEL
193 #define sn_malloc(x)    malloc(x)
194 #define sn_calloc(n, x) calloc(n, x)
195 #define sn_free(x)      free(x)
196
197 #endif //#ifdef _KERNEL
198
199 /** @defgroup packet_parser SCTP Packet Parsing
200  *
201  * Macros to:
202  * - Return pointers to the first and next SCTP chunks within an SCTP Packet
203  * - Define possible return values of the packet parsing process
204  * - SCTP message types for storing in the sctp_nat_msg structure @{
205  */
206
207 #define SN_SCTP_FIRSTCHUNK(sctphead)    (struct sctp_chunkhdr *)(((char *)sctphead) + sizeof(struct sctphdr))
208 /**< Returns a pointer to the first chunk in an SCTP packet given a pointer to the SCTP header */
209
210 #define SN_SCTP_NEXTCHUNK(chunkhead)    (struct sctp_chunkhdr *)(((char *)chunkhead) + SCTP_SIZE32(ntohs(chunkhead->chunk_length)))
211 /**< Returns a pointer to the next chunk in an SCTP packet given a pointer to the current chunk */
212
213 #define SN_SCTP_NEXTPARAM(param)        (struct sctp_paramhdr *)(((char *)param) + SCTP_SIZE32(ntohs(param->param_length)))
214 /**< Returns a pointer to the next parameter in an SCTP packet given a pointer to the current parameter */
215
216 #define SN_MIN_CHUNK_SIZE        4    /**< Smallest possible SCTP chunk size in bytes */
217 #define SN_MIN_PARAM_SIZE        4    /**< Smallest possible SCTP param size in bytes */
218 #define SN_VTAG_PARAM_SIZE      12    /**< Size of  SCTP ASCONF vtag param in bytes */
219 #define SN_ASCONFACK_PARAM_SIZE  8    /**< Size of  SCTP ASCONF ACK param in bytes */
220
221 /* Packet parsing return codes */
222 #define SN_PARSE_OK                  0    /**< Packet parsed for SCTP messages */
223 #define SN_PARSE_ERROR_IPSHL         1    /**< Packet parsing error - IP and SCTP common header len */
224 #define SN_PARSE_ERROR_AS_MALLOC     2    /**< Packet parsing error - assoc malloc */
225 #define SN_PARSE_ERROR_CHHL          3    /**< Packet parsing error - Chunk header len */
226 #define SN_PARSE_ERROR_DIR           4    /**< Packet parsing error - Direction */
227 #define SN_PARSE_ERROR_VTAG          5    /**< Packet parsing error - Vtag */
228 #define SN_PARSE_ERROR_CHUNK         6    /**< Packet parsing error - Chunk */
229 #define SN_PARSE_ERROR_PORT          7    /**< Packet parsing error - Port=0 */
230 #define SN_PARSE_ERROR_LOOKUP        8    /**< Packet parsing error - Lookup */
231 #define SN_PARSE_ERROR_PARTIALLOOKUP 9    /**< Packet parsing error - partial lookup only found */
232 #define SN_PARSE_ERROR_LOOKUP_ABORT  10   /**< Packet parsing error - Lookup - but abort packet */
233
234 /* Alias_sctp performs its processing based on a number of key messages */
235 #define SN_SCTP_ABORT       0x0000    /**< a packet containing an ABORT chunk */
236 #define SN_SCTP_INIT        0x0001    /**< a packet containing an INIT chunk */
237 #define SN_SCTP_INITACK     0x0002    /**< a packet containing an INIT-ACK chunk */
238 #define SN_SCTP_SHUTCOMP    0x0010    /**< a packet containing a SHUTDOWN-COMPLETE chunk */
239 #define SN_SCTP_SHUTACK     0x0020    /**< a packet containing a SHUTDOWN-ACK chunk */
240 #define SN_SCTP_ASCONF      0x0100    /**< a packet containing an ASCONF chunk */
241 #define SN_SCTP_ASCONFACK   0x0200    /**< a packet containing an ASCONF-ACK chunk */
242 #define SN_SCTP_OTHER       0xFFFF    /**< a packet containing a chunk that is not of interest */
243
244 /** @}
245  * @defgroup state_machine SCTP NAT State Machine
246  *
247  * Defines the various states an association can be within the NAT @{
248  */
249 #define SN_ID  0x0000           /**< Idle state */
250 #define SN_INi 0x0010           /**< Initialising, waiting for InitAck state */
251 #define SN_INa 0x0020           /**< Initialising, waiting for AddIpAck state */
252 #define SN_UP  0x0100           /**< Association in UP state */
253 #define SN_CL  0x1000           /**< Closing state */
254 #define SN_RM  0x2000           /**< Removing state */
255
256 /** @}
257  * @defgroup Logging Logging Functionality
258  *
259  * Define various log levels and a macro to call specified log functions only if
260  * the current log level (sysctl_log_level) matches the specified level @{
261  */
262 #define SN_LOG_LOW        0     
263 #define SN_LOG_EVENT      1
264 #define SN_LOG_INFO       2
265 #define SN_LOG_DETAIL     3
266 #define SN_LOG_DEBUG      4
267 #define SN_LOG_DEBUG_MAX  5
268
269 #define SN_LOG(level, action)   if (sysctl_log_level >= level) { action; } /**< Perform log action ONLY if the current log level meets the specified log level */
270
271 /** @}
272  * @defgroup Hash Hash Table Macros and Functions
273  *
274  * Defines minimum/maximum/default values for the hash table size @{
275  */
276 #define SN_MIN_HASH_SIZE        101   /**< Minimum hash table size (set to stop users choosing stupid values) */
277 #define SN_MAX_HASH_SIZE    1000001   /**< Maximum hash table size (NB must be less than max int) */
278 #define SN_DEFAULT_HASH_SIZE   2003   /**< A reasonable default size for the hash tables */
279
280 #define SN_LOCAL_TBL           0x01   /**< assoc in local table */
281 #define SN_GLOBAL_TBL          0x02   /**< assoc in global table */
282 #define SN_BOTH_TBL            0x03   /**< assoc in both tables */
283 #define SN_WAIT_TOLOCAL        0x10   /**< assoc waiting for TOLOCAL asconf ACK*/
284 #define SN_WAIT_TOGLOBAL       0x20   /**< assoc waiting for TOLOCAL asconf ACK*/
285 #define SN_NULL_TBL            0x00   /**< assoc in No table */
286 #define SN_MAX_GLOBAL_ADDRESSES 100   /**< absolute maximum global address count*/
287
288 #define SN_ADD_OK                 0   /**< Association added to the table */
289 #define SN_ADD_CLASH              1   /**< Clash when trying to add the assoc. info to the table */
290
291 #define SN_TABLE_HASH(vtag, port, size) (((u_int) vtag + (u_int) port) % (u_int) size) /**< Calculate the hash table lookup position */
292
293 /** @}
294  * @defgroup Timer Timer Queue Macros and Functions
295  *
296  * Timer macros set minimum/maximum timeout values and calculate timer expiry
297  * times for the provided libalias instance @{
298  */
299 #define SN_MIN_TIMER 1
300 #define SN_MAX_TIMER 600
301 #define SN_TIMER_QUEUE_SIZE SN_MAX_TIMER+2
302
303 #define SN_I_T(la) (la->timeStamp + sysctl_init_timer)       /**< INIT State expiration time in seconds */
304 #define SN_U_T(la) (la->timeStamp + sysctl_up_timer)         /**< UP State expiration time in seconds */
305 #define SN_C_T(la) (la->timeStamp + sysctl_shutdown_timer)   /**< CL State expiration time in seconds */
306 #define SN_X_T(la) (la->timeStamp + sysctl_holddown_timer)   /**< Wait after a shutdown complete in seconds */
307
308 /** @}
309  * @defgroup sysctl SysCtl Variable and callback function declarations
310  *
311  * Sysctl variables to modify NAT functionality in real-time along with associated functions
312  * to manage modifications to the sysctl variables @{
313  */
314
315 /* Callbacks */
316 int sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS);
317 int sysctl_chg_timer(SYSCTL_HANDLER_ARGS);
318 int sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS);
319 int sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS);
320 int sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS);
321 int sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS);
322 int sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS);
323 int sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS);
324 int sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS);
325
326 /* Sysctl variables */
327 /** @brief net.inet.ip.alias.sctp.log_level */
328 static u_int sysctl_log_level = 0; /**< Stores the current level of logging */
329 /** @brief net.inet.ip.alias.sctp.init_timer */
330 static u_int sysctl_init_timer = 15; /**< Seconds to hold an association in the table waiting for an INIT-ACK or AddIP-ACK */
331 /** @brief net.inet.ip.alias.sctp.up_timer */
332 static u_int sysctl_up_timer = 300; /**< Seconds to hold an association in the table while no packets are transmitted */
333 /** @brief net.inet.ip.alias.sctp.shutdown_timer */
334 static u_int sysctl_shutdown_timer = 15; /**< Seconds to hold an association in the table waiting for a SHUTDOWN-COMPLETE */
335 /** @brief net.inet.ip.alias.sctp.holddown_timer */
336 static u_int sysctl_holddown_timer = 0; /**< Seconds to hold an association in the table after it has been shutdown (to allow for lost SHUTDOWN-COMPLETEs) */
337 /** @brief net.inet.ip.alias.sctp.hashtable_size */
338 static u_int sysctl_hashtable_size = SN_DEFAULT_HASH_SIZE; /**< Sets the hash table size for any NEW NAT instances (existing instances retain their existing Hash Table */
339 /** @brief net.inet.ip.alias.sctp.error_on_ootb */
340 static u_int sysctl_error_on_ootb = 1; /**< NAT response  to receipt of OOTB packet
341                                           (0 - No response, 1 - NAT will send ErrorM only to local side,
342                                           2 -  NAT will send local ErrorM and global ErrorM if there was a partial association match
343                                           3 - NAT will send ErrorM to both local and global) */
344 /** @brief net.inet.ip.alias.sctp.accept_global_ootb_addip */
345 static u_int sysctl_accept_global_ootb_addip = 0; /**<NAT responset to receipt of global OOTB AddIP (0 - No response, 1 - NAT will accept OOTB global AddIP messages for processing (Security risk)) */
346 /** @brief net.inet.ip.alias.sctp.initialising_chunk_proc_limit */
347 static u_int sysctl_initialising_chunk_proc_limit = 2; /**< A limit on the number of chunks that should be searched if there is no matching association (DoS prevention) */
348 /** @brief net.inet.ip.alias.sctp.param_proc_limit */
349 static u_int sysctl_chunk_proc_limit = 5; /**< A limit on the number of chunks that should be searched (DoS prevention) */
350 /** @brief net.inet.ip.alias.sctp.param_proc_limit */
351 static u_int sysctl_param_proc_limit = 25; /**< A limit on the number of parameters (in chunks) that should be searched (DoS prevention) */
352 /** @brief net.inet.ip.alias.sctp.track_global_addresses */
353 static u_int sysctl_track_global_addresses = 0; /**< Configures the global address tracking option within the NAT (0 - Global tracking is disabled, > 0 - enables tracking but limits the number of global IP addresses to this value)
354                                                    If set to >=1 the NAT will track that many global IP addresses. This may reduce look up table conflicts, but increases processing */
355
356 #define SN_NO_ERROR_ON_OOTB              0 /**< Send no errorM on out of the blue packets */
357 #define SN_LOCAL_ERROR_ON_OOTB           1 /**< Send only local errorM on out of the blue packets */
358 #define SN_LOCALandPARTIAL_ERROR_ON_OOTB 2 /**< Send local errorM and global errorM for out of the blue packets only if partial match found */
359 #define SN_ERROR_ON_OOTB                 3 /**< Send errorM on out of the blue packets */
360
361 #ifdef SYSCTL_NODE
362
363 SYSCTL_DECL(_net_inet);
364 SYSCTL_DECL(_net_inet_ip);
365 SYSCTL_DECL(_net_inet_ip_alias);
366
367 static SYSCTL_NODE(_net_inet_ip_alias, OID_AUTO, sctp, CTLFLAG_RW, NULL,
368     "SCTP NAT");
369 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, log_level, CTLTYPE_UINT | CTLFLAG_RW,
370     &sysctl_log_level, 0, sysctl_chg_loglevel, "IU",
371     "Level of detail (0 - default, 1 - event, 2 - info, 3 - detail, 4 - debug, 5 - max debug)");
372 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, init_timer, CTLTYPE_UINT | CTLFLAG_RW,
373     &sysctl_init_timer, 0, sysctl_chg_timer, "IU",
374     "Timeout value (s) while waiting for (INIT-ACK|AddIP-ACK)");
375 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, up_timer, CTLTYPE_UINT | CTLFLAG_RW,
376     &sysctl_up_timer, 0, sysctl_chg_timer, "IU",
377     "Timeout value (s) to keep an association up with no traffic");
378 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, shutdown_timer, CTLTYPE_UINT | CTLFLAG_RW,
379     &sysctl_shutdown_timer, 0, sysctl_chg_timer, "IU",
380     "Timeout value (s) while waiting for SHUTDOWN-COMPLETE");
381 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, holddown_timer, CTLTYPE_UINT | CTLFLAG_RW,
382     &sysctl_holddown_timer, 0, sysctl_chg_timer, "IU",
383     "Hold association in table for this many seconds after receiving a SHUTDOWN-COMPLETE");
384 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, hashtable_size, CTLTYPE_UINT | CTLFLAG_RW,
385     &sysctl_hashtable_size, 0, sysctl_chg_hashtable_size, "IU",
386     "Size of hash tables used for NAT lookups (100 < prime_number > 1000001)");
387 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, error_on_ootb, CTLTYPE_UINT | CTLFLAG_RW,
388     &sysctl_error_on_ootb, 0, sysctl_chg_error_on_ootb, "IU",
389     "ErrorM sent on receipt of ootb packet:\n\t0 - none,\n\t1 - to local only,\n\t2 - to local and global if a partial association match,\n\t3 - to local and global (DoS risk)");
390 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, accept_global_ootb_addip, CTLTYPE_UINT | CTLFLAG_RW,
391     &sysctl_accept_global_ootb_addip, 0, sysctl_chg_accept_global_ootb_addip, "IU",
392     "NAT response to receipt of global OOTB AddIP:\n\t0 - No response,\n\t1 - NAT will accept OOTB global AddIP messages for processing (Security risk)");
393 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, initialising_chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW,
394     &sysctl_initialising_chunk_proc_limit, 0, sysctl_chg_initialising_chunk_proc_limit, "IU",
395     "Number of chunks that should be processed if there is no current association found:\n\t > 0 (A high value is a DoS risk)");
396 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, chunk_proc_limit, CTLTYPE_UINT | CTLFLAG_RW,
397     &sysctl_chunk_proc_limit, 0, sysctl_chg_chunk_proc_limit, "IU",
398     "Number of chunks that should be processed to find key chunk:\n\t>= initialising_chunk_proc_limit (A high value is a DoS risk)");
399 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, param_proc_limit, CTLTYPE_UINT | CTLFLAG_RW,
400     &sysctl_param_proc_limit, 0, sysctl_chg_param_proc_limit, "IU",
401     "Number of parameters (in a chunk) that should be processed to find key parameters:\n\t> 1 (A high value is a DoS risk)");
402 SYSCTL_PROC(_net_inet_ip_alias_sctp, OID_AUTO, track_global_addresses, CTLTYPE_UINT | CTLFLAG_RW,
403     &sysctl_track_global_addresses, 0, sysctl_chg_track_global_addresses, "IU",
404     "Configures the global address tracking option within the NAT:\n\t0 - Global tracking is disabled,\n\t> 0 - enables tracking but limits the number of global IP addresses to this value");
405
406 #endif /* SYSCTL_NODE */
407
408 /** @}
409  * @ingroup sysctl
410  * @brief sysctl callback for changing net.inet.ip.fw.sctp.log_level
411  *
412  * Updates the variable sysctl_log_level to the provided value and ensures
413  * it is in the valid range (SN_LOG_LOW -> SN_LOG_DEBUG)
414  */
415 int sysctl_chg_loglevel(SYSCTL_HANDLER_ARGS)
416 {
417         u_int level = *(u_int *)arg1;
418         int error;
419
420         error = sysctl_handle_int(oidp, &level, 0, req);
421         if (error) return (error);
422
423         sysctl_log_level = (level > SN_LOG_DEBUG_MAX)?(SN_LOG_DEBUG_MAX):(level);
424         sysctl_log_level = (level < SN_LOG_LOW)?(SN_LOG_LOW):(level);
425
426         return (0);
427 }
428
429 /** @ingroup sysctl
430  * @brief sysctl callback for changing net.inet.ip.fw.sctp.(init_timer|up_timer|shutdown_timer)
431  *
432  * Updates the timer-based sysctl variables. The new values are sanity-checked
433  * to make sure that they are within the range SN_MIN_TIMER-SN_MAX_TIMER. The
434  * holddown timer is allowed to be 0
435  */
436 int sysctl_chg_timer(SYSCTL_HANDLER_ARGS)
437 {
438         u_int timer = *(u_int *)arg1;
439         int error;
440
441         error = sysctl_handle_int(oidp, &timer, 0, req);
442         if (error) return (error);
443
444         timer = (timer > SN_MAX_TIMER)?(SN_MAX_TIMER):(timer);
445
446         if (((u_int *)arg1) != &sysctl_holddown_timer)
447             {
448                     timer = (timer < SN_MIN_TIMER)?(SN_MIN_TIMER):(timer);
449             }
450
451         *(u_int *)arg1 = timer;
452
453         return (0);
454 }
455
456 /** @ingroup sysctl
457  * @brief sysctl callback for changing net.inet.ip.alias.sctp.hashtable_size
458  *
459  * Updates the hashtable_size sysctl variable. The new value should be a prime
460  * number.  We sanity check to ensure that the size is within the range
461  * SN_MIN_HASH_SIZE-SN_MAX_HASH_SIZE. We then check the provided number to see
462  * if it is prime. We approximate by checking that (2,3,5,7,11) are not factors,
463  * incrementing the user provided value until we find a suitable number.
464  */
465 int sysctl_chg_hashtable_size(SYSCTL_HANDLER_ARGS)
466 {
467         u_int size = *(u_int *)arg1;
468         int error;
469
470         error = sysctl_handle_int(oidp, &size, 0, req);
471         if (error) return (error);
472
473         size = (size < SN_MIN_HASH_SIZE)?(SN_MIN_HASH_SIZE):((size > SN_MAX_HASH_SIZE)?(SN_MAX_HASH_SIZE):(size));
474
475         size |= 0x00000001; /* make odd */
476
477         for(;(((size % 3) == 0) || ((size % 5) == 0) || ((size % 7) == 0) || ((size % 11) == 0)); size+=2);
478         sysctl_hashtable_size = size;
479
480         return (0);
481 }
482
483 /** @ingroup sysctl
484  * @brief sysctl callback for changing net.inet.ip.alias.sctp.error_on_ootb
485  *
486  * Updates the error_on_clash sysctl variable. 
487  * If set to 0, no ErrorM will be sent if there is a look up table clash
488  * If set to 1, an ErrorM is sent only to the local side
489  * If set to 2, an ErrorM is sent to the local side and global side if there is
490  *                                                  a partial association match
491  * If set to 3, an ErrorM is sent to both local and global sides (DoS) risk.
492  */
493 int sysctl_chg_error_on_ootb(SYSCTL_HANDLER_ARGS)
494 {
495         u_int flag = *(u_int *)arg1;
496         int error;
497
498         error = sysctl_handle_int(oidp, &flag, 0, req);
499         if (error) return (error);
500
501         sysctl_error_on_ootb = (flag > SN_ERROR_ON_OOTB) ? SN_ERROR_ON_OOTB: flag;
502
503         return (0);
504 }
505
506 /** @ingroup sysctl
507  * @brief sysctl callback for changing net.inet.ip.alias.sctp.accept_global_ootb_addip
508  *
509  * If set to 1 the NAT will accept ootb global addip messages for processing (Security risk)
510  * Default is 0, only responding to local ootb AddIP messages
511  */
512 int sysctl_chg_accept_global_ootb_addip(SYSCTL_HANDLER_ARGS)
513 {
514         u_int flag = *(u_int *)arg1;
515         int error;
516
517         error = sysctl_handle_int(oidp, &flag, 0, req);
518         if (error) return (error);
519
520         sysctl_accept_global_ootb_addip = (flag == 1) ? 1: 0;
521
522         return (0);
523 }
524
525 /** @ingroup sysctl
526  * @brief sysctl callback for changing net.inet.ip.alias.sctp.initialising_chunk_proc_limit
527  *
528  * Updates the initialising_chunk_proc_limit sysctl variable.  Number of chunks
529  * that should be processed if there is no current association found: > 0 (A
530  * high value is a DoS risk)
531  */
532 int sysctl_chg_initialising_chunk_proc_limit(SYSCTL_HANDLER_ARGS)
533 {
534         u_int proclimit = *(u_int *)arg1;
535         int error;
536
537         error = sysctl_handle_int(oidp, &proclimit, 0, req);
538         if (error) return (error);
539
540         sysctl_initialising_chunk_proc_limit = (proclimit < 1) ? 1: proclimit;
541         sysctl_chunk_proc_limit = 
542                 (sysctl_chunk_proc_limit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : sysctl_chunk_proc_limit;
543  
544         return (0);
545 }
546
547 /** @ingroup sysctl
548  * @brief sysctl callback for changing net.inet.ip.alias.sctp.chunk_proc_limit
549  *
550  * Updates the chunk_proc_limit sysctl variable. 
551  * Number of chunks that should be processed to find key chunk:
552  *  >= initialising_chunk_proc_limit (A high value is a DoS risk)
553  */
554 int sysctl_chg_chunk_proc_limit(SYSCTL_HANDLER_ARGS)
555 {
556         u_int proclimit = *(u_int *)arg1;
557         int error;
558
559         error = sysctl_handle_int(oidp, &proclimit, 0, req);
560         if (error) return (error);
561
562         sysctl_chunk_proc_limit = 
563                 (proclimit < sysctl_initialising_chunk_proc_limit) ? sysctl_initialising_chunk_proc_limit : proclimit;
564
565         return (0);
566 }
567
568
569 /** @ingroup sysctl
570  * @brief sysctl callback for changing net.inet.ip.alias.sctp.param_proc_limit
571  *
572  * Updates the param_proc_limit sysctl variable. 
573  * Number of parameters that should be processed to find key parameters:
574  *  > 1 (A high value is a DoS risk)
575  */
576 int sysctl_chg_param_proc_limit(SYSCTL_HANDLER_ARGS)
577 {
578         u_int proclimit = *(u_int *)arg1;
579         int error;
580
581         error = sysctl_handle_int(oidp, &proclimit, 0, req);
582         if (error) return (error);
583
584         sysctl_param_proc_limit = 
585                 (proclimit < 2) ? 2 : proclimit;
586
587         return (0);
588 }
589
590 /** @ingroup sysctl
591  * @brief sysctl callback for changing net.inet.ip.alias.sctp.track_global_addresses
592  *
593  *Configures the global address tracking option within the NAT (0 - Global
594  *tracking is disabled, > 0 - enables tracking but limits the number of global
595  *IP addresses to this value)
596  */
597 int sysctl_chg_track_global_addresses(SYSCTL_HANDLER_ARGS)
598 {
599         u_int num_to_track = *(u_int *)arg1;
600         int error;
601
602         error = sysctl_handle_int(oidp, &num_to_track, 0, req);
603         if (error) return (error);
604
605         sysctl_track_global_addresses = (num_to_track > SN_MAX_GLOBAL_ADDRESSES) ? SN_MAX_GLOBAL_ADDRESSES : num_to_track;
606
607         return (0);
608 }
609
610
611 /* ----------------------------------------------------------------------
612  *                            CODE BEGINS HERE
613  * ----------------------------------------------------------------------
614  */
615 /** 
616  * @brief Initialises the SCTP NAT Implementation
617  * 
618  * Creates the look-up tables and the timer queue and initialises all state
619  * variables
620  *
621  * @param la Pointer to the relevant libalias instance
622  */
623 void AliasSctpInit(struct libalias *la)
624 {
625         /* Initialise association tables*/
626         int i;
627         la->sctpNatTableSize = sysctl_hashtable_size;
628         SN_LOG(SN_LOG_EVENT,
629             SctpAliasLog("Initialising SCTP NAT Instance (hash_table_size:%d)\n", la->sctpNatTableSize));
630         la->sctpTableLocal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableL));
631         la->sctpTableGlobal = sn_calloc(la->sctpNatTableSize, sizeof(struct sctpNatTableG));
632         la->sctpNatTimer.TimerQ = sn_calloc(SN_TIMER_QUEUE_SIZE, sizeof(struct sctpTimerQ));
633         /* Initialise hash table */
634         for (i = 0; i < la->sctpNatTableSize; i++) {
635                 LIST_INIT(&la->sctpTableLocal[i]);
636                 LIST_INIT(&la->sctpTableGlobal[i]);
637         }
638
639         /* Initialise circular timer Q*/
640         for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++)
641                 LIST_INIT(&la->sctpNatTimer.TimerQ[i]);
642 #ifdef _KERNEL
643         la->sctpNatTimer.loc_time=time_uptime; /* la->timeStamp is not set yet */
644 #else
645         la->sctpNatTimer.loc_time=la->timeStamp;
646 #endif
647         la->sctpNatTimer.cur_loc = 0;
648         la->sctpLinkCount = 0;
649 }
650
651 /** 
652  * @brief Cleans-up the SCTP NAT Implementation prior to unloading
653  *
654  * Removes all entries from the timer queue, freeing associations as it goes.
655  * We then free memory allocated to the look-up tables and the time queue
656  *
657  * NOTE: We do not need to traverse the look-up tables as each association
658  *       will always have an entry in the timer queue, freeing this memory
659  *       once will free all memory allocated to entries in the look-up tables
660  *
661  * @param la Pointer to the relevant libalias instance
662  */
663 void AliasSctpTerm(struct libalias *la)
664 {
665         struct sctp_nat_assoc *assoc1, *assoc2;
666         int                   i;
667
668         LIBALIAS_LOCK_ASSERT(la);
669         SN_LOG(SN_LOG_EVENT,
670             SctpAliasLog("Removing SCTP NAT Instance\n"));
671         for (i = 0; i < SN_TIMER_QUEUE_SIZE; i++) {
672                 assoc1 = LIST_FIRST(&la->sctpNatTimer.TimerQ[i]);
673                 while (assoc1 != NULL) {
674                         freeGlobalAddressList(assoc1);
675                         assoc2 = LIST_NEXT(assoc1, timer_Q);
676                         sn_free(assoc1);
677                         assoc1 = assoc2;
678                 }
679         }
680
681         sn_free(la->sctpTableLocal);
682         sn_free(la->sctpTableGlobal);
683         sn_free(la->sctpNatTimer.TimerQ);
684 }
685
686 /**
687  * @brief Handles SCTP packets passed from libalias
688  *
689  * This function needs to actually NAT/drop packets and possibly create and
690  * send AbortM or ErrorM packets in response. The process involves:
691  * - Validating the direction parameter passed by the caller
692  * - Checking and handling any expired timers for the NAT
693  * - Calling sctp_PktParser() to parse the packet
694  * - Call ProcessSctpMsg() to decide the appropriate outcome and to update
695  *   the NAT tables
696  * - Based on the return code either:
697  *   - NAT the packet
698  *   - Construct and send an ErrorM|AbortM packet
699  *   - Mark the association for removal from the tables
700  * - Potentially remove the association from all lookup tables
701  * - Return the appropriate result to libalias
702  *
703  * @param la Pointer to the relevant libalias instance
704  * @param pip Pointer to IP packet to process
705  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
706  * 
707  * @return  PKT_ALIAS_OK | PKT_ALIAS_IGNORE | PKT_ALIAS_ERROR
708  */
709 int
710 SctpAlias(struct libalias *la, struct ip *pip, int direction)
711 {
712         int rtnval;
713         struct sctp_nat_msg msg;
714         struct sctp_nat_assoc *assoc = NULL;
715
716         if ((direction != SN_TO_LOCAL) && (direction != SN_TO_GLOBAL)) {
717                 SctpAliasLog("ERROR: Invalid direction\n");
718                 return(PKT_ALIAS_ERROR);
719         }
720
721         sctp_CheckTimers(la); /* Check timers */ 
722
723         /* Parse the packet */
724         rtnval = sctp_PktParser(la, direction, pip, &msg, &assoc); //using *char (change to mbuf when get code from paolo)
725         switch (rtnval) {
726         case SN_PARSE_OK:
727                 break;
728         case SN_PARSE_ERROR_CHHL:
729                 /* Not an error if there is a chunk length parsing error and this is a fragmented packet */
730                 if (ntohs(pip->ip_off) & IP_MF) {
731                         rtnval = SN_PARSE_OK;
732                         break;
733                 }
734                 SN_LOG(SN_LOG_EVENT,
735                     logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction));
736                 return(PKT_ALIAS_ERROR);
737         case SN_PARSE_ERROR_PARTIALLOOKUP:
738                 if (sysctl_error_on_ootb > SN_LOCALandPARTIAL_ERROR_ON_OOTB) {
739                         SN_LOG(SN_LOG_EVENT,
740                             logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction));
741                         return(PKT_ALIAS_ERROR);
742                 }
743         case SN_PARSE_ERROR_LOOKUP:
744                 if (sysctl_error_on_ootb == SN_ERROR_ON_OOTB ||
745                     (sysctl_error_on_ootb == SN_LOCALandPARTIAL_ERROR_ON_OOTB && direction == SN_TO_LOCAL) ||
746                     (sysctl_error_on_ootb == SN_LOCAL_ERROR_ON_OOTB && direction == SN_TO_GLOBAL)) {
747                         TxAbortErrorM(la, &msg, assoc, SN_REFLECT_ERROR, direction); /*NB assoc=NULL */
748                         return(PKT_ALIAS_RESPOND);
749                 }
750         default:
751                 SN_LOG(SN_LOG_EVENT,
752                     logsctperror("SN_PARSE_ERROR", msg.sctp_hdr->v_tag, rtnval, direction));
753                 return(PKT_ALIAS_ERROR);
754         }
755
756         SN_LOG(SN_LOG_DETAIL,
757             logsctpassoc(assoc, "*");
758             logsctpparse(direction, &msg);
759                 );
760
761         /* Process the SCTP message */
762         rtnval = ProcessSctpMsg(la, direction, &msg, assoc);
763
764         SN_LOG(SN_LOG_DEBUG_MAX,
765             logsctpassoc(assoc, "-");
766             logSctpLocal(la);
767             logSctpGlobal(la);
768                 );
769         SN_LOG(SN_LOG_DEBUG, logTimerQ(la));
770
771         switch(rtnval){
772         case SN_NAT_PKT:
773                 switch(direction) {
774                 case SN_TO_LOCAL:
775                         DifferentialChecksum(&(msg.ip_hdr->ip_sum),
776                             &(assoc->l_addr), &(msg.ip_hdr->ip_dst), 2);
777                         msg.ip_hdr->ip_dst = assoc->l_addr; /* change dst address to local address*/
778                         break;
779                 case SN_TO_GLOBAL:
780                         DifferentialChecksum(&(msg.ip_hdr->ip_sum),
781                             &(assoc->a_addr),  &(msg.ip_hdr->ip_src), 2);
782                         msg.ip_hdr->ip_src = assoc->a_addr; /* change src to alias addr*/
783                         break;
784                 default:
785                         rtnval = SN_DROP_PKT; /* shouldn't get here, but if it does drop packet */
786                         SN_LOG(SN_LOG_LOW, logsctperror("ERROR: Invalid direction", msg.sctp_hdr->v_tag, rtnval, direction));
787                         break;
788                 }
789                 break;
790         case SN_DROP_PKT:
791                 SN_LOG(SN_LOG_DETAIL, logsctperror("SN_DROP_PKT", msg.sctp_hdr->v_tag, rtnval, direction));
792                 break;
793         case SN_REPLY_ABORT:
794         case SN_REPLY_ERROR:
795         case SN_SEND_ABORT: 
796                 TxAbortErrorM(la, &msg, assoc, rtnval, direction);
797                 break;
798         default:
799                 // big error, remove association and go to idle and write log messages
800                 SN_LOG(SN_LOG_LOW, logsctperror("SN_PROCESSING_ERROR", msg.sctp_hdr->v_tag, rtnval, direction));
801                 assoc->state=SN_RM;/* Mark for removal*/
802                 break;
803         }
804
805         /* Remove association if tagged for removal */
806         if (assoc->state == SN_RM) {
807                 if (assoc->TableRegister) {
808                         sctp_RmTimeOut(la, assoc);
809                         RmSctpAssoc(la, assoc);
810                 }
811                 LIBALIAS_LOCK_ASSERT(la);
812                 freeGlobalAddressList(assoc);
813                 sn_free(assoc);
814         }
815         switch(rtnval) {
816         case SN_NAT_PKT:
817                 return(PKT_ALIAS_OK);
818         case SN_SEND_ABORT:
819                 return(PKT_ALIAS_OK);
820         case SN_REPLY_ABORT:
821         case SN_REPLY_ERROR:
822         case SN_REFLECT_ERROR:
823                 return(PKT_ALIAS_RESPOND);
824         case SN_DROP_PKT:
825         default:
826                 return(PKT_ALIAS_ERROR);
827         }
828 }
829
830 /** 
831  * @brief Send an AbortM or ErrorM
832  *
833  * We construct the new SCTP packet to send in place of the existing packet we
834  * have been asked to NAT. This function can only be called if the original
835  * packet was successfully parsed as a valid SCTP packet.
836  *
837  * An AbortM (without cause) packet is the smallest SCTP packet available and as
838  * such there is always space in the existing packet buffer to fit the AbortM
839  * packet. An ErrorM packet is 4 bytes longer than the (the error cause is not
840  * optional). An ErrorM is sent in response to an AddIP when the Vtag/address
841  * combination, if added, will produce a conflict in the association look up
842  * tables. It may also be used for an unexpected packet - a packet with no
843  * matching association in the NAT table and we are requesting an AddIP so we
844  * can add it.  The smallest valid SCTP packet while the association is in an
845  * up-state is a Heartbeat packet, which is big enough to be transformed to an
846  * ErrorM.
847  *
848  * We create a temporary character array to store the packet as we are constructing
849  * it. We then populate the array with appropriate values based on:
850  * - Packet type (AbortM | ErrorM)
851  * - Initial packet direction (SN_TO_LOCAL | SN_TO_GLOBAL)
852  * - NAT response (Send packet | Reply packet)
853  *
854  * Once complete, we copy the contents of the temporary packet over the original
855  * SCTP packet we were asked to NAT
856  *
857  * @param la Pointer to the relevant libalias instance
858  * @param sm Pointer to sctp message information
859  * @param assoc Pointer to current association details
860  * @param sndrply SN_SEND_ABORT | SN_REPLY_ABORT | SN_REPLY_ERROR
861  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
862  */
863 static uint32_t
864 local_sctp_finalize_crc32(uint32_t crc32c)
865 {
866         /* This routine is duplicated from SCTP 
867          * we need to do that since it MAY be that SCTP
868          * is NOT compiled into the kernel. The CRC32C routines
869          * however are always available in libkern.
870          */
871         uint32_t result;
872 #if BYTE_ORDER == BIG_ENDIAN
873         uint8_t byte0, byte1, byte2, byte3;
874
875 #endif
876         /* Complement the result */
877         result = ~crc32c;
878 #if BYTE_ORDER == BIG_ENDIAN
879         /*
880          * For BIG-ENDIAN.. aka Motorola byte order the result is in
881          * little-endian form. So we must manually swap the bytes. Then we
882          * can call htonl() which does nothing...
883          */
884         byte0 = result & 0x000000ff;
885         byte1 = (result >> 8) & 0x000000ff;
886         byte2 = (result >> 16) & 0x000000ff;
887         byte3 = (result >> 24) & 0x000000ff;
888         crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
889 #else
890         /*
891          * For INTEL platforms the result comes out in network order. No
892          * htonl is required or the swap above. So we optimize out both the
893          * htonl and the manual swap above.
894          */
895         crc32c = result;
896 #endif
897         return (crc32c);
898 }
899
900 static void
901 TxAbortErrorM(struct libalias *la, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int sndrply, int direction)
902 {
903         int sctp_size = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_error_cause);
904         int ip_size = sizeof(struct ip) + sctp_size;
905         int include_error_cause = 1;
906         char tmp_ip[ip_size];
907
908         if (ntohs(sm->ip_hdr->ip_len) < ip_size) { /* short packet, cannot send error cause */
909                 include_error_cause = 0;
910                 ip_size = ip_size -  sizeof(struct sctp_error_cause);
911                 sctp_size = sctp_size -  sizeof(struct sctp_error_cause);
912         }
913         /* Assign header pointers packet */
914         struct ip* ip = (struct ip *) tmp_ip;
915         struct sctphdr* sctp_hdr = (struct sctphdr *) ((char *) ip + sizeof(*ip));
916         struct sctp_chunkhdr* chunk_hdr = (struct sctp_chunkhdr *) ((char *) sctp_hdr + sizeof(*sctp_hdr));
917         struct sctp_error_cause* error_cause = (struct sctp_error_cause *) ((char *) chunk_hdr + sizeof(*chunk_hdr));
918
919         /* construct ip header */
920         ip->ip_v = sm->ip_hdr->ip_v;
921         ip->ip_hl = 5; /* 5*32 bit words */
922         ip->ip_tos = 0;
923         ip->ip_len = htons(ip_size);
924         ip->ip_id =  sm->ip_hdr->ip_id;
925         ip->ip_off = 0;
926         ip->ip_ttl = 255;
927         ip->ip_p = IPPROTO_SCTP;
928         /*
929           The definitions below should be removed when they make it into the SCTP stack
930         */
931 #define SCTP_MIDDLEBOX_FLAG 0x02
932 #define SCTP_NAT_TABLE_COLLISION 0x00b0
933 #define SCTP_MISSING_NAT 0x00b1
934         chunk_hdr->chunk_type = (sndrply & SN_TX_ABORT) ? SCTP_ABORT_ASSOCIATION : SCTP_OPERATION_ERROR;
935         chunk_hdr->chunk_flags = SCTP_MIDDLEBOX_FLAG;
936         if (include_error_cause) {
937                 error_cause->code = htons((sndrply & SN_REFLECT_ERROR) ? SCTP_MISSING_NAT :  SCTP_NAT_TABLE_COLLISION);
938                 error_cause->length = htons(sizeof(struct sctp_error_cause));
939                 chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr) + sizeof(struct sctp_error_cause));
940         } else {
941                 chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr));
942         }
943
944         /* set specific values */
945         switch(sndrply) {
946         case SN_REFLECT_ERROR:
947                 chunk_hdr->chunk_flags |= SCTP_HAD_NO_TCB; /* set Tbit */
948                 sctp_hdr->v_tag =  sm->sctp_hdr->v_tag;
949                 break;
950         case SN_REPLY_ERROR:
951                 sctp_hdr->v_tag = (direction == SN_TO_LOCAL) ? assoc->g_vtag :  assoc->l_vtag ;
952                 break;
953         case SN_SEND_ABORT:
954                 sctp_hdr->v_tag =  sm->sctp_hdr->v_tag;
955                 break;
956         case SN_REPLY_ABORT:
957                 sctp_hdr->v_tag = sm->sctpchnk.Init->initiate_tag;
958                 break;
959         }
960   
961         /* Set send/reply values */
962         if (sndrply == SN_SEND_ABORT) { /*pass through NAT */
963                 ip->ip_src = (direction == SN_TO_LOCAL) ? sm->ip_hdr->ip_src : assoc->a_addr;
964                 ip->ip_dst = (direction == SN_TO_LOCAL) ? assoc->l_addr : sm->ip_hdr->ip_dst;
965                 sctp_hdr->src_port = sm->sctp_hdr->src_port;
966                 sctp_hdr->dest_port = sm->sctp_hdr->dest_port;
967         } else { /* reply and reflect */
968                 ip->ip_src = sm->ip_hdr->ip_dst;
969                 ip->ip_dst = sm->ip_hdr->ip_src;
970                 sctp_hdr->src_port = sm->sctp_hdr->dest_port;
971                 sctp_hdr->dest_port = sm->sctp_hdr->src_port;
972         }
973   
974         /* Calculate IP header checksum */
975         ip->ip_sum = in_cksum_hdr(ip);
976   
977         /* calculate SCTP header CRC32 */
978         sctp_hdr->checksum = 0;
979         sctp_hdr->checksum = local_sctp_finalize_crc32(calculate_crc32c(0xffffffff, (unsigned char *) sctp_hdr, sctp_size));
980
981         memcpy(sm->ip_hdr, ip, ip_size);
982
983         SN_LOG(SN_LOG_EVENT,SctpAliasLog("%s %s 0x%x (->%s:%u vtag=0x%x crc=0x%x)\n",
984                 ((sndrply == SN_SEND_ABORT) ? "Sending" : "Replying"),
985                 ((sndrply & SN_TX_ERROR) ? "ErrorM" : "AbortM"),
986                 (include_error_cause ? ntohs(error_cause->code) : 0),
987                 inet_ntoa(ip->ip_dst),ntohs(sctp_hdr->dest_port), 
988                 ntohl(sctp_hdr->v_tag), ntohl(sctp_hdr->checksum)));
989 }
990
991 /* ----------------------------------------------------------------------
992  *                           PACKET PARSER CODE
993  * ----------------------------------------------------------------------
994  */
995 /** @addtogroup packet_parser
996  *
997  * These functions parse the SCTP packet and fill a sctp_nat_msg structure
998  * with the parsed contents.
999  */
1000 /** @ingroup packet_parser
1001  * @brief Parses SCTP packets for the key SCTP chunk that will be processed
1002  * 
1003  * This module parses SCTP packets for the key SCTP chunk that will be processed
1004  * The module completes the sctp_nat_msg structure and either retrieves the
1005  * relevant (existing) stored association from the Hash Tables or creates a new
1006  * association entity with state SN_ID
1007  *
1008  * @param la Pointer to the relevant libalias instance
1009  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1010  * @param pip 
1011  * @param sm Pointer to sctp message information
1012  * @param passoc Pointer to the association this SCTP Message belongs to
1013  * 
1014  * @return SN_PARSE_OK | SN_PARSE_ERROR_*
1015  */
1016 static int
1017 sctp_PktParser(struct libalias *la, int direction, struct ip *pip,
1018     struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc)
1019 //sctp_PktParser(int direction, struct mbuf *ipak, int ip_hdr_len,struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc)
1020 {
1021         struct sctphdr *sctp_hdr;
1022         struct sctp_chunkhdr *chunk_hdr;
1023         struct sctp_paramhdr *param_hdr;
1024         struct in_addr ipv4addr;
1025         int bytes_left; /* bytes left in ip packet */
1026         int chunk_length;
1027         int chunk_count;
1028         int partial_match = 0;
1029         //  mbuf *mp;
1030         //  int mlen;
1031
1032         //  mlen = SCTP_HEADER_LEN(i_pak);
1033         //  mp = SCTP_HEADER_TO_CHAIN(i_pak); /* does nothing in bsd since header and chain not separate */
1034
1035         /*
1036          * Note, that if the VTag is zero, it must be an INIT
1037          * Also, I am only interested in the content of INIT and ADDIP chunks
1038          */
1039
1040         // no mbuf stuff from Paolo yet so ...
1041         sm->ip_hdr = pip;
1042         /* remove ip header length from the bytes_left */
1043         bytes_left = ntohs(pip->ip_len) - (pip->ip_hl << 2);
1044
1045         /* Check SCTP header length and move to first chunk */
1046         if (bytes_left < sizeof(struct sctphdr)) {
1047                 sm->sctp_hdr = NULL;
1048                 return(SN_PARSE_ERROR_IPSHL); /* packet not long enough*/
1049         }
1050
1051         sm->sctp_hdr = sctp_hdr = (struct sctphdr *) ip_next(pip);
1052         bytes_left -= sizeof(struct sctphdr);
1053   
1054         /* Check for valid ports (zero valued ports would find partially initialised associations */
1055         if (sctp_hdr->src_port == 0 || sctp_hdr->dest_port == 0)
1056                 return(SN_PARSE_ERROR_PORT);
1057
1058         /* Check length of first chunk */
1059         if (bytes_left < SN_MIN_CHUNK_SIZE) /* malformed chunk - could cause endless loop*/
1060                 return(SN_PARSE_ERROR_CHHL); /* packet not long enough for this chunk */
1061   
1062         /* First chunk */
1063         chunk_hdr = SN_SCTP_FIRSTCHUNK(sctp_hdr);
1064   
1065         chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length));
1066         if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) /* malformed chunk - could cause endless loop*/
1067                 return(SN_PARSE_ERROR_CHHL);
1068
1069         if ((chunk_hdr->chunk_flags & SCTP_HAD_NO_TCB) &&
1070             ((chunk_hdr->chunk_type == SCTP_ABORT_ASSOCIATION) ||
1071                 (chunk_hdr->chunk_type == SCTP_SHUTDOWN_COMPLETE))) {
1072                 /* T-Bit set */
1073                 if (direction == SN_TO_LOCAL)
1074                         *passoc = FindSctpGlobalT(la,  pip->ip_src, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port);
1075                 else
1076                         *passoc = FindSctpLocalT(la, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port);
1077         } else {
1078                 /* Proper v_tag settings */
1079                 if (direction == SN_TO_LOCAL)
1080                         *passoc = FindSctpGlobal(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match);
1081                 else
1082                         *passoc = FindSctpLocal(la, pip->ip_src,  pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port);
1083         }
1084
1085         chunk_count = 1;
1086         /* Real packet parsing occurs below */
1087         sm->msg = SN_SCTP_OTHER;/* Initialise to largest value*/
1088         sm->chunk_length = 0; /* only care about length for key chunks */
1089         while (IS_SCTP_CONTROL(chunk_hdr)) {
1090                 switch(chunk_hdr->chunk_type) {
1091                 case SCTP_INITIATION:
1092                         if (chunk_length < sizeof(struct sctp_init_chunk)) /* malformed chunk*/
1093                                 return(SN_PARSE_ERROR_CHHL);
1094                         sm->msg = SN_SCTP_INIT;
1095                         sm->sctpchnk.Init = (struct sctp_init *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr));
1096                         sm->chunk_length = chunk_length;
1097                         /* if no existing association, create a new one */
1098                         if (*passoc == NULL) {
1099                                 if (sctp_hdr->v_tag == 0){ //Init requires vtag=0
1100                                         *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc));
1101                                         if (*passoc == NULL) {/* out of resources */ 
1102                                                 return(SN_PARSE_ERROR_AS_MALLOC);
1103                                         }
1104                                         /* Initialise association - malloc initialises memory to zeros */
1105                                         (*passoc)->state = SN_ID;
1106                                         LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */
1107                                         (*passoc)->TableRegister = SN_NULL_TBL;
1108                                         return(SN_PARSE_OK);
1109                                 }
1110                                 return(SN_PARSE_ERROR_VTAG);
1111                         }
1112                         return(SN_PARSE_ERROR_LOOKUP);
1113                 case SCTP_INITIATION_ACK:
1114                         if (chunk_length < sizeof(struct sctp_init_ack_chunk)) /* malformed chunk*/
1115                                 return(SN_PARSE_ERROR_CHHL);
1116                         sm->msg = SN_SCTP_INITACK;
1117                         sm->sctpchnk.InitAck = (struct sctp_init_ack *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr));
1118                         sm->chunk_length = chunk_length;
1119                         return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK));
1120                 case SCTP_ABORT_ASSOCIATION: /* access only minimum sized chunk */
1121                         sm->msg = SN_SCTP_ABORT;
1122                         sm->chunk_length = chunk_length;
1123                         return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP_ABORT):(SN_PARSE_OK));
1124                 case SCTP_SHUTDOWN_ACK:
1125                         if (chunk_length < sizeof(struct sctp_shutdown_ack_chunk)) /* malformed chunk*/
1126                                 return(SN_PARSE_ERROR_CHHL);
1127                         if (sm->msg > SN_SCTP_SHUTACK) {
1128                                 sm->msg = SN_SCTP_SHUTACK;
1129                                 sm->chunk_length = chunk_length;
1130                         }
1131                         break;
1132                 case SCTP_SHUTDOWN_COMPLETE:  /* minimum sized chunk */
1133                         if (sm->msg > SN_SCTP_SHUTCOMP) {
1134                                 sm->msg = SN_SCTP_SHUTCOMP;
1135                                 sm->chunk_length = chunk_length;
1136                         }
1137                         return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK));
1138                 case SCTP_ASCONF:
1139                         if (sm->msg > SN_SCTP_ASCONF) {
1140                                 if (chunk_length < (sizeof(struct  sctp_asconf_chunk) + sizeof(struct  sctp_ipv4addr_param))) /* malformed chunk*/
1141                                         return(SN_PARSE_ERROR_CHHL);
1142                                 //leave parameter searching to later, if required
1143                                 param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr + sizeof(struct sctp_asconf_chunk)); /*compulsory IP parameter*/
1144                                 if (ntohs(param_hdr->param_type) == SCTP_IPV4_ADDRESS) {
1145                                         if ((*passoc == NULL) && (direction == SN_TO_LOCAL)) { /* AddIP with no association */
1146                                                 /* try look up with the ASCONF packet's alternative address */
1147                                                 ipv4addr.s_addr = ((struct sctp_ipv4addr_param *) param_hdr)->addr;
1148                                                 *passoc = FindSctpGlobal(la, ipv4addr, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match);
1149                                         }
1150                                         param_hdr = (struct sctp_paramhdr *) 
1151                                                 ((char *) param_hdr + sizeof(struct sctp_ipv4addr_param)); /*asconf's compulsory address parameter */
1152                                         sm->chunk_length = chunk_length - sizeof(struct  sctp_asconf_chunk) - sizeof(struct  sctp_ipv4addr_param); /* rest of chunk */
1153                                 } else {
1154                                         if (chunk_length < (sizeof(struct  sctp_asconf_chunk) + sizeof(struct  sctp_ipv6addr_param))) /* malformed chunk*/
1155                                                 return(SN_PARSE_ERROR_CHHL);
1156                                         param_hdr = (struct sctp_paramhdr *) 
1157                                                 ((char *) param_hdr + sizeof(struct sctp_ipv6addr_param)); /*asconf's compulsory address parameter */     
1158                                         sm->chunk_length = chunk_length - sizeof(struct  sctp_asconf_chunk) - sizeof(struct  sctp_ipv6addr_param); /* rest of chunk */
1159                                 }
1160                                 sm->msg = SN_SCTP_ASCONF;
1161                                 sm->sctpchnk.Asconf = param_hdr;
1162         
1163                                 if (*passoc == NULL) { /* AddIP with no association */
1164                                         *passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc));
1165                                         if (*passoc == NULL) {/* out of resources */ 
1166                                                 return(SN_PARSE_ERROR_AS_MALLOC);
1167                                         }
1168                                         /* Initialise association  - malloc initialises memory to zeros */
1169                                         (*passoc)->state = SN_ID;
1170                                         LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */
1171                                         (*passoc)->TableRegister = SN_NULL_TBL;
1172                                         return(SN_PARSE_OK);
1173                                 }
1174                         }
1175                         break;
1176                 case SCTP_ASCONF_ACK:
1177                         if (sm->msg > SN_SCTP_ASCONFACK) {
1178                                 if (chunk_length < sizeof(struct  sctp_asconf_ack_chunk)) /* malformed chunk*/
1179                                         return(SN_PARSE_ERROR_CHHL);
1180                                 //leave parameter searching to later, if required
1181                                 param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr 
1182                                     + sizeof(struct sctp_asconf_ack_chunk));
1183                                 sm->msg = SN_SCTP_ASCONFACK;
1184                                 sm->sctpchnk.Asconf = param_hdr;
1185                                 sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_ack_chunk);
1186                         }
1187                         break;
1188                 default:
1189                         break; /* do nothing*/
1190                 }
1191
1192                 /* if no association is found exit - we need to find an Init or AddIP within sysctl_initialising_chunk_proc_limit */
1193                 if ((*passoc == NULL) && (chunk_count >= sysctl_initialising_chunk_proc_limit))
1194                         return(SN_PARSE_ERROR_LOOKUP);
1195
1196                 /* finished with this chunk, on to the next chunk*/
1197                 bytes_left-= chunk_length;
1198
1199                 /* Is this the end of the packet ? */
1200                 if (bytes_left == 0)
1201                         return (*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK);
1202
1203                 /* Are there enough bytes in packet to at least retrieve length of next chunk ? */
1204                 if (bytes_left < SN_MIN_CHUNK_SIZE)
1205                         return(SN_PARSE_ERROR_CHHL);
1206
1207                 chunk_hdr = SN_SCTP_NEXTCHUNK(chunk_hdr);
1208
1209                 /* Is the chunk long enough to not cause endless look and are there enough bytes in packet to read the chunk ? */
1210                 chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length));
1211                 if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left))
1212                         return(SN_PARSE_ERROR_CHHL);
1213                 if(++chunk_count > sysctl_chunk_proc_limit)
1214                         return(SN_PARSE_OK); /* limit for processing chunks, take what we get */
1215         }
1216
1217         if (*passoc == NULL)
1218                 return (partial_match)?(SN_PARSE_ERROR_PARTIALLOOKUP):(SN_PARSE_ERROR_LOOKUP);
1219         else
1220                 return(SN_PARSE_OK);
1221 }
1222
1223 /** @ingroup packet_parser
1224  * @brief Extract Vtags from Asconf Chunk
1225  *
1226  * GetAsconfVtags scans an Asconf Chunk for the vtags parameter, and then
1227  * extracts the vtags.
1228  * 
1229  * GetAsconfVtags is not called from within sctp_PktParser. It is called only
1230  * from within ID_process when an AddIP has been received.
1231  *
1232  * @param la Pointer to the relevant libalias instance
1233  * @param sm Pointer to sctp message information
1234  * @param l_vtag Pointer to the local vtag in the association this SCTP Message belongs to
1235  * @param g_vtag Pointer to the local vtag in the association this SCTP Message belongs to
1236  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1237  * 
1238  * @return 1 - success | 0 - fail 
1239  */
1240 static int
1241 GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, uint32_t *l_vtag, uint32_t *g_vtag, int direction)
1242 {
1243         /* To be removed when information is in the sctp headers */
1244 #define SCTP_VTAG_PARAM 0xC007
1245         struct sctp_vtag_param {
1246                 struct sctp_paramhdr ph;/* type=SCTP_VTAG_PARAM */
1247                 uint32_t local_vtag;
1248                 uint32_t remote_vtag;
1249         }                    __attribute__((packed));
1250   
1251         struct sctp_vtag_param *vtag_param;
1252         struct sctp_paramhdr *param;
1253         int bytes_left;
1254         int param_size;
1255         int param_count;
1256
1257         param_count = 1;
1258         param = sm->sctpchnk.Asconf;
1259         param_size = SCTP_SIZE32(ntohs(param->param_length));
1260         bytes_left = sm->chunk_length;
1261         /* step through Asconf parameters */
1262         while((bytes_left >= param_size) && (bytes_left >= SN_VTAG_PARAM_SIZE)) {
1263                 if (ntohs(param->param_type) == SCTP_VTAG_PARAM) {
1264                         vtag_param = (struct sctp_vtag_param *) param;
1265                         switch(direction) {
1266                                 /* The Internet draft is a little ambigious as to order of these vtags.
1267                                    We think it is this way around. If we are wrong, the order will need
1268                                    to be changed. */
1269                         case SN_TO_GLOBAL:
1270                                 *g_vtag = vtag_param->local_vtag;
1271                                 *l_vtag = vtag_param->remote_vtag;
1272                                 break;
1273                         case SN_TO_LOCAL:
1274                                 *g_vtag = vtag_param->remote_vtag;
1275                                 *l_vtag = vtag_param->local_vtag;
1276                                 break;
1277                         }
1278                         return(1); /* found */
1279                 }
1280
1281                 bytes_left -= param_size;
1282                 if (bytes_left < SN_MIN_PARAM_SIZE) return(0);
1283
1284                 param = SN_SCTP_NEXTPARAM(param);
1285                 param_size = SCTP_SIZE32(ntohs(param->param_length));
1286                 if (++param_count > sysctl_param_proc_limit) {
1287                         SN_LOG(SN_LOG_EVENT,
1288                             logsctperror("Parameter parse limit exceeded (GetAsconfVtags)",
1289                                 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1290                         return(0); /* not found limit exceeded*/
1291                 }
1292         }
1293         return(0); /* not found */
1294 }
1295
1296 /** @ingroup packet_parser
1297  * @brief AddGlobalIPAddresses from Init,InitAck,or AddIP packets
1298  * 
1299  * AddGlobalIPAddresses scans an SCTP chunk (in sm) for Global IP addresses, and
1300  * adds them.
1301  *
1302  * @param sm Pointer to sctp message information
1303  * @param assoc Pointer to the association this SCTP Message belongs to
1304  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1305  * 
1306  */
1307 static void
1308 AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction)
1309 {
1310         struct sctp_ipv4addr_param *ipv4_param;
1311         struct sctp_paramhdr *param = NULL;
1312         struct sctp_GlobalAddress *G_Addr;
1313         struct in_addr g_addr = {0};
1314         int bytes_left = 0;
1315         int param_size;
1316         int param_count, addr_param_count = 0;
1317
1318         switch(direction) {
1319         case SN_TO_GLOBAL: /* does not contain global addresses */
1320                 g_addr = sm->ip_hdr->ip_dst;
1321                 bytes_left = 0; /* force exit */
1322                 break;
1323         case SN_TO_LOCAL:
1324                 g_addr = sm->ip_hdr->ip_src;
1325                 param_count = 1;
1326                 switch(sm->msg) {
1327                 case SN_SCTP_INIT:
1328                         bytes_left = sm->chunk_length - sizeof(struct sctp_init_chunk);
1329                         param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.Init + sizeof(struct sctp_init));
1330                         break;
1331                 case SN_SCTP_INITACK:
1332                         bytes_left = sm->chunk_length - sizeof(struct sctp_init_ack_chunk);
1333                         param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.InitAck + sizeof(struct sctp_init_ack));
1334                         break;
1335                 case SN_SCTP_ASCONF:
1336                         bytes_left = sm->chunk_length;
1337                         param = sm->sctpchnk.Asconf;
1338                         break;
1339                 }
1340         }
1341         if (bytes_left >= SN_MIN_PARAM_SIZE)    
1342                 param_size = SCTP_SIZE32(ntohs(param->param_length));
1343         else
1344                 param_size = bytes_left+1; /* force skip loop */
1345   
1346         if ((assoc->state == SN_ID) && ((sm->msg == SN_SCTP_INIT) || (bytes_left < SN_MIN_PARAM_SIZE))) {/* add pkt address */ 
1347                 G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress));
1348                 if (G_Addr == NULL) {/* out of resources */ 
1349                         SN_LOG(SN_LOG_EVENT,
1350                             logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", 
1351                                 sm->sctp_hdr->v_tag,  0, direction));
1352                         assoc->num_Gaddr = 0; /* don't track any more for this assoc*/
1353                         sysctl_track_global_addresses=0;
1354                         return;
1355                 }
1356                 G_Addr->g_addr = g_addr;
1357                 if (!Add_Global_Address_to_List(assoc, G_Addr))
1358                         SN_LOG(SN_LOG_EVENT,
1359                             logsctperror("AddGlobalIPAddress: Address already in list", 
1360                                 sm->sctp_hdr->v_tag,  assoc->num_Gaddr, direction));
1361         }
1362
1363         /* step through parameters */
1364         while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) {
1365                 if (assoc->num_Gaddr >= sysctl_track_global_addresses) {
1366                         SN_LOG(SN_LOG_EVENT,
1367                             logsctperror("AddGlobalIPAddress: Maximum Number of addresses reached", 
1368                                 sm->sctp_hdr->v_tag,  sysctl_track_global_addresses, direction));
1369                         return;
1370                 }
1371                 switch(ntohs(param->param_type)) {
1372                 case SCTP_ADD_IP_ADDRESS:
1373                         /* skip to address parameter - leave param_size so bytes left will be calculated properly*/
1374                         param = (struct sctp_paramhdr *) &((struct sctp_asconf_addrv4_param *) param)->addrp;
1375                 case SCTP_IPV4_ADDRESS:
1376                         ipv4_param = (struct sctp_ipv4addr_param *) param;
1377                         /* add addresses to association */
1378                         G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress));
1379                         if (G_Addr == NULL) {/* out of resources */ 
1380                                 SN_LOG(SN_LOG_EVENT,
1381                                     logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking", 
1382                                         sm->sctp_hdr->v_tag,  0, direction));
1383                                 assoc->num_Gaddr = 0; /* don't track any more for this assoc*/
1384                                 sysctl_track_global_addresses=0;
1385                                 return;
1386                         }
1387                         /* add address */
1388                         addr_param_count++;
1389                         if ((sm->msg == SN_SCTP_ASCONF) && (ipv4_param->addr == INADDR_ANY)) { /* use packet address */
1390                                 G_Addr->g_addr = g_addr;
1391                                 if (!Add_Global_Address_to_List(assoc, G_Addr))
1392                                         SN_LOG(SN_LOG_EVENT,
1393                                             logsctperror("AddGlobalIPAddress: Address already in list", 
1394                                                 sm->sctp_hdr->v_tag,  assoc->num_Gaddr, direction));
1395                                 return; /*shouldn't be any other addresses if the zero address is given*/
1396                         } else {
1397                                 G_Addr->g_addr.s_addr = ipv4_param->addr;
1398                                 if (!Add_Global_Address_to_List(assoc, G_Addr))
1399                                         SN_LOG(SN_LOG_EVENT,
1400                                             logsctperror("AddGlobalIPAddress: Address already in list", 
1401                                                 sm->sctp_hdr->v_tag,  assoc->num_Gaddr, direction));
1402                         }
1403                 } 
1404     
1405                 bytes_left -= param_size;
1406                 if (bytes_left < SN_MIN_PARAM_SIZE)
1407                         break;
1408     
1409                 param = SN_SCTP_NEXTPARAM(param);
1410                 param_size = SCTP_SIZE32(ntohs(param->param_length));
1411                 if (++param_count > sysctl_param_proc_limit) {
1412                         SN_LOG(SN_LOG_EVENT,
1413                             logsctperror("Parameter parse limit exceeded (AddGlobalIPAddress)",
1414                                 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1415                         break; /* limit exceeded*/
1416                 }
1417         }
1418         if (addr_param_count == 0) {
1419                 SN_LOG(SN_LOG_DETAIL,
1420                     logsctperror("AddGlobalIPAddress: no address parameters to add", 
1421                         sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction));
1422         }
1423 }
1424
1425 /** 
1426  * @brief Add_Global_Address_to_List
1427  *
1428  * Adds a global IP address to an associations address list, if it is not
1429  * already there.  The first address added us usually the packet's address, and
1430  * is most likely to be used, so it is added at the beginning. Subsequent
1431  * addresses are added after this one.
1432  * 
1433  * @param assoc Pointer to the association this SCTP Message belongs to
1434  * @param G_addr Pointer to the global address to add
1435  *
1436  * @return 1 - success | 0 - fail 
1437  */
1438 static int  Add_Global_Address_to_List(struct sctp_nat_assoc *assoc,  struct sctp_GlobalAddress *G_addr)
1439 {
1440         struct sctp_GlobalAddress *iter_G_Addr = NULL, *first_G_Addr = NULL;     
1441         first_G_Addr = LIST_FIRST(&(assoc->Gaddr));  
1442         if (first_G_Addr == NULL) {
1443                 LIST_INSERT_HEAD(&(assoc->Gaddr), G_addr, list_Gaddr); /* add new address to beginning of list*/
1444         } else {
1445                 LIST_FOREACH(iter_G_Addr, &(assoc->Gaddr), list_Gaddr) {
1446                         if (G_addr->g_addr.s_addr == iter_G_Addr->g_addr.s_addr)
1447                                 return(0); /* already exists, so don't add */
1448                 }
1449                 LIST_INSERT_AFTER(first_G_Addr, G_addr, list_Gaddr); /* add address to end of list*/
1450         }
1451         assoc->num_Gaddr++;       
1452         return(1); /* success */   
1453 }
1454
1455 /** @ingroup packet_parser
1456  * @brief RmGlobalIPAddresses from DelIP packets
1457  *
1458  * RmGlobalIPAddresses scans an ASCONF chunk for DelIP parameters to remove the
1459  * given Global IP addresses from the association. It will not delete the
1460  * the address if it is a list of one address.
1461  *
1462  *
1463  * @param sm Pointer to sctp message information
1464  * @param assoc Pointer to the association this SCTP Message belongs to
1465  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1466  * 
1467  */
1468 static void
1469 RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction)
1470 {
1471         struct sctp_asconf_addrv4_param *asconf_ipv4_param;
1472         struct sctp_paramhdr *param;
1473         struct sctp_GlobalAddress *G_Addr, *G_Addr_tmp;
1474         struct in_addr g_addr;
1475         int bytes_left;
1476         int param_size;
1477         int param_count;
1478
1479         if(direction == SN_TO_GLOBAL)
1480                 g_addr = sm->ip_hdr->ip_dst;
1481         else
1482                 g_addr = sm->ip_hdr->ip_src;
1483
1484         bytes_left = sm->chunk_length;
1485         param_count = 1;
1486         param = sm->sctpchnk.Asconf;
1487         if (bytes_left >= SN_MIN_PARAM_SIZE) {          
1488                 param_size = SCTP_SIZE32(ntohs(param->param_length));
1489         } else {
1490                 SN_LOG(SN_LOG_EVENT,
1491                     logsctperror("RmGlobalIPAddress: truncated packet - cannot remove IP addresses", 
1492                         sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction));
1493                 return;
1494         }
1495  
1496         /* step through Asconf parameters */
1497         while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) {
1498                 if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) {
1499                         asconf_ipv4_param = (struct sctp_asconf_addrv4_param *) param;
1500                         if (asconf_ipv4_param->addrp.addr == INADDR_ANY) { /* remove all bar pkt address */
1501                                 LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) {
1502                                         if(G_Addr->g_addr.s_addr != sm->ip_hdr->ip_src.s_addr) {
1503                                                 if (assoc->num_Gaddr > 1) { /* only delete if more than one */
1504                                                         LIST_REMOVE(G_Addr, list_Gaddr);
1505                                                         sn_free(G_Addr);
1506                                                         assoc->num_Gaddr--;
1507                                                 } else {
1508                                                         SN_LOG(SN_LOG_EVENT,
1509                                                             logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", 
1510                                                                 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction));
1511                                                 }
1512                                         }
1513                                 }
1514                                 return; /*shouldn't be any other addresses if the zero address is given*/
1515                         } else {
1516                                 LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) {
1517                                         if(G_Addr->g_addr.s_addr == asconf_ipv4_param->addrp.addr) {
1518                                                 if (assoc->num_Gaddr > 1) { /* only delete if more than one */
1519                                                         LIST_REMOVE(G_Addr, list_Gaddr);
1520                                                         sn_free(G_Addr);
1521                                                         assoc->num_Gaddr--;
1522                                                         break; /* Since add only adds new addresses, there should be no double entries */
1523                                                 } else {
1524                                                         SN_LOG(SN_LOG_EVENT,
1525                                                             logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)", 
1526                                                                 sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction));
1527                                                 }
1528                                         }
1529                                 }
1530                         }
1531                 }      
1532                 bytes_left -= param_size;
1533                 if (bytes_left == 0) return;
1534                 else if (bytes_left < SN_MIN_PARAM_SIZE) {
1535                         SN_LOG(SN_LOG_EVENT,
1536                             logsctperror("RmGlobalIPAddress: truncated packet - may not have removed all IP addresses", 
1537                                 sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction));
1538                         return;
1539                 }
1540     
1541                 param = SN_SCTP_NEXTPARAM(param);
1542                 param_size = SCTP_SIZE32(ntohs(param->param_length));
1543                 if (++param_count > sysctl_param_proc_limit) {
1544                         SN_LOG(SN_LOG_EVENT,
1545                             logsctperror("Parameter parse limit exceeded (RmGlobalIPAddress)",
1546                                 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1547                         return; /* limit exceeded*/
1548                 }
1549         }
1550 }
1551
1552 /**  @ingroup packet_parser
1553  * @brief Check that ASCONF was successful
1554  *
1555  * Each ASCONF configuration parameter carries a correlation ID which should be
1556  * matched with an ASCONFack. This is difficult for a NAT, since every
1557  * association could potentially have a number of outstanding ASCONF
1558  * configuration parameters, which should only be activated on receipt of the
1559  * ACK.
1560  *
1561  * Currently we only look for an ACK when the NAT is setting up a new
1562  * association (ie AddIP for a connection that the NAT does not know about
1563  * because the original Init went through a public interface or another NAT)
1564  * Since there is currently no connection on this path, there should be no other
1565  * ASCONF configuration parameters outstanding, so we presume that if there is
1566  * an ACK that it is responding to the AddIP and activate the new association.
1567  * 
1568  * @param la Pointer to the relevant libalias instance
1569  * @param sm Pointer to sctp message information
1570  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1571  * 
1572  * @return 1 - success | 0 - fail
1573  */
1574 static int
1575 IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction)
1576 {
1577         struct sctp_paramhdr *param;
1578         int bytes_left;
1579         int param_size;
1580         int param_count;
1581
1582         param_count = 1;
1583         param = sm->sctpchnk.Asconf;
1584         param_size = SCTP_SIZE32(ntohs(param->param_length));
1585         if (param_size == 8)
1586                 return(1); /*success - default acknowledgement of everything */
1587
1588         bytes_left = sm->chunk_length;
1589         if (bytes_left < param_size)
1590                 return(0); /* not found */
1591         /* step through Asconf parameters */
1592         while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) {
1593                 if (ntohs(param->param_type) == SCTP_SUCCESS_REPORT)
1594                         return(1); /* success - but can't match correlation IDs - should only be one */
1595                 /* check others just in case */
1596                 bytes_left -= param_size;
1597                 if (bytes_left >= SN_MIN_PARAM_SIZE) {
1598                         param = SN_SCTP_NEXTPARAM(param);
1599                 } else {
1600                         return(0);
1601                 }
1602                 param_size = SCTP_SIZE32(ntohs(param->param_length));
1603                 if (bytes_left < param_size) return(0);
1604
1605                 if (++param_count > sysctl_param_proc_limit) {
1606                         SN_LOG(SN_LOG_EVENT,
1607                             logsctperror("Parameter parse limit exceeded (IsASCONFack)", 
1608                                 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1609                         return(0); /* not found limit exceeded*/
1610                 }
1611         }
1612         return(0); /* not success */
1613 }
1614
1615 /**  @ingroup packet_parser
1616  * @brief Check to see if ASCONF contains an Add IP or Del IP parameter 
1617  * 
1618  * IsADDorDEL scans an ASCONF packet to see if it contains an AddIP or DelIP
1619  * parameter
1620  *
1621  * @param la Pointer to the relevant libalias instance
1622  * @param sm Pointer to sctp message information
1623  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1624  * 
1625  * @return SCTP_ADD_IP_ADDRESS | SCTP_DEL_IP_ADDRESS | 0 - fail
1626  */
1627 static int
1628 IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction)
1629 {
1630         struct sctp_paramhdr *param;
1631         int bytes_left;
1632         int param_size;
1633         int param_count;
1634
1635         param_count = 1;
1636         param = sm->sctpchnk.Asconf;
1637         param_size = SCTP_SIZE32(ntohs(param->param_length));
1638
1639         bytes_left = sm->chunk_length;
1640         if (bytes_left < param_size)
1641                 return(0); /* not found */
1642         /* step through Asconf parameters */
1643         while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) {
1644                 if (ntohs(param->param_type) == SCTP_ADD_IP_ADDRESS)
1645                         return(SCTP_ADD_IP_ADDRESS);
1646                 else if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) 
1647                         return(SCTP_DEL_IP_ADDRESS);
1648                 /* check others just in case */
1649                 bytes_left -= param_size;
1650                 if (bytes_left >= SN_MIN_PARAM_SIZE) {
1651                         param = SN_SCTP_NEXTPARAM(param);
1652                 } else {
1653                         return(0); /*Neither found */
1654                 }
1655                 param_size = SCTP_SIZE32(ntohs(param->param_length));
1656                 if (bytes_left < param_size) return(0);
1657
1658                 if (++param_count > sysctl_param_proc_limit) {
1659                         SN_LOG(SN_LOG_EVENT,
1660                             logsctperror("Parameter parse limit exceeded IsADDorDEL)", 
1661                                 sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1662                         return(0); /* not found limit exceeded*/
1663                 }
1664         }
1665         return(0);  /*Neither found */
1666 }
1667
1668 /* ----------------------------------------------------------------------
1669  *                            STATE MACHINE CODE
1670  * ----------------------------------------------------------------------
1671  */
1672 /** @addtogroup state_machine
1673  *
1674  * The SCTP NAT State Machine functions will:
1675  * - Process an already parsed packet
1676  * - Use the existing NAT Hash Tables
1677  * - Determine the next state for the association
1678  * - Update the NAT Hash Tables and Timer Queues
1679  * - Return the appropriate action to take with the packet
1680  */
1681 /** @ingroup state_machine
1682  * @brief Process SCTP message
1683  *
1684  * This function is the base state machine. It calls the processing engine for
1685  * each state.
1686  *
1687  * @param la Pointer to the relevant libalias instance
1688  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1689  * @param sm Pointer to sctp message information
1690  * @param assoc Pointer to the association this SCTP Message belongs to
1691  *
1692  * @return SN_DROP_PKT | SN_NAT_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR | SN_PROCESSING_ERROR
1693  */
1694 static int
1695 ProcessSctpMsg(struct libalias *la, int direction, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc)
1696 {
1697         int rtnval;
1698
1699         switch (assoc->state) {
1700         case SN_ID: /* Idle */
1701                 rtnval = ID_process(la, direction, assoc, sm);
1702                 if (rtnval != SN_NAT_PKT) {
1703                         assoc->state = SN_RM;/* Mark for removal*/
1704                 }
1705                 return(rtnval);
1706         case SN_INi: /* Initialising - Init */
1707                 return(INi_process(la, direction, assoc, sm));
1708         case SN_INa: /* Initialising - AddIP */
1709                 return(INa_process(la, direction, assoc, sm));
1710         case SN_UP:  /* Association UP */
1711                 return(UP_process(la, direction, assoc, sm));
1712         case SN_CL:  /* Association Closing */
1713                 return(CL_process(la, direction, assoc, sm));
1714         }
1715         return(SN_PROCESSING_ERROR);
1716 }
1717
1718 /** @ingroup state_machine
1719  * @brief Process SCTP message while in the Idle state
1720  *
1721  * This function looks for an Incoming INIT or AddIP message.
1722  *
1723  * All other SCTP messages are invalid when in SN_ID, and are dropped.
1724  *
1725  * @param la Pointer to the relevant libalias instance
1726  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1727  * @param sm Pointer to sctp message information
1728  * @param assoc Pointer to the association this SCTP Message belongs to
1729  *
1730  * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR
1731  */
1732 static int
1733 ID_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1734 {
1735         switch(sm->msg) {
1736         case SN_SCTP_ASCONF:           /* a packet containing an ASCONF chunk with ADDIP */
1737                 if (!sysctl_accept_global_ootb_addip && (direction == SN_TO_LOCAL))
1738                         return(SN_DROP_PKT);
1739                 /* if this Asconf packet does not contain the Vtag parameters it is of no use in Idle state */
1740                 if (!GetAsconfVtags(la, sm, &(assoc->l_vtag), &(assoc->g_vtag), direction))
1741                         return(SN_DROP_PKT);
1742         case SN_SCTP_INIT:            /* a packet containing an INIT chunk or an ASCONF AddIP */
1743                 if (sysctl_track_global_addresses)
1744                         AddGlobalIPAddresses(sm, assoc, direction);
1745                 switch(direction){
1746                 case SN_TO_GLOBAL:
1747                         assoc->l_addr = sm->ip_hdr->ip_src;
1748                         assoc->a_addr = FindAliasAddress(la, assoc->l_addr);
1749                         assoc->l_port = sm->sctp_hdr->src_port;
1750                         assoc->g_port = sm->sctp_hdr->dest_port;
1751                         if(sm->msg == SN_SCTP_INIT)
1752                                 assoc->g_vtag = sm->sctpchnk.Init->initiate_tag;
1753                         if (AddSctpAssocGlobal(la, assoc)) /* DB clash *///**** need to add dst address
1754                                 return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR);
1755                         if(sm->msg == SN_SCTP_ASCONF) {
1756                                 if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_dst)) /* DB clash */
1757                                         return(SN_REPLY_ERROR);
1758                                 assoc->TableRegister |= SN_WAIT_TOLOCAL; /* wait for tolocal ack */
1759                         }
1760                 break;
1761                 case SN_TO_LOCAL:
1762                         assoc->l_addr = FindSctpRedirectAddress(la, sm);
1763                         assoc->a_addr = sm->ip_hdr->ip_dst; 
1764                         assoc->l_port = sm->sctp_hdr->dest_port;
1765                         assoc->g_port = sm->sctp_hdr->src_port;
1766                         if(sm->msg == SN_SCTP_INIT)
1767                                 assoc->l_vtag = sm->sctpchnk.Init->initiate_tag;
1768                         if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) /* DB clash */
1769                                 return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR);
1770                         if(sm->msg == SN_SCTP_ASCONF) {
1771                                 if (AddSctpAssocGlobal(la, assoc)) /* DB clash */ //**** need to add src address
1772                                         return(SN_REPLY_ERROR);
1773                                 assoc->TableRegister |= SN_WAIT_TOGLOBAL; /* wait for toglobal ack */
1774                                         }
1775                         break;
1776                 }
1777         assoc->state = (sm->msg == SN_SCTP_INIT) ? SN_INi : SN_INa;
1778         assoc->exp = SN_I_T(la);
1779         sctp_AddTimeOut(la,assoc);
1780         return(SN_NAT_PKT);
1781         default: /* Any other type of SCTP message is not valid in Idle */
1782                 return(SN_DROP_PKT);
1783         }
1784 return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1785 }
1786
1787 /** @ingroup state_machine
1788  * @brief Process SCTP message while waiting for an INIT-ACK message
1789  *
1790  * Only an INIT-ACK, resent INIT, or an ABORT SCTP packet are valid in this
1791  * state, all other packets are dropped.
1792  * 
1793  * @param la Pointer to the relevant libalias instance
1794  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1795  * @param sm Pointer to sctp message information
1796  * @param assoc Pointer to the association this SCTP Message belongs to
1797  * 
1798  * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT 
1799  */
1800 static int
1801 INi_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1802 {
1803         switch(sm->msg) {
1804         case SN_SCTP_INIT:            /* a packet containing a retransmitted INIT chunk */
1805                 sctp_ResetTimeOut(la, assoc, SN_I_T(la));
1806                 return(SN_NAT_PKT);
1807         case SN_SCTP_INITACK:         /* a packet containing an INIT-ACK chunk */
1808                 switch(direction){
1809                 case SN_TO_LOCAL:
1810                         if (assoc->num_Gaddr) /*If tracking global addresses for this association */
1811                                 AddGlobalIPAddresses(sm, assoc, direction);
1812                         assoc->l_vtag = sm->sctpchnk.Init->initiate_tag;
1813                         if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) { /* DB clash */
1814                                 assoc->state = SN_RM;/* Mark for removal*/
1815                                 return(SN_SEND_ABORT);
1816                         }
1817                         break;
1818                 case SN_TO_GLOBAL:
1819                         assoc->l_addr = sm->ip_hdr->ip_src; // Only if not set in Init! *
1820                         assoc->g_vtag = sm->sctpchnk.Init->initiate_tag;
1821                         if (AddSctpAssocGlobal(la, assoc)) { /* DB clash */
1822                                 assoc->state = SN_RM;/* Mark for removal*/
1823                                 return(SN_SEND_ABORT);
1824                         }
1825                         break;
1826                 }
1827                 assoc->state = SN_UP;/* association established for NAT */
1828                 sctp_ResetTimeOut(la,assoc, SN_U_T(la));
1829                 return(SN_NAT_PKT);
1830         case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1831                 assoc->state = SN_RM;/* Mark for removal*/
1832                 return(SN_NAT_PKT);
1833         default:
1834                 return(SN_DROP_PKT);
1835         }
1836         return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1837 }
1838
1839 /** @ingroup state_machine
1840  * @brief Process SCTP message while waiting for an AddIp-ACK message
1841  * 
1842  * Only an AddIP-ACK, resent AddIP, or an ABORT message are valid, all other
1843  * SCTP packets are dropped
1844  *
1845  * @param la Pointer to the relevant libalias instance
1846  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1847  * @param sm Pointer to sctp message information
1848  * @param assoc Pointer to the association this SCTP Message belongs to
1849  * 
1850  * @return SN_NAT_PKT | SN_DROP_PKT 
1851  */
1852 static int
1853 INa_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1854 {
1855         switch(sm->msg) {
1856         case SN_SCTP_ASCONF:           /* a packet containing an ASCONF chunk*/
1857                 sctp_ResetTimeOut(la,assoc, SN_I_T(la));
1858                 return(SN_NAT_PKT);
1859         case SN_SCTP_ASCONFACK:        /* a packet containing an ASCONF chunk with a ADDIP-ACK */
1860                 switch(direction){
1861                 case SN_TO_LOCAL:
1862                         if (!(assoc->TableRegister & SN_WAIT_TOLOCAL)) /* wrong direction */
1863                                 return(SN_DROP_PKT);
1864                         break;
1865                 case SN_TO_GLOBAL:
1866                         if (!(assoc->TableRegister & SN_WAIT_TOGLOBAL)) /* wrong direction */
1867                                 return(SN_DROP_PKT);
1868                 }
1869                 if (IsASCONFack(la,sm,direction)) {
1870                         assoc->TableRegister &= SN_BOTH_TBL; /* remove wait flags */
1871                         assoc->state = SN_UP; /* association established for NAT */
1872                         sctp_ResetTimeOut(la,assoc, SN_U_T(la));
1873                         return(SN_NAT_PKT);
1874                 } else {
1875                         assoc->state = SN_RM;/* Mark for removal*/
1876                         return(SN_NAT_PKT);
1877                 }
1878         case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1879                 assoc->state = SN_RM;/* Mark for removal*/
1880                 return(SN_NAT_PKT);
1881         default:
1882                 return(SN_DROP_PKT);
1883         }
1884         return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1885 }
1886
1887 /** @ingroup state_machine
1888  * @brief Process SCTP messages while association is UP redirecting packets
1889  * 
1890  * While in the SN_UP state, all packets for the particular association
1891  * are passed. Only a SHUT-ACK or an ABORT will cause a change of state.
1892  *
1893  * @param la Pointer to the relevant libalias instance
1894  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1895  * @param sm Pointer to sctp message information
1896  * @param assoc Pointer to the association this SCTP Message belongs to
1897  * 
1898  * @return SN_NAT_PKT | SN_DROP_PKT 
1899  */
1900 static int
1901 UP_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1902 {
1903         switch(sm->msg) {
1904         case SN_SCTP_SHUTACK:         /* a packet containing a SHUTDOWN-ACK chunk */
1905                 assoc->state = SN_CL;
1906                 sctp_ResetTimeOut(la,assoc, SN_C_T(la));
1907                 return(SN_NAT_PKT);
1908         case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1909                 assoc->state = SN_RM;/* Mark for removal*/
1910                 return(SN_NAT_PKT);
1911         case SN_SCTP_ASCONF:           /* a packet containing an ASCONF chunk*/
1912                 if ((direction == SN_TO_LOCAL) && assoc->num_Gaddr) /*If tracking global addresses for this association & from global side */
1913                         switch(IsADDorDEL(la,sm,direction)) {
1914                         case SCTP_ADD_IP_ADDRESS:
1915                                 AddGlobalIPAddresses(sm, assoc, direction);
1916                                 break;
1917                         case SCTP_DEL_IP_ADDRESS:
1918                                 RmGlobalIPAddresses(sm, assoc, direction);
1919                                 break;
1920                         } /* fall through to default */
1921         default:
1922                 sctp_ResetTimeOut(la,assoc, SN_U_T(la));
1923                 return(SN_NAT_PKT);  /* forward packet */
1924         }
1925         return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1926 }
1927
1928 /** @ingroup state_machine
1929  * @brief Process SCTP message while association is in the process of closing
1930  *
1931  * This function waits for a SHUT-COMP to close the association. Depending on
1932  * the setting of sysctl_holddown_timer it may not remove the association
1933  * immediately, but leave it up until SN_X_T(la). Only SHUT-COMP, SHUT-ACK, and
1934  * ABORT packets are permitted in this state. All other packets are dropped.
1935  *
1936  * @param la Pointer to the relevant libalias instance
1937  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL 
1938  * @param sm Pointer to sctp message information
1939  * @param assoc Pointer to the association this SCTP Message belongs to
1940  * 
1941  * @return SN_NAT_PKT | SN_DROP_PKT 
1942  */
1943 static int
1944 CL_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1945 {
1946         switch(sm->msg) {
1947         case SN_SCTP_SHUTCOMP:        /* a packet containing a SHUTDOWN-COMPLETE chunk */
1948                 assoc->state = SN_CL;  /* Stay in Close state until timeout */
1949                 if (sysctl_holddown_timer > 0)
1950                         sctp_ResetTimeOut(la, assoc, SN_X_T(la));/* allow to stay open for Tbit packets*/
1951                 else
1952                         assoc->state = SN_RM;/* Mark for removal*/
1953                 return(SN_NAT_PKT);
1954         case SN_SCTP_SHUTACK:         /* a packet containing a SHUTDOWN-ACK chunk */
1955                 assoc->state = SN_CL;  /* Stay in Close state until timeout */
1956                 sctp_ResetTimeOut(la, assoc, SN_C_T(la));
1957                 return(SN_NAT_PKT);
1958         case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1959                 assoc->state = SN_RM;/* Mark for removal*/
1960                 return(SN_NAT_PKT);
1961         default:
1962                 return(SN_DROP_PKT);
1963         }
1964         return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1965 }
1966
1967 /* ----------------------------------------------------------------------
1968  *                           HASH TABLE CODE
1969  * ----------------------------------------------------------------------
1970  */
1971 /** @addtogroup Hash
1972  *
1973  * The Hash functions facilitate searching the NAT Hash Tables for associations
1974  * as well as adding/removing associations from the table(s).
1975  */
1976 /** @ingroup Hash
1977  * @brief Find the SCTP association given the local address, port and vtag
1978  * 
1979  * Searches the local look-up table for the association entry matching the
1980  * provided local <address:ports:vtag> tuple
1981  *
1982  * @param la Pointer to the relevant libalias instance
1983  * @param l_addr local address
1984  * @param g_addr global address
1985  * @param l_vtag local Vtag
1986  * @param l_port local Port
1987  * @param g_port global Port
1988  * 
1989  * @return pointer to association or NULL
1990  */
1991 static struct sctp_nat_assoc*
1992 FindSctpLocal(struct libalias *la, struct in_addr l_addr, struct in_addr g_addr, uint32_t l_vtag, uint16_t l_port, uint16_t g_port)
1993 {
1994         u_int i;
1995         struct sctp_nat_assoc *assoc = NULL;
1996         struct sctp_GlobalAddress *G_Addr = NULL;
1997   
1998         if (l_vtag != 0) { /* an init packet, vtag==0 */
1999                 i = SN_TABLE_HASH(l_vtag, l_port, la->sctpNatTableSize);
2000                 LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) {
2001                         if ((assoc->l_vtag == l_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)\
2002                             && (assoc->l_addr.s_addr == l_addr.s_addr)) {
2003                                 if (assoc->num_Gaddr) {
2004                                         LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2005                                                 if(G_Addr->g_addr.s_addr == g_addr.s_addr)
2006                                                         return(assoc);
2007                                         }
2008                                 } else {
2009                                         return(assoc);
2010                                 }
2011                         }
2012                 }
2013         }
2014         return(NULL);
2015 }
2016
2017 /** @ingroup Hash
2018  * @brief Check for Global Clash
2019  * 
2020  * Searches the global look-up table for the association entry matching the
2021  * provided global <(addresses):ports:vtag> tuple
2022  *
2023  * @param la Pointer to the relevant libalias instance
2024  * @param Cassoc association being checked for a clash
2025  * 
2026  * @return pointer to association or NULL
2027  */
2028 static struct sctp_nat_assoc*
2029 FindSctpGlobalClash(struct libalias *la,  struct sctp_nat_assoc *Cassoc)
2030 {
2031         u_int i;
2032         struct sctp_nat_assoc *assoc = NULL;
2033         struct sctp_GlobalAddress *G_Addr = NULL;
2034         struct sctp_GlobalAddress *G_AddrC = NULL;
2035   
2036         if (Cassoc->g_vtag != 0) { /* an init packet, vtag==0 */
2037                 i = SN_TABLE_HASH(Cassoc->g_vtag, Cassoc->g_port, la->sctpNatTableSize);
2038                 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2039                         if ((assoc->g_vtag == Cassoc->g_vtag) && (assoc->g_port == Cassoc->g_port) && (assoc->l_port == Cassoc->l_port)) {
2040                                 if (assoc->num_Gaddr) {
2041                                         LIST_FOREACH(G_AddrC, &(Cassoc->Gaddr), list_Gaddr) {
2042                                                 LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2043                                                         if(G_Addr->g_addr.s_addr == G_AddrC->g_addr.s_addr)
2044                                                                 return(assoc);
2045                                                 }
2046                                         }
2047                                 } else {
2048                                         return(assoc);
2049                                 }
2050                         }
2051                 }
2052         }
2053         return(NULL);
2054 }
2055
2056 /** @ingroup Hash
2057  * @brief Find the SCTP association given the global port and vtag
2058  * 
2059  * Searches the global look-up table for the association entry matching the
2060  * provided global <address:ports:vtag> tuple
2061  *
2062  * If all but the global address match it sets partial_match to 1 to indicate a
2063  * partial match. If the NAT is tracking global IP addresses for this
2064  * association, the NAT may respond with an ERRORM to request the missing
2065  * address to be added.
2066  *
2067  * @param la Pointer to the relevant libalias instance
2068  * @param g_addr global address
2069  * @param g_vtag global vtag
2070  * @param g_port global port
2071  * @param l_port local port
2072  * 
2073  * @return pointer to association or NULL
2074  */
2075 static struct sctp_nat_assoc*
2076 FindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match)
2077 {
2078         u_int i;
2079         struct sctp_nat_assoc *assoc = NULL;
2080         struct sctp_GlobalAddress *G_Addr = NULL;
2081   
2082         *partial_match = 0;
2083         if (g_vtag != 0) { /* an init packet, vtag==0 */
2084                 i = SN_TABLE_HASH(g_vtag, g_port, la->sctpNatTableSize);
2085                 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2086                         if ((assoc->g_vtag == g_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) {
2087                                 *partial_match = 1;
2088                                 if (assoc->num_Gaddr) {
2089                                         LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2090                                                 if(G_Addr->g_addr.s_addr == g_addr.s_addr)
2091                                                         return(assoc);
2092                                         }
2093                                 } else {
2094                                         return(assoc);
2095                                 }
2096                         }
2097                 }
2098         }
2099         return(NULL);
2100 }
2101
2102 /** @ingroup Hash
2103  * @brief Find the SCTP association for a T-Flag message (given the global port and local vtag)
2104  * 
2105  * Searches the local look-up table for a unique association entry matching the
2106  * provided global port and local vtag information
2107  *
2108  * @param la Pointer to the relevant libalias instance
2109  * @param g_addr global address
2110  * @param l_vtag local Vtag
2111  * @param g_port global Port
2112  * @param l_port local Port
2113  * 
2114  * @return pointer to association or NULL
2115  */
2116 static struct sctp_nat_assoc*
2117 FindSctpLocalT(struct libalias *la,  struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port)
2118 {
2119         u_int i;
2120         struct sctp_nat_assoc *assoc = NULL, *lastmatch = NULL;
2121         struct sctp_GlobalAddress *G_Addr = NULL;
2122         int cnt = 0;
2123   
2124         if (l_vtag != 0) { /* an init packet, vtag==0 */
2125                 i = SN_TABLE_HASH(l_vtag, g_port, la->sctpNatTableSize);
2126                 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2127                         if ((assoc->g_vtag == l_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) {
2128                                 if (assoc->num_Gaddr) {
2129                                         LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2130                                                 if(G_Addr->g_addr.s_addr == G_Addr->g_addr.s_addr)
2131                                                         return(assoc); /* full match */
2132                                         }
2133                                 } else {
2134                                         if (++cnt > 1) return(NULL);
2135                                         lastmatch = assoc;
2136                                 }
2137                         }
2138                 }
2139         }
2140         /* If there is more than one match we do not know which local address to send to */
2141         return( cnt ? lastmatch : NULL );
2142 }
2143
2144 /** @ingroup Hash
2145  * @brief Find the SCTP association for a T-Flag message (given the local port and global vtag)
2146  * 
2147  * Searches the global look-up table for a unique association entry matching the
2148  * provided local port and global vtag information
2149  *
2150  * @param la Pointer to the relevant libalias instance
2151  * @param g_addr global address
2152  * @param g_vtag global vtag
2153  * @param l_port local port
2154  * @param g_port global port
2155  * 
2156  * @return pointer to association or NULL
2157  */
2158 static struct sctp_nat_assoc*
2159 FindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port)
2160 {
2161         u_int i;
2162         struct sctp_nat_assoc *assoc = NULL;
2163         struct sctp_GlobalAddress *G_Addr = NULL;
2164  
2165         if (g_vtag != 0) { /* an init packet, vtag==0 */
2166                 i = SN_TABLE_HASH(g_vtag, l_port, la->sctpNatTableSize);
2167                 LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) {
2168                         if ((assoc->l_vtag == g_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)) {
2169                                 if (assoc->num_Gaddr) {
2170                                         LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2171                                                 if(G_Addr->g_addr.s_addr == g_addr.s_addr)
2172                                                         return(assoc);
2173                                         }
2174                                 } else {
2175                                         return(assoc);
2176                                 }
2177                         }
2178                 }
2179         }
2180         return(NULL);
2181 }
2182
2183 /** @ingroup Hash
2184  * @brief  Add the sctp association information to the local look up table
2185  * 
2186  * Searches the local look-up table for an existing association with the same
2187  * details. If a match exists and is ONLY in the local look-up table then this
2188  * is a repeated INIT packet, we need to remove this association from the
2189  * look-up table and add the new association
2190  *
2191  * The new association is added to the head of the list and state is updated
2192  *
2193  * @param la Pointer to the relevant libalias instance
2194  * @param assoc pointer to sctp association
2195  * @param g_addr global address
2196  * 
2197  * @return SN_ADD_OK | SN_ADD_CLASH
2198  */
2199 static int
2200 AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr)
2201 {
2202         struct sctp_nat_assoc *found;
2203
2204         LIBALIAS_LOCK_ASSERT(la);
2205         found = FindSctpLocal(la, assoc->l_addr, g_addr, assoc->l_vtag, assoc->l_port, assoc->g_port);
2206         /*
2207          * Note that if a different global address initiated this Init,
2208          * ie it wasn't resent as presumed:
2209          *  - the local receiver if receiving it for the first time will establish
2210          *    an association with the new global host
2211          *  - if receiving an init from a different global address after sending a
2212          *    lost initack it will send an initack to the new global host, the first
2213          *    association attempt will then be blocked if retried.
2214          */
2215         if (found != NULL) {
2216                 if ((found->TableRegister == SN_LOCAL_TBL) && (found->g_port == assoc->g_port)) { /* resent message */
2217                         RmSctpAssoc(la, found);
2218                         sctp_RmTimeOut(la, found);
2219                         freeGlobalAddressList(found);
2220                         sn_free(found);
2221                 } else
2222                         return(SN_ADD_CLASH);
2223         }
2224   
2225         LIST_INSERT_HEAD(&la->sctpTableLocal[SN_TABLE_HASH(assoc->l_vtag, assoc->l_port, la->sctpNatTableSize)],
2226             assoc, list_L);
2227         assoc->TableRegister |= SN_LOCAL_TBL;
2228         la->sctpLinkCount++; //increment link count
2229
2230         if (assoc->TableRegister == SN_BOTH_TBL) {
2231                 /* libalias log -- controlled by libalias */
2232                 if (la->packetAliasMode & PKT_ALIAS_LOG)
2233                         SctpShowAliasStats(la);
2234
2235                 SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^"));
2236         }
2237
2238         return(SN_ADD_OK);
2239 }
2240
2241 /** @ingroup Hash
2242  * @brief  Add the sctp association information to the global look up table
2243  *
2244  * Searches the global look-up table for an existing association with the same
2245  * details. If a match exists and is ONLY in the global look-up table then this
2246  * is a repeated INIT packet, we need to remove this association from the
2247  * look-up table and add the new association
2248  *
2249  * The new association is added to the head of the list and state is updated
2250  *
2251  * @param la Pointer to the relevant libalias instance
2252  * @param assoc pointer to sctp association
2253  *
2254  * @return SN_ADD_OK | SN_ADD_CLASH
2255  */
2256 static int
2257 AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc)
2258 {
2259         struct sctp_nat_assoc *found;
2260
2261         LIBALIAS_LOCK_ASSERT(la);
2262         found = FindSctpGlobalClash(la, assoc);
2263         if (found != NULL) {
2264                 if ((found->TableRegister == SN_GLOBAL_TBL) &&                  \
2265                     (found->l_addr.s_addr == assoc->l_addr.s_addr) && (found->l_port == assoc->l_port)) { /* resent message */
2266                         RmSctpAssoc(la, found);
2267                         sctp_RmTimeOut(la, found);
2268                         freeGlobalAddressList(found);
2269                         sn_free(found);
2270                 } else
2271                         return(SN_ADD_CLASH);
2272         }
2273  
2274         LIST_INSERT_HEAD(&la->sctpTableGlobal[SN_TABLE_HASH(assoc->g_vtag, assoc->g_port, la->sctpNatTableSize)],
2275             assoc, list_G);
2276         assoc->TableRegister |= SN_GLOBAL_TBL;
2277         la->sctpLinkCount++; //increment link count
2278
2279         if (assoc->TableRegister == SN_BOTH_TBL) {
2280                 /* libalias log -- controlled by libalias */
2281                 if (la->packetAliasMode & PKT_ALIAS_LOG)
2282                         SctpShowAliasStats(la);
2283
2284                 SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^"));
2285         }
2286
2287         return(SN_ADD_OK);
2288 }
2289
2290 /** @ingroup Hash
2291  * @brief Remove the sctp association information from the look up table
2292  * 
2293  * For each of the two (local/global) look-up tables, remove the association
2294  * from that table IF it has been registered in that table.
2295  *
2296  * NOTE: The calling code is responsible for freeing memory allocated to the
2297  *       association structure itself
2298  *
2299  * NOTE: The association is NOT removed from the timer queue
2300  *
2301  * @param la Pointer to the relevant libalias instance
2302  * @param assoc pointer to sctp association
2303  */
2304 static void
2305 RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc)
2306 {
2307         //  struct sctp_nat_assoc *found;
2308         if (assoc == NULL) {
2309                 /* very bad, log and die*/
2310                 SN_LOG(SN_LOG_LOW,
2311                     logsctperror("ERROR: alias_sctp:RmSctpAssoc(NULL)\n", 0, 0, SN_TO_NODIR));
2312                 return;
2313         }
2314         /* log if association is fully up and now closing */
2315         if (assoc->TableRegister == SN_BOTH_TBL) {
2316                 SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "$"));
2317         }
2318         LIBALIAS_LOCK_ASSERT(la);
2319         if (assoc->TableRegister & SN_LOCAL_TBL) {
2320                 assoc->TableRegister ^= SN_LOCAL_TBL;
2321                 la->sctpLinkCount--; //decrement link count
2322                 LIST_REMOVE(assoc, list_L);
2323         }
2324   
2325         if (assoc->TableRegister & SN_GLOBAL_TBL) {
2326                 assoc->TableRegister ^= SN_GLOBAL_TBL;
2327                 la->sctpLinkCount--; //decrement link count
2328                 LIST_REMOVE(assoc, list_G);
2329         }
2330         //  sn_free(assoc); //Don't remove now, remove if needed later
2331         /* libalias logging -- controlled by libalias log definition */
2332         if (la->packetAliasMode & PKT_ALIAS_LOG)
2333                 SctpShowAliasStats(la);
2334 }
2335
2336 /** 
2337  * @ingroup Hash
2338  * @brief  free the Global Address List memory
2339  * 
2340  * freeGlobalAddressList deletes all global IP addresses in an associations
2341  * global IP address list.
2342  *
2343  * @param assoc 
2344  */
2345 static void freeGlobalAddressList(struct sctp_nat_assoc *assoc)
2346 {
2347         struct sctp_GlobalAddress *gaddr1=NULL,*gaddr2=NULL;
2348         /*free global address list*/
2349         gaddr1 = LIST_FIRST(&(assoc->Gaddr));  
2350         while (gaddr1 != NULL) {
2351                 gaddr2 = LIST_NEXT(gaddr1, list_Gaddr);
2352                 sn_free(gaddr1);
2353                 gaddr1 = gaddr2;
2354         }
2355 }
2356 /* ----------------------------------------------------------------------
2357  *                            TIMER QUEUE CODE
2358  * ----------------------------------------------------------------------
2359  */
2360 /** @addtogroup Timer
2361  *
2362  * The timer queue management functions are designed to operate efficiently with
2363  * a minimum of interaction with the queues.
2364  *
2365  * Once a timeout is set in the queue it will not be altered in the queue unless
2366  * it has to be changed to a shorter time (usually only for aborts and closing).
2367  * On a queue timeout, the real expiry time is checked, and if not leq than the
2368  * timeout it is requeued (O(1)) at its later time. This is especially important
2369  * for normal packets sent during an association. When a timer expires, it is
2370  * updated to its new expiration time if necessary, or processed as a
2371  * timeout. This means that while in UP state, the timing queue is only altered
2372  * every U_T (every few minutes) for a particular association.
2373  */
2374 /** @ingroup Timer
2375  * @brief Add an association timeout to the timer queue
2376  *
2377  * Determine the location in the queue to add the timeout and insert the
2378  * association into the list at that queue position
2379  *
2380  * @param la 
2381  * @param assoc 
2382  */
2383 static void
2384 sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc)
2385 {
2386         int add_loc;
2387         LIBALIAS_LOCK_ASSERT(la);
2388         add_loc = assoc->exp - la->sctpNatTimer.loc_time + la->sctpNatTimer.cur_loc;
2389         if (add_loc >= SN_TIMER_QUEUE_SIZE)
2390                 add_loc -= SN_TIMER_QUEUE_SIZE;
2391         LIST_INSERT_HEAD(&la->sctpNatTimer.TimerQ[add_loc], assoc, timer_Q);
2392         assoc->exp_loc = add_loc;
2393 }
2394
2395 /** @ingroup Timer
2396  * @brief Remove an association from timer queue
2397  *
2398  * This is an O(1) operation to remove the association pointer from its
2399  * current position in the timer queue
2400  *
2401  * @param la Pointer to the relevant libalias instance
2402  * @param assoc pointer to sctp association
2403  */
2404 static void
2405 sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc)
2406 {
2407         LIBALIAS_LOCK_ASSERT(la);
2408         LIST_REMOVE(assoc, timer_Q);/* Note this is O(1) */
2409 }
2410
2411
2412 /** @ingroup Timer
2413  * @brief Reset timer in timer queue
2414  *
2415  * Reset the actual timeout for the specified association. If it is earlier than
2416  * the existing timeout, then remove and re-install the association into the
2417  * queue
2418  *
2419  * @param la Pointer to the relevant libalias instance
2420  * @param assoc pointer to sctp association
2421  * @param newexp New expiration time
2422  */
2423 static void
2424 sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp)
2425 {
2426         if (newexp < assoc->exp) {
2427                 sctp_RmTimeOut(la, assoc);
2428                 assoc->exp = newexp;
2429                 sctp_AddTimeOut(la, assoc);
2430         } else {
2431                 assoc->exp = newexp;
2432         }
2433 }
2434
2435 /** @ingroup Timer
2436  * @brief Check timer Q against current time
2437  * 
2438  * Loop through each entry in the timer queue since the last time we processed
2439  * the timer queue until now (the current time). For each association in the
2440  * event list, we remove it from that position in the timer queue and check if
2441  * it has really expired. If so we:
2442  * - Log the timer expiry
2443  * - Remove the association from the NAT tables
2444  * - Release the memory used by the association
2445  *
2446  * If the timer hasn't really expired we place the association into its new
2447  * correct position in the timer queue.
2448  * 
2449  * @param la  Pointer to the relevant libalias instance
2450  */
2451 void
2452 sctp_CheckTimers(struct libalias *la)
2453 {
2454         struct sctp_nat_assoc *assoc;
2455   
2456         LIBALIAS_LOCK_ASSERT(la);
2457         while(la->timeStamp >= la->sctpNatTimer.loc_time) {
2458                 while (!LIST_EMPTY(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc])) {  
2459                         assoc = LIST_FIRST(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc]);
2460                         //SLIST_REMOVE_HEAD(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc], timer_Q);
2461                         LIST_REMOVE(assoc, timer_Q);
2462                         if (la->timeStamp >= assoc->exp) { /* state expired */
2463                                 SN_LOG(((assoc->state == SN_CL)?(SN_LOG_DEBUG):(SN_LOG_INFO)),
2464                                     logsctperror("Timer Expired", assoc->g_vtag, assoc->state, SN_TO_NODIR));
2465                                 RmSctpAssoc(la, assoc);
2466                                 freeGlobalAddressList(assoc);
2467                                 sn_free(assoc);
2468                         } else {/* state not expired, reschedule timer*/
2469                                 sctp_AddTimeOut(la, assoc);
2470                         }
2471                 }
2472                 /* Goto next location in the timer queue*/
2473                 ++la->sctpNatTimer.loc_time;
2474                 if (++la->sctpNatTimer.cur_loc >= SN_TIMER_QUEUE_SIZE)
2475                         la->sctpNatTimer.cur_loc = 0;
2476         }
2477 }
2478
2479 /* ----------------------------------------------------------------------
2480  *                              LOGGING CODE 
2481  * ----------------------------------------------------------------------
2482  */
2483 /** @addtogroup Logging
2484  *
2485  * The logging functions provide logging of different items ranging from logging
2486  * a simple message, through logging an association details to logging the
2487  * current state of the NAT tables
2488  */
2489 /** @ingroup Logging
2490  * @brief Log sctp nat errors
2491  * 
2492  * @param errormsg Error message to be logged
2493  * @param vtag Current Vtag
2494  * @param error Error number
2495  * @param direction Direction of packet
2496  */
2497 static void
2498 logsctperror(char* errormsg, uint32_t vtag, int error, int direction)
2499 {
2500         char dir;
2501         switch(direction) {
2502         case SN_TO_LOCAL:
2503                 dir = 'L';
2504                 break;
2505         case SN_TO_GLOBAL:
2506                 dir = 'G';
2507                 break;
2508         default:
2509                 dir = '*';
2510                 break;
2511         }
2512         SctpAliasLog("->%c %s (vt=%u) %d\n", dir, errormsg, ntohl(vtag), error);
2513 }
2514
2515 /** @ingroup Logging
2516  * @brief Log what the parser parsed
2517  * 
2518  * @param direction Direction of packet
2519  * @param sm Pointer to sctp message information
2520  */
2521 static void
2522 logsctpparse(int direction, struct sctp_nat_msg *sm)
2523 {
2524         char *ploc, *pstate;
2525         switch(direction) {
2526         case SN_TO_LOCAL:
2527                 ploc = "TO_LOCAL -";
2528                 break;
2529         case SN_TO_GLOBAL:
2530                 ploc = "TO_GLOBAL -";
2531                 break;
2532         default:
2533                 ploc = "";
2534         }
2535         switch(sm->msg) {
2536         case SN_SCTP_INIT:
2537                 pstate = "Init";
2538                 break;
2539         case SN_SCTP_INITACK:
2540                 pstate = "InitAck";
2541                 break;
2542         case SN_SCTP_ABORT:
2543                 pstate = "Abort";
2544                 break;
2545         case SN_SCTP_SHUTACK:
2546                 pstate = "ShutAck";
2547                 break;
2548         case SN_SCTP_SHUTCOMP:
2549                 pstate = "ShutComp";
2550                 break;
2551         case SN_SCTP_ASCONF:
2552                 pstate = "Asconf";
2553                 break;
2554         case SN_SCTP_ASCONFACK:
2555                 pstate = "AsconfAck";
2556                 break;
2557         case SN_SCTP_OTHER:
2558                 pstate = "Other";
2559                 break;
2560         default:
2561                 pstate = "***ERROR***";
2562                 break;
2563         }
2564         SctpAliasLog("Parsed: %s %s\n", ploc, pstate);
2565 }
2566
2567 /** @ingroup Logging
2568  * @brief Log an SCTP association's details
2569  * 
2570  * @param assoc pointer to sctp association
2571  * @param s Character that indicates the state of processing for this packet
2572  */
2573 static void logsctpassoc(struct sctp_nat_assoc *assoc, char* s)
2574 {
2575         struct sctp_GlobalAddress *G_Addr = NULL;
2576         char *sp;
2577         switch(assoc->state) {
2578         case SN_ID:
2579                 sp = "ID ";
2580                 break;
2581         case SN_INi:
2582                 sp = "INi ";
2583                 break;
2584         case SN_INa:
2585                 sp = "INa ";
2586                 break;
2587         case SN_UP:
2588                 sp = "UP ";
2589                 break;
2590         case SN_CL:
2591                 sp = "CL ";
2592                 break;
2593         case SN_RM:
2594                 sp = "RM ";
2595                 break;
2596         default:
2597                 sp = "***ERROR***";
2598                 break;
2599         }
2600         SctpAliasLog("%sAssoc: %s exp=%u la=%s lv=%u lp=%u gv=%u gp=%u tbl=%d\n",
2601             s, sp, assoc->exp, inet_ntoa(assoc->l_addr), ntohl(assoc->l_vtag),
2602             ntohs(assoc->l_port), ntohl(assoc->g_vtag), ntohs(assoc->g_port),
2603             assoc->TableRegister);
2604         /* list global addresses */
2605         LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2606                 SctpAliasLog("\t\tga=%s\n",inet_ntoa(G_Addr->g_addr));
2607         }
2608 }
2609
2610 /** @ingroup Logging
2611  * @brief Output Global table to log 
2612  * 
2613  * @param la Pointer to the relevant libalias instance
2614  */
2615 static void logSctpGlobal(struct libalias *la)
2616 {
2617         u_int i;
2618         struct sctp_nat_assoc *assoc = NULL;
2619   
2620         SctpAliasLog("G->\n");
2621         for (i=0; i < la->sctpNatTableSize; i++) {
2622                 LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2623                         logsctpassoc(assoc, " ");
2624                 }
2625         }
2626 }
2627
2628 /** @ingroup Logging
2629  * @brief  Output Local table to log 
2630  * 
2631  * @param la Pointer to the relevant libalias instance
2632  */
2633 static void logSctpLocal(struct libalias *la)
2634 {
2635         u_int i;
2636         struct sctp_nat_assoc *assoc = NULL;
2637   
2638         SctpAliasLog("L->\n");
2639         for (i=0; i < la->sctpNatTableSize; i++) {
2640                 LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) {
2641                         logsctpassoc(assoc, " ");
2642                 }
2643         }
2644 }
2645
2646 /** @ingroup Logging
2647  * @brief Output timer queue to log
2648  * 
2649  * @param la Pointer to the relevant libalias instance
2650  */
2651 static void logTimerQ(struct libalias *la)
2652 {
2653         static char buf[50];
2654         u_int i;
2655         struct sctp_nat_assoc *assoc = NULL;
2656
2657         SctpAliasLog("t->\n");
2658         for (i=0; i < SN_TIMER_QUEUE_SIZE; i++) {
2659                 LIST_FOREACH(assoc, &la->sctpNatTimer.TimerQ[i], timer_Q) {
2660                         snprintf(buf, 50, " l=%u ",i);
2661                         //SctpAliasLog(la->logDesc," l=%d ",i);
2662                         logsctpassoc(assoc, buf);
2663                 }
2664         }
2665 }
2666
2667 /** @ingroup Logging 
2668  * @brief Sctp NAT logging function
2669  * 
2670  * This function is based on a similar function in alias_db.c
2671  *
2672  * @param str/stream logging descriptor  
2673  * @param format printf type string
2674  */
2675 #ifdef _KERNEL
2676 static void
2677 SctpAliasLog(const char *format, ...)
2678 {
2679         char buffer[LIBALIAS_BUF_SIZE];
2680         va_list ap;
2681         va_start(ap, format);
2682         vsnprintf(buffer, LIBALIAS_BUF_SIZE, format, ap);
2683         va_end(ap);
2684         log(LOG_SECURITY | LOG_INFO,
2685             "alias_sctp: %s", buffer);
2686 }
2687 #else
2688 static void
2689 SctpAliasLog(FILE *stream, const char *format, ...)
2690 {
2691         va_list ap;
2692
2693         va_start(ap, format);
2694         vfprintf(stream, format, ap);
2695         va_end(ap);
2696         fflush(stream);
2697 }
2698 #endif