xref: /freebsd/sys/netinet/libalias/alias_sctp.c (revision 13464e4a44fc58490a03bb8bfc7e3c972e9c30b2)
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 	char addrbuf[INET_ADDRSTRLEN];
908 
909 	if (ntohs(sm->ip_hdr->ip_len) < ip_size) { /* short packet, cannot send error cause */
910 		include_error_cause = 0;
911 		ip_size = ip_size -  sizeof(struct sctp_error_cause);
912 		sctp_size = sctp_size -  sizeof(struct sctp_error_cause);
913 	}
914 	/* Assign header pointers packet */
915 	struct ip* ip = (struct ip *) tmp_ip;
916 	struct sctphdr* sctp_hdr = (struct sctphdr *) ((char *) ip + sizeof(*ip));
917 	struct sctp_chunkhdr* chunk_hdr = (struct sctp_chunkhdr *) ((char *) sctp_hdr + sizeof(*sctp_hdr));
918 	struct sctp_error_cause* error_cause = (struct sctp_error_cause *) ((char *) chunk_hdr + sizeof(*chunk_hdr));
919 
920 	/* construct ip header */
921 	ip->ip_v = sm->ip_hdr->ip_v;
922 	ip->ip_hl = 5; /* 5*32 bit words */
923 	ip->ip_tos = 0;
924 	ip->ip_len = htons(ip_size);
925 	ip->ip_id =  sm->ip_hdr->ip_id;
926 	ip->ip_off = 0;
927 	ip->ip_ttl = 255;
928 	ip->ip_p = IPPROTO_SCTP;
929 	/*
930 	  The definitions below should be removed when they make it into the SCTP stack
931 	*/
932 #define SCTP_MIDDLEBOX_FLAG 0x02
933 #define SCTP_NAT_TABLE_COLLISION 0x00b0
934 #define SCTP_MISSING_NAT 0x00b1
935 	chunk_hdr->chunk_type = (sndrply & SN_TX_ABORT) ? SCTP_ABORT_ASSOCIATION : SCTP_OPERATION_ERROR;
936 	chunk_hdr->chunk_flags = SCTP_MIDDLEBOX_FLAG;
937 	if (include_error_cause) {
938 		error_cause->code = htons((sndrply & SN_REFLECT_ERROR) ? SCTP_MISSING_NAT :  SCTP_NAT_TABLE_COLLISION);
939 		error_cause->length = htons(sizeof(struct sctp_error_cause));
940 		chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr) + sizeof(struct sctp_error_cause));
941 	} else {
942 		chunk_hdr->chunk_length = htons(sizeof(*chunk_hdr));
943 	}
944 
945 	/* set specific values */
946 	switch(sndrply) {
947 	case SN_REFLECT_ERROR:
948 		chunk_hdr->chunk_flags |= SCTP_HAD_NO_TCB; /* set Tbit */
949 		sctp_hdr->v_tag =  sm->sctp_hdr->v_tag;
950 		break;
951 	case SN_REPLY_ERROR:
952 		sctp_hdr->v_tag = (direction == SN_TO_LOCAL) ? assoc->g_vtag :  assoc->l_vtag ;
953 		break;
954 	case SN_SEND_ABORT:
955 		sctp_hdr->v_tag =  sm->sctp_hdr->v_tag;
956 		break;
957 	case SN_REPLY_ABORT:
958 		sctp_hdr->v_tag = sm->sctpchnk.Init->initiate_tag;
959 		break;
960 	}
961 
962 	/* Set send/reply values */
963 	if (sndrply == SN_SEND_ABORT) { /*pass through NAT */
964 		ip->ip_src = (direction == SN_TO_LOCAL) ? sm->ip_hdr->ip_src : assoc->a_addr;
965 		ip->ip_dst = (direction == SN_TO_LOCAL) ? assoc->l_addr : sm->ip_hdr->ip_dst;
966 		sctp_hdr->src_port = sm->sctp_hdr->src_port;
967 		sctp_hdr->dest_port = sm->sctp_hdr->dest_port;
968 	} else { /* reply and reflect */
969 		ip->ip_src = sm->ip_hdr->ip_dst;
970 		ip->ip_dst = sm->ip_hdr->ip_src;
971 		sctp_hdr->src_port = sm->sctp_hdr->dest_port;
972 		sctp_hdr->dest_port = sm->sctp_hdr->src_port;
973 	}
974 
975 	/* Calculate IP header checksum */
976 	ip->ip_sum = in_cksum_hdr(ip);
977 
978 	/* calculate SCTP header CRC32 */
979 	sctp_hdr->checksum = 0;
980 	sctp_hdr->checksum = local_sctp_finalize_crc32(calculate_crc32c(0xffffffff, (unsigned char *) sctp_hdr, sctp_size));
981 
982 	memcpy(sm->ip_hdr, ip, ip_size);
983 
984 	SN_LOG(SN_LOG_EVENT,SctpAliasLog("%s %s 0x%x (->%s:%u vtag=0x%x crc=0x%x)\n",
985 		((sndrply == SN_SEND_ABORT) ? "Sending" : "Replying"),
986 		((sndrply & SN_TX_ERROR) ? "ErrorM" : "AbortM"),
987 		(include_error_cause ? ntohs(error_cause->code) : 0),
988 		inet_ntoa_r(ip->ip_dst, INET_NTOA_BUF(addrbuf)),
989 		ntohs(sctp_hdr->dest_port),
990 		ntohl(sctp_hdr->v_tag), ntohl(sctp_hdr->checksum)));
991 }
992 
993 /* ----------------------------------------------------------------------
994  *                           PACKET PARSER CODE
995  * ----------------------------------------------------------------------
996  */
997 /** @addtogroup packet_parser
998  *
999  * These functions parse the SCTP packet and fill a sctp_nat_msg structure
1000  * with the parsed contents.
1001  */
1002 /** @ingroup packet_parser
1003  * @brief Parses SCTP packets for the key SCTP chunk that will be processed
1004  *
1005  * This module parses SCTP packets for the key SCTP chunk that will be processed
1006  * The module completes the sctp_nat_msg structure and either retrieves the
1007  * relevant (existing) stored association from the Hash Tables or creates a new
1008  * association entity with state SN_ID
1009  *
1010  * @param la Pointer to the relevant libalias instance
1011  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1012  * @param pip
1013  * @param sm Pointer to sctp message information
1014  * @param passoc Pointer to the association this SCTP Message belongs to
1015  *
1016  * @return SN_PARSE_OK | SN_PARSE_ERROR_*
1017  */
1018 static int
1019 sctp_PktParser(struct libalias *la, int direction, struct ip *pip,
1020     struct sctp_nat_msg *sm, struct sctp_nat_assoc **passoc)
1021 //sctp_PktParser(int direction, struct mbuf *ipak, int ip_hdr_len,struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc)
1022 {
1023 	struct sctphdr *sctp_hdr;
1024 	struct sctp_chunkhdr *chunk_hdr;
1025 	struct sctp_paramhdr *param_hdr;
1026 	struct in_addr ipv4addr;
1027 	int bytes_left; /* bytes left in ip packet */
1028 	int chunk_length;
1029 	int chunk_count;
1030 	int partial_match = 0;
1031 	//  mbuf *mp;
1032 	//  int mlen;
1033 
1034 	//  mlen = SCTP_HEADER_LEN(i_pak);
1035 	//  mp = SCTP_HEADER_TO_CHAIN(i_pak); /* does nothing in bsd since header and chain not separate */
1036 
1037 	/*
1038 	 * Note, that if the VTag is zero, it must be an INIT
1039 	 * Also, I am only interested in the content of INIT and ADDIP chunks
1040 	 */
1041 
1042 	// no mbuf stuff from Paolo yet so ...
1043 	sm->ip_hdr = pip;
1044 	/* remove ip header length from the bytes_left */
1045 	bytes_left = ntohs(pip->ip_len) - (pip->ip_hl << 2);
1046 
1047 	/* Check SCTP header length and move to first chunk */
1048 	if (bytes_left < sizeof(struct sctphdr)) {
1049 		sm->sctp_hdr = NULL;
1050 		return(SN_PARSE_ERROR_IPSHL); /* packet not long enough*/
1051 	}
1052 
1053 	sm->sctp_hdr = sctp_hdr = (struct sctphdr *) ip_next(pip);
1054 	bytes_left -= sizeof(struct sctphdr);
1055 
1056 	/* Check for valid ports (zero valued ports would find partially initialised associations */
1057 	if (sctp_hdr->src_port == 0 || sctp_hdr->dest_port == 0)
1058 		return(SN_PARSE_ERROR_PORT);
1059 
1060 	/* Check length of first chunk */
1061 	if (bytes_left < SN_MIN_CHUNK_SIZE) /* malformed chunk - could cause endless loop*/
1062 		return(SN_PARSE_ERROR_CHHL); /* packet not long enough for this chunk */
1063 
1064 	/* First chunk */
1065 	chunk_hdr = SN_SCTP_FIRSTCHUNK(sctp_hdr);
1066 
1067 	chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length));
1068 	if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left)) /* malformed chunk - could cause endless loop*/
1069 		return(SN_PARSE_ERROR_CHHL);
1070 
1071 	if ((chunk_hdr->chunk_flags & SCTP_HAD_NO_TCB) &&
1072 	    ((chunk_hdr->chunk_type == SCTP_ABORT_ASSOCIATION) ||
1073 		(chunk_hdr->chunk_type == SCTP_SHUTDOWN_COMPLETE))) {
1074 		/* T-Bit set */
1075 		if (direction == SN_TO_LOCAL)
1076 			*passoc = FindSctpGlobalT(la,  pip->ip_src, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port);
1077 		else
1078 			*passoc = FindSctpLocalT(la, pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->dest_port, sctp_hdr->src_port);
1079 	} else {
1080 		/* Proper v_tag settings */
1081 		if (direction == SN_TO_LOCAL)
1082 			*passoc = FindSctpGlobal(la, pip->ip_src, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match);
1083 		else
1084 			*passoc = FindSctpLocal(la, pip->ip_src,  pip->ip_dst, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port);
1085 	}
1086 
1087 	chunk_count = 1;
1088 	/* Real packet parsing occurs below */
1089 	sm->msg = SN_SCTP_OTHER;/* Initialise to largest value*/
1090 	sm->chunk_length = 0; /* only care about length for key chunks */
1091 	while (IS_SCTP_CONTROL(chunk_hdr)) {
1092 		switch(chunk_hdr->chunk_type) {
1093 		case SCTP_INITIATION:
1094 			if (chunk_length < sizeof(struct sctp_init_chunk)) /* malformed chunk*/
1095 				return(SN_PARSE_ERROR_CHHL);
1096 			sm->msg = SN_SCTP_INIT;
1097 			sm->sctpchnk.Init = (struct sctp_init *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr));
1098 			sm->chunk_length = chunk_length;
1099 			/* if no existing association, create a new one */
1100 			if (*passoc == NULL) {
1101 				if (sctp_hdr->v_tag == 0){ //Init requires vtag=0
1102 					*passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc));
1103 					if (*passoc == NULL) {/* out of resources */
1104 						return(SN_PARSE_ERROR_AS_MALLOC);
1105 					}
1106 					/* Initialise association - malloc initialises memory to zeros */
1107 					(*passoc)->state = SN_ID;
1108 					LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */
1109 					(*passoc)->TableRegister = SN_NULL_TBL;
1110 					return(SN_PARSE_OK);
1111 				}
1112 				return(SN_PARSE_ERROR_VTAG);
1113 			}
1114 			return(SN_PARSE_ERROR_LOOKUP);
1115 		case SCTP_INITIATION_ACK:
1116 			if (chunk_length < sizeof(struct sctp_init_ack_chunk)) /* malformed chunk*/
1117 				return(SN_PARSE_ERROR_CHHL);
1118 			sm->msg = SN_SCTP_INITACK;
1119 			sm->sctpchnk.InitAck = (struct sctp_init_ack *) ((char *) chunk_hdr + sizeof(struct sctp_chunkhdr));
1120 			sm->chunk_length = chunk_length;
1121 			return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK));
1122 		case SCTP_ABORT_ASSOCIATION: /* access only minimum sized chunk */
1123 			sm->msg = SN_SCTP_ABORT;
1124 			sm->chunk_length = chunk_length;
1125 			return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP_ABORT):(SN_PARSE_OK));
1126 		case SCTP_SHUTDOWN_ACK:
1127 			if (chunk_length < sizeof(struct sctp_shutdown_ack_chunk)) /* malformed chunk*/
1128 				return(SN_PARSE_ERROR_CHHL);
1129 			if (sm->msg > SN_SCTP_SHUTACK) {
1130 				sm->msg = SN_SCTP_SHUTACK;
1131 				sm->chunk_length = chunk_length;
1132 			}
1133 			break;
1134 		case SCTP_SHUTDOWN_COMPLETE:  /* minimum sized chunk */
1135 			if (sm->msg > SN_SCTP_SHUTCOMP) {
1136 				sm->msg = SN_SCTP_SHUTCOMP;
1137 				sm->chunk_length = chunk_length;
1138 			}
1139 			return ((*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK));
1140 		case SCTP_ASCONF:
1141 			if (sm->msg > SN_SCTP_ASCONF) {
1142 				if (chunk_length < (sizeof(struct  sctp_asconf_chunk) + sizeof(struct  sctp_ipv4addr_param))) /* malformed chunk*/
1143 					return(SN_PARSE_ERROR_CHHL);
1144 				//leave parameter searching to later, if required
1145 				param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr + sizeof(struct sctp_asconf_chunk)); /*compulsory IP parameter*/
1146 				if (ntohs(param_hdr->param_type) == SCTP_IPV4_ADDRESS) {
1147 					if ((*passoc == NULL) && (direction == SN_TO_LOCAL)) { /* AddIP with no association */
1148 						/* try look up with the ASCONF packet's alternative address */
1149 						ipv4addr.s_addr = ((struct sctp_ipv4addr_param *) param_hdr)->addr;
1150 						*passoc = FindSctpGlobal(la, ipv4addr, sctp_hdr->v_tag, sctp_hdr->src_port, sctp_hdr->dest_port, &partial_match);
1151 					}
1152 					param_hdr = (struct sctp_paramhdr *)
1153 						((char *) param_hdr + sizeof(struct sctp_ipv4addr_param)); /*asconf's compulsory address parameter */
1154 					sm->chunk_length = chunk_length - sizeof(struct  sctp_asconf_chunk) - sizeof(struct  sctp_ipv4addr_param); /* rest of chunk */
1155 				} else {
1156 					if (chunk_length < (sizeof(struct  sctp_asconf_chunk) + sizeof(struct  sctp_ipv6addr_param))) /* malformed chunk*/
1157 						return(SN_PARSE_ERROR_CHHL);
1158 					param_hdr = (struct sctp_paramhdr *)
1159 						((char *) param_hdr + sizeof(struct sctp_ipv6addr_param)); /*asconf's compulsory address parameter */
1160 					sm->chunk_length = chunk_length - sizeof(struct  sctp_asconf_chunk) - sizeof(struct  sctp_ipv6addr_param); /* rest of chunk */
1161 				}
1162 				sm->msg = SN_SCTP_ASCONF;
1163 				sm->sctpchnk.Asconf = param_hdr;
1164 
1165 				if (*passoc == NULL) { /* AddIP with no association */
1166 					*passoc = (struct sctp_nat_assoc *) sn_malloc(sizeof(struct sctp_nat_assoc));
1167 					if (*passoc == NULL) {/* out of resources */
1168 						return(SN_PARSE_ERROR_AS_MALLOC);
1169 					}
1170 					/* Initialise association  - malloc initialises memory to zeros */
1171 					(*passoc)->state = SN_ID;
1172 					LIST_INIT(&((*passoc)->Gaddr)); /* always initialise to avoid memory problems */
1173 					(*passoc)->TableRegister = SN_NULL_TBL;
1174 					return(SN_PARSE_OK);
1175 				}
1176 			}
1177 			break;
1178 		case SCTP_ASCONF_ACK:
1179 			if (sm->msg > SN_SCTP_ASCONFACK) {
1180 				if (chunk_length < sizeof(struct  sctp_asconf_ack_chunk)) /* malformed chunk*/
1181 					return(SN_PARSE_ERROR_CHHL);
1182 				//leave parameter searching to later, if required
1183 				param_hdr = (struct sctp_paramhdr *) ((char *) chunk_hdr
1184 				    + sizeof(struct sctp_asconf_ack_chunk));
1185 				sm->msg = SN_SCTP_ASCONFACK;
1186 				sm->sctpchnk.Asconf = param_hdr;
1187 				sm->chunk_length = chunk_length - sizeof(struct sctp_asconf_ack_chunk);
1188 			}
1189 			break;
1190 		default:
1191 			break; /* do nothing*/
1192 		}
1193 
1194 		/* if no association is found exit - we need to find an Init or AddIP within sysctl_initialising_chunk_proc_limit */
1195 		if ((*passoc == NULL) && (chunk_count >= sysctl_initialising_chunk_proc_limit))
1196 			return(SN_PARSE_ERROR_LOOKUP);
1197 
1198 		/* finished with this chunk, on to the next chunk*/
1199 		bytes_left-= chunk_length;
1200 
1201 		/* Is this the end of the packet ? */
1202 		if (bytes_left == 0)
1203 			return (*passoc == NULL)?(SN_PARSE_ERROR_LOOKUP):(SN_PARSE_OK);
1204 
1205 		/* Are there enough bytes in packet to at least retrieve length of next chunk ? */
1206 		if (bytes_left < SN_MIN_CHUNK_SIZE)
1207 			return(SN_PARSE_ERROR_CHHL);
1208 
1209 		chunk_hdr = SN_SCTP_NEXTCHUNK(chunk_hdr);
1210 
1211 		/* Is the chunk long enough to not cause endless look and are there enough bytes in packet to read the chunk ? */
1212 		chunk_length = SCTP_SIZE32(ntohs(chunk_hdr->chunk_length));
1213 		if ((chunk_length < SN_MIN_CHUNK_SIZE) || (chunk_length > bytes_left))
1214 			return(SN_PARSE_ERROR_CHHL);
1215 		if(++chunk_count > sysctl_chunk_proc_limit)
1216 			return(SN_PARSE_OK); /* limit for processing chunks, take what we get */
1217 	}
1218 
1219 	if (*passoc == NULL)
1220 		return (partial_match)?(SN_PARSE_ERROR_PARTIALLOOKUP):(SN_PARSE_ERROR_LOOKUP);
1221 	else
1222 		return(SN_PARSE_OK);
1223 }
1224 
1225 /** @ingroup packet_parser
1226  * @brief Extract Vtags from Asconf Chunk
1227  *
1228  * GetAsconfVtags scans an Asconf Chunk for the vtags parameter, and then
1229  * extracts the vtags.
1230  *
1231  * GetAsconfVtags is not called from within sctp_PktParser. It is called only
1232  * from within ID_process when an AddIP has been received.
1233  *
1234  * @param la Pointer to the relevant libalias instance
1235  * @param sm Pointer to sctp message information
1236  * @param l_vtag Pointer to the local vtag in the association this SCTP Message belongs to
1237  * @param g_vtag Pointer to the local vtag in the association this SCTP Message belongs to
1238  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1239  *
1240  * @return 1 - success | 0 - fail
1241  */
1242 static int
1243 GetAsconfVtags(struct libalias *la, struct sctp_nat_msg *sm, uint32_t *l_vtag, uint32_t *g_vtag, int direction)
1244 {
1245 	/* To be removed when information is in the sctp headers */
1246 #define SCTP_VTAG_PARAM 0xC007
1247 	struct sctp_vtag_param {
1248 		struct sctp_paramhdr ph;/* type=SCTP_VTAG_PARAM */
1249 		uint32_t local_vtag;
1250 		uint32_t remote_vtag;
1251 	}                    __attribute__((packed));
1252 
1253 	struct sctp_vtag_param *vtag_param;
1254 	struct sctp_paramhdr *param;
1255 	int bytes_left;
1256 	int param_size;
1257 	int param_count;
1258 
1259 	param_count = 1;
1260 	param = sm->sctpchnk.Asconf;
1261 	param_size = SCTP_SIZE32(ntohs(param->param_length));
1262 	bytes_left = sm->chunk_length;
1263 	/* step through Asconf parameters */
1264 	while((bytes_left >= param_size) && (bytes_left >= SN_VTAG_PARAM_SIZE)) {
1265 		if (ntohs(param->param_type) == SCTP_VTAG_PARAM) {
1266 			vtag_param = (struct sctp_vtag_param *) param;
1267 			switch(direction) {
1268 				/* The Internet draft is a little ambigious as to order of these vtags.
1269 				   We think it is this way around. If we are wrong, the order will need
1270 				   to be changed. */
1271 			case SN_TO_GLOBAL:
1272 				*g_vtag = vtag_param->local_vtag;
1273 				*l_vtag = vtag_param->remote_vtag;
1274 				break;
1275 			case SN_TO_LOCAL:
1276 				*g_vtag = vtag_param->remote_vtag;
1277 				*l_vtag = vtag_param->local_vtag;
1278 				break;
1279 			}
1280 			return(1); /* found */
1281 		}
1282 
1283 		bytes_left -= param_size;
1284 		if (bytes_left < SN_MIN_PARAM_SIZE) return(0);
1285 
1286 		param = SN_SCTP_NEXTPARAM(param);
1287 		param_size = SCTP_SIZE32(ntohs(param->param_length));
1288 		if (++param_count > sysctl_param_proc_limit) {
1289 			SN_LOG(SN_LOG_EVENT,
1290 			    logsctperror("Parameter parse limit exceeded (GetAsconfVtags)",
1291 				sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1292 			return(0); /* not found limit exceeded*/
1293 		}
1294 	}
1295 	return(0); /* not found */
1296 }
1297 
1298 /** @ingroup packet_parser
1299  * @brief AddGlobalIPAddresses from Init,InitAck,or AddIP packets
1300  *
1301  * AddGlobalIPAddresses scans an SCTP chunk (in sm) for Global IP addresses, and
1302  * adds them.
1303  *
1304  * @param sm Pointer to sctp message information
1305  * @param assoc Pointer to the association this SCTP Message belongs to
1306  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1307  *
1308  */
1309 static void
1310 AddGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction)
1311 {
1312 	struct sctp_ipv4addr_param *ipv4_param;
1313 	struct sctp_paramhdr *param = NULL;
1314 	struct sctp_GlobalAddress *G_Addr;
1315 	struct in_addr g_addr = {0};
1316 	int bytes_left = 0;
1317 	int param_size;
1318 	int param_count, addr_param_count = 0;
1319 
1320 	switch(direction) {
1321 	case SN_TO_GLOBAL: /* does not contain global addresses */
1322 		g_addr = sm->ip_hdr->ip_dst;
1323 		bytes_left = 0; /* force exit */
1324 		break;
1325 	case SN_TO_LOCAL:
1326 		g_addr = sm->ip_hdr->ip_src;
1327 		param_count = 1;
1328 		switch(sm->msg) {
1329 		case SN_SCTP_INIT:
1330 			bytes_left = sm->chunk_length - sizeof(struct sctp_init_chunk);
1331 			param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.Init + sizeof(struct sctp_init));
1332 			break;
1333 		case SN_SCTP_INITACK:
1334 			bytes_left = sm->chunk_length - sizeof(struct sctp_init_ack_chunk);
1335 			param = (struct sctp_paramhdr *)((char *)sm->sctpchnk.InitAck + sizeof(struct sctp_init_ack));
1336 			break;
1337 		case SN_SCTP_ASCONF:
1338 			bytes_left = sm->chunk_length;
1339 			param = sm->sctpchnk.Asconf;
1340 			break;
1341 		}
1342 	}
1343 	if (bytes_left >= SN_MIN_PARAM_SIZE)
1344 		param_size = SCTP_SIZE32(ntohs(param->param_length));
1345 	else
1346 		param_size = bytes_left+1; /* force skip loop */
1347 
1348 	if ((assoc->state == SN_ID) && ((sm->msg == SN_SCTP_INIT) || (bytes_left < SN_MIN_PARAM_SIZE))) {/* add pkt address */
1349 		G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress));
1350 		if (G_Addr == NULL) {/* out of resources */
1351 			SN_LOG(SN_LOG_EVENT,
1352 			    logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking",
1353 				sm->sctp_hdr->v_tag,  0, direction));
1354 			assoc->num_Gaddr = 0; /* don't track any more for this assoc*/
1355 			sysctl_track_global_addresses=0;
1356 			return;
1357 		}
1358 		G_Addr->g_addr = g_addr;
1359 		if (!Add_Global_Address_to_List(assoc, G_Addr))
1360 			SN_LOG(SN_LOG_EVENT,
1361 			    logsctperror("AddGlobalIPAddress: Address already in list",
1362 				sm->sctp_hdr->v_tag,  assoc->num_Gaddr, direction));
1363 	}
1364 
1365 	/* step through parameters */
1366 	while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) {
1367 		if (assoc->num_Gaddr >= sysctl_track_global_addresses) {
1368 			SN_LOG(SN_LOG_EVENT,
1369 			    logsctperror("AddGlobalIPAddress: Maximum Number of addresses reached",
1370 				sm->sctp_hdr->v_tag,  sysctl_track_global_addresses, direction));
1371 			return;
1372 		}
1373 		switch(ntohs(param->param_type)) {
1374 		case SCTP_ADD_IP_ADDRESS:
1375 			/* skip to address parameter - leave param_size so bytes left will be calculated properly*/
1376 			param = (struct sctp_paramhdr *) &((struct sctp_asconf_addrv4_param *) param)->addrp;
1377 		case SCTP_IPV4_ADDRESS:
1378 			ipv4_param = (struct sctp_ipv4addr_param *) param;
1379 			/* add addresses to association */
1380 			G_Addr = (struct sctp_GlobalAddress *) sn_malloc(sizeof(struct sctp_GlobalAddress));
1381 			if (G_Addr == NULL) {/* out of resources */
1382 				SN_LOG(SN_LOG_EVENT,
1383 				    logsctperror("AddGlobalIPAddress: No resources for adding global address - revert to no tracking",
1384 					sm->sctp_hdr->v_tag,  0, direction));
1385 				assoc->num_Gaddr = 0; /* don't track any more for this assoc*/
1386 				sysctl_track_global_addresses=0;
1387 				return;
1388 			}
1389 			/* add address */
1390 			addr_param_count++;
1391 			if ((sm->msg == SN_SCTP_ASCONF) && (ipv4_param->addr == INADDR_ANY)) { /* use packet address */
1392 				G_Addr->g_addr = g_addr;
1393 				if (!Add_Global_Address_to_List(assoc, G_Addr))
1394 					SN_LOG(SN_LOG_EVENT,
1395 					    logsctperror("AddGlobalIPAddress: Address already in list",
1396 						sm->sctp_hdr->v_tag,  assoc->num_Gaddr, direction));
1397 				return; /*shouldn't be any other addresses if the zero address is given*/
1398 			} else {
1399 				G_Addr->g_addr.s_addr = ipv4_param->addr;
1400 				if (!Add_Global_Address_to_List(assoc, G_Addr))
1401 					SN_LOG(SN_LOG_EVENT,
1402 					    logsctperror("AddGlobalIPAddress: Address already in list",
1403 						sm->sctp_hdr->v_tag,  assoc->num_Gaddr, direction));
1404 			}
1405 		}
1406 
1407 		bytes_left -= param_size;
1408 		if (bytes_left < SN_MIN_PARAM_SIZE)
1409 			break;
1410 
1411 		param = SN_SCTP_NEXTPARAM(param);
1412 		param_size = SCTP_SIZE32(ntohs(param->param_length));
1413 		if (++param_count > sysctl_param_proc_limit) {
1414 			SN_LOG(SN_LOG_EVENT,
1415 			    logsctperror("Parameter parse limit exceeded (AddGlobalIPAddress)",
1416 				sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1417 			break; /* limit exceeded*/
1418 		}
1419 	}
1420 	if (addr_param_count == 0) {
1421 		SN_LOG(SN_LOG_DETAIL,
1422 		    logsctperror("AddGlobalIPAddress: no address parameters to add",
1423 			sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction));
1424 	}
1425 }
1426 
1427 /**
1428  * @brief Add_Global_Address_to_List
1429  *
1430  * Adds a global IP address to an associations address list, if it is not
1431  * already there.  The first address added us usually the packet's address, and
1432  * is most likely to be used, so it is added at the beginning. Subsequent
1433  * addresses are added after this one.
1434  *
1435  * @param assoc Pointer to the association this SCTP Message belongs to
1436  * @param G_addr Pointer to the global address to add
1437  *
1438  * @return 1 - success | 0 - fail
1439  */
1440 static int  Add_Global_Address_to_List(struct sctp_nat_assoc *assoc,  struct sctp_GlobalAddress *G_addr)
1441 {
1442 	struct sctp_GlobalAddress *iter_G_Addr = NULL, *first_G_Addr = NULL;
1443 	first_G_Addr = LIST_FIRST(&(assoc->Gaddr));
1444 	if (first_G_Addr == NULL) {
1445 		LIST_INSERT_HEAD(&(assoc->Gaddr), G_addr, list_Gaddr); /* add new address to beginning of list*/
1446 	} else {
1447 		LIST_FOREACH(iter_G_Addr, &(assoc->Gaddr), list_Gaddr) {
1448 			if (G_addr->g_addr.s_addr == iter_G_Addr->g_addr.s_addr)
1449 				return(0); /* already exists, so don't add */
1450 		}
1451 		LIST_INSERT_AFTER(first_G_Addr, G_addr, list_Gaddr); /* add address to end of list*/
1452 	}
1453 	assoc->num_Gaddr++;
1454 	return(1); /* success */
1455 }
1456 
1457 /** @ingroup packet_parser
1458  * @brief RmGlobalIPAddresses from DelIP packets
1459  *
1460  * RmGlobalIPAddresses scans an ASCONF chunk for DelIP parameters to remove the
1461  * given Global IP addresses from the association. It will not delete the
1462  * the address if it is a list of one address.
1463  *
1464  *
1465  * @param sm Pointer to sctp message information
1466  * @param assoc Pointer to the association this SCTP Message belongs to
1467  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1468  *
1469  */
1470 static void
1471 RmGlobalIPAddresses(struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc, int direction)
1472 {
1473 	struct sctp_asconf_addrv4_param *asconf_ipv4_param;
1474 	struct sctp_paramhdr *param;
1475 	struct sctp_GlobalAddress *G_Addr, *G_Addr_tmp;
1476 	struct in_addr g_addr;
1477 	int bytes_left;
1478 	int param_size;
1479 	int param_count;
1480 
1481 	if(direction == SN_TO_GLOBAL)
1482 		g_addr = sm->ip_hdr->ip_dst;
1483 	else
1484 		g_addr = sm->ip_hdr->ip_src;
1485 
1486 	bytes_left = sm->chunk_length;
1487 	param_count = 1;
1488 	param = sm->sctpchnk.Asconf;
1489 	if (bytes_left >= SN_MIN_PARAM_SIZE) {
1490 		param_size = SCTP_SIZE32(ntohs(param->param_length));
1491 	} else {
1492 		SN_LOG(SN_LOG_EVENT,
1493 		    logsctperror("RmGlobalIPAddress: truncated packet - cannot remove IP addresses",
1494 			sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction));
1495 		return;
1496 	}
1497 
1498 	/* step through Asconf parameters */
1499 	while((bytes_left >= param_size) && (bytes_left >= sizeof(struct sctp_ipv4addr_param))) {
1500 		if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS) {
1501 			asconf_ipv4_param = (struct sctp_asconf_addrv4_param *) param;
1502 			if (asconf_ipv4_param->addrp.addr == INADDR_ANY) { /* remove all bar pkt address */
1503 				LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) {
1504 					if(G_Addr->g_addr.s_addr != sm->ip_hdr->ip_src.s_addr) {
1505 						if (assoc->num_Gaddr > 1) { /* only delete if more than one */
1506 							LIST_REMOVE(G_Addr, list_Gaddr);
1507 							sn_free(G_Addr);
1508 							assoc->num_Gaddr--;
1509 						} else {
1510 							SN_LOG(SN_LOG_EVENT,
1511 							    logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)",
1512 								sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction));
1513 						}
1514 					}
1515 				}
1516 				return; /*shouldn't be any other addresses if the zero address is given*/
1517 			} else {
1518 				LIST_FOREACH_SAFE(G_Addr, &(assoc->Gaddr), list_Gaddr, G_Addr_tmp) {
1519 					if(G_Addr->g_addr.s_addr == asconf_ipv4_param->addrp.addr) {
1520 						if (assoc->num_Gaddr > 1) { /* only delete if more than one */
1521 							LIST_REMOVE(G_Addr, list_Gaddr);
1522 							sn_free(G_Addr);
1523 							assoc->num_Gaddr--;
1524 							break; /* Since add only adds new addresses, there should be no double entries */
1525 						} else {
1526 							SN_LOG(SN_LOG_EVENT,
1527 							    logsctperror("RmGlobalIPAddress: Request to remove last IP address (didn't)",
1528 								sm->sctp_hdr->v_tag, assoc->num_Gaddr, direction));
1529 						}
1530 					}
1531 				}
1532 			}
1533 		}
1534 		bytes_left -= param_size;
1535 		if (bytes_left == 0) return;
1536 		else if (bytes_left < SN_MIN_PARAM_SIZE) {
1537 			SN_LOG(SN_LOG_EVENT,
1538 			    logsctperror("RmGlobalIPAddress: truncated packet - may not have removed all IP addresses",
1539 				sm->sctp_hdr->v_tag, sysctl_track_global_addresses, direction));
1540 			return;
1541 		}
1542 
1543 		param = SN_SCTP_NEXTPARAM(param);
1544 		param_size = SCTP_SIZE32(ntohs(param->param_length));
1545 		if (++param_count > sysctl_param_proc_limit) {
1546 			SN_LOG(SN_LOG_EVENT,
1547 			    logsctperror("Parameter parse limit exceeded (RmGlobalIPAddress)",
1548 				sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1549 			return; /* limit exceeded*/
1550 		}
1551 	}
1552 }
1553 
1554 /**  @ingroup packet_parser
1555  * @brief Check that ASCONF was successful
1556  *
1557  * Each ASCONF configuration parameter carries a correlation ID which should be
1558  * matched with an ASCONFack. This is difficult for a NAT, since every
1559  * association could potentially have a number of outstanding ASCONF
1560  * configuration parameters, which should only be activated on receipt of the
1561  * ACK.
1562  *
1563  * Currently we only look for an ACK when the NAT is setting up a new
1564  * association (ie AddIP for a connection that the NAT does not know about
1565  * because the original Init went through a public interface or another NAT)
1566  * Since there is currently no connection on this path, there should be no other
1567  * ASCONF configuration parameters outstanding, so we presume that if there is
1568  * an ACK that it is responding to the AddIP and activate the new association.
1569  *
1570  * @param la Pointer to the relevant libalias instance
1571  * @param sm Pointer to sctp message information
1572  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1573  *
1574  * @return 1 - success | 0 - fail
1575  */
1576 static int
1577 IsASCONFack(struct libalias *la, struct sctp_nat_msg *sm, int direction)
1578 {
1579 	struct sctp_paramhdr *param;
1580 	int bytes_left;
1581 	int param_size;
1582 	int param_count;
1583 
1584 	param_count = 1;
1585 	param = sm->sctpchnk.Asconf;
1586 	param_size = SCTP_SIZE32(ntohs(param->param_length));
1587 	if (param_size == 8)
1588 		return(1); /*success - default acknowledgement of everything */
1589 
1590 	bytes_left = sm->chunk_length;
1591 	if (bytes_left < param_size)
1592 		return(0); /* not found */
1593 	/* step through Asconf parameters */
1594 	while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) {
1595 		if (ntohs(param->param_type) == SCTP_SUCCESS_REPORT)
1596 			return(1); /* success - but can't match correlation IDs - should only be one */
1597 		/* check others just in case */
1598 		bytes_left -= param_size;
1599 		if (bytes_left >= SN_MIN_PARAM_SIZE) {
1600 			param = SN_SCTP_NEXTPARAM(param);
1601 		} else {
1602 			return(0);
1603 		}
1604 		param_size = SCTP_SIZE32(ntohs(param->param_length));
1605 		if (bytes_left < param_size) return(0);
1606 
1607 		if (++param_count > sysctl_param_proc_limit) {
1608 			SN_LOG(SN_LOG_EVENT,
1609 			    logsctperror("Parameter parse limit exceeded (IsASCONFack)",
1610 				sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1611 			return(0); /* not found limit exceeded*/
1612 		}
1613 	}
1614 	return(0); /* not success */
1615 }
1616 
1617 /**  @ingroup packet_parser
1618  * @brief Check to see if ASCONF contains an Add IP or Del IP parameter
1619  *
1620  * IsADDorDEL scans an ASCONF packet to see if it contains an AddIP or DelIP
1621  * parameter
1622  *
1623  * @param la Pointer to the relevant libalias instance
1624  * @param sm Pointer to sctp message information
1625  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1626  *
1627  * @return SCTP_ADD_IP_ADDRESS | SCTP_DEL_IP_ADDRESS | 0 - fail
1628  */
1629 static int
1630 IsADDorDEL(struct libalias *la, struct sctp_nat_msg *sm, int direction)
1631 {
1632 	struct sctp_paramhdr *param;
1633 	int bytes_left;
1634 	int param_size;
1635 	int param_count;
1636 
1637 	param_count = 1;
1638 	param = sm->sctpchnk.Asconf;
1639 	param_size = SCTP_SIZE32(ntohs(param->param_length));
1640 
1641 	bytes_left = sm->chunk_length;
1642 	if (bytes_left < param_size)
1643 		return(0); /* not found */
1644 	/* step through Asconf parameters */
1645 	while(bytes_left >= SN_ASCONFACK_PARAM_SIZE) {
1646 		if (ntohs(param->param_type) == SCTP_ADD_IP_ADDRESS)
1647 			return(SCTP_ADD_IP_ADDRESS);
1648 		else if (ntohs(param->param_type) == SCTP_DEL_IP_ADDRESS)
1649 			return(SCTP_DEL_IP_ADDRESS);
1650 		/* check others just in case */
1651 		bytes_left -= param_size;
1652 		if (bytes_left >= SN_MIN_PARAM_SIZE) {
1653 			param = SN_SCTP_NEXTPARAM(param);
1654 		} else {
1655 			return(0); /*Neither found */
1656 		}
1657 		param_size = SCTP_SIZE32(ntohs(param->param_length));
1658 		if (bytes_left < param_size) return(0);
1659 
1660 		if (++param_count > sysctl_param_proc_limit) {
1661 			SN_LOG(SN_LOG_EVENT,
1662 			    logsctperror("Parameter parse limit exceeded IsADDorDEL)",
1663 				sm->sctp_hdr->v_tag, sysctl_param_proc_limit, direction));
1664 			return(0); /* not found limit exceeded*/
1665 		}
1666 	}
1667 	return(0);  /*Neither found */
1668 }
1669 
1670 /* ----------------------------------------------------------------------
1671  *                            STATE MACHINE CODE
1672  * ----------------------------------------------------------------------
1673  */
1674 /** @addtogroup state_machine
1675  *
1676  * The SCTP NAT State Machine functions will:
1677  * - Process an already parsed packet
1678  * - Use the existing NAT Hash Tables
1679  * - Determine the next state for the association
1680  * - Update the NAT Hash Tables and Timer Queues
1681  * - Return the appropriate action to take with the packet
1682  */
1683 /** @ingroup state_machine
1684  * @brief Process SCTP message
1685  *
1686  * This function is the base state machine. It calls the processing engine for
1687  * each state.
1688  *
1689  * @param la Pointer to the relevant libalias instance
1690  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1691  * @param sm Pointer to sctp message information
1692  * @param assoc Pointer to the association this SCTP Message belongs to
1693  *
1694  * @return SN_DROP_PKT | SN_NAT_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR | SN_PROCESSING_ERROR
1695  */
1696 static int
1697 ProcessSctpMsg(struct libalias *la, int direction, struct sctp_nat_msg *sm, struct sctp_nat_assoc *assoc)
1698 {
1699 	int rtnval;
1700 
1701 	switch (assoc->state) {
1702 	case SN_ID: /* Idle */
1703 		rtnval = ID_process(la, direction, assoc, sm);
1704 		if (rtnval != SN_NAT_PKT) {
1705 			assoc->state = SN_RM;/* Mark for removal*/
1706 		}
1707 		return(rtnval);
1708 	case SN_INi: /* Initialising - Init */
1709 		return(INi_process(la, direction, assoc, sm));
1710 	case SN_INa: /* Initialising - AddIP */
1711 		return(INa_process(la, direction, assoc, sm));
1712 	case SN_UP:  /* Association UP */
1713 		return(UP_process(la, direction, assoc, sm));
1714 	case SN_CL:  /* Association Closing */
1715 		return(CL_process(la, direction, assoc, sm));
1716 	}
1717 	return(SN_PROCESSING_ERROR);
1718 }
1719 
1720 /** @ingroup state_machine
1721  * @brief Process SCTP message while in the Idle state
1722  *
1723  * This function looks for an Incoming INIT or AddIP message.
1724  *
1725  * All other SCTP messages are invalid when in SN_ID, and are dropped.
1726  *
1727  * @param la Pointer to the relevant libalias instance
1728  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1729  * @param sm Pointer to sctp message information
1730  * @param assoc Pointer to the association this SCTP Message belongs to
1731  *
1732  * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT | SN_REPLY_ERROR
1733  */
1734 static int
1735 ID_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1736 {
1737 	switch(sm->msg) {
1738 	case SN_SCTP_ASCONF:           /* a packet containing an ASCONF chunk with ADDIP */
1739 		if (!sysctl_accept_global_ootb_addip && (direction == SN_TO_LOCAL))
1740 			return(SN_DROP_PKT);
1741 		/* if this Asconf packet does not contain the Vtag parameters it is of no use in Idle state */
1742 		if (!GetAsconfVtags(la, sm, &(assoc->l_vtag), &(assoc->g_vtag), direction))
1743 			return(SN_DROP_PKT);
1744 	case SN_SCTP_INIT:            /* a packet containing an INIT chunk or an ASCONF AddIP */
1745 		if (sysctl_track_global_addresses)
1746 			AddGlobalIPAddresses(sm, assoc, direction);
1747 		switch(direction){
1748 		case SN_TO_GLOBAL:
1749 			assoc->l_addr = sm->ip_hdr->ip_src;
1750 			assoc->a_addr = FindAliasAddress(la, assoc->l_addr);
1751 			assoc->l_port = sm->sctp_hdr->src_port;
1752 			assoc->g_port = sm->sctp_hdr->dest_port;
1753 			if(sm->msg == SN_SCTP_INIT)
1754 				assoc->g_vtag = sm->sctpchnk.Init->initiate_tag;
1755 			if (AddSctpAssocGlobal(la, assoc)) /* DB clash *///**** need to add dst address
1756 				return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR);
1757 			if(sm->msg == SN_SCTP_ASCONF) {
1758 				if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_dst)) /* DB clash */
1759 					return(SN_REPLY_ERROR);
1760 				assoc->TableRegister |= SN_WAIT_TOLOCAL; /* wait for tolocal ack */
1761 			}
1762 		break;
1763 		case SN_TO_LOCAL:
1764 			assoc->l_addr = FindSctpRedirectAddress(la, sm);
1765 			assoc->a_addr = sm->ip_hdr->ip_dst;
1766 			assoc->l_port = sm->sctp_hdr->dest_port;
1767 			assoc->g_port = sm->sctp_hdr->src_port;
1768 			if(sm->msg == SN_SCTP_INIT)
1769 				assoc->l_vtag = sm->sctpchnk.Init->initiate_tag;
1770 			if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) /* DB clash */
1771 				return((sm->msg == SN_SCTP_INIT) ? SN_REPLY_ABORT : SN_REPLY_ERROR);
1772 			if(sm->msg == SN_SCTP_ASCONF) {
1773 				if (AddSctpAssocGlobal(la, assoc)) /* DB clash */ //**** need to add src address
1774 					return(SN_REPLY_ERROR);
1775 				assoc->TableRegister |= SN_WAIT_TOGLOBAL; /* wait for toglobal ack */
1776 					}
1777 			break;
1778 		}
1779 	assoc->state = (sm->msg == SN_SCTP_INIT) ? SN_INi : SN_INa;
1780 	assoc->exp = SN_I_T(la);
1781 	sctp_AddTimeOut(la,assoc);
1782 	return(SN_NAT_PKT);
1783 	default: /* Any other type of SCTP message is not valid in Idle */
1784 		return(SN_DROP_PKT);
1785 	}
1786 return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1787 }
1788 
1789 /** @ingroup state_machine
1790  * @brief Process SCTP message while waiting for an INIT-ACK message
1791  *
1792  * Only an INIT-ACK, resent INIT, or an ABORT SCTP packet are valid in this
1793  * state, all other packets are dropped.
1794  *
1795  * @param la Pointer to the relevant libalias instance
1796  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1797  * @param sm Pointer to sctp message information
1798  * @param assoc Pointer to the association this SCTP Message belongs to
1799  *
1800  * @return SN_NAT_PKT | SN_DROP_PKT | SN_REPLY_ABORT
1801  */
1802 static int
1803 INi_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1804 {
1805 	switch(sm->msg) {
1806 	case SN_SCTP_INIT:            /* a packet containing a retransmitted INIT chunk */
1807 		sctp_ResetTimeOut(la, assoc, SN_I_T(la));
1808 		return(SN_NAT_PKT);
1809 	case SN_SCTP_INITACK:         /* a packet containing an INIT-ACK chunk */
1810 		switch(direction){
1811 		case SN_TO_LOCAL:
1812 			if (assoc->num_Gaddr) /*If tracking global addresses for this association */
1813 				AddGlobalIPAddresses(sm, assoc, direction);
1814 			assoc->l_vtag = sm->sctpchnk.Init->initiate_tag;
1815 			if (AddSctpAssocLocal(la, assoc, sm->ip_hdr->ip_src)) { /* DB clash */
1816 				assoc->state = SN_RM;/* Mark for removal*/
1817 				return(SN_SEND_ABORT);
1818 			}
1819 			break;
1820 		case SN_TO_GLOBAL:
1821 			assoc->l_addr = sm->ip_hdr->ip_src; // Only if not set in Init! *
1822 			assoc->g_vtag = sm->sctpchnk.Init->initiate_tag;
1823 			if (AddSctpAssocGlobal(la, assoc)) { /* DB clash */
1824 				assoc->state = SN_RM;/* Mark for removal*/
1825 				return(SN_SEND_ABORT);
1826 			}
1827 			break;
1828 		}
1829 		assoc->state = SN_UP;/* association established for NAT */
1830 		sctp_ResetTimeOut(la,assoc, SN_U_T(la));
1831 		return(SN_NAT_PKT);
1832 	case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1833 		assoc->state = SN_RM;/* Mark for removal*/
1834 		return(SN_NAT_PKT);
1835 	default:
1836 		return(SN_DROP_PKT);
1837 	}
1838 	return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1839 }
1840 
1841 /** @ingroup state_machine
1842  * @brief Process SCTP message while waiting for an AddIp-ACK message
1843  *
1844  * Only an AddIP-ACK, resent AddIP, or an ABORT message are valid, all other
1845  * SCTP packets are dropped
1846  *
1847  * @param la Pointer to the relevant libalias instance
1848  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1849  * @param sm Pointer to sctp message information
1850  * @param assoc Pointer to the association this SCTP Message belongs to
1851  *
1852  * @return SN_NAT_PKT | SN_DROP_PKT
1853  */
1854 static int
1855 INa_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1856 {
1857 	switch(sm->msg) {
1858 	case SN_SCTP_ASCONF:           /* a packet containing an ASCONF chunk*/
1859 		sctp_ResetTimeOut(la,assoc, SN_I_T(la));
1860 		return(SN_NAT_PKT);
1861 	case SN_SCTP_ASCONFACK:        /* a packet containing an ASCONF chunk with a ADDIP-ACK */
1862 		switch(direction){
1863 		case SN_TO_LOCAL:
1864 			if (!(assoc->TableRegister & SN_WAIT_TOLOCAL)) /* wrong direction */
1865 				return(SN_DROP_PKT);
1866 			break;
1867 		case SN_TO_GLOBAL:
1868 			if (!(assoc->TableRegister & SN_WAIT_TOGLOBAL)) /* wrong direction */
1869 				return(SN_DROP_PKT);
1870 		}
1871 		if (IsASCONFack(la,sm,direction)) {
1872 			assoc->TableRegister &= SN_BOTH_TBL; /* remove wait flags */
1873 			assoc->state = SN_UP; /* association established for NAT */
1874 			sctp_ResetTimeOut(la,assoc, SN_U_T(la));
1875 			return(SN_NAT_PKT);
1876 		} else {
1877 			assoc->state = SN_RM;/* Mark for removal*/
1878 			return(SN_NAT_PKT);
1879 		}
1880 	case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1881 		assoc->state = SN_RM;/* Mark for removal*/
1882 		return(SN_NAT_PKT);
1883 	default:
1884 		return(SN_DROP_PKT);
1885 	}
1886 	return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1887 }
1888 
1889 /** @ingroup state_machine
1890  * @brief Process SCTP messages while association is UP redirecting packets
1891  *
1892  * While in the SN_UP state, all packets for the particular association
1893  * are passed. Only a SHUT-ACK or an ABORT will cause a change of state.
1894  *
1895  * @param la Pointer to the relevant libalias instance
1896  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1897  * @param sm Pointer to sctp message information
1898  * @param assoc Pointer to the association this SCTP Message belongs to
1899  *
1900  * @return SN_NAT_PKT | SN_DROP_PKT
1901  */
1902 static int
1903 UP_process(struct libalias *la, int direction, struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1904 {
1905 	switch(sm->msg) {
1906 	case SN_SCTP_SHUTACK:         /* a packet containing a SHUTDOWN-ACK chunk */
1907 		assoc->state = SN_CL;
1908 		sctp_ResetTimeOut(la,assoc, SN_C_T(la));
1909 		return(SN_NAT_PKT);
1910 	case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1911 		assoc->state = SN_RM;/* Mark for removal*/
1912 		return(SN_NAT_PKT);
1913 	case SN_SCTP_ASCONF:           /* a packet containing an ASCONF chunk*/
1914 		if ((direction == SN_TO_LOCAL) && assoc->num_Gaddr) /*If tracking global addresses for this association & from global side */
1915 			switch(IsADDorDEL(la,sm,direction)) {
1916 			case SCTP_ADD_IP_ADDRESS:
1917 				AddGlobalIPAddresses(sm, assoc, direction);
1918 				break;
1919 			case SCTP_DEL_IP_ADDRESS:
1920 				RmGlobalIPAddresses(sm, assoc, direction);
1921 				break;
1922 			} /* fall through to default */
1923 	default:
1924 		sctp_ResetTimeOut(la,assoc, SN_U_T(la));
1925 		return(SN_NAT_PKT);  /* forward packet */
1926 	}
1927 	return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1928 }
1929 
1930 /** @ingroup state_machine
1931  * @brief Process SCTP message while association is in the process of closing
1932  *
1933  * This function waits for a SHUT-COMP to close the association. Depending on
1934  * the setting of sysctl_holddown_timer it may not remove the association
1935  * immediately, but leave it up until SN_X_T(la). Only SHUT-COMP, SHUT-ACK, and
1936  * ABORT packets are permitted in this state. All other packets are dropped.
1937  *
1938  * @param la Pointer to the relevant libalias instance
1939  * @param direction SN_TO_LOCAL | SN_TO_GLOBAL
1940  * @param sm Pointer to sctp message information
1941  * @param assoc Pointer to the association this SCTP Message belongs to
1942  *
1943  * @return SN_NAT_PKT | SN_DROP_PKT
1944  */
1945 static int
1946 CL_process(struct libalias *la, int direction,struct sctp_nat_assoc *assoc, struct sctp_nat_msg *sm)
1947 {
1948 	switch(sm->msg) {
1949 	case SN_SCTP_SHUTCOMP:        /* a packet containing a SHUTDOWN-COMPLETE chunk */
1950 		assoc->state = SN_CL;  /* Stay in Close state until timeout */
1951 		if (sysctl_holddown_timer > 0)
1952 			sctp_ResetTimeOut(la, assoc, SN_X_T(la));/* allow to stay open for Tbit packets*/
1953 		else
1954 			assoc->state = SN_RM;/* Mark for removal*/
1955 		return(SN_NAT_PKT);
1956 	case SN_SCTP_SHUTACK:         /* a packet containing a SHUTDOWN-ACK chunk */
1957 		assoc->state = SN_CL;  /* Stay in Close state until timeout */
1958 		sctp_ResetTimeOut(la, assoc, SN_C_T(la));
1959 		return(SN_NAT_PKT);
1960 	case SN_SCTP_ABORT:           /* a packet containing an ABORT chunk */
1961 		assoc->state = SN_RM;/* Mark for removal*/
1962 		return(SN_NAT_PKT);
1963 	default:
1964 		return(SN_DROP_PKT);
1965 	}
1966 	return(SN_DROP_PKT);/* shouldn't get here very bad: log, drop and hope for the best */
1967 }
1968 
1969 /* ----------------------------------------------------------------------
1970  *                           HASH TABLE CODE
1971  * ----------------------------------------------------------------------
1972  */
1973 /** @addtogroup Hash
1974  *
1975  * The Hash functions facilitate searching the NAT Hash Tables for associations
1976  * as well as adding/removing associations from the table(s).
1977  */
1978 /** @ingroup Hash
1979  * @brief Find the SCTP association given the local address, port and vtag
1980  *
1981  * Searches the local look-up table for the association entry matching the
1982  * provided local <address:ports:vtag> tuple
1983  *
1984  * @param la Pointer to the relevant libalias instance
1985  * @param l_addr local address
1986  * @param g_addr global address
1987  * @param l_vtag local Vtag
1988  * @param l_port local Port
1989  * @param g_port global Port
1990  *
1991  * @return pointer to association or NULL
1992  */
1993 static struct sctp_nat_assoc*
1994 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)
1995 {
1996 	u_int i;
1997 	struct sctp_nat_assoc *assoc = NULL;
1998 	struct sctp_GlobalAddress *G_Addr = NULL;
1999 
2000 	if (l_vtag != 0) { /* an init packet, vtag==0 */
2001 		i = SN_TABLE_HASH(l_vtag, l_port, la->sctpNatTableSize);
2002 		LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) {
2003 			if ((assoc->l_vtag == l_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)\
2004 			    && (assoc->l_addr.s_addr == l_addr.s_addr)) {
2005 				if (assoc->num_Gaddr) {
2006 					LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2007 						if(G_Addr->g_addr.s_addr == g_addr.s_addr)
2008 							return(assoc);
2009 					}
2010 				} else {
2011 					return(assoc);
2012 				}
2013 			}
2014 		}
2015 	}
2016 	return(NULL);
2017 }
2018 
2019 /** @ingroup Hash
2020  * @brief Check for Global Clash
2021  *
2022  * Searches the global look-up table for the association entry matching the
2023  * provided global <(addresses):ports:vtag> tuple
2024  *
2025  * @param la Pointer to the relevant libalias instance
2026  * @param Cassoc association being checked for a clash
2027  *
2028  * @return pointer to association or NULL
2029  */
2030 static struct sctp_nat_assoc*
2031 FindSctpGlobalClash(struct libalias *la,  struct sctp_nat_assoc *Cassoc)
2032 {
2033 	u_int i;
2034 	struct sctp_nat_assoc *assoc = NULL;
2035 	struct sctp_GlobalAddress *G_Addr = NULL;
2036 	struct sctp_GlobalAddress *G_AddrC = NULL;
2037 
2038 	if (Cassoc->g_vtag != 0) { /* an init packet, vtag==0 */
2039 		i = SN_TABLE_HASH(Cassoc->g_vtag, Cassoc->g_port, la->sctpNatTableSize);
2040 		LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2041 			if ((assoc->g_vtag == Cassoc->g_vtag) && (assoc->g_port == Cassoc->g_port) && (assoc->l_port == Cassoc->l_port)) {
2042 				if (assoc->num_Gaddr) {
2043 					LIST_FOREACH(G_AddrC, &(Cassoc->Gaddr), list_Gaddr) {
2044 						LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2045 							if(G_Addr->g_addr.s_addr == G_AddrC->g_addr.s_addr)
2046 								return(assoc);
2047 						}
2048 					}
2049 				} else {
2050 					return(assoc);
2051 				}
2052 			}
2053 		}
2054 	}
2055 	return(NULL);
2056 }
2057 
2058 /** @ingroup Hash
2059  * @brief Find the SCTP association given the global port and vtag
2060  *
2061  * Searches the global look-up table for the association entry matching the
2062  * provided global <address:ports:vtag> tuple
2063  *
2064  * If all but the global address match it sets partial_match to 1 to indicate a
2065  * partial match. If the NAT is tracking global IP addresses for this
2066  * association, the NAT may respond with an ERRORM to request the missing
2067  * address to be added.
2068  *
2069  * @param la Pointer to the relevant libalias instance
2070  * @param g_addr global address
2071  * @param g_vtag global vtag
2072  * @param g_port global port
2073  * @param l_port local port
2074  *
2075  * @return pointer to association or NULL
2076  */
2077 static struct sctp_nat_assoc*
2078 FindSctpGlobal(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t g_port, uint16_t l_port, int *partial_match)
2079 {
2080 	u_int i;
2081 	struct sctp_nat_assoc *assoc = NULL;
2082 	struct sctp_GlobalAddress *G_Addr = NULL;
2083 
2084 	*partial_match = 0;
2085 	if (g_vtag != 0) { /* an init packet, vtag==0 */
2086 		i = SN_TABLE_HASH(g_vtag, g_port, la->sctpNatTableSize);
2087 		LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2088 			if ((assoc->g_vtag == g_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) {
2089 				*partial_match = 1;
2090 				if (assoc->num_Gaddr) {
2091 					LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2092 						if(G_Addr->g_addr.s_addr == g_addr.s_addr)
2093 							return(assoc);
2094 					}
2095 				} else {
2096 					return(assoc);
2097 				}
2098 			}
2099 		}
2100 	}
2101 	return(NULL);
2102 }
2103 
2104 /** @ingroup Hash
2105  * @brief Find the SCTP association for a T-Flag message (given the global port and local vtag)
2106  *
2107  * Searches the local look-up table for a unique association entry matching the
2108  * provided global port and local vtag information
2109  *
2110  * @param la Pointer to the relevant libalias instance
2111  * @param g_addr global address
2112  * @param l_vtag local Vtag
2113  * @param g_port global Port
2114  * @param l_port local Port
2115  *
2116  * @return pointer to association or NULL
2117  */
2118 static struct sctp_nat_assoc*
2119 FindSctpLocalT(struct libalias *la,  struct in_addr g_addr, uint32_t l_vtag, uint16_t g_port, uint16_t l_port)
2120 {
2121 	u_int i;
2122 	struct sctp_nat_assoc *assoc = NULL, *lastmatch = NULL;
2123 	struct sctp_GlobalAddress *G_Addr = NULL;
2124 	int cnt = 0;
2125 
2126 	if (l_vtag != 0) { /* an init packet, vtag==0 */
2127 		i = SN_TABLE_HASH(l_vtag, g_port, la->sctpNatTableSize);
2128 		LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2129 			if ((assoc->g_vtag == l_vtag) && (assoc->g_port == g_port) && (assoc->l_port == l_port)) {
2130 				if (assoc->num_Gaddr) {
2131 					LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2132 						if(G_Addr->g_addr.s_addr == G_Addr->g_addr.s_addr)
2133 							return(assoc); /* full match */
2134 					}
2135 				} else {
2136 					if (++cnt > 1) return(NULL);
2137 					lastmatch = assoc;
2138 				}
2139 			}
2140 		}
2141 	}
2142 	/* If there is more than one match we do not know which local address to send to */
2143 	return( cnt ? lastmatch : NULL );
2144 }
2145 
2146 /** @ingroup Hash
2147  * @brief Find the SCTP association for a T-Flag message (given the local port and global vtag)
2148  *
2149  * Searches the global look-up table for a unique association entry matching the
2150  * provided local port and global vtag information
2151  *
2152  * @param la Pointer to the relevant libalias instance
2153  * @param g_addr global address
2154  * @param g_vtag global vtag
2155  * @param l_port local port
2156  * @param g_port global port
2157  *
2158  * @return pointer to association or NULL
2159  */
2160 static struct sctp_nat_assoc*
2161 FindSctpGlobalT(struct libalias *la, struct in_addr g_addr, uint32_t g_vtag, uint16_t l_port, uint16_t g_port)
2162 {
2163 	u_int i;
2164 	struct sctp_nat_assoc *assoc = NULL;
2165 	struct sctp_GlobalAddress *G_Addr = NULL;
2166 
2167 	if (g_vtag != 0) { /* an init packet, vtag==0 */
2168 		i = SN_TABLE_HASH(g_vtag, l_port, la->sctpNatTableSize);
2169 		LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) {
2170 			if ((assoc->l_vtag == g_vtag) && (assoc->l_port == l_port) && (assoc->g_port == g_port)) {
2171 				if (assoc->num_Gaddr) {
2172 					LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2173 						if(G_Addr->g_addr.s_addr == g_addr.s_addr)
2174 							return(assoc);
2175 					}
2176 				} else {
2177 					return(assoc);
2178 				}
2179 			}
2180 		}
2181 	}
2182 	return(NULL);
2183 }
2184 
2185 /** @ingroup Hash
2186  * @brief  Add the sctp association information to the local look up table
2187  *
2188  * Searches the local look-up table for an existing association with the same
2189  * details. If a match exists and is ONLY in the local look-up table then this
2190  * is a repeated INIT packet, we need to remove this association from the
2191  * look-up table and add the new association
2192  *
2193  * The new association is added to the head of the list and state is updated
2194  *
2195  * @param la Pointer to the relevant libalias instance
2196  * @param assoc pointer to sctp association
2197  * @param g_addr global address
2198  *
2199  * @return SN_ADD_OK | SN_ADD_CLASH
2200  */
2201 static int
2202 AddSctpAssocLocal(struct libalias *la, struct sctp_nat_assoc *assoc, struct in_addr g_addr)
2203 {
2204 	struct sctp_nat_assoc *found;
2205 
2206 	LIBALIAS_LOCK_ASSERT(la);
2207 	found = FindSctpLocal(la, assoc->l_addr, g_addr, assoc->l_vtag, assoc->l_port, assoc->g_port);
2208 	/*
2209 	 * Note that if a different global address initiated this Init,
2210 	 * ie it wasn't resent as presumed:
2211 	 *  - the local receiver if receiving it for the first time will establish
2212 	 *    an association with the new global host
2213 	 *  - if receiving an init from a different global address after sending a
2214 	 *    lost initack it will send an initack to the new global host, the first
2215 	 *    association attempt will then be blocked if retried.
2216 	 */
2217 	if (found != NULL) {
2218 		if ((found->TableRegister == SN_LOCAL_TBL) && (found->g_port == assoc->g_port)) { /* resent message */
2219 			RmSctpAssoc(la, found);
2220 			sctp_RmTimeOut(la, found);
2221 			freeGlobalAddressList(found);
2222 			sn_free(found);
2223 		} else
2224 			return(SN_ADD_CLASH);
2225 	}
2226 
2227 	LIST_INSERT_HEAD(&la->sctpTableLocal[SN_TABLE_HASH(assoc->l_vtag, assoc->l_port, la->sctpNatTableSize)],
2228 	    assoc, list_L);
2229 	assoc->TableRegister |= SN_LOCAL_TBL;
2230 	la->sctpLinkCount++; //increment link count
2231 
2232 	if (assoc->TableRegister == SN_BOTH_TBL) {
2233 		/* libalias log -- controlled by libalias */
2234 		if (la->packetAliasMode & PKT_ALIAS_LOG)
2235 			SctpShowAliasStats(la);
2236 
2237 		SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^"));
2238 	}
2239 
2240 	return(SN_ADD_OK);
2241 }
2242 
2243 /** @ingroup Hash
2244  * @brief  Add the sctp association information to the global look up table
2245  *
2246  * Searches the global look-up table for an existing association with the same
2247  * details. If a match exists and is ONLY in the global look-up table then this
2248  * is a repeated INIT packet, we need to remove this association from the
2249  * look-up table and add the new association
2250  *
2251  * The new association is added to the head of the list and state is updated
2252  *
2253  * @param la Pointer to the relevant libalias instance
2254  * @param assoc pointer to sctp association
2255  *
2256  * @return SN_ADD_OK | SN_ADD_CLASH
2257  */
2258 static int
2259 AddSctpAssocGlobal(struct libalias *la, struct sctp_nat_assoc *assoc)
2260 {
2261 	struct sctp_nat_assoc *found;
2262 
2263 	LIBALIAS_LOCK_ASSERT(la);
2264 	found = FindSctpGlobalClash(la, assoc);
2265 	if (found != NULL) {
2266 		if ((found->TableRegister == SN_GLOBAL_TBL) &&			\
2267 		    (found->l_addr.s_addr == assoc->l_addr.s_addr) && (found->l_port == assoc->l_port)) { /* resent message */
2268 			RmSctpAssoc(la, found);
2269 			sctp_RmTimeOut(la, found);
2270 			freeGlobalAddressList(found);
2271 			sn_free(found);
2272 		} else
2273 			return(SN_ADD_CLASH);
2274 	}
2275 
2276 	LIST_INSERT_HEAD(&la->sctpTableGlobal[SN_TABLE_HASH(assoc->g_vtag, assoc->g_port, la->sctpNatTableSize)],
2277 	    assoc, list_G);
2278 	assoc->TableRegister |= SN_GLOBAL_TBL;
2279 	la->sctpLinkCount++; //increment link count
2280 
2281 	if (assoc->TableRegister == SN_BOTH_TBL) {
2282 		/* libalias log -- controlled by libalias */
2283 		if (la->packetAliasMode & PKT_ALIAS_LOG)
2284 			SctpShowAliasStats(la);
2285 
2286 		SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "^"));
2287 	}
2288 
2289 	return(SN_ADD_OK);
2290 }
2291 
2292 /** @ingroup Hash
2293  * @brief Remove the sctp association information from the look up table
2294  *
2295  * For each of the two (local/global) look-up tables, remove the association
2296  * from that table IF it has been registered in that table.
2297  *
2298  * NOTE: The calling code is responsible for freeing memory allocated to the
2299  *       association structure itself
2300  *
2301  * NOTE: The association is NOT removed from the timer queue
2302  *
2303  * @param la Pointer to the relevant libalias instance
2304  * @param assoc pointer to sctp association
2305  */
2306 static void
2307 RmSctpAssoc(struct libalias *la, struct sctp_nat_assoc *assoc)
2308 {
2309 	//  struct sctp_nat_assoc *found;
2310 	if (assoc == NULL) {
2311 		/* very bad, log and die*/
2312 		SN_LOG(SN_LOG_LOW,
2313 		    logsctperror("ERROR: alias_sctp:RmSctpAssoc(NULL)\n", 0, 0, SN_TO_NODIR));
2314 		return;
2315 	}
2316 	/* log if association is fully up and now closing */
2317 	if (assoc->TableRegister == SN_BOTH_TBL) {
2318 		SN_LOG(SN_LOG_INFO, logsctpassoc(assoc, "$"));
2319 	}
2320 	LIBALIAS_LOCK_ASSERT(la);
2321 	if (assoc->TableRegister & SN_LOCAL_TBL) {
2322 		assoc->TableRegister ^= SN_LOCAL_TBL;
2323 		la->sctpLinkCount--; //decrement link count
2324 		LIST_REMOVE(assoc, list_L);
2325 	}
2326 
2327 	if (assoc->TableRegister & SN_GLOBAL_TBL) {
2328 		assoc->TableRegister ^= SN_GLOBAL_TBL;
2329 		la->sctpLinkCount--; //decrement link count
2330 		LIST_REMOVE(assoc, list_G);
2331 	}
2332 	//  sn_free(assoc); //Don't remove now, remove if needed later
2333 	/* libalias logging -- controlled by libalias log definition */
2334 	if (la->packetAliasMode & PKT_ALIAS_LOG)
2335 		SctpShowAliasStats(la);
2336 }
2337 
2338 /**
2339  * @ingroup Hash
2340  * @brief  free the Global Address List memory
2341  *
2342  * freeGlobalAddressList deletes all global IP addresses in an associations
2343  * global IP address list.
2344  *
2345  * @param assoc
2346  */
2347 static void freeGlobalAddressList(struct sctp_nat_assoc *assoc)
2348 {
2349 	struct sctp_GlobalAddress *gaddr1=NULL,*gaddr2=NULL;
2350 	/*free global address list*/
2351 	gaddr1 = LIST_FIRST(&(assoc->Gaddr));
2352 	while (gaddr1 != NULL) {
2353 		gaddr2 = LIST_NEXT(gaddr1, list_Gaddr);
2354 		sn_free(gaddr1);
2355 		gaddr1 = gaddr2;
2356 	}
2357 }
2358 /* ----------------------------------------------------------------------
2359  *                            TIMER QUEUE CODE
2360  * ----------------------------------------------------------------------
2361  */
2362 /** @addtogroup Timer
2363  *
2364  * The timer queue management functions are designed to operate efficiently with
2365  * a minimum of interaction with the queues.
2366  *
2367  * Once a timeout is set in the queue it will not be altered in the queue unless
2368  * it has to be changed to a shorter time (usually only for aborts and closing).
2369  * On a queue timeout, the real expiry time is checked, and if not leq than the
2370  * timeout it is requeued (O(1)) at its later time. This is especially important
2371  * for normal packets sent during an association. When a timer expires, it is
2372  * updated to its new expiration time if necessary, or processed as a
2373  * timeout. This means that while in UP state, the timing queue is only altered
2374  * every U_T (every few minutes) for a particular association.
2375  */
2376 /** @ingroup Timer
2377  * @brief Add an association timeout to the timer queue
2378  *
2379  * Determine the location in the queue to add the timeout and insert the
2380  * association into the list at that queue position
2381  *
2382  * @param la
2383  * @param assoc
2384  */
2385 static void
2386 sctp_AddTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc)
2387 {
2388 	int add_loc;
2389 	LIBALIAS_LOCK_ASSERT(la);
2390 	add_loc = assoc->exp - la->sctpNatTimer.loc_time + la->sctpNatTimer.cur_loc;
2391 	if (add_loc >= SN_TIMER_QUEUE_SIZE)
2392 		add_loc -= SN_TIMER_QUEUE_SIZE;
2393 	LIST_INSERT_HEAD(&la->sctpNatTimer.TimerQ[add_loc], assoc, timer_Q);
2394 	assoc->exp_loc = add_loc;
2395 }
2396 
2397 /** @ingroup Timer
2398  * @brief Remove an association from timer queue
2399  *
2400  * This is an O(1) operation to remove the association pointer from its
2401  * current position in the timer queue
2402  *
2403  * @param la Pointer to the relevant libalias instance
2404  * @param assoc pointer to sctp association
2405  */
2406 static void
2407 sctp_RmTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc)
2408 {
2409 	LIBALIAS_LOCK_ASSERT(la);
2410 	LIST_REMOVE(assoc, timer_Q);/* Note this is O(1) */
2411 }
2412 
2413 
2414 /** @ingroup Timer
2415  * @brief Reset timer in timer queue
2416  *
2417  * Reset the actual timeout for the specified association. If it is earlier than
2418  * the existing timeout, then remove and re-install the association into the
2419  * queue
2420  *
2421  * @param la Pointer to the relevant libalias instance
2422  * @param assoc pointer to sctp association
2423  * @param newexp New expiration time
2424  */
2425 static void
2426 sctp_ResetTimeOut(struct libalias *la, struct sctp_nat_assoc *assoc, int newexp)
2427 {
2428 	if (newexp < assoc->exp) {
2429 		sctp_RmTimeOut(la, assoc);
2430 		assoc->exp = newexp;
2431 		sctp_AddTimeOut(la, assoc);
2432 	} else {
2433 		assoc->exp = newexp;
2434 	}
2435 }
2436 
2437 /** @ingroup Timer
2438  * @brief Check timer Q against current time
2439  *
2440  * Loop through each entry in the timer queue since the last time we processed
2441  * the timer queue until now (the current time). For each association in the
2442  * event list, we remove it from that position in the timer queue and check if
2443  * it has really expired. If so we:
2444  * - Log the timer expiry
2445  * - Remove the association from the NAT tables
2446  * - Release the memory used by the association
2447  *
2448  * If the timer hasn't really expired we place the association into its new
2449  * correct position in the timer queue.
2450  *
2451  * @param la  Pointer to the relevant libalias instance
2452  */
2453 void
2454 sctp_CheckTimers(struct libalias *la)
2455 {
2456 	struct sctp_nat_assoc *assoc;
2457 
2458 	LIBALIAS_LOCK_ASSERT(la);
2459 	while(la->timeStamp >= la->sctpNatTimer.loc_time) {
2460 		while (!LIST_EMPTY(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc])) {
2461 			assoc = LIST_FIRST(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc]);
2462 			//SLIST_REMOVE_HEAD(&la->sctpNatTimer.TimerQ[la->sctpNatTimer.cur_loc], timer_Q);
2463 			LIST_REMOVE(assoc, timer_Q);
2464 			if (la->timeStamp >= assoc->exp) { /* state expired */
2465 				SN_LOG(((assoc->state == SN_CL)?(SN_LOG_DEBUG):(SN_LOG_INFO)),
2466 				    logsctperror("Timer Expired", assoc->g_vtag, assoc->state, SN_TO_NODIR));
2467 				RmSctpAssoc(la, assoc);
2468 				freeGlobalAddressList(assoc);
2469 				sn_free(assoc);
2470 			} else {/* state not expired, reschedule timer*/
2471 				sctp_AddTimeOut(la, assoc);
2472 			}
2473 		}
2474 		/* Goto next location in the timer queue*/
2475 		++la->sctpNatTimer.loc_time;
2476 		if (++la->sctpNatTimer.cur_loc >= SN_TIMER_QUEUE_SIZE)
2477 			la->sctpNatTimer.cur_loc = 0;
2478 	}
2479 }
2480 
2481 /* ----------------------------------------------------------------------
2482  *                              LOGGING CODE
2483  * ----------------------------------------------------------------------
2484  */
2485 /** @addtogroup Logging
2486  *
2487  * The logging functions provide logging of different items ranging from logging
2488  * a simple message, through logging an association details to logging the
2489  * current state of the NAT tables
2490  */
2491 /** @ingroup Logging
2492  * @brief Log sctp nat errors
2493  *
2494  * @param errormsg Error message to be logged
2495  * @param vtag Current Vtag
2496  * @param error Error number
2497  * @param direction Direction of packet
2498  */
2499 static void
2500 logsctperror(char* errormsg, uint32_t vtag, int error, int direction)
2501 {
2502 	char dir;
2503 	switch(direction) {
2504 	case SN_TO_LOCAL:
2505 		dir = 'L';
2506 		break;
2507 	case SN_TO_GLOBAL:
2508 		dir = 'G';
2509 		break;
2510 	default:
2511 		dir = '*';
2512 		break;
2513 	}
2514 	SctpAliasLog("->%c %s (vt=%u) %d\n", dir, errormsg, ntohl(vtag), error);
2515 }
2516 
2517 /** @ingroup Logging
2518  * @brief Log what the parser parsed
2519  *
2520  * @param direction Direction of packet
2521  * @param sm Pointer to sctp message information
2522  */
2523 static void
2524 logsctpparse(int direction, struct sctp_nat_msg *sm)
2525 {
2526 	char *ploc, *pstate;
2527 	switch(direction) {
2528 	case SN_TO_LOCAL:
2529 		ploc = "TO_LOCAL -";
2530 		break;
2531 	case SN_TO_GLOBAL:
2532 		ploc = "TO_GLOBAL -";
2533 		break;
2534 	default:
2535 		ploc = "";
2536 	}
2537 	switch(sm->msg) {
2538 	case SN_SCTP_INIT:
2539 		pstate = "Init";
2540 		break;
2541 	case SN_SCTP_INITACK:
2542 		pstate = "InitAck";
2543 		break;
2544 	case SN_SCTP_ABORT:
2545 		pstate = "Abort";
2546 		break;
2547 	case SN_SCTP_SHUTACK:
2548 		pstate = "ShutAck";
2549 		break;
2550 	case SN_SCTP_SHUTCOMP:
2551 		pstate = "ShutComp";
2552 		break;
2553 	case SN_SCTP_ASCONF:
2554 		pstate = "Asconf";
2555 		break;
2556 	case SN_SCTP_ASCONFACK:
2557 		pstate = "AsconfAck";
2558 		break;
2559 	case SN_SCTP_OTHER:
2560 		pstate = "Other";
2561 		break;
2562 	default:
2563 		pstate = "***ERROR***";
2564 		break;
2565 	}
2566 	SctpAliasLog("Parsed: %s %s\n", ploc, pstate);
2567 }
2568 
2569 /** @ingroup Logging
2570  * @brief Log an SCTP association's details
2571  *
2572  * @param assoc pointer to sctp association
2573  * @param s Character that indicates the state of processing for this packet
2574  */
2575 static void logsctpassoc(struct sctp_nat_assoc *assoc, char* s)
2576 {
2577 	struct sctp_GlobalAddress *G_Addr = NULL;
2578 	char *sp;
2579 	char addrbuf[INET_ADDRSTRLEN];
2580 
2581 	switch(assoc->state) {
2582 	case SN_ID:
2583 		sp = "ID ";
2584 		break;
2585 	case SN_INi:
2586 		sp = "INi ";
2587 		break;
2588 	case SN_INa:
2589 		sp = "INa ";
2590 		break;
2591 	case SN_UP:
2592 		sp = "UP ";
2593 		break;
2594 	case SN_CL:
2595 		sp = "CL ";
2596 		break;
2597 	case SN_RM:
2598 		sp = "RM ";
2599 		break;
2600 	default:
2601 		sp = "***ERROR***";
2602 		break;
2603 	}
2604 	SctpAliasLog("%sAssoc: %s exp=%u la=%s lv=%u lp=%u gv=%u gp=%u tbl=%d\n",
2605 	    s, sp, assoc->exp, inet_ntoa_r(assoc->l_addr, addrbuf),
2606 	    ntohl(assoc->l_vtag), ntohs(assoc->l_port),
2607 	    ntohl(assoc->g_vtag), ntohs(assoc->g_port),
2608 	    assoc->TableRegister);
2609 	/* list global addresses */
2610 	LIST_FOREACH(G_Addr, &(assoc->Gaddr), list_Gaddr) {
2611 		SctpAliasLog("\t\tga=%s\n",
2612 		    inet_ntoa_r(G_Addr->g_addr, addrbuf));
2613 	}
2614 }
2615 
2616 /** @ingroup Logging
2617  * @brief Output Global table to log
2618  *
2619  * @param la Pointer to the relevant libalias instance
2620  */
2621 static void logSctpGlobal(struct libalias *la)
2622 {
2623 	u_int i;
2624 	struct sctp_nat_assoc *assoc = NULL;
2625 
2626 	SctpAliasLog("G->\n");
2627 	for (i=0; i < la->sctpNatTableSize; i++) {
2628 		LIST_FOREACH(assoc, &la->sctpTableGlobal[i], list_G) {
2629 			logsctpassoc(assoc, " ");
2630 		}
2631 	}
2632 }
2633 
2634 /** @ingroup Logging
2635  * @brief  Output Local table to log
2636  *
2637  * @param la Pointer to the relevant libalias instance
2638  */
2639 static void logSctpLocal(struct libalias *la)
2640 {
2641 	u_int i;
2642 	struct sctp_nat_assoc *assoc = NULL;
2643 
2644 	SctpAliasLog("L->\n");
2645 	for (i=0; i < la->sctpNatTableSize; i++) {
2646 		LIST_FOREACH(assoc, &la->sctpTableLocal[i], list_L) {
2647 			logsctpassoc(assoc, " ");
2648 		}
2649 	}
2650 }
2651 
2652 /** @ingroup Logging
2653  * @brief Output timer queue to log
2654  *
2655  * @param la Pointer to the relevant libalias instance
2656  */
2657 static void logTimerQ(struct libalias *la)
2658 {
2659 	static char buf[50];
2660 	u_int i;
2661 	struct sctp_nat_assoc *assoc = NULL;
2662 
2663 	SctpAliasLog("t->\n");
2664 	for (i=0; i < SN_TIMER_QUEUE_SIZE; i++) {
2665 		LIST_FOREACH(assoc, &la->sctpNatTimer.TimerQ[i], timer_Q) {
2666 			snprintf(buf, 50, " l=%u ",i);
2667 			//SctpAliasLog(la->logDesc," l=%d ",i);
2668 			logsctpassoc(assoc, buf);
2669 		}
2670 	}
2671 }
2672 
2673 /** @ingroup Logging
2674  * @brief Sctp NAT logging function
2675  *
2676  * This function is based on a similar function in alias_db.c
2677  *
2678  * @param str/stream logging descriptor
2679  * @param format printf type string
2680  */
2681 #ifdef _KERNEL
2682 static void
2683 SctpAliasLog(const char *format, ...)
2684 {
2685 	char buffer[LIBALIAS_BUF_SIZE];
2686 	va_list ap;
2687 	va_start(ap, format);
2688 	vsnprintf(buffer, LIBALIAS_BUF_SIZE, format, ap);
2689 	va_end(ap);
2690 	log(LOG_SECURITY | LOG_INFO,
2691 	    "alias_sctp: %s", buffer);
2692 }
2693 #else
2694 static void
2695 SctpAliasLog(FILE *stream, const char *format, ...)
2696 {
2697 	va_list ap;
2698 
2699 	va_start(ap, format);
2700 	vfprintf(stream, format, ap);
2701 	va_end(ap);
2702 	fflush(stream);
2703 }
2704 #endif
2705