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