blob: 4d674c90c53e06c1060a0899f5df65e6bef84130 [file] [log] [blame]
Ben Menchaca84f36632014-02-28 20:57:38 +00001/*
2 **************************************************************************
Gareth Williamsd5618a82015-05-20 11:13:32 +01003 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
Ben Menchaca84f36632014-02-28 20:57:38 +00004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
16
Murat Sezginb3731e82014-11-26 12:20:59 -080017#include <linux/version.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000018#include <linux/types.h>
19#include <linux/ip.h>
20#include <linux/tcp.h>
21#include <linux/module.h>
22#include <linux/skbuff.h>
23#include <linux/icmp.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000024#include <linux/kthread.h>
Murat Sezgin908ecb32015-05-10 20:54:36 -070025#include <linux/debugfs.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000026#include <linux/pkt_sched.h>
27#include <linux/string.h>
Gareth Williams54d15d92015-04-24 19:28:27 +010028#include <linux/random.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000029#include <net/route.h>
30#include <net/ip.h>
31#include <net/tcp.h>
32#include <asm/unaligned.h>
33#include <asm/uaccess.h> /* for put_user */
34#include <net/ipv6.h>
35#include <linux/inet.h>
36#include <linux/in.h>
37#include <linux/udp.h>
38#include <linux/tcp.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000039#include <linux/netfilter_ipv4.h>
40#include <linux/netfilter_bridge.h>
41#include <net/netfilter/nf_conntrack.h>
42#include <net/netfilter/nf_conntrack_helper.h>
43#include <net/netfilter/nf_conntrack_l4proto.h>
44#include <net/netfilter/nf_conntrack_l3proto.h>
45#include <net/netfilter/nf_conntrack_core.h>
46#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
47#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
48
49/*
50 * Debug output levels
51 * 0 = OFF
52 * 1 = ASSERTS / ERRORS
53 * 2 = 1 + WARN
54 * 3 = 2 + INFO
55 * 4 = 3 + TRACE
56 */
57#define DEBUG_LEVEL ECM_DB_DEBUG_LEVEL
58
Ben Menchaca84f36632014-02-28 20:57:38 +000059#include "ecm_types.h"
60#include "ecm_db_types.h"
Gareth Williamsd5618a82015-05-20 11:13:32 +010061#include "ecm_state.h"
Ben Menchaca84f36632014-02-28 20:57:38 +000062#include "ecm_tracker.h"
63#include "ecm_classifier.h"
64#include "ecm_front_end_types.h"
65#include "ecm_classifier_default.h"
66#include "ecm_db.h"
67
68/*
69 * Magic numbers
70 */
71#define ECM_DB_CONNECTION_INSTANCE_MAGIC 0xff23
72#define ECM_DB_HOST_INSTANCE_MAGIC 0x2873
73#define ECM_DB_MAPPING_INSTANCE_MAGIC 0x8765
74#define ECM_DB_LISTENER_INSTANCE_MAGIC 0x9876
75#define ECM_DB_NODE_INSTANCE_MAGIC 0x3312
76#define ECM_DB_IFACE_INSTANCE_MAGIC 0xAEF1
Gareth Williamsb39e7c22015-03-25 10:15:33 +000077#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010078#define ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC 0xAEF4
Gareth Williamsb39e7c22015-03-25 10:15:33 +000079#endif
Shyam Sunder1f037262015-05-18 20:04:13 +053080#ifdef ECM_MULTICAST_ENABLE
81#define ECM_DB_MULTICAST_INSTANCE_MAGIC 0xc34a
82#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000083
84/*
85 * Global lists.
86 * All instances are inserted into global list - this allows easy iteration of all instances of a particular type.
87 * The list is doubly linked for fast removal. The list is in no particular order.
88 */
89struct ecm_db_connection_instance *ecm_db_connections = NULL;
90struct ecm_db_mapping_instance *ecm_db_mappings = NULL;
91struct ecm_db_host_instance *ecm_db_hosts = NULL;
92struct ecm_db_node_instance *ecm_db_nodes = NULL;
93struct ecm_db_iface_instance *ecm_db_interfaces = NULL;
94
95/*
96 * Connection hash table
97 */
98#define ECM_DB_CONNECTION_HASH_SLOTS 32768
99static struct ecm_db_connection_instance *ecm_db_connection_table[ECM_DB_CONNECTION_HASH_SLOTS];
100 /* Slots of the connection hash table */
101static int ecm_db_connection_table_lengths[ECM_DB_CONNECTION_HASH_SLOTS];
102 /* Tracks how long each chain is */
103static int ecm_db_connection_count = 0; /* Number of connections allocated */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100104static int ecm_db_connection_serial = 0; /* Serial number - ensures each connection has a unique serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000105 * Serial numbers are used mainly by classifiers that keep their own state
106 * and can 'link' their state to the right connection using a serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000107 * The serial number is also used as a soft linkage to other subsystems such as NA.
108 */
109typedef uint32_t ecm_db_connection_hash_t;
110
111/*
112 * Connection serial number hash table
113 */
114#define ECM_DB_CONNECTION_SERIAL_HASH_SLOTS 32768
115static struct ecm_db_connection_instance *ecm_db_connection_serial_table[ECM_DB_CONNECTION_SERIAL_HASH_SLOTS];
116 /* Slots of the connection serial hash table */
117static int ecm_db_connection_serial_table_lengths[ECM_DB_CONNECTION_SERIAL_HASH_SLOTS];
118 /* Tracks how long each chain is */
119typedef uint32_t ecm_db_connection_serial_hash_t;
120
121/*
122 * Mapping hash table
123 */
124#define ECM_DB_MAPPING_HASH_SLOTS 32768
125static struct ecm_db_mapping_instance *ecm_db_mapping_table[ECM_DB_MAPPING_HASH_SLOTS];
126 /* Slots of the mapping hash table */
127static int ecm_db_mapping_table_lengths[ECM_DB_MAPPING_HASH_SLOTS];
128 /* Tracks how long each chain is */
129static int ecm_db_mapping_count = 0; /* Number of mappings allocated */
130typedef uint32_t ecm_db_mapping_hash_t;
131
132/*
133 * Host hash table
134 */
135#define ECM_DB_HOST_HASH_SLOTS 32768
136static struct ecm_db_host_instance *ecm_db_host_table[ECM_DB_HOST_HASH_SLOTS];
137 /* Slots of the host hash table */
138static int ecm_db_host_table_lengths[ECM_DB_HOST_HASH_SLOTS];
139 /* Tracks how long each chain is */
140static int ecm_db_host_count = 0; /* Number of hosts allocated */
141typedef uint32_t ecm_db_host_hash_t;
142
143/*
144 * Node hash table
145 */
146#define ECM_DB_NODE_HASH_SLOTS 32768
147static struct ecm_db_node_instance *ecm_db_node_table[ECM_DB_NODE_HASH_SLOTS];
148 /* Slots of the node hash table */
149static int ecm_db_node_table_lengths[ECM_DB_NODE_HASH_SLOTS];
150 /* Tracks how long each chain is */
151static int ecm_db_node_count = 0; /* Number of nodes allocated */
152typedef uint32_t ecm_db_node_hash_t;
153
154/*
155 * Interface hash table
156 */
157#define ECM_DB_IFACE_HASH_SLOTS 8
158static struct ecm_db_iface_instance *ecm_db_iface_table[ECM_DB_IFACE_HASH_SLOTS];
159 /* Slots of the interface hash table */
160static int ecm_db_iface_table_lengths[ECM_DB_IFACE_HASH_SLOTS];
161 /* Tracks how long each chain is */
162static int ecm_db_iface_count = 0; /* Number of interfaces allocated */
163typedef uint32_t ecm_db_iface_hash_t;
164
Murat Sezgin91c5d712015-06-12 15:16:22 -0700165#define ECM_DB_IFACE_ID_HASH_SLOTS 8
166static struct ecm_db_iface_instance *ecm_db_iface_id_table[ECM_DB_IFACE_ID_HASH_SLOTS];
167 /* Slots of the interface id hash table */
168static int ecm_db_iface_id_table_lengths[ECM_DB_IFACE_ID_HASH_SLOTS];
169 /* Tracks how long each chain is */
170typedef uint32_t ecm_db_iface_id_hash_t;
171
Ben Menchaca84f36632014-02-28 20:57:38 +0000172/*
173 * Listeners
174 */
175static int ecm_db_listeners_count = 0; /* Number of listeners allocated */
176static struct ecm_db_listener_instance *ecm_db_listeners = NULL;
177 /* Event listeners */
178
Gareth Williamsf98d4192015-03-11 16:55:41 +0000179#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000180/*
Gareth Williamsd5618a82015-05-20 11:13:32 +0100181 * ecm_db_iface_state_get_method_t
182 * Used to obtain interface state
Ben Menchaca84f36632014-02-28 20:57:38 +0000183 */
Gareth Williamsd5618a82015-05-20 11:13:32 +0100184typedef int (*ecm_db_iface_state_get_method_t)(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +0000185#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000186
187/*
188 * struct ecm_db_iface_instance
189 */
190struct ecm_db_iface_instance {
191 struct ecm_db_iface_instance *next; /* Next instance in global list */
192 struct ecm_db_iface_instance *prev; /* Previous instance in global list */
193 struct ecm_db_iface_instance *hash_next; /* Next Interface in the chain of Interfaces */
194 struct ecm_db_iface_instance *hash_prev; /* previous Interface in the chain of Interfaces */
195 ecm_db_iface_type_t type; /* RO: Type of interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000196 uint32_t time_added; /* RO: DB time stamp when the Interface was added into the database */
197
198 int32_t interface_identifier; /* RO: The operating system dependent identifier of this interface */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700199 int32_t ae_interface_identifier; /* RO: The accel engine identifier of this interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000200 char name[IFNAMSIZ]; /* Name of interface */
201 int32_t mtu; /* Interface MTU */
202
Murat Sezgin91c5d712015-06-12 15:16:22 -0700203 struct ecm_db_iface_instance *iface_id_hash_next; /* Next interface in the chain of interface id table */
204 struct ecm_db_iface_instance *iface_id_hash_prev; /* Previous interface in the chain of interface id table */
205 ecm_db_iface_id_hash_t iface_id_hash_index; /* Hash index value of chains */
206
Gareth Williams85331c92015-03-11 20:39:18 +0000207#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000208 uint64_t from_data_total; /* Total of data sent by this Interface */
209 uint64_t to_data_total; /* Total of data sent to this Interface */
210 uint64_t from_packet_total; /* Total of packets sent by this Interface */
211 uint64_t to_packet_total; /* Total of packets sent to this Interface */
212 uint64_t from_data_total_dropped;
213 uint64_t to_data_total_dropped;
214 uint64_t from_packet_total_dropped;
215 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000216#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000217
Gareth Williamsb5903892015-03-20 15:13:07 +0000218#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000219 /*
220 * For convenience interfaces keep lists of connections that have been established
221 * from them and to them.
222 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
223 * Interfaces keep this information for rapid iteration of connections e.g. when an interface 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700224 * can defunct all associated connections or destroy any accel engine rules.
Ben Menchaca84f36632014-02-28 20:57:38 +0000225 */
226 struct ecm_db_connection_instance *from_connections; /* list of connections made from this interface */
227 struct ecm_db_connection_instance *to_connections; /* list of connections made to this interface */
228
229 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this interface */
230 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this interface */
231
232 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000233 * Normally only the node refers to the interfaces which it is reachable upon.
234 * The interface also keeps a list of all nodes that can be reached.
235 */
236 struct ecm_db_node_instance *nodes; /* Nodes associated with this Interface */
237 int node_count; /* Number of Nodes in the nodes list */
238#endif
239
240 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000241 * Interface specific information.
242 * type identifies which information is applicable.
243 */
244 union {
245 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700246#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000247 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700248#endif
Murat Sezgin910c9662015-03-11 16:15:06 -0700249#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000250 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
Murat Sezgin910c9662015-03-11 16:15:06 -0700251#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000252 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530253#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000254 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
Murat Sezginaad635c2015-03-06 16:11:41 -0800255#endif
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530256#ifdef ECM_INTERFACE_L2TPV2_ENABLE
257 struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2; /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
258#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000259 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
260 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
Murat Sezgin69a27532015-03-12 14:09:40 -0700261#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000262 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
Murat Sezgin69a27532015-03-12 14:09:40 -0700263#endif
Murat Sezginbde55f92015-03-11 16:44:11 -0700264#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000265 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT (6-in-4) */
Murat Sezginbde55f92015-03-11 16:44:11 -0700266#endif
Murat Sezginc1402562015-03-12 12:32:20 -0700267#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +0000268#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000269 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 (IPIP v6 Tunnel i.e. TUNNEL6) */
Murat Sezginc1402562015-03-12 12:32:20 -0700270#endif
Gareth Williams8ac34292015-03-17 14:06:58 +0000271#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000272 } type_info;
273
Gareth Williamsf98d4192015-03-11 16:55:41 +0000274#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +0100275 ecm_db_iface_state_get_method_t state_get; /* Type specific method to return state */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000276#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000277
278 ecm_db_iface_final_callback_t final; /* Callback to owner when object is destroyed */
279 void *arg; /* Argument returned to owner in callbacks */
280 uint32_t flags;
281 int refs; /* Integer to trap we never go negative */
282 ecm_db_iface_hash_t hash_index;
283#if (DEBUG_LEVEL > 0)
284 uint16_t magic;
285#endif
286};
287
288/*
289 * Interface flags
290 */
291#define ECM_DB_IFACE_FLAGS_INSERTED 1 /* Interface is inserted into connection database tables */
292
293/*
294 * struct ecm_db_node_instance
295 */
296struct ecm_db_node_instance {
297 struct ecm_db_node_instance *next; /* Next instance in global list */
298 struct ecm_db_node_instance *prev; /* Previous instance in global list */
Gareth Williams90f2a282014-08-27 15:56:25 +0100299 struct ecm_db_node_instance *hash_next; /* Next node in the chain of nodes */
300 struct ecm_db_node_instance *hash_prev; /* previous node in the chain of nodes */
Ben Menchaca84f36632014-02-28 20:57:38 +0000301 uint8_t address[ETH_ALEN]; /* RO: MAC Address of this node */
Gareth Williams90f2a282014-08-27 15:56:25 +0100302
Gareth Williamsb5903892015-03-20 15:13:07 +0000303#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +0100304 /*
305 * For convenience nodes keep lists of connections that have been established from them and to them.
306 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
307 * Nodes keep this information for rapid iteration of connections e.g. when a node 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700308 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williams90f2a282014-08-27 15:56:25 +0100309 */
310 struct ecm_db_connection_instance *from_connections; /* list of connections made from this node */
311 struct ecm_db_connection_instance *to_connections; /* list of connections made to this node */
312 int from_connections_count; /* Number of connections in the from_connections list */
313 int to_connections_count; /* Number of connections in the to_connections list */
314
315 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this node */
316 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this node */
317 int from_nat_connections_count; /* Number of connections in the from_nat_connections list */
318 int to_nat_connections_count; /* Number of connections in the to_nat_connections list */
319
Gareth Williamsb5903892015-03-20 15:13:07 +0000320 /*
321 * Nodes reachable from an interface are stored in a linked list maintained by that interface.
322 * This is so, given an interface, you can examine all nodes reachable from it.
323 */
324 struct ecm_db_node_instance *node_next; /* The next node within the same iface nodes list */
325 struct ecm_db_node_instance *node_prev; /* The previous node within the same iface nodes list */
326#endif
327
Ben Menchaca84f36632014-02-28 20:57:38 +0000328 uint32_t time_added; /* RO: DB time stamp when the node was added into the database */
329
Gareth Williams85331c92015-03-11 20:39:18 +0000330#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000331 uint64_t from_data_total; /* Total of data sent by this node */
332 uint64_t to_data_total; /* Total of data sent to this node */
333 uint64_t from_packet_total; /* Total of packets sent by this node */
334 uint64_t to_packet_total; /* Total of packets sent to this node */
335 uint64_t from_data_total_dropped;
336 uint64_t to_data_total_dropped;
337 uint64_t from_packet_total_dropped;
338 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000339#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000340
341 struct ecm_db_iface_instance *iface; /* The interface to which this node relates */
Ben Menchaca84f36632014-02-28 20:57:38 +0000342
343 ecm_db_node_final_callback_t final; /* Callback to owner when object is destroyed */
344 void *arg; /* Argument returned to owner in callbacks */
345 uint8_t flags;
346 int refs; /* Integer to trap we never go negative */
347 ecm_db_node_hash_t hash_index;
348#if (DEBUG_LEVEL > 0)
349 uint16_t magic;
350#endif
351};
352
353/*
354 * Node flags
355 */
356#define ECM_DB_NODE_FLAGS_INSERTED 1 /* Node is inserted into connection database tables */
357
358/*
359 * struct ecm_db_host_instance
360 */
361struct ecm_db_host_instance {
362 struct ecm_db_host_instance *next; /* Next instance in global list */
363 struct ecm_db_host_instance *prev; /* Previous instance in global list */
364 struct ecm_db_host_instance *hash_next; /* Next host in the chain of hosts */
365 struct ecm_db_host_instance *hash_prev; /* previous host in the chain of hosts */
366 ip_addr_t address; /* RO: IPv4/v6 Address of this host */
367 bool on_link; /* RO: false when this host is reached via a gateway */
Gareth Williamsb5903892015-03-20 15:13:07 +0000368 uint32_t time_added; /* RO: DB time stamp when the host was added into the database */
369
370#ifdef ECM_DB_XREF_ENABLE
371 /*
372 * Normally the mapping refers to the host it requires.
373 * However the host also keeps a list of all mappings that are associated with it.
374 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000375 struct ecm_db_mapping_instance *mappings; /* Mappings made on this host */
376 int mapping_count; /* Number of mappings in the mapping list */
Gareth Williamsb5903892015-03-20 15:13:07 +0000377#endif
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530378
Gareth Williams85331c92015-03-11 20:39:18 +0000379#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000380 uint64_t from_data_total; /* Total of data sent by this host */
381 uint64_t to_data_total; /* Total of data sent to this host */
382 uint64_t from_packet_total; /* Total of packets sent by this host */
383 uint64_t to_packet_total; /* Total of packets sent to this host */
384 uint64_t from_data_total_dropped;
385 uint64_t to_data_total_dropped;
386 uint64_t from_packet_total_dropped;
387 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000388#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000389
390 ecm_db_host_final_callback_t final; /* Callback to owner when object is destroyed */
391 void *arg; /* Argument returned to owner in callbacks */
392 uint32_t flags;
393 int refs; /* Integer to trap we never go negative */
394 ecm_db_host_hash_t hash_index;
395#if (DEBUG_LEVEL > 0)
396 uint16_t magic;
397#endif
398};
399
400/*
401 * Host flags
402 */
403#define ECM_DB_HOST_FLAGS_INSERTED 1 /* Host is inserted into connection database tables */
404
405/*
406 * struct ecm_db_mapping_instance
407 */
408struct ecm_db_mapping_instance {
409 struct ecm_db_mapping_instance *next; /* Next instance in global list */
410 struct ecm_db_mapping_instance *prev; /* Previous instance in global list */
411
412 struct ecm_db_mapping_instance *hash_next; /* Next mapping in the chain of mappings */
413 struct ecm_db_mapping_instance *hash_prev; /* previous mapping in the chain of mappings */
414
415 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
416 struct ecm_db_host_instance *host; /* The host to which this mapping relates */
417 int port; /* RO: The port number on the host - only applicable for mapping protocols that are port based */
Ben Menchaca84f36632014-02-28 20:57:38 +0000418
Gareth Williamsb5903892015-03-20 15:13:07 +0000419#ifdef ECM_DB_XREF_ENABLE
420 /*
421 * For convenience mappings keep lists of connections that have been established from them and to them.
422 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
423 * Mappings keep this information for rapid iteration of connections e.g. given a mapping we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700424 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williamsb5903892015-03-20 15:13:07 +0000425 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000426 struct ecm_db_connection_instance *from_connections; /* list of connections made from this host mapping */
427 struct ecm_db_connection_instance *to_connections; /* list of connections made to this host mapping */
428
429 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this host mapping */
430 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this host mapping */
431
432 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000433 * While a mapping refers to the host it requires.
434 * The host also keeps a list of all mappings that are associated with it, this is that list linkage.
435 */
436 struct ecm_db_mapping_instance *mapping_next; /* Next mapping in the list of mappings for the host */
437 struct ecm_db_mapping_instance *mapping_prev; /* previous mapping in the list of mappings for the host */
438#endif
439
440 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000441 * Connection counts
442 */
443 int tcp_from;
444 int tcp_to;
445 int udp_from;
446 int udp_to;
447 int tcp_nat_from;
448 int tcp_nat_to;
449 int udp_nat_from;
450 int udp_nat_to;
451
452 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000453 * Connection counts
Ben Menchaca84f36632014-02-28 20:57:38 +0000454 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000455 int from; /* Number of connections made from */
456 int to; /* Number of connections made to */
457 int nat_from; /* Number of connections made from (nat) */
458 int nat_to; /* Number of connections made to (nat) */
Ben Menchaca84f36632014-02-28 20:57:38 +0000459
Gareth Williams85331c92015-03-11 20:39:18 +0000460#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000461 /*
462 * Data totals
463 */
464 uint64_t from_data_total; /* Total of data sent by this mapping */
465 uint64_t to_data_total; /* Total of data sent to this mapping */
466 uint64_t from_packet_total; /* Total of packets sent by this mapping */
467 uint64_t to_packet_total; /* Total of packets sent to this mapping */
468 uint64_t from_data_total_dropped;
469 uint64_t to_data_total_dropped;
470 uint64_t from_packet_total_dropped;
471 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000472#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000473
474 ecm_db_mapping_final_callback_t final; /* Callback to owner when object is destroyed */
475 void *arg; /* Argument returned to owner in callbacks */
476 uint32_t flags;
477 int refs; /* Integer to trap we never go negative */
478 ecm_db_mapping_hash_t hash_index;
479#if (DEBUG_LEVEL > 0)
480 uint16_t magic;
481#endif
482};
483
484/*
485 * Mapping flags
486 */
487#define ECM_DB_MAPPING_FLAGS_INSERTED 1 /* Mapping is inserted into connection database tables */
488
489/*
490 * struct ecm_db_timer_group
491 * A timer group - all group members within the same group have the same TTL reset value.
492 *
493 * Expiry of entries occurs from tail to head.
494 */
495struct ecm_db_timer_group {
496 struct ecm_db_timer_group_entry *head; /* Most recently used entry in this timer group */
497 struct ecm_db_timer_group_entry *tail; /* Least recently used entry in this timer group. */
498 uint32_t time; /* Time in seconds a group entry will be given to live when 'touched' */
499 ecm_db_timer_group_t tg; /* RO: The group id */
500#if (DEBUG_LEVEL > 0)
501 uint16_t magic;
502#endif
503};
504
505/*
506 * Timers and cleanup
507 */
508static uint32_t ecm_db_time = 0; /* Time in seconds since start */
509static struct ecm_db_timer_group ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_MAX];
510 /* Timer groups */
511static struct timer_list ecm_db_timer; /* Timer to drive timer groups */
512
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000513#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000514/*
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000515 * Classifier TYPE assignment lists.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100516 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000517 * For each type of classifier a list is kept of all connections assigned a classifier of that type.
518 * This permits a classifier type to rapidly retrieve all connections with classifiers assigned to it of that type.
519 *
520 * NOTE: This is in addition to the basic functionality whereby a connection keeps a list of classifier instances
521 * that are assigned to it in descending order of priority.
522 */
523
524/*
525 * struct ecm_db_connection_classifier_type_assignment
526 * List linkage
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100527 */
528struct ecm_db_connection_classifier_type_assignment {
529 struct ecm_db_connection_instance *next; /* Next connection assigned to a classifier of this type */
530 struct ecm_db_connection_instance *prev; /* Previous connection assigned to a classifier of this type */
531 int iteration_count; /* >0 if something is examining this list entry and it may not be unlinked. The connection will persist. */
532 bool pending_unassign; /* True when the connection has been unassigned from the type, when iteration_count drops to 0 it may be removed from the list */
533#if (DEBUG_LEVEL > 0)
534 uint16_t magic;
535#endif
536};
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000537
538/*
539 * struct ecm_db_connection_classifier_type_assignment_list
540 * A list, one for each classifier type.
541 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100542struct ecm_db_connection_classifier_type_assignment_list {
543 struct ecm_db_connection_instance *type_assignments_list;
544 /* Lists of connections assigned to this type of classifier */
545 int32_t type_assignment_count; /* Number of connections in the list */
546} ecm_db_connection_classifier_type_assignments[ECM_CLASSIFIER_TYPES];
547 /* Each classifier type has a list of connections that are assigned to classifier instances of that type */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000548#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100549
550/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000551 * struct ecm_db_connection_instance
552 */
553struct ecm_db_connection_instance {
554 struct ecm_db_connection_instance *next; /* Next instance in global list */
555 struct ecm_db_connection_instance *prev; /* Previous instance in global list */
556
557 struct ecm_db_connection_instance *hash_next; /* Next connection in chain */
558 struct ecm_db_connection_instance *hash_prev; /* Previous connection in chain */
559 ecm_db_connection_hash_t hash_index; /* The hash table slot whose chain of connections this is inserted into */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530560
Ben Menchaca84f36632014-02-28 20:57:38 +0000561 struct ecm_db_connection_instance *serial_hash_next; /* Next connection in serial hash chain */
562 struct ecm_db_connection_instance *serial_hash_prev; /* Previous connection in serial hash chain */
563 ecm_db_connection_hash_t serial_hash_index; /* The hash table slot whose chain of connections this is inserted into */
564
565 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
566
Gareth Williams3e5b37f2015-05-13 10:04:12 +0100567 int ip_version; /* RO: The version of IP protocol this connection was established for */
Ben Menchaca84f36632014-02-28 20:57:38 +0000568 int protocol; /* RO: Protocol of the connection */
569 ecm_db_direction_t direction; /* RO: 'Direction' of connection establishment. */
570 bool is_routed; /* RO: True when connection is routed, false when not */
571
572 /*
573 * Connection endpoint mapping
574 */
575 struct ecm_db_mapping_instance *mapping_from; /* The connection was established from this mapping */
576 struct ecm_db_mapping_instance *mapping_to; /* The connection was established to this mapping */
Ben Menchaca84f36632014-02-28 20:57:38 +0000577
578 /*
579 * Connection endpoint mapping for NAT purposes
580 * NOTE: For non-NAT connections these would be identical to the endpoint mappings.
581 */
582 struct ecm_db_mapping_instance *mapping_nat_from; /* The connection was established from this mapping */
583 struct ecm_db_mapping_instance *mapping_nat_to; /* The connection was established to this mapping */
Gareth Williamsb5903892015-03-20 15:13:07 +0000584
585 /*
586 * From / To Node (NAT and non-NAT).
587 * Connections keep references to the nodes upon which they operate.
588 * Gut feeling would tell us this is unusual since it should be the case that
589 * the HOST refer to the node, e.g. IP address to a MAC address.
590 * However there are some 'interesting' usage models where the same IP address may appear
591 * from different nodes / MAC addresses because of this the unique element here is the connection
592 * and so we record the node information directly here.
593 */
594 struct ecm_db_node_instance *from_node; /* Node from which this connection was established */
595 struct ecm_db_node_instance *to_node; /* Node to which this connection was established */
596 struct ecm_db_node_instance *from_nat_node; /* Node from which this connection was established */
597 struct ecm_db_node_instance *to_nat_node; /* Node to which this connection was established */
598
599#ifdef ECM_DB_XREF_ENABLE
600 /*
601 * The connection has references to the mappings (both nat and non-nat) as required above.
602 * Also mappings keep lists of connections made to/from them so that they may be iterated
603 * to determine associated connections in each direction/situation (e.g. "defuncting all connections made to/from a mapping").
604 */
605 struct ecm_db_connection_instance *from_next; /* Next connection made from the same mapping */
606 struct ecm_db_connection_instance *from_prev; /* Previous connection made from the same mapping */
607 struct ecm_db_connection_instance *to_next; /* Next connection made to the same mapping */
608 struct ecm_db_connection_instance *to_prev; /* Previous connection made to the same mapping */
609
Ben Menchaca84f36632014-02-28 20:57:38 +0000610 struct ecm_db_connection_instance *from_nat_next; /* Next connection made from the same mapping */
611 struct ecm_db_connection_instance *from_nat_prev; /* Previous connection made from the same mapping */
612 struct ecm_db_connection_instance *to_nat_next; /* Next connection made to the same mapping */
613 struct ecm_db_connection_instance *to_nat_prev; /* Previous connection made to the same mapping */
614
615 /*
616 * Connection endpoint interface
Gareth Williamsb5903892015-03-20 15:13:07 +0000617 * GGG TODO Deprecated - use interface lists instead.
618 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000619 */
620 struct ecm_db_connection_instance *iface_from_next; /* Next connection made from the same interface */
621 struct ecm_db_connection_instance *iface_from_prev; /* Previous connection made from the same interface */
622 struct ecm_db_connection_instance *iface_to_next; /* Next connection made to the same interface */
623 struct ecm_db_connection_instance *iface_to_prev; /* Previous connection made to the same interface */
624
625 /*
626 * Connection endpoint interface for NAT purposes
627 * NOTE: For non-NAT connections these would be identical to the endpoint interface.
Gareth Williamsb5903892015-03-20 15:13:07 +0000628 * GGG TODO Deprecated - use interface lists instead.
629 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000630 */
631 struct ecm_db_connection_instance *iface_from_nat_next; /* Next connection made from the same interface */
632 struct ecm_db_connection_instance *iface_from_nat_prev; /* Previous connection made from the same interface */
633 struct ecm_db_connection_instance *iface_to_nat_next; /* Next connection made to the same interface */
634 struct ecm_db_connection_instance *iface_to_nat_prev; /* Previous connection made to the same interface */
635
636 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000637 * As well as keeping a reference to the node which this connection uses the nodes
638 * also keep lists of connections made from/to them.
639 */
640 struct ecm_db_connection_instance *node_from_next; /* Next connection in the nodes from_connections list */
641 struct ecm_db_connection_instance *node_from_prev; /* Prev connection in the nodes from_connections list */
642 struct ecm_db_connection_instance *node_to_next; /* Next connection in the nodes to_connections list */
643 struct ecm_db_connection_instance *node_to_prev; /* Prev connection in the nodes to_connections list */
644
645 struct ecm_db_connection_instance *node_from_nat_next; /* Next connection in the nodes from_nat_connections list */
646 struct ecm_db_connection_instance *node_from_nat_prev; /* Prev connection in the nodes from_nat_connections list */
647 struct ecm_db_connection_instance *node_to_nat_next; /* Next connection in the nodes to_nat_connections list */
648 struct ecm_db_connection_instance *node_to_nat_prev; /* Prev connection in the nodes to_nat_connections list */
649#endif
650
651 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000652 * From / To interfaces list
653 */
654 struct ecm_db_iface_instance *from_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
655 /* The outermost to innnermost interface this connection is using in the from path.
656 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
657 */
658 int32_t from_interface_first; /* The index of the first interface in the list */
659 bool from_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
660 struct ecm_db_iface_instance *to_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
661 /* The outermost to innnermost interface this connection is using in the to path */
662 int32_t to_interface_first; /* The index of the first interface in the list */
663 bool to_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
664
665 /*
666 * From / To NAT interfaces list
Gareth Williams90f2a282014-08-27 15:56:25 +0100667 * GGG TODO Not sure if NAT interface lists are necessary or appropriate or practical.
668 * Needs to be assessed if it gives any clear benefit and possibly remove these if not.
Ben Menchaca84f36632014-02-28 20:57:38 +0000669 */
670 struct ecm_db_iface_instance *from_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
671 /* The outermost to innnermost interface this connection is using in the from path.
672 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
673 */
674 int32_t from_nat_interface_first; /* The index of the first interface in the list */
675 bool from_nat_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
676 struct ecm_db_iface_instance *to_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
677 /* The outermost to innnermost interface this connection is using in the to path */
678 int32_t to_nat_interface_first; /* The index of the first interface in the list */
679 bool to_nat_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
680
Shyam Sunder1f037262015-05-18 20:04:13 +0530681#ifdef ECM_MULTICAST_ENABLE
682 /*
683 * Destination Multicast interfaces list
684 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +0530685 struct ecm_db_iface_instance *to_mcast_interfaces;
686 /* The outermost to innnermost interfaces this connection is using in multicast path.
687 * The size of the buffer allocated for the to_mcast_interfaces heirarchies is as large as
688 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX. */
Shyam Sunder1f037262015-05-18 20:04:13 +0530689 int32_t to_mcast_interface_first[ECM_DB_MULTICAST_IF_MAX];
690 /* The indexes of the first interfaces in the destinaiton interface list */
691 struct ecm_db_multicast_tuple_instance *ti; /* Multicast Connection instance */
692 bool to_mcast_interfaces_set; /* Flag to indicate if the destination interface list is currently empty or not */
693#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000694 /*
695 * Time values in seconds
696 */
697 struct ecm_db_timer_group_entry defunct_timer; /* Used to defunct the connection on inactivity */
698
699 /*
700 * Byte and packet counts
701 */
702 uint64_t from_data_total; /* Totals of data as sent by the 'from' side of this connection */
703 uint64_t to_data_total; /* Totals of data as sent by the 'to' side of this connection */
704 uint64_t from_packet_total; /* Totals of packets as sent by the 'from' side of this connection */
705 uint64_t to_packet_total; /* Totals of packets as sent by the 'to' side of this connection */
706 uint64_t from_data_total_dropped; /* Total data sent by the 'from' side that we purposely dropped - the 'to' side has not seen this data */
707 uint64_t to_data_total_dropped; /* Total data sent by the 'to' side that we purposely dropped - the 'from' side has not seen this data */
708 uint64_t from_packet_total_dropped; /* Total packets sent by the 'from' side that we purposely dropped - the 'to' side has not seen this data */
709 uint64_t to_packet_total_dropped; /* Total packets sent by the 'to' side that we purposely dropped - the 'from' side has not seen this data */
710
711 /*
712 * Classifiers attached to this connection
713 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000714 struct ecm_classifier_instance *assignments; /* A list of all classifiers that are still assigned to this connection.
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000715 * When a connection is created, one instance of every type of classifier is assigned to the connection.
Ben Menchaca84f36632014-02-28 20:57:38 +0000716 * Classifiers are added in ascending order of priority - so the most important processes a packet last.
717 * Classifiers may drop out of this list (become unassigned) at any time.
718 */
719 struct ecm_classifier_instance *assignments_by_type[ECM_CLASSIFIER_TYPES];
720 /* All assignments are also recorded in this array, since there can be only one of each type, this array allows
721 * rapid retrieval of a classifier type, saving having to iterate the assignments list.
722 */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000723
724#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100725 struct ecm_db_connection_classifier_type_assignment type_assignment[ECM_CLASSIFIER_TYPES];
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000726 /*
727 * Each classifier TYPE has a list of connections that are assigned to it.
728 * This permits a classifier TYPE to rapidly retrieve all connections associated with it.
729 */
730#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100731
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530732 /*
733 * Re-generation.
734 * When system or classifier state changes, affected connections may need to have their state re-generated.
735 * This ensures that a connection does not continue to operate on stale state which could affect the sanity of acceleration rules.
736 * A connection needs to be re-generated when its regen_required is > 0.
737 * When a re-generation is completed successfully the counter is decremented.
738 * The counter ensures that any further changes of state while re-generation is under way is not missed.
739 * While a connection needs re-generation (regen_required > 0), acceleration should not be permitted.
740 * It may not always be practical to flag individual connections for re-generation (time consuming with large numbers of connections).
741 * The "generation" is a numerical counter comparison against the global "ecm_db_connection_generation".
742 * This ecm_db_connection_generation can be incremented causing a numerical difference between the connections counter and this global.
743 * This is enough to flag that a re-generation is needed.
744 * Further, it is possible that re-generation may be required DURING a rule construction. Since constructing a rule
745 * can require lengthy non-atomic processes there needs to be a way to ensure that changes during construction of a rule are caught.
746 * The regen_occurances is a counter that is incremented whenever regen_required is also incremented.
747 * However it is never decremented. This permits the caller to obtain this count before a non-atomic procedure and then afterwards.
748 * If there is any change in the counter value there is a change of generation! And the operation should be aborted.
749 */
750 bool regen_in_progress; /* The connection is under regeneration right now and is used to provide atomic re-generation in SMP */
751 uint16_t regen_required; /* The connection needs to be re-generated when > 0 */
752 uint16_t regen_occurances; /* Total number of regens required */
753 uint16_t generation; /* Used to detect when a re-evaluation of this connection is necessary by comparing with ecm_db_connection_generation */
754 uint32_t regen_success; /* Tracks how many times re-generation was successfully completed */
755 uint32_t regen_fail; /* Tracks how many times re-generation failed */
756
Ben Menchaca84f36632014-02-28 20:57:38 +0000757 struct ecm_front_end_connection_instance *feci; /* Front end instance specific to this connection */
758
Murat Sezgin7f6cdf62014-09-11 13:41:06 -0700759 ecm_db_connection_defunct_callback_t defunct; /* Callback to be called when connection has become defunct */
Ben Menchaca84f36632014-02-28 20:57:38 +0000760 ecm_db_connection_final_callback_t final; /* Callback to owner when object is destroyed */
761 void *arg; /* Argument returned to owner in callbacks */
762
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100763 uint32_t serial; /* RO: Serial number for the connection - unique for run lifetime */
Ben Menchaca84f36632014-02-28 20:57:38 +0000764 uint32_t flags;
765 int refs; /* Integer to trap we never go negative */
766#if (DEBUG_LEVEL > 0)
767 uint16_t magic;
768#endif
769};
770
771/*
772 * Connection flags
773 */
774#define ECM_DB_CONNECTION_FLAGS_INSERTED 1 /* Connection is inserted into connection database tables */
775
776/*
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530777 * struct ecm_db_listener_instance
Ben Menchaca84f36632014-02-28 20:57:38 +0000778 * listener instances
779 */
780struct ecm_db_listener_instance {
781 struct ecm_db_listener_instance *next;
782 struct ecm_db_listener_instance *event_next;
783 uint32_t flags;
784 void *arg;
785 int refs; /* Integer to trap we never go negative */
786 ecm_db_mapping_final_callback_t final; /* Final callback for this instance */
787
788 ecm_db_iface_listener_added_callback_t iface_added;
789 ecm_db_iface_listener_removed_callback_t iface_removed;
790 ecm_db_node_listener_added_callback_t node_added;
791 ecm_db_node_listener_removed_callback_t node_removed;
792 ecm_db_host_listener_added_callback_t host_added;
793 ecm_db_host_listener_removed_callback_t host_removed;
794 ecm_db_mapping_listener_added_callback_t mapping_added;
795 ecm_db_mapping_listener_removed_callback_t mapping_removed;
796 ecm_db_connection_listener_added_callback_t connection_added;
797 ecm_db_connection_listener_removed_callback_t connection_removed;
798#if (DEBUG_LEVEL > 0)
799 uint16_t magic;
800#endif
801};
802
803/*
804 * Listener flags
805 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000806#define ECM_DB_LISTENER_FLAGS_INSERTED 1 /* Is inserted into database */
Ben Menchaca84f36632014-02-28 20:57:38 +0000807
Shyam Sunder1f037262015-05-18 20:04:13 +0530808#ifdef ECM_MULTICAST_ENABLE
809/*
810 * struct ecm_db_multicast_tuple_instance
811 * Tuple information for an accelerated multicast connection.
812 * This tuple information is further used to find an attached
813 * connection for the multicast flow.
814 */
815struct ecm_db_multicast_tuple_instance {
816 struct ecm_db_multicast_tuple_instance *next; /* Next instance in global list */
817 struct ecm_db_multicast_tuple_instance *prev; /* Previous instance in global list */
Shyam Sunder3af86a52015-08-28 18:04:10 +0530818 struct ecm_db_connection_instance *ci; /* Pointer to the DB Connection Instance */
Shyam Sunder1f037262015-05-18 20:04:13 +0530819 uint16_t src_port; /* RO: IPv4/v6 Source Port */
820 uint16_t dst_port; /* RO: IPv4/v6 Destination Port */
821 ip_addr_t src_ip; /* RO: IPv4/v6 Source Address */
822 ip_addr_t grp_ip; /* RO: IPv4/v6 Multicast Group Address */
823 uint32_t flags; /* Flags for this instance node */
824 uint32_t hash_index; /* Hash index of this node */
825 int proto; /* RO: Protocol */
826 int refs; /* Integer to trap we never go negative */
827#if (DEBUG_LEVEL > 0)
828 uint16_t magic; /* Magic value for debug */
829#endif
830};
831
832#define ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS 16
833typedef uint32_t ecm_db_multicast_tuple_instance_hash_t;
834
835/*
836 * Multicast connection tuple table
837 * This table is used to lookup a complete tuple for multicast connections
838 * using the multicast group address
839 */
840static struct ecm_db_multicast_tuple_instance *ecm_db_multicast_tuple_instance_table[ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS];
841#endif
842
Ben Menchaca84f36632014-02-28 20:57:38 +0000843/*
844 * Simple stats
845 */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000846#define ECM_DB_PROTOCOL_COUNT 256
847static int ecm_db_connection_count_by_protocol[ECM_DB_PROTOCOL_COUNT]; /* Each IP protocol has its own count */
Ben Menchaca84f36632014-02-28 20:57:38 +0000848
849/*
850 * Locking of the database - concurrency control
851 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700852static DEFINE_SPINLOCK(ecm_db_lock); /* Protect the table from SMP access. */
Ben Menchaca84f36632014-02-28 20:57:38 +0000853
854/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530855 * Connection state validity
856 * This counter is incremented whenever a general change is detected which requires re-generation of state for ALL connections.
Ben Menchaca84f36632014-02-28 20:57:38 +0000857 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530858static uint16_t ecm_db_connection_generation = 0; /* Generation counter to detect when all connection state is considered stale and all must be re-generated */
Ben Menchaca84f36632014-02-28 20:57:38 +0000859
860/*
Murat Sezgin908ecb32015-05-10 20:54:36 -0700861 * Debugfs dentry object.
Ben Menchaca84f36632014-02-28 20:57:38 +0000862 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700863static struct dentry *ecm_db_dentry;
Ben Menchaca84f36632014-02-28 20:57:38 +0000864
865/*
866 * Management thread control
867 */
868static bool ecm_db_terminate_pending = false; /* When true the user has requested termination */
Ben Menchaca84f36632014-02-28 20:57:38 +0000869
870/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000871 * ecm_db_interface_type_names[]
872 * Array that maps the interface type to a string
873 */
874static char *ecm_db_interface_type_names[ECM_DB_IFACE_TYPE_COUNT] = {
875 "ETHERNET",
876 "PPPoE",
877 "LINK-AGGREGATION",
878 "VLAN",
879 "BRIDGE",
880 "LOOPBACK",
881 "IPSEC_TUNNEL",
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530882 "UNKNOWN",
Murat Sezginb3cc8792014-06-06 19:16:51 -0700883 "SIT",
884 "TUNIPIP6",
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530885 "PPPoL2TPV2"
Ben Menchaca84f36632014-02-28 20:57:38 +0000886};
887
888/*
Gareth Williams54d15d92015-04-24 19:28:27 +0100889 * Random seed used during hash calculations
890 */
891static uint32_t ecm_db_jhash_rnd __read_mostly;
892
893/*
Gareth Williamsf28ba5f2015-02-13 11:07:28 +0000894 * ecm_db_connection_count_get()
895 * Return the connection count
896 */
897int ecm_db_connection_count_get(void)
898{
899 int count;
900
901 spin_lock_bh(&ecm_db_lock);
902 count = ecm_db_connection_count;
903 spin_unlock_bh(&ecm_db_lock);
904 return count;
905}
906EXPORT_SYMBOL(ecm_db_connection_count_get);
907
908/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000909 * ecm_db_interface_type_to_string()
910 * Return a string buffer containing the type name of the interface
911 */
912char *ecm_db_interface_type_to_string(ecm_db_iface_type_t type)
913{
914 DEBUG_ASSERT((type >= 0) && (type < ECM_DB_IFACE_TYPE_COUNT), "Invalid type: %d\n", type);
915 return ecm_db_interface_type_names[(int)type];
916}
917EXPORT_SYMBOL(ecm_db_interface_type_to_string);
918
919/*
Gareth Williamsf98d4192015-03-11 16:55:41 +0000920 * ecm_db_connection_count_by_protocol_get()
921 * Return # connections for the given protocol
922 */
923int ecm_db_connection_count_by_protocol_get(int protocol)
924{
925 int count;
926
927 DEBUG_ASSERT((protocol >= 0) && (protocol < ECM_DB_PROTOCOL_COUNT), "Bad protocol: %d\n", protocol);
928 spin_lock_bh(&ecm_db_lock);
929 count = ecm_db_connection_count_by_protocol[protocol];
930 spin_unlock_bh(&ecm_db_lock);
931 return count;
932}
933EXPORT_SYMBOL(ecm_db_connection_count_by_protocol_get);
934
935/*
Murat Sezgin91c5d712015-06-12 15:16:22 -0700936 * ecm_db_iface_ae_interface_identifier_get()
937 * Return the accel engine interface number of this ecm interface
Ben Menchaca84f36632014-02-28 20:57:38 +0000938 */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700939int32_t ecm_db_iface_ae_interface_identifier_get(struct ecm_db_iface_instance *ii)
Ben Menchaca84f36632014-02-28 20:57:38 +0000940{
941 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
Murat Sezgin91c5d712015-06-12 15:16:22 -0700942 return ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +0000943}
Murat Sezgin91c5d712015-06-12 15:16:22 -0700944EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_get);
Ben Menchaca84f36632014-02-28 20:57:38 +0000945
946/*
Kiran Kumar C. S. K451b62e2014-05-19 20:34:06 +0530947 * ecm_db_iface_interface_identifier_get()
948 * Return the interface number of this ecm interface
949 */
950int32_t ecm_db_iface_interface_identifier_get(struct ecm_db_iface_instance *ii)
951{
952 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
953 return ii->interface_identifier;
954}
955EXPORT_SYMBOL(ecm_db_iface_interface_identifier_get);
956
957/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000958 * ecm_db_iface_mtu_reset()
959 * Reset the mtu
960 */
961int32_t ecm_db_iface_mtu_reset(struct ecm_db_iface_instance *ii, int32_t mtu)
962{
963 int32_t mtu_old;
964 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
965 spin_lock_bh(&ecm_db_lock);
966 mtu_old = ii->mtu;
967 ii->mtu = mtu;
968 spin_unlock_bh(&ecm_db_lock);
969 DEBUG_INFO("%p: Mtu change from %d to %d\n", ii, mtu_old, mtu);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530970
Ben Menchaca84f36632014-02-28 20:57:38 +0000971 return mtu_old;
972}
973EXPORT_SYMBOL(ecm_db_iface_mtu_reset);
974
975/*
976 * ecm_db_connection_front_end_get_and_ref()
977 * Return ref to the front end instance of the connection
978 */
979struct ecm_front_end_connection_instance *ecm_db_connection_front_end_get_and_ref(struct ecm_db_connection_instance *ci)
980{
981 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
982 ci->feci->ref(ci->feci);
983 return ci->feci;
984}
985EXPORT_SYMBOL(ecm_db_connection_front_end_get_and_ref);
986
987/*
988 * ecm_db_connection_defunct_callback()
989 * Invoked by the expiration of the defunct_timer contained in a connection instance
990 */
991static void ecm_db_connection_defunct_callback(void *arg)
992{
993 struct ecm_db_connection_instance *ci = (struct ecm_db_connection_instance *)arg;
994 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
995
996 DEBUG_INFO("%p: defunct timer expired\n", ci);
Gareth Williams2bfb0b82015-01-15 16:31:15 +0000997
998 if (ci->defunct) {
999 ci->defunct(ci->feci);
1000 }
1001
Ben Menchaca84f36632014-02-28 20:57:38 +00001002 ecm_db_connection_deref(ci);
1003}
1004
1005/*
1006 * ecm_db_connection_defunct_timer_reset()
1007 * Set/change the timer group associated with a connection. Returns false if the connection has become defunct and the new group cannot be set for that reason.
1008 */
1009bool ecm_db_connection_defunct_timer_reset(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg)
1010{
1011 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1012 return ecm_db_timer_group_entry_reset(&ci->defunct_timer, tg);
1013}
1014EXPORT_SYMBOL(ecm_db_connection_defunct_timer_reset);
1015
1016/*
1017 * ecm_db_connection_defunct_timer_touch()
1018 * Update the connections defunct timer to stop it timing out. Returns false if the connection defunct timer has expired.
1019 */
1020bool ecm_db_connection_defunct_timer_touch(struct ecm_db_connection_instance *ci)
1021{
1022 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1023 return ecm_db_timer_group_entry_touch(&ci->defunct_timer);
1024}
1025EXPORT_SYMBOL(ecm_db_connection_defunct_timer_touch);
1026
1027/*
1028 * ecm_db_connection_timer_group_get()
1029 * Return the timer group id
1030 */
1031ecm_db_timer_group_t ecm_db_connection_timer_group_get(struct ecm_db_connection_instance *ci)
1032{
1033 ecm_db_timer_group_t tg;
1034 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1035
1036 spin_lock_bh(&ecm_db_lock);
1037 tg = ci->defunct_timer.group;
1038 spin_unlock_bh(&ecm_db_lock);
1039 return tg;
1040}
1041EXPORT_SYMBOL(ecm_db_connection_timer_group_get);
1042
1043/*
1044 * ecm_db_connection_make_defunct()
1045 * Make connection defunct.
1046 */
1047void ecm_db_connection_make_defunct(struct ecm_db_connection_instance *ci)
1048{
1049 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07001050
1051 if (ci->defunct) {
1052 ci->defunct(ci->feci);
1053 }
1054
Ben Menchaca84f36632014-02-28 20:57:38 +00001055 if (ecm_db_timer_group_entry_remove(&ci->defunct_timer)) {
1056 ecm_db_connection_deref(ci);
1057 }
1058}
1059EXPORT_SYMBOL(ecm_db_connection_make_defunct);
1060
1061/*
1062 * ecm_db_connection_data_totals_update()
1063 * Update the total data (and packets) sent/received by the given host
1064 */
1065void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1066{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001067 int32_t i;
1068
Ben Menchaca84f36632014-02-28 20:57:38 +00001069 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1070
1071 spin_lock_bh(&ecm_db_lock);
1072
1073 if (is_from) {
1074 /*
1075 * Update totals sent by the FROM side of connection
1076 */
1077 ci->from_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001078 ci->from_packet_total += packets;
1079#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001080 ci->mapping_from->from_data_total += size;
1081 ci->mapping_from->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001082 ci->from_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001083 ci->mapping_from->from_packet_total += packets;
1084 ci->mapping_from->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001085 ci->from_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001086
1087 /*
1088 * Data from the host is essentially TO the interface on which the host is reachable
1089 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001090 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1091 ci->from_interfaces[i]->to_data_total += size;
1092 ci->from_interfaces[i]->to_packet_total += packets;
1093 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001094
1095 /*
1096 * Update totals sent TO the other side of the connection
1097 */
1098 ci->mapping_to->to_data_total += size;
1099 ci->mapping_to->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001100 ci->to_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001101 ci->mapping_to->to_packet_total += packets;
1102 ci->mapping_to->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001103 ci->to_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001104
1105 /*
1106 * Sending to the other side means FROM the interface we reach that host
1107 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001108 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1109 ci->to_interfaces[i]->from_data_total += size;
1110 ci->to_interfaces[i]->from_packet_total += packets;
1111 }
Gareth Williams85331c92015-03-11 20:39:18 +00001112#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001113 spin_unlock_bh(&ecm_db_lock);
1114 return;
1115 }
1116
1117 /*
1118 * Update totals sent by the TO side of this connection
1119 */
1120 ci->to_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001121 ci->to_packet_total += packets;
1122#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001123 ci->mapping_to->from_data_total += size;
1124 ci->mapping_to->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001125 ci->to_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001126 ci->mapping_to->from_packet_total += packets;
1127 ci->mapping_to->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001128 ci->to_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001129
1130 /*
1131 * Data from the host is essentially TO the interface on which the host is reachable
1132 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001133 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1134 ci->to_interfaces[i]->to_data_total += size;
1135 ci->to_interfaces[i]->to_packet_total += packets;
1136 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001137
1138 /*
1139 * Update totals sent TO the other side of the connection
1140 */
1141 ci->mapping_from->to_data_total += size;
1142 ci->mapping_from->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001143 ci->from_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001144 ci->mapping_from->to_packet_total += packets;
1145 ci->mapping_from->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001146 ci->from_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001147
1148 /*
1149 * Sending to the other side means FROM the interface we reach that host
1150 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001151 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1152 ci->from_interfaces[i]->from_data_total += size;
1153 ci->from_interfaces[i]->from_packet_total += packets;
1154 }
Gareth Williams85331c92015-03-11 20:39:18 +00001155#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001156 spin_unlock_bh(&ecm_db_lock);
1157}
1158EXPORT_SYMBOL(ecm_db_connection_data_totals_update);
1159
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301160#ifdef ECM_MULTICAST_ENABLE
1161/*
1162 * ecm_db_multicast_connection_data_totals_update()
1163 * Update the total bytes and packets sent/received by the multicast connection
1164 * TODO: This function is almost similar to unicast connection_data_totals_update() except few
1165 * lines of code. The next merge should have a common logic for both unicast and multicast.
1166 */
1167void ecm_db_multicast_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1168{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001169 int32_t i;
1170
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301171 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1172
1173 spin_lock_bh(&ecm_db_lock);
1174
1175 if (is_from) {
1176 /*
1177 * Update totals sent by the FROM side of connection
1178 */
1179 ci->from_data_total += size;
1180 ci->from_packet_total += packets;
1181#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1182 ci->mapping_from->from_data_total += size;
1183 ci->mapping_from->host->from_data_total += size;
1184 ci->from_node->from_data_total += size;
1185 ci->mapping_from->from_packet_total += packets;
1186 ci->mapping_from->host->from_packet_total += packets;
1187 ci->from_node->from_packet_total += packets;
1188
1189 /*
1190 * Data from the host is essentially TO the interface on which the host is reachable
1191 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001192 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1193 ci->from_interfaces[i]->to_data_total += size;
1194 ci->from_interfaces[i]->to_packet_total += packets;
1195 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301196
1197 /*
1198 * Update totals sent TO the other side of the connection
1199 */
1200 ci->mapping_to->to_data_total += size;
1201 ci->mapping_to->host->to_data_total += size;
1202 ci->to_node->to_data_total += size;
1203 ci->mapping_to->to_packet_total += packets;
1204 ci->mapping_to->host->to_packet_total += packets;
1205 ci->to_node->to_packet_total += packets;
1206#endif
1207 spin_unlock_bh(&ecm_db_lock);
1208 return;
1209 }
1210
1211 /*
1212 * Update totals sent by the TO side of this connection
1213 */
1214 ci->to_data_total += size;
1215 ci->to_packet_total += packets;
1216#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1217 ci->mapping_to->from_data_total += size;
1218 ci->mapping_to->host->from_data_total += size;
1219 ci->to_node->from_data_total += size;
1220 ci->mapping_to->from_packet_total += packets;
1221 ci->mapping_to->host->from_packet_total += packets;
1222 ci->to_node->from_packet_total += packets;
1223
1224 /*
1225 * Update totals sent TO the other side of the connection
1226 */
1227 ci->mapping_from->to_data_total += size;
1228 ci->mapping_from->host->to_data_total += size;
1229 ci->from_node->to_data_total += size;
1230 ci->mapping_from->to_packet_total += packets;
1231 ci->mapping_from->host->to_packet_total += packets;
1232 ci->from_node->to_packet_total += packets;
1233
1234 /*
1235 * Sending to the other side means FROM the interface we reach that host
1236 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001237 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1238 ci->from_interfaces[i]->from_data_total += size;
1239 ci->from_interfaces[i]->from_packet_total += packets;
1240 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301241#endif
1242 spin_unlock_bh(&ecm_db_lock);
1243}
1244EXPORT_SYMBOL(ecm_db_multicast_connection_data_totals_update);
1245
1246/*
1247 * ecm_db_multicast_connection_interface_heirarchy_stats_update()
1248 * Traverse through the multicast destination interface heirarchy and update the stats (data and packets).
1249 */
1250void ecm_db_multicast_connection_interface_heirarchy_stats_update(struct ecm_db_connection_instance *ci, uint64_t size, uint64_t packets)
1251{
1252 struct ecm_db_iface_instance *to_mc_ifaces;
1253 struct ecm_db_iface_instance *ii;
1254 struct ecm_db_iface_instance **ifaces;
1255 struct ecm_db_iface_instance *ii_temp;
1256 int32_t *to_mc_ifaces_first;
1257 int heirarchy_index;
1258 int ret;
1259
1260 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &to_mc_ifaces, &to_mc_ifaces_first);
1261 if (ret == 0) {
1262 DEBUG_WARN("%p: no interfaces in to_multicast_interfaces list!\n", ci);
1263 return;
1264 }
1265
1266 spin_lock_bh(&ecm_db_lock);
1267 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
1268
1269 if (to_mc_ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
1270 ii_temp = ecm_db_multicast_if_heirarchy_get(to_mc_ifaces, heirarchy_index);
1271 ii_temp = ecm_db_multicast_if_instance_get_at_index(ii_temp, ECM_DB_IFACE_HEIRARCHY_MAX - 1);
1272 ifaces = (struct ecm_db_iface_instance **)ii_temp;
1273 ii = *ifaces;
1274 ii->to_data_total += size;
1275 ii->to_packet_total += packets;
1276 }
1277 }
1278 spin_unlock_bh(&ecm_db_lock);
1279
1280 ecm_db_multicast_connection_to_interfaces_deref_all(to_mc_ifaces, to_mc_ifaces_first);
1281}
1282EXPORT_SYMBOL(ecm_db_multicast_connection_interface_heirarchy_stats_update);
1283#endif
1284
Ben Menchaca84f36632014-02-28 20:57:38 +00001285/*
1286 * ecm_db_connection_data_totals_update_dropped()
1287 * Update the total data (and packets) sent by the given host but which we dropped
1288 */
1289void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1290{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001291 int32_t i;
1292
Ben Menchaca84f36632014-02-28 20:57:38 +00001293 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1294
1295 if (is_from) {
1296 /*
1297 * Update dropped totals sent by the FROM side
1298 */
1299 spin_lock_bh(&ecm_db_lock);
1300 ci->from_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001301 ci->from_packet_total_dropped += packets;
1302#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001303 ci->mapping_from->from_data_total_dropped += size;
1304 ci->mapping_from->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001305 ci->from_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001306 ci->mapping_from->from_packet_total_dropped += packets;
1307 ci->mapping_from->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001308 ci->from_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001309
1310 /*
1311 * Data from the host is essentially TO the interface on which the host is reachable
1312 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001313 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1314 ci->from_interfaces[i]->to_data_total_dropped += size;
1315 ci->from_interfaces[i]->to_packet_total_dropped += packets;
1316 }
Gareth Williams85331c92015-03-11 20:39:18 +00001317#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001318 spin_unlock_bh(&ecm_db_lock);
1319 return;
1320 }
1321
1322 /*
1323 * Update dropped totals sent by the TO side of this connection
1324 */
1325 spin_lock_bh(&ecm_db_lock);
1326 ci->to_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001327 ci->to_packet_total_dropped += packets;
1328#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001329 ci->mapping_to->from_data_total_dropped += size;
1330 ci->mapping_to->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001331 ci->to_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001332 ci->mapping_to->from_packet_total_dropped += packets;
1333 ci->mapping_to->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001334 ci->to_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001335
1336 /*
1337 * Data from the host is essentially TO the interface on which the host is reachable
1338 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001339 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1340 ci->to_interfaces[i]->to_data_total_dropped += size;
1341 ci->to_interfaces[i]->to_packet_total_dropped += packets;
1342 }
Gareth Williams85331c92015-03-11 20:39:18 +00001343#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001344 spin_unlock_bh(&ecm_db_lock);
1345}
1346EXPORT_SYMBOL(ecm_db_connection_data_totals_update_dropped);
1347
1348/*
1349 * ecm_db_connection_data_stats_get()
1350 * Return data stats for the instance
1351 */
1352void ecm_db_connection_data_stats_get(struct ecm_db_connection_instance *ci, uint64_t *from_data_total, uint64_t *to_data_total,
1353 uint64_t *from_packet_total, uint64_t *to_packet_total,
1354 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1355 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1356{
1357 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1358
1359 spin_lock_bh(&ecm_db_lock);
1360 if (from_data_total) {
1361 *from_data_total = ci->from_data_total;
1362 }
1363 if (to_data_total) {
1364 *to_data_total = ci->to_data_total;
1365 }
1366 if (from_packet_total) {
1367 *from_packet_total = ci->from_packet_total;
1368 }
1369 if (to_packet_total) {
1370 *to_packet_total = ci->to_packet_total;
1371 }
1372 if (from_data_total_dropped) {
1373 *from_data_total_dropped = ci->from_data_total_dropped;
1374 }
1375 if (to_data_total_dropped) {
1376 *to_data_total_dropped = ci->to_data_total_dropped;
1377 }
1378 if (from_packet_total_dropped) {
1379 *from_packet_total_dropped = ci->from_packet_total_dropped;
1380 }
1381 if (to_packet_total_dropped) {
1382 *to_packet_total_dropped = ci->to_packet_total_dropped;
1383 }
1384 spin_unlock_bh(&ecm_db_lock);
1385}
1386EXPORT_SYMBOL(ecm_db_connection_data_stats_get);
1387
Gareth Williams85331c92015-03-11 20:39:18 +00001388#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001389/*
1390 * ecm_db_mapping_data_stats_get()
1391 * Return data stats for the instance
1392 */
1393void ecm_db_mapping_data_stats_get(struct ecm_db_mapping_instance *mi, uint64_t *from_data_total, uint64_t *to_data_total,
1394 uint64_t *from_packet_total, uint64_t *to_packet_total,
1395 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1396 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1397{
1398 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1399 spin_lock_bh(&ecm_db_lock);
1400 if (from_data_total) {
1401 *from_data_total = mi->from_data_total;
1402 }
1403 if (to_data_total) {
1404 *to_data_total = mi->to_data_total;
1405 }
1406 if (from_packet_total) {
1407 *from_packet_total = mi->from_packet_total;
1408 }
1409 if (to_packet_total) {
1410 *to_packet_total = mi->to_packet_total;
1411 }
1412 if (from_data_total_dropped) {
1413 *from_data_total_dropped = mi->from_data_total_dropped;
1414 }
1415 if (to_data_total_dropped) {
1416 *to_data_total_dropped = mi->to_data_total_dropped;
1417 }
1418 if (from_packet_total_dropped) {
1419 *from_packet_total_dropped = mi->from_packet_total_dropped;
1420 }
1421 if (to_packet_total_dropped) {
1422 *to_packet_total_dropped = mi->to_packet_total_dropped;
1423 }
1424 spin_unlock_bh(&ecm_db_lock);
1425}
1426EXPORT_SYMBOL(ecm_db_mapping_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001427#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001428
Gareth Williams85331c92015-03-11 20:39:18 +00001429#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001430/*
1431 * ecm_db_host_data_stats_get()
1432 * Return data stats for the instance
1433 */
1434void ecm_db_host_data_stats_get(struct ecm_db_host_instance *hi, uint64_t *from_data_total, uint64_t *to_data_total,
1435 uint64_t *from_packet_total, uint64_t *to_packet_total,
1436 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1437 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1438{
1439 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1440 spin_lock_bh(&ecm_db_lock);
1441 if (from_data_total) {
1442 *from_data_total = hi->from_data_total;
1443 }
1444 if (to_data_total) {
1445 *to_data_total = hi->to_data_total;
1446 }
1447 if (from_packet_total) {
1448 *from_packet_total = hi->from_packet_total;
1449 }
1450 if (to_packet_total) {
1451 *to_packet_total = hi->to_packet_total;
1452 }
1453 if (from_data_total_dropped) {
1454 *from_data_total_dropped = hi->from_data_total_dropped;
1455 }
1456 if (to_data_total_dropped) {
1457 *to_data_total_dropped = hi->to_data_total_dropped;
1458 }
1459 if (from_packet_total_dropped) {
1460 *from_packet_total_dropped = hi->from_packet_total_dropped;
1461 }
1462 if (to_packet_total_dropped) {
1463 *to_packet_total_dropped = hi->to_packet_total_dropped;
1464 }
1465 spin_unlock_bh(&ecm_db_lock);
1466}
1467EXPORT_SYMBOL(ecm_db_host_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001468#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001469
Gareth Williams85331c92015-03-11 20:39:18 +00001470#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001471/*
1472 * ecm_db_node_data_stats_get()
1473 * Return data stats for the instance
1474 */
1475void ecm_db_node_data_stats_get(struct ecm_db_node_instance *ni, uint64_t *from_data_total, uint64_t *to_data_total,
1476 uint64_t *from_packet_total, uint64_t *to_packet_total,
1477 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1478 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1479{
1480 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1481 spin_lock_bh(&ecm_db_lock);
1482 if (from_data_total) {
1483 *from_data_total = ni->from_data_total;
1484 }
1485 if (to_data_total) {
1486 *to_data_total = ni->to_data_total;
1487 }
1488 if (from_packet_total) {
1489 *from_packet_total = ni->from_packet_total;
1490 }
1491 if (to_packet_total) {
1492 *to_packet_total = ni->to_packet_total;
1493 }
1494 if (from_data_total_dropped) {
1495 *from_data_total_dropped = ni->from_data_total_dropped;
1496 }
1497 if (to_data_total_dropped) {
1498 *to_data_total_dropped = ni->to_data_total_dropped;
1499 }
1500 if (from_packet_total_dropped) {
1501 *from_packet_total_dropped = ni->from_packet_total_dropped;
1502 }
1503 if (to_packet_total_dropped) {
1504 *to_packet_total_dropped = ni->to_packet_total_dropped;
1505 }
1506 spin_unlock_bh(&ecm_db_lock);
1507}
1508EXPORT_SYMBOL(ecm_db_node_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001509#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001510
Gareth Williams85331c92015-03-11 20:39:18 +00001511#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001512/*
1513 * ecm_db_iface_data_stats_get()
1514 * Return data stats for the instance
1515 */
1516void ecm_db_iface_data_stats_get(struct ecm_db_iface_instance *ii, uint64_t *from_data_total, uint64_t *to_data_total,
1517 uint64_t *from_packet_total, uint64_t *to_packet_total,
1518 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1519 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1520{
1521 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1522 spin_lock_bh(&ecm_db_lock);
1523 if (from_data_total) {
1524 *from_data_total = ii->from_data_total;
1525 }
1526 if (to_data_total) {
1527 *to_data_total = ii->to_data_total;
1528 }
1529 if (from_packet_total) {
1530 *from_packet_total = ii->from_packet_total;
1531 }
1532 if (to_packet_total) {
1533 *to_packet_total = ii->to_packet_total;
1534 }
1535 if (from_data_total_dropped) {
1536 *from_data_total_dropped = ii->from_data_total_dropped;
1537 }
1538 if (to_data_total_dropped) {
1539 *to_data_total_dropped = ii->to_data_total_dropped;
1540 }
1541 if (from_packet_total_dropped) {
1542 *from_packet_total_dropped = ii->from_packet_total_dropped;
1543 }
1544 if (to_packet_total_dropped) {
1545 *to_packet_total_dropped = ii->to_packet_total_dropped;
1546 }
1547 spin_unlock_bh(&ecm_db_lock);
1548}
1549EXPORT_SYMBOL(ecm_db_iface_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001550#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001551
1552/*
1553 * ecm_db_connection_serial_get()
1554 * Return serial
1555 */
1556uint32_t ecm_db_connection_serial_get(struct ecm_db_connection_instance *ci)
1557{
1558 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1559 return ci->serial;
1560}
1561EXPORT_SYMBOL(ecm_db_connection_serial_get);
1562
1563/*
1564 * ecm_db_connection_from_address_get()
1565 * Return ip address address
1566 */
1567void ecm_db_connection_from_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1568{
1569 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1570 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1571 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1572 ECM_IP_ADDR_COPY(addr, ci->mapping_from->host->address);
1573}
1574EXPORT_SYMBOL(ecm_db_connection_from_address_get);
1575
1576/*
1577 * ecm_db_connection_from_address_nat_get()
1578 * Return NAT ip address address
1579 */
1580void ecm_db_connection_from_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1581{
1582 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1583 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1584 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1585 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_from->host->address);
1586}
1587EXPORT_SYMBOL(ecm_db_connection_from_address_nat_get);
1588
1589/*
1590 * ecm_db_connection_to_address_get()
1591 * Return ip address address
1592 */
1593void ecm_db_connection_to_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1594{
1595 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1596 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1597 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1598 ECM_IP_ADDR_COPY(addr, ci->mapping_to->host->address);
1599}
1600EXPORT_SYMBOL(ecm_db_connection_to_address_get);
1601
1602/*
1603 * ecm_db_connection_to_address_nat_get()
1604 * Return NAT ip address address
1605 */
1606void ecm_db_connection_to_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1607{
1608 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1609 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1610 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1611 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_to->host->address);
1612}
1613EXPORT_SYMBOL(ecm_db_connection_to_address_nat_get);
1614
1615/*
1616 * ecm_db_connection_to_port_get()
1617 * Return port
1618 */
1619int ecm_db_connection_to_port_get(struct ecm_db_connection_instance *ci)
1620{
1621 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1622 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1623 return ci->mapping_to->port;
1624}
1625EXPORT_SYMBOL(ecm_db_connection_to_port_get);
1626
1627/*
1628 * ecm_db_connection_to_port_nat_get()
1629 * Return port
1630 */
1631int ecm_db_connection_to_port_nat_get(struct ecm_db_connection_instance *ci)
1632{
1633 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1634 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1635 return ci->mapping_nat_to->port;
1636}
1637EXPORT_SYMBOL(ecm_db_connection_to_port_nat_get);
1638
1639/*
1640 * ecm_db_connection_from_port_get()
1641 * Return port
1642 */
1643int ecm_db_connection_from_port_get(struct ecm_db_connection_instance *ci)
1644{
1645 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1646 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1647 return ci->mapping_from->port;
1648}
1649EXPORT_SYMBOL(ecm_db_connection_from_port_get);
1650
1651/*
1652 * ecm_db_connection_from_port_nat_get()
1653 * Return port
1654 */
1655int ecm_db_connection_from_port_nat_get(struct ecm_db_connection_instance *ci)
1656{
1657 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1658 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1659 return ci->mapping_nat_from->port;
1660}
1661EXPORT_SYMBOL(ecm_db_connection_from_port_nat_get);
1662
1663/*
1664 * ecm_db_connection_to_node_address_get()
1665 * Return address of the node used when sending packets to the 'to' side.
1666 */
1667void ecm_db_connection_to_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1668{
1669 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001670 memcpy(address_buffer, ci->to_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001671}
1672EXPORT_SYMBOL(ecm_db_connection_to_node_address_get);
1673
1674/*
1675 * ecm_db_connection_from_node_address_get()
1676 * Return address of the node used when sending packets to the 'from' side.
1677 */
1678void ecm_db_connection_from_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1679{
1680 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001681 memcpy(address_buffer, ci->from_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001682}
1683EXPORT_SYMBOL(ecm_db_connection_from_node_address_get);
1684
1685/*
1686 * ecm_db_connection_to_nat_node_address_get()
1687 * Return address of the node used when sending packets to the 'to' NAT side.
1688 */
1689void ecm_db_connection_to_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1690{
1691 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001692 memcpy(address_buffer, ci->to_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001693}
1694EXPORT_SYMBOL(ecm_db_connection_to_nat_node_address_get);
1695
1696/*
1697 * ecm_db_connection_from_nat_node_address_get()
1698 * Return address of the node used when sending packets to the 'from' NAT side.
1699 */
1700void ecm_db_connection_from_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1701{
1702 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001703 memcpy(address_buffer, ci->from_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001704}
1705EXPORT_SYMBOL(ecm_db_connection_from_nat_node_address_get);
1706
1707/*
1708 * ecm_db_connection_to_iface_name_get()
1709 * Return name of interface on which the 'to' side may be reached
1710 */
1711void ecm_db_connection_to_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1712{
1713 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001714 strcpy(name_buffer, ci->to_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001715}
1716EXPORT_SYMBOL(ecm_db_connection_to_iface_name_get);
1717
1718/*
1719 * ecm_db_connection_from_iface_name_get()
1720 * Return name of interface on which the 'from' side may be reached
1721 */
1722void ecm_db_connection_from_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1723{
1724 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001725 strcpy(name_buffer, ci->from_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001726}
1727EXPORT_SYMBOL(ecm_db_connection_from_iface_name_get);
1728
1729/*
1730 * ecm_db_connection_to_iface_mtu_get()
1731 * Return MTU of interface on which the 'to' side may be reached
1732 */
1733int ecm_db_connection_to_iface_mtu_get(struct ecm_db_connection_instance *ci)
1734{
1735 int mtu;
1736 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1737 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001738 mtu = ci->to_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001739 spin_unlock_bh(&ecm_db_lock);
1740 return mtu;
1741}
1742EXPORT_SYMBOL(ecm_db_connection_to_iface_mtu_get);
1743
1744/*
1745 * ecm_db_connection_to_iface_type_get()
1746 * Return type of interface on which the 'to' side may be reached
1747 */
1748ecm_db_iface_type_t ecm_db_connection_to_iface_type_get(struct ecm_db_connection_instance *ci)
1749{
1750 ecm_db_iface_type_t type;
1751
1752 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1753 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001754 type = ci->to_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001755 spin_unlock_bh(&ecm_db_lock);
1756 return type;
1757}
1758EXPORT_SYMBOL(ecm_db_connection_to_iface_type_get);
1759
1760/*
1761 * ecm_db_connection_from_iface_mtu_get()
1762 * Return MTU of interface on which the 'from' side may be reached
1763 */
1764int ecm_db_connection_from_iface_mtu_get(struct ecm_db_connection_instance *ci)
1765{
1766 int mtu;
1767 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1768 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001769 mtu = ci->from_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001770 spin_unlock_bh(&ecm_db_lock);
1771 return mtu;
1772}
1773EXPORT_SYMBOL(ecm_db_connection_from_iface_mtu_get);
1774
1775/*
1776 * ecm_db_connection_from_iface_type_get()
1777 * Return type of interface on which the 'from' side may be reached
1778 */
1779ecm_db_iface_type_t ecm_db_connection_from_iface_type_get(struct ecm_db_connection_instance *ci)
1780{
1781 ecm_db_iface_type_t type;
1782
1783 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1784 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001785 type = ci->from_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001786 spin_unlock_bh(&ecm_db_lock);
1787 return type;
1788}
1789EXPORT_SYMBOL(ecm_db_connection_from_iface_type_get);
1790
1791/*
1792 * ecm_db_connection_iface_type_get()
1793 * Return type of interface
1794 */
1795ecm_db_iface_type_t ecm_db_connection_iface_type_get(struct ecm_db_iface_instance *ii)
1796{
1797 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1798 return ii->type;
1799}
1800EXPORT_SYMBOL(ecm_db_connection_iface_type_get);
1801
1802/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301803 * ecm_db_connection_regeneration_occurrances_get()
1804 * Get the number of regeneration occurrances that have occurred since the connection was created.
Ben Menchaca84f36632014-02-28 20:57:38 +00001805 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301806uint16_t ecm_db_connection_regeneration_occurrances_get(struct ecm_db_connection_instance *ci)
1807{
1808 uint16_t occurances;
1809 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1810
1811 spin_lock_bh(&ecm_db_lock);
1812 occurances = ci->regen_occurances;
1813 spin_unlock_bh(&ecm_db_lock);
1814 return occurances;
1815}
1816EXPORT_SYMBOL(ecm_db_connection_regeneration_occurrances_get);
1817
1818/*
1819 * ecm_db_conection_regeneration_completed()
1820 * Re-generation was completed successfully
1821 */
1822void ecm_db_conection_regeneration_completed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001823{
1824 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1825
1826 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301827
1828 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1829 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1830
1831 /*
1832 * Decrement the required counter by 1.
1833 * This may mean that regeneration is still required due to another change occuring _during_ re-generation.
1834 */
1835 ci->regen_required--;
1836 ci->regen_in_progress = false;
1837 ci->regen_success++;
1838 spin_unlock_bh(&ecm_db_lock);
1839}
1840EXPORT_SYMBOL(ecm_db_conection_regeneration_completed);
1841
1842/*
1843 * ecm_db_conection_regeneration_failed()
1844 * Re-generation failed
1845 */
1846void ecm_db_conection_regeneration_failed(struct ecm_db_connection_instance *ci)
1847{
1848 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1849
1850 spin_lock_bh(&ecm_db_lock);
1851
1852 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1853 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1854
1855 /*
1856 * Re-generation is no longer in progress BUT we leave the regen
1857 * counter as it is so as to indicate re-generation is still needed
1858 */
1859 ci->regen_in_progress = false;
1860 ci->regen_fail++;
1861 spin_unlock_bh(&ecm_db_lock);
1862}
1863EXPORT_SYMBOL(ecm_db_conection_regeneration_failed);
1864
1865/*
1866 * ecm_db_connection_regeneration_required_check()
1867 * Returns true if the connection needs to be re-generated.
1868 *
1869 * If re-generation is needed this will mark the connection to indicate that re-generation is needed AND in progress.
1870 * If the return code is TRUE the caller MUST handle the re-generation.
1871 * Upon re-generation completion you must call ecm_db_conection_regeneration_completed() or ecm_db_conection_regeneration_failed().
1872 */
1873bool ecm_db_connection_regeneration_required_check(struct ecm_db_connection_instance *ci)
1874{
1875 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1876
1877 /*
1878 * Check the global generation counter for changes
1879 */
1880 spin_lock_bh(&ecm_db_lock);
1881 if (ci->generation != ecm_db_connection_generation) {
1882 /*
1883 * Re-generation is needed
1884 */
1885 ci->regen_occurances++;
1886 ci->regen_required++;
1887
1888 /*
1889 * Record that we have seen this change
1890 */
1891 ci->generation = ecm_db_connection_generation;
1892 }
1893
1894 /*
1895 * If re-generation is in progress then something is handling re-generation already
1896 * so we tell the caller that it cannot handle re-generation.
1897 */
1898 if (ci->regen_in_progress) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001899 spin_unlock_bh(&ecm_db_lock);
1900 return false;
1901 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301902
1903 /*
1904 * Is re-generation required?
1905 */
1906 if (ci->regen_required == 0) {
1907 spin_unlock_bh(&ecm_db_lock);
1908 return false;
1909 }
1910
1911 /*
1912 * Flag that re-generation is in progress and tell the caller to handle re-generation
1913 */
1914 ci->regen_in_progress = true;
Ben Menchaca84f36632014-02-28 20:57:38 +00001915 spin_unlock_bh(&ecm_db_lock);
1916 return true;
1917}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301918EXPORT_SYMBOL(ecm_db_connection_regeneration_required_check);
Ben Menchaca84f36632014-02-28 20:57:38 +00001919
1920/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301921 * ecm_db_connection_regeneration_required_peek()
1922 * Returns true if the connection needs to be regenerated.
Ben Menchaca84f36632014-02-28 20:57:38 +00001923 *
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301924 * NOTE: The caller MUST NOT handle re-generation, the caller may use this indication
1925 * to determine the sanity of the connection state and whether acceleration is permitted.
Ben Menchaca84f36632014-02-28 20:57:38 +00001926 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301927bool ecm_db_connection_regeneration_required_peek(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001928{
1929 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1930
1931 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301932
1933 /*
1934 * Check the global generation counter for changes (record any change now)
1935 */
1936 if (ci->generation != ecm_db_connection_generation) {
1937 /*
1938 * Re-generation is needed, flag the connection as needing re-generation now.
1939 */
1940 ci->regen_occurances++;
1941 ci->regen_required++;
1942
1943 /*
1944 * Record that we have seen this change
1945 */
1946 ci->generation = ecm_db_connection_generation;
1947 }
1948 if (ci->regen_required == 0) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001949 spin_unlock_bh(&ecm_db_lock);
1950 return false;
1951 }
1952 spin_unlock_bh(&ecm_db_lock);
1953 return true;
1954}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301955EXPORT_SYMBOL(ecm_db_connection_regeneration_required_peek);
Ben Menchaca84f36632014-02-28 20:57:38 +00001956
1957/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301958 * ecm_db_connection_regeneration_needed()
1959 * Cause a specific connection to require re-generation
1960 *
1961 * NOTE: This only flags that re-generation is needed.
1962 * The connection will typically be re-generated when ecm_db_connection_regeneration_required_check() is invoked.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01001963 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301964void ecm_db_connection_regeneration_needed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001965{
1966 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1967
1968 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301969 ci->regen_occurances++;
1970 ci->regen_required++;
Ben Menchaca84f36632014-02-28 20:57:38 +00001971 spin_unlock_bh(&ecm_db_lock);
1972}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301973EXPORT_SYMBOL(ecm_db_connection_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00001974
1975/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301976 * ecm_db_regeneration_needed()
1977 * Bump the global generation index to cause a re-generation of all connections state.
Ben Menchaca84f36632014-02-28 20:57:38 +00001978 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301979void ecm_db_regeneration_needed(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00001980{
1981 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301982 ecm_db_connection_generation++;
Ben Menchaca84f36632014-02-28 20:57:38 +00001983 spin_unlock_bh(&ecm_db_lock);
1984}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301985EXPORT_SYMBOL(ecm_db_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00001986
1987/*
Xiaoping Faned6d37e2015-09-17 14:13:47 -07001988 * ecm_db_connection_regenerate()
1989 * Re-generate a specific connection
1990 */
1991void ecm_db_connection_regenerate(struct ecm_db_connection_instance *ci)
1992{
1993 struct ecm_front_end_connection_instance *feci;
1994
1995 DEBUG_TRACE("Regenerate connection: %p\n", ci);
1996
1997 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1998
1999 /*
2000 * Notify front end to regenerate a connection.
2001 */
2002 feci = ecm_db_connection_front_end_get_and_ref(ci);
2003 feci->regenerate(feci, ci);
2004 feci->deref(feci);
2005}
2006EXPORT_SYMBOL(ecm_db_connection_regenerate);
2007
2008/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002009 * ecm_db_connection_direction_get()
2010 * Return direction of the connection.
2011 *
2012 * NOTE: an EGRESS connection means that packets being sent to mapping_to should have qos applied.
2013 * INGRESS means that packets being sent to mapping_from should have qos applied.
2014 */
2015ecm_db_direction_t ecm_db_connection_direction_get(struct ecm_db_connection_instance *ci)
2016{
2017 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2018 return ci->direction;
2019}
2020EXPORT_SYMBOL(ecm_db_connection_direction_get);
2021
2022/*
2023 * ecm_db_mapping_port_count_get()
2024 * Return port count stats for a mapping.
2025 */
2026void ecm_db_mapping_port_count_get(struct ecm_db_mapping_instance *mi,
2027 int *tcp_from, int *tcp_to, int *udp_from, int *udp_to, int *from, int *to,
2028 int *tcp_nat_from, int *tcp_nat_to, int *udp_nat_from, int *udp_nat_to, int *nat_from, int *nat_to)
2029{
2030 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2031
2032 spin_lock_bh(&ecm_db_lock);
2033
2034 *tcp_from = mi->tcp_from;
2035 *tcp_to = mi->tcp_to;
2036 *udp_from = mi->udp_from;
2037 *udp_to = mi->udp_to;
2038 *from = mi->from;
2039 *to = mi->to;
2040
2041 *tcp_nat_from = mi->tcp_nat_from;
2042 *tcp_nat_to = mi->tcp_nat_to;
2043 *udp_nat_from = mi->udp_nat_from;
2044 *udp_nat_to = mi->udp_nat_to;
2045 *nat_from = mi->nat_from;
2046 *nat_to = mi->nat_to;
2047
2048 spin_unlock_bh(&ecm_db_lock);
2049}
2050EXPORT_SYMBOL(ecm_db_mapping_port_count_get);
2051
2052/*
2053 * ecm_db_connection_is_routed_get()
2054 * Return whether connection is a routed path or not
2055 */
2056bool ecm_db_connection_is_routed_get(struct ecm_db_connection_instance *ci)
2057{
2058 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2059 return ci->is_routed;
2060}
2061EXPORT_SYMBOL(ecm_db_connection_is_routed_get);
2062
2063/*
2064 * ecm_db_connection_protocol_get()
2065 * Return protocol of connection
2066 */
2067int ecm_db_connection_protocol_get(struct ecm_db_connection_instance *ci)
2068{
2069 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2070 return ci->protocol;
2071}
2072EXPORT_SYMBOL(ecm_db_connection_protocol_get);
2073
2074/*
Gareth Williams3e5b37f2015-05-13 10:04:12 +01002075 * ecm_db_connection_ip_version_get()
2076 * Return IP version of connection
2077 */
2078int ecm_db_connection_ip_version_get(struct ecm_db_connection_instance *ci)
2079{
2080 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2081 return ci->ip_version;
2082}
2083EXPORT_SYMBOL(ecm_db_connection_ip_version_get);
2084
2085/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002086 * ecm_db_host_address_get()
2087 * Return address of host
2088 */
2089void ecm_db_host_address_get(struct ecm_db_host_instance *hi, ip_addr_t addr)
2090{
2091 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2092 ECM_IP_ADDR_COPY(addr, hi->address);
2093}
2094EXPORT_SYMBOL(ecm_db_host_address_get);
2095
2096/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002097 * ecm_db_host_on_link_get()
2098 * Return on link status of host
2099 */
2100bool ecm_db_host_on_link_get(struct ecm_db_host_instance *hi)
2101{
2102 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2103 return hi->on_link;
2104}
2105EXPORT_SYMBOL(ecm_db_host_on_link_get);
2106
2107/*
2108 * ecm_db_mapping_adress_get()
2109 * Return address
2110 */
2111void ecm_db_mapping_adress_get(struct ecm_db_mapping_instance *mi, ip_addr_t addr)
2112{
2113 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2114 ECM_IP_ADDR_COPY(addr, mi->host->address);
2115}
2116EXPORT_SYMBOL(ecm_db_mapping_adress_get);
2117
2118/*
2119 * ecm_db_mapping_port_get()
2120 * Return port
2121 */
2122int ecm_db_mapping_port_get(struct ecm_db_mapping_instance *mi)
2123{
2124 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2125 return mi->port;
2126}
2127EXPORT_SYMBOL(ecm_db_mapping_port_get);
2128
2129/*
2130 * ecm_db_node_adress_get()
2131 * Return address
2132 */
2133void ecm_db_node_adress_get(struct ecm_db_node_instance *ni, uint8_t *address_buffer)
2134{
2135 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2136 memcpy(address_buffer, ni->address, ETH_ALEN);
2137}
2138EXPORT_SYMBOL(ecm_db_node_adress_get);
2139
2140/*
2141 * _ecm_db_timer_group_entry_remove()
2142 * Remove the entry from its timer group, returns false if the entry has already expired.
2143 */
2144static bool _ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2145{
2146 struct ecm_db_timer_group *timer_group;
2147
2148 /*
2149 * If not in a timer group then it is already removed
2150 */
2151 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2152 return false;
2153 }
2154
2155 /*
2156 * Remove the connection from its current group
2157 */
2158 timer_group = &ecm_db_timer_groups[tge->group];
2159
2160 /*
2161 * Somewhere in the list?
2162 */
2163 if (tge->prev) {
2164 tge->prev->next = tge->next;
2165 } else {
2166 /*
2167 * First in the group
2168 */
2169 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p, got %p\n", timer_group, tge, timer_group->head);
2170 timer_group->head = tge->next;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302171 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002172
2173 if (tge->next) {
2174 tge->next->prev = tge->prev;
2175 } else {
2176 /*
2177 * No next so this must be the last item - we need to adjust the tail pointer
2178 */
2179 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2180 timer_group->tail = tge->prev;
2181 }
2182
2183 /*
2184 * No longer a part of a timer group
2185 */
2186 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2187 return true;
2188}
2189
2190/*
2191 * ecm_db_timer_group_entry_remove()
2192 * Remove the connection from its timer group, returns false if the entry has already expired.
2193 */
2194bool ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2195{
2196 bool res;
2197 spin_lock_bh(&ecm_db_lock);
2198 res = _ecm_db_timer_group_entry_remove(tge);
2199 spin_unlock_bh(&ecm_db_lock);
2200 return res;
2201}
2202EXPORT_SYMBOL(ecm_db_timer_group_entry_remove);
2203
2204/*
2205 * _ecm_db_timer_group_entry_set()
2206 * Set the timer group to which this entry will be a member
2207 */
2208void _ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2209{
2210 struct ecm_db_timer_group *timer_group;
2211
2212 DEBUG_ASSERT(tge->group == ECM_DB_TIMER_GROUPS_MAX, "%p: already set\n", tge);
2213
2214 /*
2215 * Set group
2216 */
2217 tge->group = tg;
2218 timer_group = &ecm_db_timer_groups[tge->group];
2219 tge->timeout = timer_group->time + ecm_db_time;
2220
2221 /*
2222 * Insert into a timer group at the head (as this is now touched)
2223 */
2224 tge->prev = NULL;
2225 tge->next = timer_group->head;
2226 if (!timer_group->head) {
2227 /*
2228 * As there is no head there is also no tail so we need to set that
2229 */
2230 timer_group->tail = tge;
2231 } else {
2232 /*
2233 * As there is a head already there must be a tail. Since we insert before
2234 * the current head we don't adjust the tail.
2235 */
2236 timer_group->head->prev = tge;
2237 }
2238 timer_group->head = tge;
2239}
2240
2241/*
2242 * ecm_db_timer_group_entry_reset()
2243 * Re-set the timer group to which this entry will be a member.
2244 *
2245 * Returns false if the timer cannot be reset because it has expired
2246 */
2247bool ecm_db_timer_group_entry_reset(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2248{
2249 spin_lock_bh(&ecm_db_lock);
2250
2251 /*
2252 * Remove it from its current group, if any
2253 */
2254 if (!_ecm_db_timer_group_entry_remove(tge)) {
2255 spin_unlock_bh(&ecm_db_lock);
2256 return false;
2257 }
2258
2259 /*
2260 * Set new group
2261 */
2262 _ecm_db_timer_group_entry_set(tge, tg);
2263 spin_unlock_bh(&ecm_db_lock);
2264 return true;
2265}
2266EXPORT_SYMBOL(ecm_db_timer_group_entry_reset);
2267
2268/*
2269 * ecm_db_timer_group_entry_set()
2270 * Set the timer group to which this entry will be a member
2271 */
2272void ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2273{
2274 spin_lock_bh(&ecm_db_lock);
2275 _ecm_db_timer_group_entry_set(tge, tg);
2276 spin_unlock_bh(&ecm_db_lock);
2277}
2278EXPORT_SYMBOL(ecm_db_timer_group_entry_set);
2279
2280/*
2281 * ecm_db_timer_group_entry_init()
2282 * Initialise a timer entry ready for setting
2283 */
2284void ecm_db_timer_group_entry_init(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_entry_callback_t fn, void *arg)
2285{
2286 memset(tge, 0, sizeof(struct ecm_db_timer_group_entry));
2287 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2288 tge->arg = arg;
2289 tge->fn = fn;
2290}
2291EXPORT_SYMBOL(ecm_db_timer_group_entry_init);
2292
2293/*
2294 * ecm_db_timer_group_entry_touch()
2295 * Update the timeout, if the timer is not running this has no effect.
2296 * It returns false if the timer is not running.
2297 */
2298bool ecm_db_timer_group_entry_touch(struct ecm_db_timer_group_entry *tge)
2299{
2300 struct ecm_db_timer_group *timer_group;
2301
2302 spin_lock_bh(&ecm_db_lock);
2303
2304 /*
2305 * If not in a timer group then do nothing
2306 */
2307 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2308 spin_unlock_bh(&ecm_db_lock);
2309 return false;
2310 }
2311
2312 /*
2313 * Update time to live
2314 */
2315 timer_group = &ecm_db_timer_groups[tge->group];
2316
2317 /*
2318 * Link out of its current position.
2319 */
2320 if (!tge->prev) {
2321 /*
2322 * Already at the head, just update the time
2323 */
2324 tge->timeout = timer_group->time + ecm_db_time;
2325 spin_unlock_bh(&ecm_db_lock);
2326 return true;
2327 }
2328
2329 /*
2330 * tge->prev is not null, so:
2331 * 1) it is in a timer list
2332 * 2) is not at the head of the list
2333 * 3) there is a head already (so more than one item on the list)
2334 * 4) there is a prev pointer.
2335 * Somewhere in the group list - unlink it.
2336 */
2337 tge->prev->next = tge->next;
2338
2339 if (tge->next) {
2340 tge->next->prev = tge->prev;
2341 } else {
2342 /*
2343 * Since there is no next this must be the tail
2344 */
2345 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2346 timer_group->tail = tge->prev;
2347 }
2348
2349 /*
2350 * Link in to head.
2351 */
Sol Kavy213e45d2014-06-05 18:04:07 -07002352 tge->timeout = timer_group->time + ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00002353 tge->prev = NULL;
2354 tge->next = timer_group->head;
2355 timer_group->head->prev = tge;
2356 timer_group->head = tge;
2357 spin_unlock_bh(&ecm_db_lock);
2358 return true;
2359}
2360EXPORT_SYMBOL(ecm_db_timer_group_entry_touch);
2361
2362/*
2363 * _ecm_db_connection_ref()
2364 */
2365static void _ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2366{
2367 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2368 ci->refs++;
2369 DEBUG_TRACE("%p: connection ref %d\n", ci, ci->refs);
2370 DEBUG_ASSERT(ci->refs > 0, "%p: ref wrap\n", ci);
2371}
2372
2373/*
2374 * ecm_db_connection_ref()
2375 */
2376void ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2377{
2378 spin_lock_bh(&ecm_db_lock);
2379 _ecm_db_connection_ref(ci);
2380 spin_unlock_bh(&ecm_db_lock);
2381}
2382EXPORT_SYMBOL(ecm_db_connection_ref);
2383
2384/*
2385 * _ecm_db_mapping_ref()
2386 */
2387static void _ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2388{
2389 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
2390 mi->refs++;
2391 DEBUG_TRACE("%p: mapping ref %d\n", mi, mi->refs);
2392 DEBUG_ASSERT(mi->refs > 0, "%p: ref wrap\n", mi);
2393}
2394
2395/*
2396 * ecm_db_mapping_ref()
2397 */
2398void ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2399{
2400 spin_lock_bh(&ecm_db_lock);
2401 _ecm_db_mapping_ref(mi);
2402 spin_unlock_bh(&ecm_db_lock);
2403}
2404EXPORT_SYMBOL(ecm_db_mapping_ref);
2405
2406/*
2407 * _ecm_db_host_ref()
2408 */
2409static void _ecm_db_host_ref(struct ecm_db_host_instance *hi)
2410{
2411 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
2412 hi->refs++;
2413 DEBUG_TRACE("%p: host ref %d\n", hi, hi->refs);
2414 DEBUG_ASSERT(hi->refs > 0, "%p: ref wrap\n", hi);
2415}
2416
2417/*
2418 * ecm_db_host_ref()
2419 */
2420void ecm_db_host_ref(struct ecm_db_host_instance *hi)
2421{
2422 spin_lock_bh(&ecm_db_lock);
2423 _ecm_db_host_ref(hi);
2424 spin_unlock_bh(&ecm_db_lock);
2425}
2426EXPORT_SYMBOL(ecm_db_host_ref);
2427
2428/*
2429 * _ecm_db_node_ref()
2430 */
2431static void _ecm_db_node_ref(struct ecm_db_node_instance *ni)
2432{
2433 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
2434 ni->refs++;
2435 DEBUG_TRACE("%p: node ref %d\n", ni, ni->refs);
2436 DEBUG_ASSERT(ni->refs > 0, "%p: ref wrap\n", ni);
2437}
2438
2439/*
2440 * ecm_db_node_ref()
2441 */
2442void ecm_db_node_ref(struct ecm_db_node_instance *ni)
2443{
2444 spin_lock_bh(&ecm_db_lock);
2445 _ecm_db_node_ref(ni);
2446 spin_unlock_bh(&ecm_db_lock);
2447}
2448EXPORT_SYMBOL(ecm_db_node_ref);
2449
2450/*
2451 * _ecm_db_iface_ref()
2452 */
2453static void _ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2454{
2455 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
2456 ii->refs++;
2457 DEBUG_TRACE("%p: iface ref %d\n", ii, ii->refs);
2458 DEBUG_ASSERT(ii->refs > 0, "%p: ref wrap\n", ii);
2459}
2460
2461/*
2462 * ecm_db_iface_ref()
2463 */
2464void ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2465{
2466 spin_lock_bh(&ecm_db_lock);
2467 _ecm_db_iface_ref(ii);
2468 spin_unlock_bh(&ecm_db_lock);
2469}
2470EXPORT_SYMBOL(ecm_db_iface_ref);
2471
2472/*
2473 * _ecm_db_listener_ref()
2474 */
2475static void _ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2476{
2477 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2478 li->refs++;
2479 DEBUG_ASSERT(li->refs > 0, "%p: ref wrap\n", li);
2480}
2481
2482/*
2483 * ecm_db_listener_ref()
2484 */
2485void ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2486{
2487 spin_lock_bh(&ecm_db_lock);
2488 _ecm_db_listener_ref(li);
2489 spin_unlock_bh(&ecm_db_lock);
2490}
2491EXPORT_SYMBOL(ecm_db_listener_ref);
2492
2493/*
2494 * ecm_db_connections_get_and_ref_first()
2495 * Obtain a ref to the first connection instance, if any
2496 */
Gareth Williamsf98d4192015-03-11 16:55:41 +00002497struct ecm_db_connection_instance *ecm_db_connections_get_and_ref_first(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002498{
2499 struct ecm_db_connection_instance *ci;
2500 spin_lock_bh(&ecm_db_lock);
2501 ci = ecm_db_connections;
2502 if (ci) {
2503 _ecm_db_connection_ref(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302504 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002505 spin_unlock_bh(&ecm_db_lock);
2506 return ci;
2507}
2508EXPORT_SYMBOL(ecm_db_connections_get_and_ref_first);
2509
2510/*
2511 * ecm_db_connection_get_and_ref_next()
2512 * Return the next connection in the list given a connection
2513 */
2514struct ecm_db_connection_instance *ecm_db_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
2515{
2516 struct ecm_db_connection_instance *cin;
2517 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2518 spin_lock_bh(&ecm_db_lock);
2519 cin = ci->next;
2520 if (cin) {
2521 _ecm_db_connection_ref(cin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302522 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002523 spin_unlock_bh(&ecm_db_lock);
2524 return cin;
2525}
2526EXPORT_SYMBOL(ecm_db_connection_get_and_ref_next);
2527
2528/*
2529 * ecm_db_mappings_get_and_ref_first()
2530 * Obtain a ref to the first mapping instance, if any
2531 */
2532struct ecm_db_mapping_instance *ecm_db_mappings_get_and_ref_first(void)
2533{
2534 struct ecm_db_mapping_instance *mi;
2535 spin_lock_bh(&ecm_db_lock);
2536 mi = ecm_db_mappings;
2537 if (mi) {
2538 _ecm_db_mapping_ref(mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302539 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002540 spin_unlock_bh(&ecm_db_lock);
2541 return mi;
2542}
2543EXPORT_SYMBOL(ecm_db_mappings_get_and_ref_first);
2544
2545/*
2546 * ecm_db_mapping_get_and_ref_next()
2547 * Return the next mapping in the list given a mapping
2548 */
2549struct ecm_db_mapping_instance *ecm_db_mapping_get_and_ref_next(struct ecm_db_mapping_instance *mi)
2550{
2551 struct ecm_db_mapping_instance *min;
2552 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2553 spin_lock_bh(&ecm_db_lock);
2554 min = mi->next;
2555 if (min) {
2556 _ecm_db_mapping_ref(min);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302557 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002558 spin_unlock_bh(&ecm_db_lock);
2559 return min;
2560}
2561EXPORT_SYMBOL(ecm_db_mapping_get_and_ref_next);
2562
2563/*
2564 * ecm_db_hosts_get_and_ref_first()
2565 * Obtain a ref to the first host instance, if any
2566 */
2567struct ecm_db_host_instance *ecm_db_hosts_get_and_ref_first(void)
2568{
2569 struct ecm_db_host_instance *hi;
2570 spin_lock_bh(&ecm_db_lock);
2571 hi = ecm_db_hosts;
2572 if (hi) {
2573 _ecm_db_host_ref(hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302574 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002575 spin_unlock_bh(&ecm_db_lock);
2576 return hi;
2577}
2578EXPORT_SYMBOL(ecm_db_hosts_get_and_ref_first);
2579
2580/*
2581 * ecm_db_host_get_and_ref_next()
2582 * Return the next host in the list given a host
2583 */
2584struct ecm_db_host_instance *ecm_db_host_get_and_ref_next(struct ecm_db_host_instance *hi)
2585{
2586 struct ecm_db_host_instance *hin;
2587 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2588 spin_lock_bh(&ecm_db_lock);
2589 hin = hi->next;
2590 if (hin) {
2591 _ecm_db_host_ref(hin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302592 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002593 spin_unlock_bh(&ecm_db_lock);
2594 return hin;
2595}
2596EXPORT_SYMBOL(ecm_db_host_get_and_ref_next);
2597
2598/*
2599 * ecm_db_listeners_get_and_ref_first()
2600 * Obtain a ref to the first listener instance, if any
2601 */
2602static struct ecm_db_listener_instance *ecm_db_listeners_get_and_ref_first(void)
2603{
2604 struct ecm_db_listener_instance *li;
2605 spin_lock_bh(&ecm_db_lock);
2606 li = ecm_db_listeners;
2607 if (li) {
2608 _ecm_db_listener_ref(li);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302609 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002610 spin_unlock_bh(&ecm_db_lock);
2611 return li;
2612}
2613
2614/*
2615 * ecm_db_listener_get_and_ref_next()
2616 * Return the next listener in the list given a listener
2617 */
2618static struct ecm_db_listener_instance *ecm_db_listener_get_and_ref_next(struct ecm_db_listener_instance *li)
2619{
2620 struct ecm_db_listener_instance *lin;
2621 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2622 spin_lock_bh(&ecm_db_lock);
2623 lin = li->next;
2624 if (lin) {
2625 _ecm_db_listener_ref(lin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302626 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002627 spin_unlock_bh(&ecm_db_lock);
2628 return lin;
2629}
2630
2631/*
2632 * ecm_db_nodes_get_and_ref_first()
2633 * Obtain a ref to the first node instance, if any
2634 */
2635struct ecm_db_node_instance *ecm_db_nodes_get_and_ref_first(void)
2636{
2637 struct ecm_db_node_instance *ni;
2638 spin_lock_bh(&ecm_db_lock);
2639 ni = ecm_db_nodes;
2640 if (ni) {
2641 _ecm_db_node_ref(ni);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302642 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002643 spin_unlock_bh(&ecm_db_lock);
2644 return ni;
2645}
2646EXPORT_SYMBOL(ecm_db_nodes_get_and_ref_first);
2647
2648/*
2649 * ecm_db_node_get_and_ref_next()
2650 * Return the next node in the list given a node
2651 */
2652struct ecm_db_node_instance *ecm_db_node_get_and_ref_next(struct ecm_db_node_instance *ni)
2653{
2654 struct ecm_db_node_instance *nin;
2655 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2656 spin_lock_bh(&ecm_db_lock);
2657 nin = ni->next;
2658 if (nin) {
2659 _ecm_db_node_ref(nin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302660 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002661 spin_unlock_bh(&ecm_db_lock);
2662 return nin;
2663}
2664EXPORT_SYMBOL(ecm_db_node_get_and_ref_next);
2665
2666/*
2667 * ecm_db_interfaces_get_and_ref_first()
2668 * Obtain a ref to the first iface instance, if any
2669 */
2670struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void)
2671{
2672 struct ecm_db_iface_instance *ii;
2673 spin_lock_bh(&ecm_db_lock);
2674 ii = ecm_db_interfaces;
2675 if (ii) {
2676 _ecm_db_iface_ref(ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302677 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002678 spin_unlock_bh(&ecm_db_lock);
2679 return ii;
2680}
2681EXPORT_SYMBOL(ecm_db_interfaces_get_and_ref_first);
2682
2683/*
2684 * ecm_db_interface_get_and_ref_next()
2685 * Return the next iface in the list given a iface
2686 */
2687struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii)
2688{
2689 struct ecm_db_iface_instance *iin;
2690 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
2691 spin_lock_bh(&ecm_db_lock);
2692 iin = ii->next;
2693 if (iin) {
2694 _ecm_db_iface_ref(iin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302695 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002696 spin_unlock_bh(&ecm_db_lock);
2697 return iin;
2698}
2699EXPORT_SYMBOL(ecm_db_interface_get_and_ref_next);
2700
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002701#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002702/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002703 * _ecm_db_classifier_type_assignment_remove()
2704 * Remove the connection from the classifier type assignment list (of the given type)
2705 */
2706static void _ecm_db_classifier_type_assignment_remove(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
2707{
2708 struct ecm_db_connection_classifier_type_assignment *ta;
2709 struct ecm_db_connection_classifier_type_assignment_list *tal;
2710
2711 DEBUG_TRACE("%p: Classifier type assignment remove: %d\n", ci, ca_type);
2712 ta = &ci->type_assignment[ca_type];
2713 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p\n", ta, ci);
2714 DEBUG_ASSERT(ta->iteration_count == 0, "%p: iteration count: %d, type: %d\n", ci, ta->iteration_count, ca_type);
2715
2716 if (ta->next) {
2717 struct ecm_db_connection_classifier_type_assignment *tan = &ta->next->type_assignment[ca_type];
2718 DEBUG_ASSERT(tan->prev == ci, "Bad list, expecting: %p, got: %p\n", ci, tan->prev);
2719 tan->prev = ta->prev;
2720 }
2721
2722 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
2723 if (ta->prev) {
2724 struct ecm_db_connection_classifier_type_assignment *tap = &ta->prev->type_assignment[ca_type];
2725 DEBUG_ASSERT(tap->next == ci, "Bad list, expecting: %p, got: %p\n", ci, tap->next);
2726 tap->next = ta->next;
2727 } else {
2728 /*
2729 * Set new head of list
2730 */
2731 DEBUG_ASSERT(tal->type_assignments_list == ci, "Bad head, expecting %p, got %p, type: %d\n", ci, tal->type_assignments_list, ca_type);
2732 tal->type_assignments_list = ta->next;
2733 }
2734 ta->next = NULL;
2735 ta->prev = NULL;
2736 ta->pending_unassign = false;
2737
2738 /*
2739 * Decrement assignment count
2740 */
2741 tal->type_assignment_count--;
2742 DEBUG_ASSERT(tal->type_assignment_count >= 0, "Bad type assignment count: %d, type: %d\n", tal->type_assignment_count, ca_type);
2743
2744 DEBUG_CLEAR_MAGIC(ta);
2745}
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002746#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002747
2748/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002749 * ecm_db_connection_deref()
2750 * Release reference to connection. Connection is removed from database on final deref and destroyed.
2751 */
2752int ecm_db_connection_deref(struct ecm_db_connection_instance *ci)
2753{
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002754#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002755 ecm_classifier_type_t ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002756#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002757 int32_t i;
2758
2759 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2760
2761 spin_lock_bh(&ecm_db_lock);
2762 ci->refs--;
2763 DEBUG_TRACE("%p: connection deref %d\n", ci, ci->refs);
2764 DEBUG_ASSERT(ci->refs >= 0, "%p: ref wrap\n", ci);
2765
2766 if (ci->refs > 0) {
2767 int refs = ci->refs;
2768 spin_unlock_bh(&ecm_db_lock);
2769 return refs;
2770 }
2771
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002772#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002773 /*
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002774 * Unlink from the "assignments by classifier type" lists.
ratheesh kannoth37e35b02015-03-26 11:25:02 +05302775 *
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002776 * This is done whether the connection is inserted into the database or not - this is because
2777 * classifier assignments take place before adding into the db.
2778 *
2779 * NOTE: We know that the ci is not being iterated in any of these lists because otherwise
2780 * ci would be being held as part of iteration and so we would not be here!
2781 * Equally we know that if the assignments_by_type[] element is non-null then it must also be in the relevant list too.
2782 */
2783 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
2784 if (!ci->assignments_by_type[ca_type]) {
2785 /*
2786 * No assignment of this type, so would not be in the classifier type assignments list
2787 */
2788 continue;
2789 }
2790 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
2791 }
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002792#endif
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002793
2794 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002795 * Remove from database if inserted
2796 */
2797 if (!ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED) {
2798 spin_unlock_bh(&ecm_db_lock);
2799 } else {
2800 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00002801#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002802 struct ecm_db_iface_instance *iface_from;
2803 struct ecm_db_iface_instance *iface_to;
2804 struct ecm_db_iface_instance *iface_nat_from;
2805 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00002806#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002807
2808 /*
2809 * Remove it from the connection hash table
2810 */
2811 if (!ci->hash_prev) {
2812 DEBUG_ASSERT(ecm_db_connection_table[ci->hash_index] == ci, "%p: hash table bad\n", ci);
2813 ecm_db_connection_table[ci->hash_index] = ci->hash_next;
2814 } else {
2815 ci->hash_prev->hash_next = ci->hash_next;
2816 }
2817 if (ci->hash_next) {
2818 ci->hash_next->hash_prev = ci->hash_prev;
2819 }
2820 ecm_db_connection_table_lengths[ci->hash_index]--;
2821 DEBUG_ASSERT(ecm_db_connection_table_lengths[ci->hash_index] >= 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[ci->hash_index]);
2822
2823 /*
2824 * Remove it from the connection serial hash table
2825 */
2826 if (!ci->serial_hash_prev) {
2827 DEBUG_ASSERT(ecm_db_connection_serial_table[ci->serial_hash_index] == ci, "%p: hash table bad\n", ci);
2828 ecm_db_connection_serial_table[ci->serial_hash_index] = ci->serial_hash_next;
2829 } else {
2830 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
2831 }
2832 if (ci->serial_hash_next) {
2833 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
2834 }
2835 ecm_db_connection_serial_table_lengths[ci->serial_hash_index]--;
2836 DEBUG_ASSERT(ecm_db_connection_serial_table_lengths[ci->serial_hash_index] >= 0, "%p: invalid table len %d\n", ci, ecm_db_connection_serial_table_lengths[ci->serial_hash_index]);
2837
2838 /*
2839 * Remove from the global list
2840 */
2841 if (!ci->prev) {
2842 DEBUG_ASSERT(ecm_db_connections == ci, "%p: conn table bad\n", ci);
2843 ecm_db_connections = ci->next;
2844 } else {
2845 ci->prev->next = ci->next;
2846 }
2847 if (ci->next) {
2848 ci->next->prev = ci->prev;
2849 }
2850
Gareth Williamsb5903892015-03-20 15:13:07 +00002851#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002852 /*
2853 * Remove connection from the "from" mapping connection list
2854 */
2855 if (!ci->from_prev) {
2856 DEBUG_ASSERT(ci->mapping_from->from_connections == ci, "%p: from conn table bad\n", ci);
2857 ci->mapping_from->from_connections = ci->from_next;
2858 } else {
2859 ci->from_prev->from_next = ci->from_next;
2860 }
2861 if (ci->from_next) {
2862 ci->from_next->from_prev = ci->from_prev;
2863 }
2864
2865 /*
2866 * Remove connection from the "to" mapping connection list
2867 */
2868 if (!ci->to_prev) {
2869 DEBUG_ASSERT(ci->mapping_to->to_connections == ci, "%p: to conn table bad\n", ci);
2870 ci->mapping_to->to_connections = ci->to_next;
2871 } else {
2872 ci->to_prev->to_next = ci->to_next;
2873 }
2874 if (ci->to_next) {
2875 ci->to_next->to_prev = ci->to_prev;
2876 }
2877
2878 /*
2879 * Remove connection from the "from" NAT mapping connection list
2880 */
2881 if (!ci->from_nat_prev) {
2882 DEBUG_ASSERT(ci->mapping_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2883 ci->mapping_nat_from->from_nat_connections = ci->from_nat_next;
2884 } else {
2885 ci->from_nat_prev->from_nat_next = ci->from_nat_next;
2886 }
2887 if (ci->from_nat_next) {
2888 ci->from_nat_next->from_nat_prev = ci->from_nat_prev;
2889 }
2890
2891 /*
2892 * Remove connection from the "to" NAT mapping connection list
2893 */
2894 if (!ci->to_nat_prev) {
2895 DEBUG_ASSERT(ci->mapping_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2896 ci->mapping_nat_to->to_nat_connections = ci->to_nat_next;
2897 } else {
2898 ci->to_nat_prev->to_nat_next = ci->to_nat_next;
2899 }
2900 if (ci->to_nat_next) {
2901 ci->to_nat_next->to_nat_prev = ci->to_nat_prev;
2902 }
2903
2904 /*
2905 * Remove connection from the "from" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002906 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002907 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002908 iface_from = ci->from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002909 if (!ci->iface_from_prev) {
2910 DEBUG_ASSERT(iface_from->from_connections == ci, "%p: iface from conn table bad\n", ci);
2911 iface_from->from_connections = ci->iface_from_next;
2912 } else {
2913 ci->iface_from_prev->iface_from_next = ci->iface_from_next;
2914 }
2915 if (ci->iface_from_next) {
2916 ci->iface_from_next->iface_from_prev = ci->iface_from_prev;
2917 }
2918
2919 /*
2920 * Remove connection from the "to" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002921 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002922 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002923 iface_to = ci->to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002924 if (!ci->iface_to_prev) {
2925 DEBUG_ASSERT(iface_to->to_connections == ci, "%p: to conn table bad\n", ci);
2926 iface_to->to_connections = ci->iface_to_next;
2927 } else {
2928 ci->iface_to_prev->iface_to_next = ci->iface_to_next;
2929 }
2930 if (ci->iface_to_next) {
2931 ci->iface_to_next->iface_to_prev = ci->iface_to_prev;
2932 }
2933
2934 /*
2935 * Remove connection from the "from" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002936 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002937 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002938 iface_nat_from = ci->from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002939 if (!ci->iface_from_nat_prev) {
2940 DEBUG_ASSERT(iface_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2941 iface_nat_from->from_nat_connections = ci->iface_from_nat_next;
2942 } else {
2943 ci->iface_from_nat_prev->iface_from_nat_next = ci->iface_from_nat_next;
2944 }
2945 if (ci->iface_from_nat_next) {
2946 ci->iface_from_nat_next->iface_from_nat_prev = ci->iface_from_nat_prev;
2947 }
2948
2949 /*
2950 * Remove connection from the "to" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002951 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002952 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002953 iface_nat_to = ci->to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002954 if (!ci->iface_to_nat_prev) {
2955 DEBUG_ASSERT(iface_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2956 iface_nat_to->to_nat_connections = ci->iface_to_nat_next;
2957 } else {
2958 ci->iface_to_nat_prev->iface_to_nat_next = ci->iface_to_nat_next;
2959 }
2960 if (ci->iface_to_nat_next) {
2961 ci->iface_to_nat_next->iface_to_nat_prev = ci->iface_to_nat_prev;
2962 }
2963
2964 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01002965 * Remove connection from its "from node" node connection list
2966 */
2967 if (!ci->node_from_prev) {
2968 DEBUG_ASSERT(ci->from_node->from_connections == ci, "%p: from node conn table bad, got: %p\n", ci, ci->from_node->from_connections);
2969 ci->from_node->from_connections = ci->node_from_next;
2970 } else {
2971 ci->node_from_prev->node_from_next = ci->node_from_next;
2972 }
2973 if (ci->node_from_next) {
2974 ci->node_from_next->node_from_prev = ci->node_from_prev;
2975 }
2976 ci->from_node->from_connections_count--;
2977 DEBUG_ASSERT(ci->from_node->from_connections_count >= 0, "%p: bad count\n", ci);
2978
2979 /*
2980 * Remove connection from its "to node" node connection list
2981 */
2982 if (!ci->node_to_prev) {
2983 DEBUG_ASSERT(ci->to_node->to_connections == ci, "%p: to node conn table bad, got: %p\n", ci, ci->to_node->to_connections);
2984 ci->to_node->to_connections = ci->node_to_next;
2985 } else {
2986 ci->node_to_prev->node_to_next = ci->node_to_next;
2987 }
2988 if (ci->node_to_next) {
2989 ci->node_to_next->node_to_prev = ci->node_to_prev;
2990 }
2991 ci->to_node->to_connections_count--;
2992 DEBUG_ASSERT(ci->to_node->to_connections_count >= 0, "%p: bad count\n", ci);
2993
2994 /*
2995 * Remove connection from its "from nat node" node connection list
2996 */
2997 if (!ci->node_from_nat_prev) {
2998 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections == ci, "%p: from nat node conn table bad, got: %p\n", ci, ci->from_nat_node->from_nat_connections);
2999 ci->from_nat_node->from_nat_connections = ci->node_from_nat_next;
3000 } else {
3001 ci->node_from_nat_prev->node_from_nat_next = ci->node_from_nat_next;
3002 }
3003 if (ci->node_from_nat_next) {
3004 ci->node_from_nat_next->node_from_nat_prev = ci->node_from_nat_prev;
3005 }
3006 ci->from_nat_node->from_nat_connections_count--;
3007 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections_count >= 0, "%p: bad count\n", ci);
3008
3009 /*
3010 * Remove connection from its "to nat node" node connection list
3011 */
3012 if (!ci->node_to_nat_prev) {
3013 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections == ci, "%p: to nat node conn table bad, got: %p\n", ci, ci->to_nat_node->to_nat_connections);
3014 ci->to_nat_node->to_nat_connections = ci->node_to_nat_next;
3015 } else {
3016 ci->node_to_nat_prev->node_to_nat_next = ci->node_to_nat_next;
3017 }
3018 if (ci->node_to_nat_next) {
3019 ci->node_to_nat_next->node_to_nat_prev = ci->node_to_nat_prev;
3020 }
3021 ci->to_nat_node->to_nat_connections_count--;
3022 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections_count >= 0, "%p: bad count\n", ci);
Gareth Williamsb5903892015-03-20 15:13:07 +00003023#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01003024
3025 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003026 * Update the counters in the mappings
3027 */
3028 if (ci->protocol == IPPROTO_UDP) {
3029 ci->mapping_from->udp_from--;
3030 ci->mapping_to->udp_to--;
3031 ci->mapping_nat_from->udp_nat_from--;
3032 ci->mapping_nat_to->udp_nat_to--;
3033 } else if (ci->protocol == IPPROTO_TCP) {
3034 ci->mapping_from->tcp_from--;
3035 ci->mapping_to->tcp_to--;
3036 ci->mapping_nat_from->tcp_nat_from--;
3037 ci->mapping_nat_to->tcp_nat_to--;
3038 }
3039
3040 ci->mapping_from->from--;
3041 ci->mapping_to->to--;
3042 ci->mapping_nat_from->nat_from--;
3043 ci->mapping_nat_to->nat_to--;
3044
3045 /*
3046 * Assert that the defunt timer has been detached
3047 */
3048 DEBUG_ASSERT(ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX, "%p: unexpected timer group %d\n", ci, ci->defunct_timer.group);
3049
3050 /*
3051 * Decrement protocol counter stats
3052 */
3053 ecm_db_connection_count_by_protocol[ci->protocol]--;
3054 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[ci->protocol] >= 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[ci->protocol]);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01003055
Ben Menchaca84f36632014-02-28 20:57:38 +00003056 spin_unlock_bh(&ecm_db_lock);
3057
3058 /*
3059 * Throw removed event to listeners
3060 */
3061 DEBUG_TRACE("%p: Throw connection removed event\n", ci);
3062 li = ecm_db_listeners_get_and_ref_first();
3063 while (li) {
3064 struct ecm_db_listener_instance *lin;
3065 if (li->connection_removed) {
3066 li->connection_removed(li->arg, ci);
3067 }
3068
3069 /*
3070 * Get next listener
3071 */
3072 lin = ecm_db_listener_get_and_ref_next(li);
3073 ecm_db_listener_deref(li);
3074 li = lin;
3075 }
3076 }
3077
3078 /*
3079 * Throw final event
3080 */
3081 if (ci->final) {
3082 ci->final(ci->arg);
3083 }
3084
3085 /*
3086 * Release instances to the objects referenced by the connection
3087 */
3088 while (ci->assignments) {
3089 struct ecm_classifier_instance *classi = ci->assignments;
3090 ci->assignments = classi->ca_next;
3091 classi->deref(classi);
3092 }
3093
Ben Menchaca84f36632014-02-28 20:57:38 +00003094 if (ci->mapping_from) {
3095 ecm_db_mapping_deref(ci->mapping_from);
3096 }
3097 if (ci->mapping_to) {
3098 ecm_db_mapping_deref(ci->mapping_to);
3099 }
3100 if (ci->mapping_nat_from) {
3101 ecm_db_mapping_deref(ci->mapping_nat_from);
3102 }
3103 if (ci->mapping_nat_to) {
3104 ecm_db_mapping_deref(ci->mapping_nat_to);
3105 }
3106 if (ci->feci) {
3107 ci->feci->deref(ci->feci);
3108 }
Gareth Williams90f2a282014-08-27 15:56:25 +01003109 if (ci->from_node) {
3110 ecm_db_node_deref(ci->from_node);
3111 }
3112 if (ci->to_node) {
3113 ecm_db_node_deref(ci->to_node);
3114 }
3115 if (ci->from_nat_node) {
3116 ecm_db_node_deref(ci->from_nat_node);
3117 }
3118 if (ci->to_nat_node) {
3119 ecm_db_node_deref(ci->to_nat_node);
3120 }
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05303121#ifdef ECM_MULTICAST_ENABLE
3122 if (ci->ti) {
3123 ecm_db_multicast_tuple_instance_deref(ci->ti);
3124 }
3125#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003126 /*
3127 * Remove references to the interfaces in our heirarchy lists
3128 */
3129 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3130 DEBUG_TRACE("%p: from interface %d remove: %p\n", ci, i, ci->from_interfaces[i]);
3131 ecm_db_iface_deref(ci->from_interfaces[i]);
3132 }
3133 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3134 DEBUG_TRACE("%p: to interface %d remove: %p\n", ci, i, ci->to_interfaces[i]);
3135 ecm_db_iface_deref(ci->to_interfaces[i]);
3136 }
3137 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3138 DEBUG_TRACE("%p: from nat interface %d remove: %p\n", ci, i, ci->from_nat_interfaces[i]);
3139 ecm_db_iface_deref(ci->from_nat_interfaces[i]);
3140 }
3141 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3142 DEBUG_TRACE("%p: to nat interface %d remove: %p\n", ci, i, ci->to_nat_interfaces[i]);
3143 ecm_db_iface_deref(ci->to_nat_interfaces[i]);
3144 }
3145
3146 /*
3147 * We can now destroy the instance
3148 */
3149 DEBUG_CLEAR_MAGIC(ci);
3150 kfree(ci);
3151
3152 /*
3153 * Decrease global connection count
3154 */
3155 spin_lock_bh(&ecm_db_lock);
3156 ecm_db_connection_count--;
3157 DEBUG_ASSERT(ecm_db_connection_count >= 0, "%p: connection count wrap\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00003158 spin_unlock_bh(&ecm_db_lock);
3159
Ben Menchaca84f36632014-02-28 20:57:38 +00003160 return 0;
3161}
3162EXPORT_SYMBOL(ecm_db_connection_deref);
3163
3164/*
3165 * ecm_db_mapping_deref()
3166 * Release ref to mapping, possibly removing it from the database and destroying it.
3167 */
3168int ecm_db_mapping_deref(struct ecm_db_mapping_instance *mi)
3169{
3170 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
3171
3172 spin_lock_bh(&ecm_db_lock);
3173 mi->refs--;
3174 DEBUG_TRACE("%p: mapping deref %d\n", mi, mi->refs);
3175 DEBUG_ASSERT(mi->refs >= 0, "%p: ref wrap\n", mi);
3176
3177 if (mi->refs > 0) {
3178 int refs = mi->refs;
3179 spin_unlock_bh(&ecm_db_lock);
3180 return refs;
3181 }
3182
Gareth Williamsb5903892015-03-20 15:13:07 +00003183 DEBUG_ASSERT(!mi->tcp_from && !mi->udp_from && !mi->from, "%p: from not zero: %d, %d, %d\n",
3184 mi, mi->tcp_from, mi->udp_from, mi->from);
3185 DEBUG_ASSERT(!mi->tcp_to && !mi->udp_to && !mi->to, "%p: to not zero: %d, %d, %d\n",
3186 mi, mi->tcp_to, mi->udp_to, mi->to);
3187 DEBUG_ASSERT(!mi->tcp_nat_from && !mi->udp_nat_from && !mi->nat_from, "%p: nat_from not zero: %d, %d, %d\n",
3188 mi, mi->tcp_nat_from, mi->udp_nat_from, mi->nat_from);
3189 DEBUG_ASSERT(!mi->tcp_nat_to && !mi->udp_nat_to && !mi->nat_to, "%p: nat_to not zero: %d, %d, %d\n",
3190 mi, mi->tcp_nat_to, mi->udp_nat_to, mi->nat_to);
3191
3192#ifdef ECM_DB_XREF_ENABLE
3193 DEBUG_ASSERT(!mi->from_connections, "%p: from not null: %p\n", mi, mi->from_connections);
3194 DEBUG_ASSERT(!mi->to_connections, "%p: to not null: %p\n", mi, mi->to_connections);
3195 DEBUG_ASSERT(!mi->from_nat_connections, "%p: nat_from not null: %p\n", mi, mi->from_nat_connections);
3196 DEBUG_ASSERT(!mi->to_nat_connections, "%p: nat_to not null: %p\n", mi, mi->to_nat_connections);
3197#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003198
3199 /*
3200 * Remove from database if inserted
3201 */
3202 if (!mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED) {
3203 spin_unlock_bh(&ecm_db_lock);
3204 } else {
3205 struct ecm_db_listener_instance *li;
3206
3207 /*
3208 * Remove from the global list
3209 */
3210 if (!mi->prev) {
3211 DEBUG_ASSERT(ecm_db_mappings == mi, "%p: mapping table bad\n", mi);
3212 ecm_db_mappings = mi->next;
3213 } else {
3214 mi->prev->next = mi->next;
3215 }
3216 if (mi->next) {
3217 mi->next->prev = mi->prev;
3218 }
3219
3220 /*
3221 * Unlink it from the mapping hash table
3222 */
3223 if (!mi->hash_prev) {
3224 DEBUG_ASSERT(ecm_db_mapping_table[mi->hash_index] == mi, "%p: hash table bad\n", mi);
3225 ecm_db_mapping_table[mi->hash_index] = mi->hash_next;
3226 } else {
3227 mi->hash_prev->hash_next = mi->hash_next;
3228 }
3229 if (mi->hash_next) {
3230 mi->hash_next->hash_prev = mi->hash_prev;
3231 }
3232 mi->hash_next = NULL;
3233 mi->hash_prev = NULL;
3234 ecm_db_mapping_table_lengths[mi->hash_index]--;
3235 DEBUG_ASSERT(ecm_db_mapping_table_lengths[mi->hash_index] >= 0, "%p: invalid table len %d\n", mi, ecm_db_mapping_table_lengths[mi->hash_index]);
3236
Gareth Williamsb5903892015-03-20 15:13:07 +00003237#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003238 /*
3239 * Unlink it from the host mapping list
3240 */
3241 if (!mi->mapping_prev) {
3242 DEBUG_ASSERT(mi->host->mappings == mi, "%p: mapping table bad\n", mi);
3243 mi->host->mappings = mi->mapping_next;
3244 } else {
3245 mi->mapping_prev->mapping_next = mi->mapping_next;
3246 }
3247 if (mi->mapping_next) {
3248 mi->mapping_next->mapping_prev = mi->mapping_prev;
3249 }
3250 mi->mapping_next = NULL;
3251 mi->mapping_prev = NULL;
3252
3253 mi->host->mapping_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003254#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003255 spin_unlock_bh(&ecm_db_lock);
3256
3257 /*
3258 * Throw removed event to listeners
3259 */
3260 DEBUG_TRACE("%p: Throw mapping removed event\n", mi);
3261 li = ecm_db_listeners_get_and_ref_first();
3262 while (li) {
3263 struct ecm_db_listener_instance *lin;
3264 if (li->mapping_removed) {
3265 li->mapping_removed(li->arg, mi);
3266 }
3267
3268 /*
3269 * Get next listener
3270 */
3271 lin = ecm_db_listener_get_and_ref_next(li);
3272 ecm_db_listener_deref(li);
3273 li = lin;
3274 }
3275 }
3276
3277 /*
3278 * Throw final event
3279 */
3280 if (mi->final) {
3281 mi->final(mi->arg);
3282 }
3283
3284 /*
3285 * Now release the host instance if the mapping had one
3286 */
3287 if (mi->host) {
3288 ecm_db_host_deref(mi->host);
3289 }
3290
3291 /*
3292 * We can now destroy the instance
3293 */
3294 DEBUG_CLEAR_MAGIC(mi);
3295 kfree(mi);
3296
3297 /*
3298 * Decrease global mapping count
3299 */
3300 spin_lock_bh(&ecm_db_lock);
3301 ecm_db_mapping_count--;
3302 DEBUG_ASSERT(ecm_db_mapping_count >= 0, "%p: mapping count wrap\n", mi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003303 spin_unlock_bh(&ecm_db_lock);
3304
Ben Menchaca84f36632014-02-28 20:57:38 +00003305 return 0;
3306}
3307EXPORT_SYMBOL(ecm_db_mapping_deref);
3308
3309/*
3310 * ecm_db_host_deref()
3311 * Release a ref to a host instance, possibly causing removal from the database and destruction of the instance
3312 */
3313int ecm_db_host_deref(struct ecm_db_host_instance *hi)
3314{
3315 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
3316
3317 spin_lock_bh(&ecm_db_lock);
3318 hi->refs--;
3319 DEBUG_TRACE("%p: host deref %d\n", hi, hi->refs);
3320 DEBUG_ASSERT(hi->refs >= 0, "%p: ref wrap\n", hi);
3321
3322 if (hi->refs > 0) {
3323 int refs = hi->refs;
3324 spin_unlock_bh(&ecm_db_lock);
3325 return refs;
3326 }
3327
Gareth Williamsb5903892015-03-20 15:13:07 +00003328#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003329 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00003330#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003331
3332 /*
3333 * Remove from database if inserted
3334 */
3335 if (!hi->flags & ECM_DB_HOST_FLAGS_INSERTED) {
3336 spin_unlock_bh(&ecm_db_lock);
3337 } else {
3338 struct ecm_db_listener_instance *li;
3339
3340 /*
3341 * Remove from the global list
3342 */
3343 if (!hi->prev) {
3344 DEBUG_ASSERT(ecm_db_hosts == hi, "%p: host table bad\n", hi);
3345 ecm_db_hosts = hi->next;
3346 } else {
3347 hi->prev->next = hi->next;
3348 }
3349 if (hi->next) {
3350 hi->next->prev = hi->prev;
3351 }
3352
3353 /*
3354 * Unlink it from the host hash table
3355 */
3356 if (!hi->hash_prev) {
3357 DEBUG_ASSERT(ecm_db_host_table[hi->hash_index] == hi, "%p: hash table bad\n", hi);
3358 ecm_db_host_table[hi->hash_index] = hi->hash_next;
3359 } else {
3360 hi->hash_prev->hash_next = hi->hash_next;
3361 }
3362 if (hi->hash_next) {
3363 hi->hash_next->hash_prev = hi->hash_prev;
3364 }
3365 hi->hash_next = NULL;
3366 hi->hash_prev = NULL;
3367 ecm_db_host_table_lengths[hi->hash_index]--;
3368 DEBUG_ASSERT(ecm_db_host_table_lengths[hi->hash_index] >= 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hi->hash_index]);
3369
Ben Menchaca84f36632014-02-28 20:57:38 +00003370 spin_unlock_bh(&ecm_db_lock);
3371
3372 /*
3373 * Throw removed event to listeners
3374 */
3375 DEBUG_TRACE("%p: Throw host removed event\n", hi);
3376 li = ecm_db_listeners_get_and_ref_first();
3377 while (li) {
3378 struct ecm_db_listener_instance *lin;
3379 if (li->host_removed) {
3380 li->host_removed(li->arg, hi);
3381 }
3382
3383 /*
3384 * Get next listener
3385 */
3386 lin = ecm_db_listener_get_and_ref_next(li);
3387 ecm_db_listener_deref(li);
3388 li = lin;
3389 }
3390 }
3391
3392 /*
3393 * Throw final event
3394 */
3395 if (hi->final) {
3396 hi->final(hi->arg);
3397 }
3398
3399 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003400 * We can now destroy the instance
3401 */
3402 DEBUG_CLEAR_MAGIC(hi);
3403 kfree(hi);
3404
3405 /*
3406 * Decrease global host count
3407 */
3408 spin_lock_bh(&ecm_db_lock);
3409 ecm_db_host_count--;
3410 DEBUG_ASSERT(ecm_db_host_count >= 0, "%p: host count wrap\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003411 spin_unlock_bh(&ecm_db_lock);
3412
Ben Menchaca84f36632014-02-28 20:57:38 +00003413 return 0;
3414}
3415EXPORT_SYMBOL(ecm_db_host_deref);
3416
3417/*
3418 * ecm_db_node_deref()
3419 * Deref a node. Removing it on the last ref and destroying it.
3420 */
3421int ecm_db_node_deref(struct ecm_db_node_instance *ni)
3422{
3423 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
3424
3425 spin_lock_bh(&ecm_db_lock);
3426 ni->refs--;
3427 DEBUG_TRACE("%p: node deref %d\n", ni, ni->refs);
3428 DEBUG_ASSERT(ni->refs >= 0, "%p: ref wrap\n", ni);
3429
3430 if (ni->refs > 0) {
3431 int refs = ni->refs;
3432 spin_unlock_bh(&ecm_db_lock);
3433 return refs;
3434 }
3435
Gareth Williamsb5903892015-03-20 15:13:07 +00003436#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01003437 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
3438 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
3439 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
3440 DEBUG_ASSERT((ni->to_nat_connections == NULL) && (ni->to_nat_connections_count == 0), "%p: to_nat_connections not null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00003441#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003442
3443 /*
3444 * Remove from database if inserted
3445 */
3446 if (!ni->flags & ECM_DB_NODE_FLAGS_INSERTED) {
3447 spin_unlock_bh(&ecm_db_lock);
3448 } else {
3449 struct ecm_db_listener_instance *li;
3450
3451 /*
3452 * Remove from the global list
3453 */
3454 if (!ni->prev) {
3455 DEBUG_ASSERT(ecm_db_nodes == ni, "%p: node table bad\n", ni);
3456 ecm_db_nodes = ni->next;
3457 } else {
3458 ni->prev->next = ni->next;
3459 }
3460 if (ni->next) {
3461 ni->next->prev = ni->prev;
3462 }
3463
3464 /*
3465 * Link out of hash table
3466 */
3467 if (!ni->hash_prev) {
3468 DEBUG_ASSERT(ecm_db_node_table[ni->hash_index] == ni, "%p: hash table bad\n", ni);
3469 ecm_db_node_table[ni->hash_index] = ni->hash_next;
3470 } else {
3471 ni->hash_prev->hash_next = ni->hash_next;
3472 }
3473 if (ni->hash_next) {
3474 ni->hash_next->hash_prev = ni->hash_prev;
3475 }
3476 ni->hash_next = NULL;
3477 ni->hash_prev = NULL;
3478 ecm_db_node_table_lengths[ni->hash_index]--;
3479 DEBUG_ASSERT(ecm_db_node_table_lengths[ni->hash_index] >= 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[ni->hash_index]);
3480
Gareth Williamsb5903892015-03-20 15:13:07 +00003481#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003482 /*
3483 * Unlink it from the iface node list
3484 */
3485 if (!ni->node_prev) {
3486 DEBUG_ASSERT(ni->iface->nodes == ni, "%p: nodes table bad\n", ni);
3487 ni->iface->nodes = ni->node_next;
3488 } else {
3489 ni->node_prev->node_next = ni->node_next;
3490 }
3491 if (ni->node_next) {
3492 ni->node_next->node_prev = ni->node_prev;
3493 }
3494 ni->node_next = NULL;
3495 ni->node_prev = NULL;
3496 ni->iface->node_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003497#endif
3498
Ben Menchaca84f36632014-02-28 20:57:38 +00003499 spin_unlock_bh(&ecm_db_lock);
3500
3501 /*
3502 * Throw removed event to listeners
3503 */
3504 DEBUG_TRACE("%p: Throw node removed event\n", ni);
3505 li = ecm_db_listeners_get_and_ref_first();
3506 while (li) {
3507 struct ecm_db_listener_instance *lin;
3508 if (li->node_removed) {
3509 li->node_removed(li->arg, ni);
3510 }
3511
3512 /*
3513 * Get next listener
3514 */
3515 lin = ecm_db_listener_get_and_ref_next(li);
3516 ecm_db_listener_deref(li);
3517 li = lin;
3518 }
3519 }
3520
3521 /*
3522 * Throw final event
3523 */
3524 if (ni->final) {
3525 ni->final(ni->arg);
3526 }
3527
3528 /*
3529 * Now release the iface instance if the node had one
3530 */
3531 if (ni->iface) {
3532 ecm_db_iface_deref(ni->iface);
3533 }
3534
3535 /*
3536 * We can now destroy the instance
3537 */
3538 DEBUG_CLEAR_MAGIC(ni);
3539 kfree(ni);
3540
3541 /*
3542 * Decrease global node count
3543 */
3544 spin_lock_bh(&ecm_db_lock);
3545 ecm_db_node_count--;
3546 DEBUG_ASSERT(ecm_db_node_count >= 0, "%p: node count wrap\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00003547 spin_unlock_bh(&ecm_db_lock);
3548
Ben Menchaca84f36632014-02-28 20:57:38 +00003549 return 0;
3550}
3551EXPORT_SYMBOL(ecm_db_node_deref);
3552
3553/*
3554 * ecm_db_iface_deref()
3555 * Deref a interface instance, removing it from the database on the last ref release
3556 */
3557int ecm_db_iface_deref(struct ecm_db_iface_instance *ii)
3558{
3559 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
3560
3561 /*
3562 * Decrement reference count
3563 */
3564 spin_lock_bh(&ecm_db_lock);
3565 ii->refs--;
3566 DEBUG_TRACE("%p: iface deref %d\n", ii, ii->refs);
3567 DEBUG_ASSERT(ii->refs >= 0, "%p: ref wrap\n", ii);
3568
3569 if (ii->refs > 0) {
3570 int refs = ii->refs;
3571 spin_unlock_bh(&ecm_db_lock);
3572 return refs;
3573 }
3574
Gareth Williamsb5903892015-03-20 15:13:07 +00003575#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003576 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00003577#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003578
3579 /*
3580 * Remove from database if inserted
3581 */
3582 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
3583 spin_unlock_bh(&ecm_db_lock);
3584 } else {
3585 struct ecm_db_listener_instance *li;
3586
3587 /*
3588 * Remove from the global list
3589 */
3590 if (!ii->prev) {
3591 DEBUG_ASSERT(ecm_db_interfaces == ii, "%p: interface table bad\n", ii);
3592 ecm_db_interfaces = ii->next;
3593 } else {
3594 ii->prev->next = ii->next;
3595 }
3596 if (ii->next) {
3597 ii->next->prev = ii->prev;
3598 }
3599
3600 /*
3601 * Link out of hash table
3602 */
3603 if (!ii->hash_prev) {
3604 DEBUG_ASSERT(ecm_db_iface_table[ii->hash_index] == ii, "%p: hash table bad got %p for hash index %u\n", ii, ecm_db_iface_table[ii->hash_index], ii->hash_index);
3605 ecm_db_iface_table[ii->hash_index] = ii->hash_next;
3606 } else {
3607 ii->hash_prev->hash_next = ii->hash_next;
3608 }
3609 if (ii->hash_next) {
3610 ii->hash_next->hash_prev = ii->hash_prev;
3611 }
3612 ii->hash_next = NULL;
3613 ii->hash_prev = NULL;
3614 ecm_db_iface_table_lengths[ii->hash_index]--;
3615 DEBUG_ASSERT(ecm_db_iface_table_lengths[ii->hash_index] >= 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[ii->hash_index]);
Murat Sezgin91c5d712015-06-12 15:16:22 -07003616
3617 /*
3618 * Link out of interface identifier hash table
3619 */
3620 if (!ii->iface_id_hash_prev) {
3621 DEBUG_ASSERT(ecm_db_iface_id_table[ii->iface_id_hash_index] == ii, "%p: hash table bad got %p for hash index %u\n", ii, ecm_db_iface_id_table[ii->iface_id_hash_index], ii->iface_id_hash_index);
3622 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
3623 } else {
3624 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
3625 }
3626 if (ii->iface_id_hash_next) {
3627 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
3628 }
3629 ii->iface_id_hash_next = NULL;
3630 ii->iface_id_hash_prev = NULL;
3631 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
3632 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[ii->iface_id_hash_index] >= 0, "%p: invalid table len %d\n", ii, ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]);
Ben Menchaca84f36632014-02-28 20:57:38 +00003633 spin_unlock_bh(&ecm_db_lock);
3634
3635 /*
3636 * Throw removed event to listeners
3637 */
3638 DEBUG_TRACE("%p: Throw iface removed event\n", ii);
3639 li = ecm_db_listeners_get_and_ref_first();
3640 while (li) {
3641 struct ecm_db_listener_instance *lin;
3642 if (li->iface_removed) {
3643 li->iface_removed(li->arg, ii);
3644 }
3645
3646 /*
3647 * Get next listener
3648 */
3649 lin = ecm_db_listener_get_and_ref_next(li);
3650 ecm_db_listener_deref(li);
3651 li = lin;
3652 }
3653 }
3654
3655 /*
3656 * Throw final event
3657 */
3658 if (ii->final) {
3659 ii->final(ii->arg);
3660 }
3661
3662 /*
3663 * We can now destroy the instance
3664 */
3665 DEBUG_CLEAR_MAGIC(ii);
3666 kfree(ii);
3667
3668 /*
3669 * Decrease global interface count
3670 */
3671 spin_lock_bh(&ecm_db_lock);
3672 ecm_db_iface_count--;
3673 DEBUG_ASSERT(ecm_db_iface_count >= 0, "%p: iface count wrap\n", ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00003674 spin_unlock_bh(&ecm_db_lock);
3675
Ben Menchaca84f36632014-02-28 20:57:38 +00003676 return 0;
3677}
3678EXPORT_SYMBOL(ecm_db_iface_deref);
3679
3680/*
3681 * ecm_db_listener_deref()
3682 * Release reference to listener.
3683 *
3684 * On final reference release listener shall be removed from the database.
3685 */
3686int ecm_db_listener_deref(struct ecm_db_listener_instance *li)
3687{
3688 struct ecm_db_listener_instance *cli;
3689 struct ecm_db_listener_instance **cli_prev;
3690
3691 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
3692
3693 spin_lock_bh(&ecm_db_lock);
3694 li->refs--;
3695 DEBUG_ASSERT(li->refs >= 0, "%p: ref wrap\n", li);
3696 if (li->refs > 0) {
3697 int refs;
3698 refs = li->refs;
3699 spin_unlock_bh(&ecm_db_lock);
3700 return refs;
3701 }
3702
3703 /*
3704 * Instance is to be removed and destroyed.
3705 * Link the listener out of the listener list.
3706 */
3707 cli = ecm_db_listeners;
3708 cli_prev = &ecm_db_listeners;
3709 while (cli) {
3710 if (cli == li) {
3711 *cli_prev = cli->next;
3712 break;
3713 }
3714 cli_prev = &cli->next;
3715 cli = cli->next;
3716 }
3717 DEBUG_ASSERT(cli, "%p: not found\n", li);
3718 spin_unlock_bh(&ecm_db_lock);
3719
3720 /*
3721 * Invoke final callback
3722 */
3723 if (li->final) {
3724 li->final(li->arg);
3725 }
3726 DEBUG_CLEAR_MAGIC(li);
3727 kfree(li);
3728
3729 /*
3730 * Decrease global listener count
3731 */
3732 spin_lock_bh(&ecm_db_lock);
3733 ecm_db_listeners_count--;
3734 DEBUG_ASSERT(ecm_db_listeners_count >= 0, "%p: listener count wrap\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00003735 spin_unlock_bh(&ecm_db_lock);
3736
Ben Menchaca84f36632014-02-28 20:57:38 +00003737 return 0;
3738}
3739EXPORT_SYMBOL(ecm_db_listener_deref);
3740
3741/*
3742 * ecm_db_connection_defunct_all()
3743 * Make defunct ALL connections.
3744 *
3745 * This API is typically used in shutdown situations commanded by the user.
3746 * NOTE: Ensure all front ends are stopped to avoid further connections being created while this is running.
3747 */
3748void ecm_db_connection_defunct_all(void)
3749{
3750 struct ecm_db_connection_instance *ci;
3751
3752 DEBUG_INFO("Defuncting all\n");
3753
3754 /*
3755 * Iterate all connections
3756 */
3757 ci = ecm_db_connections_get_and_ref_first();
3758 while (ci) {
3759 struct ecm_db_connection_instance *cin;
3760
3761 DEBUG_TRACE("%p: defunct\n", ci);
3762 ecm_db_connection_make_defunct(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303763
Ben Menchaca84f36632014-02-28 20:57:38 +00003764 cin = ecm_db_connection_get_and_ref_next(ci);
3765 ecm_db_connection_deref(ci);
3766 ci = cin;
3767 }
3768 DEBUG_INFO("Defuncting complete\n");
3769}
3770EXPORT_SYMBOL(ecm_db_connection_defunct_all);
3771
3772/*
3773 * ecm_db_connection_generate_hash_index()
3774 * Calculate the hash index.
3775 *
3776 * Note: The hash we produce is symmetric - i.e. we can swap the "from" and "to"
3777 * details without generating a different hash index!
3778 */
3779static inline ecm_db_connection_hash_t ecm_db_connection_generate_hash_index(ip_addr_t host1_addr, uint32_t host1_port, ip_addr_t host2_addr, uint32_t host2_port, int protocol)
3780{
Gareth Williams54d15d92015-04-24 19:28:27 +01003781 uint32_t hah1;
3782 uint32_t hah2;
3783 uint32_t ht1;
Ben Menchaca84f36632014-02-28 20:57:38 +00003784 uint32_t hash_val;
3785
3786 /*
3787 * The hash function only uses both host 1 address/port, host 2 address/port
3788 * and protocol fields.
3789 */
Gareth Williams54d15d92015-04-24 19:28:27 +01003790 ECM_IP_ADDR_HASH(hah1, host1_addr);
3791 ECM_IP_ADDR_HASH(hah2, host2_addr);
3792 ht1 = (u32)hah1 + host1_port + hah2 + host2_port + (uint32_t)protocol;
3793 hash_val = (uint32_t)jhash_1word(ht1, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003794 return (ecm_db_connection_hash_t)(hash_val & (ECM_DB_CONNECTION_HASH_SLOTS - 1));
3795}
3796
3797/*
3798 * ecm_db_connection_generate_serial_hash_index()
3799 * Calculate the serial hash index.
3800 */
3801static inline ecm_db_connection_serial_hash_t ecm_db_connection_generate_serial_hash_index(uint32_t serial)
3802{
Gareth Williams54d15d92015-04-24 19:28:27 +01003803 uint32_t hash_val;
3804 hash_val = (uint32_t)jhash_1word(serial, ecm_db_jhash_rnd);
3805
3806 return (ecm_db_connection_serial_hash_t)(hash_val & (ECM_DB_CONNECTION_SERIAL_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003807}
3808
Shyam Sunder1f037262015-05-18 20:04:13 +05303809#ifdef ECM_MULTICAST_ENABLE
3810/*
3811 * ecm_db_multicast_generate_hash_index()
3812 * Calculate the hash index given a multicast group address.
3813 */
3814static inline ecm_db_multicast_tuple_instance_hash_t ecm_db_multicast_generate_hash_index(ip_addr_t address)
3815{
3816 uint32_t temp;
3817 uint32_t hash_val;
3818
3819 if (ECM_IP_ADDR_IS_V4(address)){
3820 temp = (uint32_t)address[0];
3821 } else {
3822 temp = (uint32_t)address[3];
3823 }
3824
3825 hash_val = (uint32_t)jhash_1word(temp, ecm_db_jhash_rnd);
3826
3827 return (ecm_db_multicast_tuple_instance_hash_t)(hash_val & (ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS - 1));
3828}
3829#endif
3830
Ben Menchaca84f36632014-02-28 20:57:38 +00003831/*
3832 * ecm_db_mapping_generate_hash_index()
3833 * Calculate the hash index.
3834 */
3835static inline ecm_db_mapping_hash_t ecm_db_mapping_generate_hash_index(ip_addr_t address, uint32_t port)
3836{
Gareth Williams54d15d92015-04-24 19:28:27 +01003837 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00003838 uint32_t hash_val;
3839
Gareth Williams54d15d92015-04-24 19:28:27 +01003840 ECM_IP_ADDR_HASH(tuple, address);
3841 hash_val = (uint32_t)jhash_2words(tuple, port, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003842 return (ecm_db_mapping_hash_t)(hash_val & (ECM_DB_MAPPING_HASH_SLOTS - 1));
3843}
3844
3845/*
3846 * ecm_db_host_generate_hash_index()
3847 * Calculate the hash index.
3848 */
3849static inline ecm_db_host_hash_t ecm_db_host_generate_hash_index(ip_addr_t address)
3850{
Gareth Williams54d15d92015-04-24 19:28:27 +01003851 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00003852 uint32_t hash_val;
3853
Gareth Williams54d15d92015-04-24 19:28:27 +01003854 ECM_IP_ADDR_HASH(tuple, address);
3855 hash_val = (uint32_t)jhash_1word(tuple, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003856 return (ecm_db_host_hash_t)(hash_val & (ECM_DB_HOST_HASH_SLOTS - 1));
3857}
3858
3859/*
3860 * ecm_db_node_generate_hash_index()
3861 * Calculate the hash index.
3862 */
3863static inline ecm_db_node_hash_t ecm_db_node_generate_hash_index(uint8_t *address)
3864{
3865 uint32_t hash_val;
3866
Gareth Williams54d15d92015-04-24 19:28:27 +01003867 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003868 hash_val &= (ECM_DB_NODE_HASH_SLOTS - 1);
3869
3870 return (ecm_db_node_hash_t)hash_val;
3871}
3872
Murat Sezgin91c5d712015-06-12 15:16:22 -07003873/*
3874 * ecm_db_iface_id_generate_hash_index()
3875 * Calculate the hash index based on interface identifier.
3876 */
3877static inline ecm_db_iface_id_hash_t ecm_db_iface_id_generate_hash_index(int32_t interface_id)
3878{
3879 uint32_t hash_val;
3880
3881 hash_val = (uint32_t)jhash_1word((uint32_t)interface_id, ecm_db_jhash_rnd);
3882 return (ecm_db_iface_id_hash_t)(hash_val & (ECM_DB_IFACE_ID_HASH_SLOTS - 1));
3883}
3884
Murat Sezginbde55f92015-03-11 16:44:11 -07003885#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003886/*
3887 * ecm_db_iface_generate_hash_index_sit()
3888 * Calculate the hash index.
3889 */
3890static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_sit(ip_addr_t saddr, ip_addr_t daddr)
3891{
Gareth Williams54d15d92015-04-24 19:28:27 +01003892 uint32_t tuple1;
3893 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00003894 uint32_t hash_val;
3895
Gareth Williams54d15d92015-04-24 19:28:27 +01003896 ECM_IP_ADDR_HASH(tuple1, saddr);
3897 ECM_IP_ADDR_HASH(tuple2, daddr);
3898 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003899 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3900}
Murat Sezginbde55f92015-03-11 16:44:11 -07003901#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003902
Murat Sezginc1402562015-03-12 12:32:20 -07003903#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00003904#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003905/*
3906 * ecm_db_iface_generate_hash_index_tunipip6()
3907 * Calculate the hash index.
3908 */
3909static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
3910{
Gareth Williams54d15d92015-04-24 19:28:27 +01003911 uint32_t tuple1;
3912 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00003913 uint32_t hash_val;
3914
Gareth Williams54d15d92015-04-24 19:28:27 +01003915 ECM_IP_ADDR_HASH(tuple1, saddr);
3916 ECM_IP_ADDR_HASH(tuple2, daddr);
3917 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003918 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3919}
Murat Sezginc1402562015-03-12 12:32:20 -07003920#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00003921#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003922
3923/*
3924 * ecm_db_iface_generate_hash_index_ethernet()
3925 * Calculate the hash index.
3926 */
3927static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ethernet(uint8_t *address)
3928{
Gareth Williams54d15d92015-04-24 19:28:27 +01003929 uint32_t hash_val;
3930 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
3931 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003932}
3933
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303934#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003935/*
3936 * ecm_db_iface_generate_hash_index_pppoe()
3937 * Calculate the hash index.
3938 */
3939static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppoe(uint16_t pppoe_session_id)
3940{
Gareth Williams54d15d92015-04-24 19:28:27 +01003941 uint32_t hash_val;
3942 hash_val = (uint32_t)jhash_1word((uint32_t)pppoe_session_id, ecm_db_jhash_rnd);
3943 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003944}
Murat Sezginaad635c2015-03-06 16:11:41 -08003945#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003946
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303947#ifdef ECM_INTERFACE_L2TPV2_ENABLE
3948/*
3949 * ecm_db_iface_generate_hash_index_pppol2tpv2()
3950 * Calculate the hash index.
3951 */
3952static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
3953{
3954 uint32_t hash_val;
3955 hash_val = (uint32_t)jhash_2words(pppol2tpv2_tunnel_id, pppol2tpv2_session_id, ecm_db_jhash_rnd);
3956 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3957}
3958
3959#endif
3960
Ben Menchaca84f36632014-02-28 20:57:38 +00003961/*
3962 * ecm_db_iface_generate_hash_index_unknown()
3963 * Calculate the hash index.
3964 */
3965static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_unknown(uint32_t os_specific_ident)
3966{
Gareth Williams54d15d92015-04-24 19:28:27 +01003967 uint32_t hash_val;
3968 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
3969 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003970}
3971
3972/*
3973 * ecm_db_iface_generate_hash_index_loopback()
3974 * Calculate the hash index.
3975 */
3976static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_loopback(uint32_t os_specific_ident)
3977{
Gareth Williams54d15d92015-04-24 19:28:27 +01003978 uint32_t hash_val;
3979 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
3980 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003981}
3982
Murat Sezgin69a27532015-03-12 14:09:40 -07003983#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003984/*
3985 * ecm_db_iface_generate_hash_index_ipsec_tunnel()
3986 * Calculate the hash index.
3987 * GGG TODO Flesh this out using actual tunnel endpoint keys
3988 */
3989static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ipsec_tunnel(uint32_t os_specific_ident)
3990{
Gareth Williams54d15d92015-04-24 19:28:27 +01003991 uint32_t hash_val;
3992 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
3993 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003994}
Murat Sezgin69a27532015-03-12 14:09:40 -07003995#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003996
3997/*
3998 * ecm_db_host_find_and_ref()
3999 * Lookup and return a host reference if any
4000 */
4001struct ecm_db_host_instance *ecm_db_host_find_and_ref(ip_addr_t address)
4002{
4003 ecm_db_host_hash_t hash_index;
4004 struct ecm_db_host_instance *hi;
4005
4006 DEBUG_TRACE("Lookup host with addr " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(address));
4007
4008 /*
4009 * Compute the hash chain index and prepare to walk the chain
4010 */
4011 hash_index = ecm_db_host_generate_hash_index(address);
4012
4013 /*
4014 * Iterate the chain looking for a host with matching details
4015 */
4016 spin_lock_bh(&ecm_db_lock);
4017 hi = ecm_db_host_table[hash_index];
4018 while (hi) {
4019 if (!ECM_IP_ADDR_MATCH(hi->address, address)) {
4020 hi = hi->hash_next;
4021 continue;
4022 }
4023
4024 _ecm_db_host_ref(hi);
4025 spin_unlock_bh(&ecm_db_lock);
4026 DEBUG_TRACE("host found %p\n", hi);
4027 return hi;
4028 }
4029 spin_unlock_bh(&ecm_db_lock);
4030 DEBUG_TRACE("Host not found\n");
4031 return NULL;
4032}
4033EXPORT_SYMBOL(ecm_db_host_find_and_ref);
4034
4035/*
4036 * ecm_db_node_find_and_ref()
4037 * Lookup and return a node reference if any
4038 */
4039struct ecm_db_node_instance *ecm_db_node_find_and_ref(uint8_t *address)
4040{
4041 ecm_db_node_hash_t hash_index;
4042 struct ecm_db_node_instance *ni;
4043
4044 DEBUG_TRACE("Lookup node with addr %pM\n", address);
4045
4046 /*
4047 * Compute the hash chain index and prepare to walk the chain
4048 */
4049 hash_index = ecm_db_node_generate_hash_index(address);
4050
4051 /*
4052 * Iterate the chain looking for a host with matching details
4053 */
4054 spin_lock_bh(&ecm_db_lock);
4055 ni = ecm_db_node_table[hash_index];
4056 while (ni) {
4057 if (memcmp(ni->address, address, ETH_ALEN)) {
4058 ni = ni->hash_next;
4059 continue;
4060 }
4061
4062 _ecm_db_node_ref(ni);
4063 spin_unlock_bh(&ecm_db_lock);
4064 DEBUG_TRACE("node found %p\n", ni);
4065 return ni;
4066 }
4067 spin_unlock_bh(&ecm_db_lock);
4068 DEBUG_TRACE("Node not found\n");
4069 return NULL;
4070}
4071EXPORT_SYMBOL(ecm_db_node_find_and_ref);
4072
4073/*
4074 * ecm_db_iface_ethernet_address_get()
4075 * Obtain the ethernet address for an ethernet interface
4076 */
4077void ecm_db_iface_ethernet_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4078{
4079 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4080 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_ETHERNET, "%p: Bad type, expected ethernet, actual: %d\n", ii, ii->type);
4081 spin_lock_bh(&ecm_db_lock);
4082 memcpy(address, ii->type_info.ethernet.address, sizeof(ii->type_info.ethernet.address));
4083 spin_unlock_bh(&ecm_db_lock);
4084}
4085EXPORT_SYMBOL(ecm_db_iface_ethernet_address_get);
4086
4087/*
Gareth Williams83125b12014-05-26 19:58:09 +01004088 * ecm_db_iface_bridge_address_get()
4089 * Obtain the ethernet address for a bridge interface
4090 */
4091void ecm_db_iface_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4092{
4093 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4094 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_BRIDGE, "%p: Bad type, expected bridge, actual: %d\n", ii, ii->type);
4095 spin_lock_bh(&ecm_db_lock);
4096 memcpy(address, ii->type_info.bridge.address, sizeof(ii->type_info.bridge.address));
4097 spin_unlock_bh(&ecm_db_lock);
4098}
4099EXPORT_SYMBOL(ecm_db_iface_bridge_address_get);
4100
Gareth Williamsf98d4192015-03-11 16:55:41 +00004101/*
Shyam Sunder39e25672015-09-03 14:28:09 +05304102 * _ecm_db_iface_identifier_hash_table_insert_entry()
4103 * Calculate the hash index based on updated interface_identifier, and
4104 * re-insert into interface identifier chain.
4105 *
4106 * Note: Must take ecm_db_lock before calling this.
4107 */
4108static void _ecm_db_iface_identifier_hash_table_insert_entry(struct ecm_db_iface_instance *ii, int32_t interface_identifier)
4109{
4110 ecm_db_iface_id_hash_t iface_id_hash_index;
4111
4112 /*
4113 * Compute hash chain for insertion
4114 */
4115 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
4116 ii->iface_id_hash_index = iface_id_hash_index;
4117
4118 /*
4119 * Insert into interface identifier chain
4120 */
4121 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
4122 if (ecm_db_iface_id_table[iface_id_hash_index]) {
4123 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
4124 }
4125
4126 ecm_db_iface_id_table[iface_id_hash_index] = ii;
4127 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
4128 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
4129}
4130
4131/*
4132 * _ecm_db_iface_identifier_hash_table_remove_entry()
4133 * Remove an entry of a given interface instance from interface identifier chain.
4134 *
4135 * Note: Must take ecm_db_lock before calling this.
4136 */
4137static void _ecm_db_iface_identifier_hash_table_remove_entry(struct ecm_db_iface_instance *ii)
4138{
4139 /*
4140 * Remove from database if inserted
4141 */
4142 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
4143 return;
4144 }
4145
4146 /*
4147 * Link out of interface identifier hash table
4148 */
4149 if (!ii->iface_id_hash_prev) {
4150 DEBUG_ASSERT(ecm_db_iface_id_table[ii->iface_id_hash_index] == ii, "%p: hash table bad got %p for hash index %u\n", ii, ecm_db_iface_id_table[ii->iface_id_hash_index], ii->iface_id_hash_index);
4151 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
4152 } else {
4153 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
4154 }
4155
4156 if (ii->iface_id_hash_next) {
4157 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
4158 }
4159
4160 ii->iface_id_hash_next = NULL;
4161 ii->iface_id_hash_prev = NULL;
4162 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
4163 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[ii->iface_id_hash_index] >= 0, "%p: invalid table len %d\n", ii, ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]);
4164}
4165
4166/*
4167 * ecm_db_iface_identifier_hash_table_entry_check_and_update()
4168 * Update the hash table entry of interface identifier hash table.
4169 * First remove the 'ii' from curent hash index position, re-calculate new hash and re-insert
4170 * the 'ii' at new hash index position into interface identifier hash table.
4171 */
4172void ecm_db_iface_identifier_hash_table_entry_check_and_update(struct ecm_db_iface_instance *ii, int32_t new_interface_identifier)
4173{
4174 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4175 spin_lock_bh(&ecm_db_lock);
4176 if (ii->interface_identifier == new_interface_identifier) {
4177 spin_unlock_bh(&ecm_db_lock);
4178 return;
4179 }
4180
4181 DEBUG_TRACE("%p: interface ifindex has changed Old %d, New %d \n", ii, ii->interface_identifier, new_interface_identifier);
4182 _ecm_db_iface_identifier_hash_table_remove_entry(ii);
4183 ii->interface_identifier = new_interface_identifier;
4184 _ecm_db_iface_identifier_hash_table_insert_entry(ii, new_interface_identifier);
4185 spin_unlock_bh(&ecm_db_lock);
4186}
4187EXPORT_SYMBOL(ecm_db_iface_identifier_hash_table_entry_check_and_update);
4188
4189/*
Murat Sezgin91c5d712015-06-12 15:16:22 -07004190 * ecm_db_iface_find_and_ref_by_interface_identifier()
4191 * Return an interface based on a hlos interface identifier
4192 */
4193struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_by_interface_identifier(int32_t interface_id)
4194{
4195 ecm_db_iface_id_hash_t hash_index;
4196 struct ecm_db_iface_instance *ii;
4197
4198 DEBUG_TRACE("Lookup database iface with interface_id %d\n", interface_id);
4199
4200 /*
4201 * Compute the hash chain index and prepare to walk the chain
4202 */
4203 hash_index = ecm_db_iface_id_generate_hash_index(interface_id);
4204
4205 /*
4206 * Iterate the chain looking for a host with matching details
4207 */
4208 spin_lock_bh(&ecm_db_lock);
4209 ii = ecm_db_iface_id_table[hash_index];
4210 if (ii) {
4211 _ecm_db_iface_ref(ii);
4212 }
4213 spin_unlock_bh(&ecm_db_lock);
4214 while (ii) {
4215 struct ecm_db_iface_instance *iin;
4216
4217 if (ii->interface_identifier == interface_id) {
4218 DEBUG_TRACE("iface found %p\n", ii);
4219 return ii;
4220 }
4221
4222 /*
4223 * Try next
4224 */
4225 spin_lock_bh(&ecm_db_lock);
4226 iin = ii->iface_id_hash_next;
4227 if (iin) {
4228 _ecm_db_iface_ref(iin);
4229 }
4230 spin_unlock_bh(&ecm_db_lock);
4231 ecm_db_iface_deref(ii);
4232 ii = iin;
4233 }
4234 DEBUG_TRACE("Iface not found\n");
4235 return NULL;
4236}
4237EXPORT_SYMBOL(ecm_db_iface_find_and_ref_by_interface_identifier);
4238
4239/*
Gareth Williamsf98d4192015-03-11 16:55:41 +00004240 * ecm_db_iface_ifidx_find_and_ref_ethernet()
4241 * Return an interface based on a MAC address and interface hlos interface identifier
4242 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304243struct ecm_db_iface_instance *ecm_db_iface_ifidx_find_and_ref_ethernet(uint8_t *address, int32_t ifidx)
Ben Menchaca84f36632014-02-28 20:57:38 +00004244{
4245 ecm_db_iface_hash_t hash_index;
4246 struct ecm_db_iface_instance *ii;
4247
4248 DEBUG_TRACE("Lookup ethernet iface with addr %pM\n", address);
4249
4250 /*
4251 * Compute the hash chain index and prepare to walk the chain
4252 */
4253 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4254
4255 /*
4256 * Iterate the chain looking for a host with matching details
4257 */
4258 spin_lock_bh(&ecm_db_lock);
4259 ii = ecm_db_iface_table[hash_index];
4260 while (ii) {
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304261 if ((ii->type != ECM_DB_IFACE_TYPE_ETHERNET)
4262 || memcmp(ii->type_info.ethernet.address, address, ETH_ALEN)
4263 || ii->interface_identifier != ifidx) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004264 ii = ii->hash_next;
4265 continue;
4266 }
4267
4268 _ecm_db_iface_ref(ii);
4269 spin_unlock_bh(&ecm_db_lock);
4270 DEBUG_TRACE("iface found %p\n", ii);
4271 return ii;
4272 }
4273 spin_unlock_bh(&ecm_db_lock);
4274 DEBUG_TRACE("Iface not found\n");
4275 return NULL;
4276}
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304277EXPORT_SYMBOL(ecm_db_iface_ifidx_find_and_ref_ethernet);
4278
Murat Sezgin37fb3952015-03-10 16:45:13 -07004279#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004280/*
4281 * ecm_db_iface_vlan_info_get()
4282 * Get vlan interface specific information
4283 */
4284void ecm_db_iface_vlan_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_vlan *vlan_info)
4285{
4286 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4287 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_VLAN, "%p: Bad type, expected vlan, actual: %d\n", ii, ii->type);
4288 spin_lock_bh(&ecm_db_lock);
4289 memcpy(vlan_info->address, ii->type_info.vlan.address, sizeof(ii->type_info.vlan.address));
4290 vlan_info->vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304291 vlan_info->vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00004292 spin_unlock_bh(&ecm_db_lock);
4293}
4294EXPORT_SYMBOL(ecm_db_iface_vlan_info_get);
4295
4296/*
4297 * ecm_db_iface_find_and_ref_vlan()
4298 * Lookup and return a iface reference if any
4299 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304300struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_vlan(uint8_t *address, uint16_t vlan_tag, uint16_t vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00004301{
4302 ecm_db_iface_hash_t hash_index;
4303 struct ecm_db_iface_instance *ii;
4304
Sol Kavyd7583592014-06-05 18:51:46 -07004305 DEBUG_TRACE("Lookup vlan iface with addr %pM, vlan tag: %x vlan tpid: %x\n", address, vlan_tag, vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00004306
4307 /*
4308 * Compute the hash chain index and prepare to walk the chain
4309 */
4310 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4311
4312 /*
4313 * Iterate the chain looking for a host with matching details
4314 */
4315 spin_lock_bh(&ecm_db_lock);
4316 ii = ecm_db_iface_table[hash_index];
4317 while (ii) {
4318 if ((ii->type != ECM_DB_IFACE_TYPE_VLAN) || (ii->type_info.vlan.vlan_tag != vlan_tag)
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304319 || (ii->type_info.vlan.vlan_tpid != vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00004320 || memcmp(ii->type_info.vlan.address, address, ETH_ALEN)) {
4321 ii = ii->hash_next;
4322 continue;
4323 }
4324
4325 _ecm_db_iface_ref(ii);
4326 spin_unlock_bh(&ecm_db_lock);
4327 DEBUG_TRACE("iface found %p\n", ii);
4328 return ii;
4329 }
4330 spin_unlock_bh(&ecm_db_lock);
4331 DEBUG_TRACE("Iface not found\n");
4332 return NULL;
4333}
4334EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
Murat Sezgin37fb3952015-03-10 16:45:13 -07004335#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004336
4337/*
4338 * ecm_db_iface_find_and_ref_bridge()
4339 * Lookup and return a iface reference if any
4340 */
4341struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_bridge(uint8_t *address)
4342{
4343 ecm_db_iface_hash_t hash_index;
4344 struct ecm_db_iface_instance *ii;
4345
4346 DEBUG_TRACE("Lookup bridge iface with addr %pM\n", address);
4347
4348 /*
4349 * Compute the hash chain index and prepare to walk the chain
4350 */
4351 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4352
4353 /*
4354 * Iterate the chain looking for a host with matching details
4355 */
4356 spin_lock_bh(&ecm_db_lock);
4357 ii = ecm_db_iface_table[hash_index];
4358 while (ii) {
4359 if ((ii->type != ECM_DB_IFACE_TYPE_BRIDGE) || memcmp(ii->type_info.bridge.address, address, ETH_ALEN)) {
4360 ii = ii->hash_next;
4361 continue;
4362 }
4363
4364 _ecm_db_iface_ref(ii);
4365 spin_unlock_bh(&ecm_db_lock);
4366 DEBUG_TRACE("iface found %p\n", ii);
4367 return ii;
4368 }
4369 spin_unlock_bh(&ecm_db_lock);
4370 DEBUG_TRACE("Iface not found\n");
4371 return NULL;
4372}
4373EXPORT_SYMBOL(ecm_db_iface_find_and_ref_bridge);
4374
Murat Sezgin910c9662015-03-11 16:15:06 -07004375#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004376/*
4377 * ecm_db_iface_find_and_ref_lag()
4378 * Lookup and return a iface reference if any
4379 */
4380struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_lag(uint8_t *address)
4381{
4382 ecm_db_iface_hash_t hash_index;
4383 struct ecm_db_iface_instance *ii;
4384
4385 DEBUG_TRACE("Lookup lag iface with addr %pM\n", address);
4386
4387 /*
4388 * Compute the hash chain index and prepare to walk the chain
4389 */
4390 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4391
4392 /*
4393 * Iterate the chain looking for a host with matching details
4394 */
4395 spin_lock_bh(&ecm_db_lock);
4396 ii = ecm_db_iface_table[hash_index];
4397 while (ii) {
4398 if ((ii->type != ECM_DB_IFACE_TYPE_LAG) || memcmp(ii->type_info.lag.address, address, ETH_ALEN)) {
4399 ii = ii->hash_next;
4400 continue;
4401 }
4402
4403 _ecm_db_iface_ref(ii);
4404 spin_unlock_bh(&ecm_db_lock);
4405 DEBUG_TRACE("iface found %p\n", ii);
4406 return ii;
4407 }
4408 spin_unlock_bh(&ecm_db_lock);
4409 DEBUG_TRACE("Iface not found\n");
4410 return NULL;
4411}
4412EXPORT_SYMBOL(ecm_db_iface_find_and_ref_lag);
Murat Sezgin910c9662015-03-11 16:15:06 -07004413#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004414
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304415#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004416/*
4417 * ecm_db_iface_pppoe_session_info_get()
Murat Sezgin37fb3952015-03-10 16:45:13 -07004418 * Get pppoe interface specific information
Ben Menchaca84f36632014-02-28 20:57:38 +00004419 */
4420void ecm_db_iface_pppoe_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppoe *pppoe_info)
4421{
4422 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4423 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOE, "%p: Bad type, expected pppoe, actual: %d\n", ii, ii->type);
4424 spin_lock_bh(&ecm_db_lock);
4425 memcpy(pppoe_info->remote_mac, ii->type_info.pppoe.remote_mac, sizeof(ii->type_info.pppoe.remote_mac));
4426 pppoe_info->pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
4427 spin_unlock_bh(&ecm_db_lock);
4428}
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304429
Ben Menchaca84f36632014-02-28 20:57:38 +00004430EXPORT_SYMBOL(ecm_db_iface_pppoe_session_info_get);
4431
4432/*
4433 * ecm_db_iface_find_and_ref_pppoe()
4434 * Lookup and return a iface reference if any
4435 */
4436struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppoe(uint16_t pppoe_session_id, uint8_t *remote_mac)
4437{
4438 ecm_db_iface_hash_t hash_index;
4439 struct ecm_db_iface_instance *ii;
4440
4441 DEBUG_TRACE("Lookup pppoe iface with addr %x\n", pppoe_session_id);
4442
4443 /*
4444 * Compute the hash chain index and prepare to walk the chain
4445 */
4446 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
4447
4448 /*
4449 * Iterate the chain looking for a host with matching details
4450 */
4451 spin_lock_bh(&ecm_db_lock);
4452 ii = ecm_db_iface_table[hash_index];
4453 while (ii) {
4454 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOE)
4455 || (ii->type_info.pppoe.pppoe_session_id != pppoe_session_id)
4456 || memcmp(ii->type_info.pppoe.remote_mac, remote_mac, ETH_ALEN)) {
4457 ii = ii->hash_next;
4458 continue;
4459 }
4460
4461 _ecm_db_iface_ref(ii);
4462 spin_unlock_bh(&ecm_db_lock);
4463 DEBUG_TRACE("iface found %p\n", ii);
4464 return ii;
4465 }
4466 spin_unlock_bh(&ecm_db_lock);
4467 DEBUG_TRACE("Iface not found\n");
4468 return NULL;
4469}
4470EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppoe);
Murat Sezginaad635c2015-03-06 16:11:41 -08004471#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004472
ratheesh kannothed721852015-09-28 12:39:52 +05304473/*
4474 * ecm_db_iface_update_ae_interface_identifier()
4475 * update ae_interface_identifier in iface instance.
4476 */
4477void ecm_db_iface_update_ae_interface_identifier(struct ecm_db_iface_instance *ii, int32_t ae_interface_identifier)
4478{
4479 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304480
ratheesh kannothed721852015-09-28 12:39:52 +05304481 spin_lock_bh(&ecm_db_lock);
4482 if (ii->ae_interface_identifier == ae_interface_identifier) {
4483 spin_unlock_bh(&ecm_db_lock);
4484 return;
4485 }
4486 ii->ae_interface_identifier = ae_interface_identifier;
4487 spin_unlock_bh(&ecm_db_lock);
4488}
4489EXPORT_SYMBOL(ecm_db_iface_update_ae_interface_identifier);
4490
4491#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304492/*
4493 * ecm_db_iface_pppol2tpv2_session_info_get
4494 * get l2tpv2 specific info
4495 */
4496void ecm_db_iface_pppol2tpv2_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info)
4497{
4498 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4499 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOL2TPV2, "%p: Bad type, expected pppol2tpv2, actual: %d\n", ii, ii->type);
4500 spin_lock_bh(&ecm_db_lock);
4501 memcpy(pppol2tpv2_info, &ii->type_info.pppol2tpv2, sizeof(struct ecm_db_interface_info_pppol2tpv2));
4502 spin_unlock_bh(&ecm_db_lock);
4503}
4504EXPORT_SYMBOL(ecm_db_iface_pppol2tpv2_session_info_get);
4505
4506/*
4507 * ecm_db_iface_find_and_ref_pppol2tpv2()
4508 * Lookup and return a iface reference if any
4509 */
4510struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
4511{
4512 ecm_db_iface_hash_t hash_index;
4513 struct ecm_db_iface_instance *ii;
4514
4515 /*
4516 * Compute the hash chain index and prepare to walk the chain
4517 */
4518 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(pppol2tpv2_tunnel_id, pppol2tpv2_session_id);
4519
4520 DEBUG_TRACE("Lookup pppol2tpv2 iface with local_tunnel_id = %d, local_session_id = %d, hash = 0x%x\n", pppol2tpv2_tunnel_id,
4521 pppol2tpv2_session_id, hash_index);
4522
4523 /*
4524 * Iterate the chain looking for a host with matching details
4525 */
4526 spin_lock_bh(&ecm_db_lock);
4527 ii = ecm_db_iface_table[hash_index];
4528
4529 while (ii) {
4530 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOL2TPV2)
4531 || (ii->type_info.pppol2tpv2.l2tp.session.session_id != pppol2tpv2_session_id)
4532 || (ii->type_info.pppol2tpv2.l2tp.tunnel.tunnel_id != pppol2tpv2_tunnel_id)) {
4533 ii = ii->hash_next;
4534 continue;
4535 }
4536
4537 _ecm_db_iface_ref(ii);
4538 spin_unlock_bh(&ecm_db_lock);
4539 DEBUG_TRACE("iface found %p\n", ii);
4540 return ii;
4541 }
4542 spin_unlock_bh(&ecm_db_lock);
4543
4544 DEBUG_TRACE("Iface not found\n");
4545 return NULL;
4546}
4547EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppol2tpv2);
4548
4549#endif
4550
Ben Menchaca84f36632014-02-28 20:57:38 +00004551/*
4552 * ecm_db_iface_find_and_ref_unknown()
4553 * Lookup and return a iface reference if any
4554 */
4555struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_unknown(uint32_t os_specific_ident)
4556{
4557 ecm_db_iface_hash_t hash_index;
4558 struct ecm_db_iface_instance *ii;
4559
4560 DEBUG_TRACE("Lookup unknown iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4561
4562 /*
4563 * Compute the hash chain index and prepare to walk the chain
4564 */
4565 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
4566
4567 /*
4568 * Iterate the chain looking for a host with matching details
4569 */
4570 spin_lock_bh(&ecm_db_lock);
4571 ii = ecm_db_iface_table[hash_index];
4572 while (ii) {
4573 if ((ii->type != ECM_DB_IFACE_TYPE_UNKNOWN) || (ii->type_info.unknown.os_specific_ident != os_specific_ident)) {
4574 ii = ii->hash_next;
4575 continue;
4576 }
4577
4578 _ecm_db_iface_ref(ii);
4579 spin_unlock_bh(&ecm_db_lock);
4580 DEBUG_TRACE("iface found %p\n", ii);
4581 return ii;
4582 }
4583 spin_unlock_bh(&ecm_db_lock);
4584 DEBUG_TRACE("Iface not found\n");
4585 return NULL;
4586}
4587EXPORT_SYMBOL(ecm_db_iface_find_and_ref_unknown);
4588
4589/*
4590 * ecm_db_iface_find_and_ref_loopback()
4591 * Lookup and return a iface reference if any
4592 */
4593struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident)
4594{
4595 ecm_db_iface_hash_t hash_index;
4596 struct ecm_db_iface_instance *ii;
4597
4598 DEBUG_TRACE("Lookup loopback iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4599
4600 /*
4601 * Compute the hash chain index and prepare to walk the chain
4602 */
4603 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
4604
4605 /*
4606 * Iterate the chain looking for a host with matching details
4607 */
4608 spin_lock_bh(&ecm_db_lock);
4609 ii = ecm_db_iface_table[hash_index];
4610 while (ii) {
4611 if ((ii->type != ECM_DB_IFACE_TYPE_LOOPBACK) || (ii->type_info.loopback.os_specific_ident != os_specific_ident)) {
4612 ii = ii->hash_next;
4613 continue;
4614 }
4615
4616 _ecm_db_iface_ref(ii);
4617 spin_unlock_bh(&ecm_db_lock);
4618 DEBUG_TRACE("iface found %p\n", ii);
4619 return ii;
4620 }
4621 spin_unlock_bh(&ecm_db_lock);
4622 DEBUG_TRACE("Iface not found\n");
4623 return NULL;
4624}
4625EXPORT_SYMBOL(ecm_db_iface_find_and_ref_loopback);
4626
Murat Sezgin69a27532015-03-12 14:09:40 -07004627#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004628/*
4629 * ecm_db_iface_find_and_ref_ipsec_tunnel()
4630 * Lookup and return a iface reference if any.
4631 * GGG TODO Flesh this out using tunnel endpoint keys
4632 */
4633struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident)
4634{
4635 ecm_db_iface_hash_t hash_index;
4636 struct ecm_db_iface_instance *ii;
4637
4638 DEBUG_TRACE("Lookup ipsec_tunnel iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4639
4640 /*
4641 * Compute the hash chain index and prepare to walk the chain
4642 */
4643 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
4644
4645 /*
4646 * Iterate the chain looking for a host with matching details
4647 */
4648 spin_lock_bh(&ecm_db_lock);
4649 ii = ecm_db_iface_table[hash_index];
4650 while (ii) {
4651 if ((ii->type != ECM_DB_IFACE_TYPE_IPSEC_TUNNEL) || (ii->type_info.ipsec_tunnel.os_specific_ident != os_specific_ident)) {
4652 ii = ii->hash_next;
4653 continue;
4654 }
4655
4656 _ecm_db_iface_ref(ii);
4657 spin_unlock_bh(&ecm_db_lock);
4658 DEBUG_TRACE("iface found %p\n", ii);
4659 return ii;
4660 }
4661 spin_unlock_bh(&ecm_db_lock);
4662 DEBUG_TRACE("Iface not found\n");
4663 return NULL;
4664}
4665EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -07004666#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004667
Murat Sezginbde55f92015-03-11 16:44:11 -07004668#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004669/*
4670 * ecm_db_iface_find_and_ref_sit()
4671 * Lookup and return a iface reference if any
4672 */
4673struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_sit(ip_addr_t saddr, ip_addr_t daddr)
4674{
4675 ecm_db_iface_hash_t hash_index;
4676 struct ecm_db_iface_instance *ii;
4677
4678 DEBUG_TRACE("Lookup sit (6-in-4) iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
4679 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
4680
4681 /*
4682 * Compute the hash chain index and prepare to walk the chain
4683 */
4684 hash_index = ecm_db_iface_generate_hash_index_sit(saddr, daddr);
4685
4686 /*
4687 * Iterate the chain looking for a host with matching details
4688 */
4689 spin_lock_bh(&ecm_db_lock);
4690 ii = ecm_db_iface_table[hash_index];
4691 while (ii) {
4692 if ((ii->type != ECM_DB_IFACE_TYPE_SIT)
4693 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.saddr, saddr)
4694 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.daddr, daddr)) {
4695 ii = ii->hash_next;
4696 continue;
4697 }
4698
4699 _ecm_db_iface_ref(ii);
4700 spin_unlock_bh(&ecm_db_lock);
4701 DEBUG_TRACE("iface found %p\n", ii);
4702 return ii;
4703 }
4704 spin_unlock_bh(&ecm_db_lock);
4705 DEBUG_TRACE("Iface not found\n");
4706 return NULL;
4707}
4708EXPORT_SYMBOL(ecm_db_iface_find_and_ref_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -07004709#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004710
Murat Sezginc1402562015-03-12 12:32:20 -07004711#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00004712#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004713/*
4714 * ecm_db_iface_find_and_ref_tunipip6()
4715 * Lookup and return a iface reference if any
4716 */
4717struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
4718{
4719 ecm_db_iface_hash_t hash_index;
4720 struct ecm_db_iface_instance *ii;
4721
4722 DEBUG_TRACE("Lookup TUNIPIP6 iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
4723 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
4724
4725 /*
4726 * Compute the hash chain index and prepare to walk the chain
4727 */
4728 hash_index = ecm_db_iface_generate_hash_index_tunipip6(saddr, daddr);
4729
4730 /*
4731 * Iterate the chain looking for a host with matching details
4732 */
4733 spin_lock_bh(&ecm_db_lock);
4734 ii = ecm_db_iface_table[hash_index];
4735 while (ii) {
4736 if ((ii->type != ECM_DB_IFACE_TYPE_TUNIPIP6)
4737 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.saddr, saddr)
4738 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.daddr, daddr)) {
4739 ii = ii->hash_next;
4740 continue;
4741 }
4742
4743 _ecm_db_iface_ref(ii);
4744 spin_unlock_bh(&ecm_db_lock);
4745 DEBUG_TRACE("iface found %p\n", ii);
4746 return ii;
4747 }
4748 spin_unlock_bh(&ecm_db_lock);
4749 DEBUG_TRACE("Iface not found\n");
4750 return NULL;
4751}
4752EXPORT_SYMBOL(ecm_db_iface_find_and_ref_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -07004753#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00004754#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004755
4756/*
4757 * ecm_db_mapping_find_and_ref()
4758 * Lookup and return a mapping reference if any.
4759 *
4760 * NOTE: For non-port based protocols the ports are expected to be -(protocol)
4761 */
4762struct ecm_db_mapping_instance *ecm_db_mapping_find_and_ref(ip_addr_t address, int port)
4763{
4764 ecm_db_mapping_hash_t hash_index;
4765 struct ecm_db_mapping_instance *mi;
4766
4767 DEBUG_TRACE("Lookup mapping with addr " ECM_IP_ADDR_OCTAL_FMT " and port %d\n", ECM_IP_ADDR_TO_OCTAL(address), port);
4768
4769 /*
4770 * Compute the hash chain index and prepare to walk the chain
4771 */
4772 hash_index = ecm_db_mapping_generate_hash_index(address, port);
4773
4774 /*
4775 * Iterate the chain looking for a mapping with matching details
4776 */
4777 spin_lock_bh(&ecm_db_lock);
4778 mi = ecm_db_mapping_table[hash_index];
4779 while (mi) {
4780 if (mi->port != port) {
4781 mi = mi->hash_next;
4782 continue;
4783 }
4784
4785 if (!ECM_IP_ADDR_MATCH(mi->host->address, address)) {
4786 mi = mi->hash_next;
4787 continue;
4788 }
4789
4790 _ecm_db_mapping_ref(mi);
4791 spin_unlock_bh(&ecm_db_lock);
4792 DEBUG_TRACE("Mapping found %p\n", mi);
4793 return mi;
4794 }
4795 spin_unlock_bh(&ecm_db_lock);
4796 DEBUG_TRACE("Mapping not found\n");
4797 return NULL;
4798}
4799EXPORT_SYMBOL(ecm_db_mapping_find_and_ref);
4800
4801/*
Gareth Williams54d15d92015-04-24 19:28:27 +01004802 * ecm_db_connection_find_and_ref_chain()
4803 * Given a hash chain index locate the connection
Ben Menchaca84f36632014-02-28 20:57:38 +00004804 */
Gareth Williams54d15d92015-04-24 19:28:27 +01004805static struct ecm_db_connection_instance *ecm_db_connection_find_and_ref_chain(ecm_db_connection_hash_t hash_index,
4806 ip_addr_t host1_addr, ip_addr_t host2_addr,
4807 int protocol, int host1_port, int host2_port)
Ben Menchaca84f36632014-02-28 20:57:38 +00004808{
Ben Menchaca84f36632014-02-28 20:57:38 +00004809 struct ecm_db_connection_instance *ci;
4810
Ben Menchaca84f36632014-02-28 20:57:38 +00004811 /*
4812 * Iterate the chain looking for a connection with matching details
4813 */
4814 spin_lock_bh(&ecm_db_lock);
4815 ci = ecm_db_connection_table[hash_index];
4816 if (ci) {
4817 _ecm_db_connection_ref(ci);
4818 }
4819 spin_unlock_bh(&ecm_db_lock);
4820 while (ci) {
4821 struct ecm_db_connection_instance *cin;
4822
4823 /*
4824 * The use of unlikely() is liberally used because under fast-hit scenarios the connection would always be at the start of a chain
4825 */
4826 if (unlikely(ci->protocol != protocol)) {
4827 goto try_next;
4828 }
4829
4830 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_from->host->address))) {
4831 goto try_reverse;
4832 }
4833
4834 if (unlikely(host1_port != ci->mapping_from->port)) {
4835 goto try_reverse;
4836 }
4837
4838 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_to->host->address))) {
4839 goto try_reverse;
4840 }
4841
4842 if (unlikely(host2_port != ci->mapping_to->port)) {
4843 goto try_reverse;
4844 }
4845
4846 goto connection_found;
4847
4848try_reverse:
4849 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_to->host->address))) {
4850 goto try_next;
4851 }
4852
4853 if (unlikely(host1_port != ci->mapping_to->port)) {
4854 goto try_next;
4855 }
4856
4857 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_from->host->address))) {
4858 goto try_next;
4859 }
4860
4861 if (unlikely(host2_port != ci->mapping_from->port)) {
4862 goto try_next;
4863 }
4864
4865 goto connection_found;
4866
4867try_next:
4868 spin_lock_bh(&ecm_db_lock);
4869 cin = ci->hash_next;
4870 if (cin) {
4871 _ecm_db_connection_ref(cin);
4872 }
4873 spin_unlock_bh(&ecm_db_lock);
4874 ecm_db_connection_deref(ci);
4875 ci = cin;
4876 }
Gareth Williams54d15d92015-04-24 19:28:27 +01004877 DEBUG_TRACE("Connection not found in hash chain\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00004878 return NULL;
4879
4880connection_found:
4881 DEBUG_TRACE("Connection found %p\n", ci);
4882
4883 /*
4884 * Move this connection to the head of the hash chain.
4885 * This will win for us with heavy hit connections - we bubble MRU to the front of the list to
4886 * avoid too much chain walking.
4887 */
4888 spin_lock_bh(&ecm_db_lock);
4889 if (!ci->hash_prev) {
4890 /*
4891 * No prev pointer - ci is at the head of the list already
4892 */
4893 DEBUG_ASSERT(ecm_db_connection_table[hash_index] == ci, "%p: hash table bad\n", ci);
4894 spin_unlock_bh(&ecm_db_lock);
4895 return ci;
4896 }
4897
4898 /*
4899 * Link out
4900 */
4901 ci->hash_prev->hash_next = ci->hash_next;
4902 if (ci->hash_next) {
4903 ci->hash_next->hash_prev = ci->hash_prev;
4904 }
4905
4906 /*
4907 * Re-insert at the head.
4908 * NOTE: We know that there is a head already that is different to ci.
4909 */
4910 ci->hash_next = ecm_db_connection_table[hash_index];
4911 ecm_db_connection_table[hash_index]->hash_prev = ci;
4912 ecm_db_connection_table[hash_index] = ci;
4913 ci->hash_prev = NULL;
4914 spin_unlock_bh(&ecm_db_lock);
4915 return ci;
4916}
Gareth Williams54d15d92015-04-24 19:28:27 +01004917
4918/*
4919 * ecm_db_connection_find_and_ref()
4920 * Locate a connection instance based on addressing, protocol and optional port information.
4921 *
4922 * NOTE: For non-port based protocols then ports are expected to be -(protocol).
4923 */
4924struct ecm_db_connection_instance *ecm_db_connection_find_and_ref(ip_addr_t host1_addr, ip_addr_t host2_addr, int protocol, int host1_port, int host2_port)
4925{
4926 ecm_db_connection_hash_t hash_index;
4927
4928 DEBUG_TRACE("Lookup connection " ECM_IP_ADDR_OCTAL_FMT ":%d <> " ECM_IP_ADDR_OCTAL_FMT ":%d protocol %d\n", ECM_IP_ADDR_TO_OCTAL(host1_addr), host1_port, ECM_IP_ADDR_TO_OCTAL(host2_addr), host2_port, protocol);
4929
4930 /*
4931 * Compute the hash chain index and prepare to walk the chain
4932 */
4933 hash_index = ecm_db_connection_generate_hash_index(host1_addr, host1_port, host2_addr, host2_port, protocol);
4934 return ecm_db_connection_find_and_ref_chain(hash_index, host1_addr, host2_addr, protocol, host1_port, host2_port);
4935}
Ben Menchaca84f36632014-02-28 20:57:38 +00004936EXPORT_SYMBOL(ecm_db_connection_find_and_ref);
4937
4938/*
4939 * ecm_db_connection_serial_find_and_ref()
4940 * Locate a connection instance based on serial if it still exists
4941 */
4942struct ecm_db_connection_instance *ecm_db_connection_serial_find_and_ref(uint32_t serial)
4943{
4944 ecm_db_connection_serial_hash_t serial_hash_index;
4945 struct ecm_db_connection_instance *ci;
4946
4947 DEBUG_TRACE("Lookup connection serial: %u\n", serial);
4948
4949 /*
4950 * Compute the hash chain index and prepare to walk the chain
4951 */
4952 serial_hash_index = ecm_db_connection_generate_serial_hash_index(serial);
4953
4954 /*
4955 * Iterate the chain looking for a connection with matching serial
4956 */
4957 spin_lock_bh(&ecm_db_lock);
4958 ci = ecm_db_connection_serial_table[serial_hash_index];
4959 if (ci) {
4960 _ecm_db_connection_ref(ci);
4961 }
4962 spin_unlock_bh(&ecm_db_lock);
4963 while (ci) {
4964 struct ecm_db_connection_instance *cin;
4965
4966 /*
4967 * The use of likely() is used because under fast-hit scenarios the connection would always be at the start of a chain
4968 */
4969 if (likely(ci->serial == serial)) {
4970 goto connection_found;
4971 }
4972
4973 /*
4974 * Try next
4975 */
4976 spin_lock_bh(&ecm_db_lock);
4977 cin = ci->serial_hash_next;
4978 if (cin) {
4979 _ecm_db_connection_ref(cin);
4980 }
4981 spin_unlock_bh(&ecm_db_lock);
4982 ecm_db_connection_deref(ci);
4983 ci = cin;
4984 }
4985 DEBUG_TRACE("Connection not found\n");
4986 return NULL;
4987
4988connection_found:
4989 DEBUG_TRACE("Connection found %p\n", ci);
4990
4991 /*
4992 * Move this connection to the head of the hash chain.
4993 * This will win for us with heavy hit connections - we bubble MRU to the front of the list to
4994 * avoid too much chain walking.
4995 */
4996 spin_lock_bh(&ecm_db_lock);
4997 if (!ci->serial_hash_prev) {
4998 /*
4999 * No prev pointer - ci is at the head of the list already
5000 */
5001 DEBUG_ASSERT(ecm_db_connection_serial_table[serial_hash_index] == ci, "%p: hash table bad\n", ci);
5002 spin_unlock_bh(&ecm_db_lock);
5003 return ci;
5004 }
5005
5006 /*
5007 * Link out
5008 */
5009 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
5010 if (ci->serial_hash_next) {
5011 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
5012 }
5013
5014 /*
5015 * Re-insert at the head.
5016 * NOTE: We know that there is a head already that is different to ci.
5017 */
5018 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
5019 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
5020 ecm_db_connection_serial_table[serial_hash_index] = ci;
5021 ci->serial_hash_prev = NULL;
5022 spin_unlock_bh(&ecm_db_lock);
5023 return ci;
5024}
5025EXPORT_SYMBOL(ecm_db_connection_serial_find_and_ref);
5026
5027/*
Gareth Williamsb5903892015-03-20 15:13:07 +00005028 * ecm_db_connection_node_to_get_and_ref()
5029 * Return node reference
5030 */
5031struct ecm_db_node_instance *ecm_db_connection_node_to_get_and_ref(struct ecm_db_connection_instance *ci)
5032{
5033 struct ecm_db_node_instance *ni;
5034
5035 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5036
5037 spin_lock_bh(&ecm_db_lock);
5038 ni = ci->to_node;
5039 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5040 _ecm_db_node_ref(ni);
5041 spin_unlock_bh(&ecm_db_lock);
5042 return ni;
5043}
5044EXPORT_SYMBOL(ecm_db_connection_node_to_get_and_ref);
5045
5046/*
5047 * ecm_db_connection_node_from_get_and_ref()
5048 * Return node reference
5049 */
5050struct ecm_db_node_instance *ecm_db_connection_node_from_get_and_ref(struct ecm_db_connection_instance *ci)
5051{
5052 struct ecm_db_node_instance *ni;
5053
5054 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5055
5056 spin_lock_bh(&ecm_db_lock);
5057 ni = ci->from_node;
5058 _ecm_db_node_ref(ni);
5059 spin_unlock_bh(&ecm_db_lock);
5060 return ni;
5061}
5062EXPORT_SYMBOL(ecm_db_connection_node_from_get_and_ref);
5063
5064#ifdef ECM_DB_XREF_ENABLE
5065/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005066 * ecm_db_mapping_connections_from_get_and_ref_first()
5067 * Return a reference to the first connection made from this mapping
5068 */
5069struct ecm_db_connection_instance *ecm_db_mapping_connections_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5070{
5071 struct ecm_db_connection_instance *ci;
5072
5073 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5074
5075 spin_lock_bh(&ecm_db_lock);
5076 ci = mi->from_connections;
5077 if (ci) {
5078 _ecm_db_connection_ref(ci);
5079 }
5080 spin_unlock_bh(&ecm_db_lock);
5081
5082 return ci;
5083}
5084EXPORT_SYMBOL(ecm_db_mapping_connections_from_get_and_ref_first);
5085
5086/*
5087 * ecm_db_mapping_connections_to_get_and_ref_first()
5088 * Return a reference to the first connection made to this mapping
5089 */
5090struct ecm_db_connection_instance *ecm_db_mapping_connections_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5091{
5092 struct ecm_db_connection_instance *ci;
5093
5094 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5095
5096 spin_lock_bh(&ecm_db_lock);
5097 ci = mi->to_connections;
5098 if (ci) {
5099 _ecm_db_connection_ref(ci);
5100 }
5101 spin_unlock_bh(&ecm_db_lock);
5102
5103 return ci;
5104}
5105EXPORT_SYMBOL(ecm_db_mapping_connections_to_get_and_ref_first);
5106
5107/*
5108 * ecm_db_mapping_connections_nat_from_get_and_ref_first()
5109 * Return a reference to the first NAT connection made from this mapping
5110 */
5111struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5112{
5113 struct ecm_db_connection_instance *ci;
5114
5115 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5116
5117 spin_lock_bh(&ecm_db_lock);
5118 ci = mi->from_nat_connections;
5119 if (ci) {
5120 _ecm_db_connection_ref(ci);
5121 }
5122 spin_unlock_bh(&ecm_db_lock);
5123
5124 return ci;
5125}
5126EXPORT_SYMBOL(ecm_db_mapping_connections_nat_from_get_and_ref_first);
5127
5128/*
5129 * ecm_db_mapping_connections_nat_to_get_and_ref_first()
5130 * Return a reference to the first NAT connection made to this mapping
5131 */
5132struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5133{
5134 struct ecm_db_connection_instance *ci;
5135
5136 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5137
5138 spin_lock_bh(&ecm_db_lock);
5139 ci = mi->to_nat_connections;
5140 if (ci) {
5141 _ecm_db_connection_ref(ci);
5142 }
5143 spin_unlock_bh(&ecm_db_lock);
5144
5145 return ci;
5146}
5147EXPORT_SYMBOL(ecm_db_mapping_connections_nat_to_get_and_ref_first);
5148
5149/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005150 * ecm_db_connection_mapping_from_get_and_ref_next()
5151 * Return reference to next connection in from mapping chain
5152 */
5153struct ecm_db_connection_instance *ecm_db_connection_mapping_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5154{
5155 struct ecm_db_connection_instance *nci;
5156
5157 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5158
5159 spin_lock_bh(&ecm_db_lock);
5160 nci = ci->from_next;
5161 if (nci) {
5162 _ecm_db_connection_ref(nci);
5163 }
5164 spin_unlock_bh(&ecm_db_lock);
5165
5166 return nci;
5167}
5168EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref_next);
5169
5170/*
5171 * ecm_db_connection_mapping_to_get_and_ref_next()
5172 * Return reference to next connection in to mapping chain
5173 */
5174struct ecm_db_connection_instance *ecm_db_connection_mapping_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5175{
5176 struct ecm_db_connection_instance *nci;
5177
5178 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5179
5180 spin_lock_bh(&ecm_db_lock);
5181 nci = ci->to_next;
5182 if (nci) {
5183 _ecm_db_connection_ref(nci);
5184 }
5185 spin_unlock_bh(&ecm_db_lock);
5186
5187 return nci;
5188}
5189EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref_next);
5190
5191/*
5192 * ecm_db_connection_mapping_nat_from_get_and_ref_next()
5193 * Return reference to next connection in from NAT mapping chain
5194 */
5195struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5196{
5197 struct ecm_db_connection_instance *nci;
5198
5199 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5200
5201 spin_lock_bh(&ecm_db_lock);
5202 nci = ci->from_nat_next;
5203 if (nci) {
5204 _ecm_db_connection_ref(nci);
5205 }
5206 spin_unlock_bh(&ecm_db_lock);
5207
5208 return nci;
5209}
5210EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref_next);
5211
5212/*
5213 * ecm_db_connection_mapping_nat_to_get_and_ref_next()
5214 * Return reference to next connection in to NAT mapping chain
5215 */
5216struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5217{
5218 struct ecm_db_connection_instance *nci;
5219
5220 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5221
5222 spin_lock_bh(&ecm_db_lock);
5223 nci = ci->to_nat_next;
5224 if (nci) {
5225 _ecm_db_connection_ref(nci);
5226 }
5227 spin_unlock_bh(&ecm_db_lock);
5228
5229 return nci;
5230}
5231EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref_next);
5232
5233/*
5234 * ecm_db_iface_connections_from_get_and_ref_first()
5235 * Return a reference to the first connection made from this iface
5236 */
5237struct ecm_db_connection_instance *ecm_db_iface_connections_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5238{
5239 struct ecm_db_connection_instance *ci;
5240
5241 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5242
5243 spin_lock_bh(&ecm_db_lock);
5244 ci = ii->from_connections;
5245 if (ci) {
5246 _ecm_db_connection_ref(ci);
5247 }
5248 spin_unlock_bh(&ecm_db_lock);
5249
5250 return ci;
5251}
5252EXPORT_SYMBOL(ecm_db_iface_connections_from_get_and_ref_first);
5253
5254/*
5255 * ecm_db_iface_connections_to_get_and_ref_first()
5256 * Return a reference to the first connection made to this iface
5257 */
5258struct ecm_db_connection_instance *ecm_db_iface_connections_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5259{
5260 struct ecm_db_connection_instance *ci;
5261
5262 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5263
5264 spin_lock_bh(&ecm_db_lock);
5265 ci = ii->to_connections;
5266 if (ci) {
5267 _ecm_db_connection_ref(ci);
5268 }
5269 spin_unlock_bh(&ecm_db_lock);
5270
5271 return ci;
5272}
5273EXPORT_SYMBOL(ecm_db_iface_connections_to_get_and_ref_first);
5274
5275/*
5276 * ecm_db_iface_connections_nat_from_get_and_ref_first()
5277 * Return a reference to the first NAT connection made from this iface
5278 */
5279struct ecm_db_connection_instance *ecm_db_iface_connections_nat_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5280{
5281 struct ecm_db_connection_instance *ci;
5282
5283 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5284
5285 spin_lock_bh(&ecm_db_lock);
5286 ci = ii->from_nat_connections;
5287 if (ci) {
5288 _ecm_db_connection_ref(ci);
5289 }
5290 spin_unlock_bh(&ecm_db_lock);
5291
5292 return ci;
5293}
5294EXPORT_SYMBOL(ecm_db_iface_connections_nat_from_get_and_ref_first);
5295
5296/*
5297 * ecm_db_iface_connections_nat_to_get_and_ref_first()
5298 * Return a reference to the first NAT connection made to this iface
5299 */
5300struct ecm_db_connection_instance *ecm_db_iface_connections_nat_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5301{
5302 struct ecm_db_connection_instance *ci;
5303
5304 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5305
5306 spin_lock_bh(&ecm_db_lock);
5307 ci = ii->to_nat_connections;
5308 if (ci) {
5309 _ecm_db_connection_ref(ci);
5310 }
5311 spin_unlock_bh(&ecm_db_lock);
5312
5313 return ci;
5314}
5315EXPORT_SYMBOL(ecm_db_iface_connections_nat_to_get_and_ref_first);
5316
5317/*
5318 * ecm_db_connection_iface_from_get_and_ref_next()
5319 * Return reference to next connection in from iface chain
5320 */
5321struct ecm_db_connection_instance *ecm_db_connection_iface_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5322{
5323 struct ecm_db_connection_instance *nci;
5324
5325 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5326
5327 spin_lock_bh(&ecm_db_lock);
5328 nci = ci->iface_from_next;
5329 if (nci) {
5330 _ecm_db_connection_ref(nci);
5331 }
5332 spin_unlock_bh(&ecm_db_lock);
5333
5334 return nci;
5335}
5336EXPORT_SYMBOL(ecm_db_connection_iface_from_get_and_ref_next);
5337
5338/*
5339 * ecm_db_connection_iface_to_get_and_ref_next()
5340 * Return reference to next connection in to iface chain
5341 */
5342struct ecm_db_connection_instance *ecm_db_connection_iface_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5343{
5344 struct ecm_db_connection_instance *nci;
5345
5346 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5347
5348 spin_lock_bh(&ecm_db_lock);
5349 nci = ci->iface_to_next;
5350 if (nci) {
5351 _ecm_db_connection_ref(nci);
5352 }
5353 spin_unlock_bh(&ecm_db_lock);
5354
5355 return nci;
5356}
5357EXPORT_SYMBOL(ecm_db_connection_iface_to_get_and_ref_next);
5358
5359/*
5360 * ecm_db_connection_iface_nat_from_get_and_ref_next()
5361 * Return reference to next connection in from NAT iface chain
5362 */
5363struct ecm_db_connection_instance *ecm_db_connection_iface_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5364{
5365 struct ecm_db_connection_instance *nci;
5366
5367 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5368
5369 spin_lock_bh(&ecm_db_lock);
5370 nci = ci->iface_from_nat_next;
5371 if (nci) {
5372 _ecm_db_connection_ref(nci);
5373 }
5374 spin_unlock_bh(&ecm_db_lock);
5375
5376 return nci;
5377}
5378EXPORT_SYMBOL(ecm_db_connection_iface_nat_from_get_and_ref_next);
5379
5380/*
5381 * ecm_db_connection_iface_nat_to_get_and_ref_next()
5382 * Return reference to next connection in to NAT iface chain
5383 */
5384struct ecm_db_connection_instance *ecm_db_connection_iface_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5385{
5386 struct ecm_db_connection_instance *nci;
5387
5388 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5389
5390 spin_lock_bh(&ecm_db_lock);
5391 nci = ci->iface_to_nat_next;
5392 if (nci) {
5393 _ecm_db_connection_ref(nci);
5394 }
5395 spin_unlock_bh(&ecm_db_lock);
5396
5397 return nci;
5398}
5399EXPORT_SYMBOL(ecm_db_connection_iface_nat_to_get_and_ref_next);
5400
5401/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005402 * ecm_db_iface_nodes_get_and_ref_first()
5403 * Return a reference to the first node made from this iface
5404 */
5405struct ecm_db_node_instance *ecm_db_iface_nodes_get_and_ref_first(struct ecm_db_iface_instance *ii)
5406{
5407 struct ecm_db_node_instance *ni;
5408
5409 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5410
5411 spin_lock_bh(&ecm_db_lock);
5412 ni = ii->nodes;
5413 if (ni) {
5414 _ecm_db_node_ref(ni);
5415 }
5416 spin_unlock_bh(&ecm_db_lock);
5417
5418 return ni;
5419}
5420EXPORT_SYMBOL(ecm_db_iface_nodes_get_and_ref_first);
5421
5422/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005423 * ecm_db_iface_node_count_get()
5424 * Return the number of nodes to this iface
5425 */
5426int ecm_db_iface_node_count_get(struct ecm_db_iface_instance *ii)
5427{
5428 int count;
5429
5430 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305431
Ben Menchaca84f36632014-02-28 20:57:38 +00005432 spin_lock_bh(&ecm_db_lock);
5433 count = ii->node_count;
5434 spin_unlock_bh(&ecm_db_lock);
5435 return count;
5436}
5437EXPORT_SYMBOL(ecm_db_iface_node_count_get);
5438
5439/*
5440 * ecm_db_host_mapping_count_get()
5441 * Return the number of mappings to this host
5442 */
5443int ecm_db_host_mapping_count_get(struct ecm_db_host_instance *hi)
5444{
5445 int count;
5446
5447 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305448
Ben Menchaca84f36632014-02-28 20:57:38 +00005449 spin_lock_bh(&ecm_db_lock);
5450 count = hi->mapping_count;
5451 spin_unlock_bh(&ecm_db_lock);
5452 return count;
5453}
5454EXPORT_SYMBOL(ecm_db_host_mapping_count_get);
Gareth Williamsb5903892015-03-20 15:13:07 +00005455#endif
5456
5457/*
5458 * ecm_db_mapping_host_get_and_ref()
5459 */
5460struct ecm_db_host_instance *ecm_db_mapping_host_get_and_ref(struct ecm_db_mapping_instance *mi)
5461{
5462 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
5463
5464 spin_lock_bh(&ecm_db_lock);
5465 _ecm_db_host_ref(mi->host);
5466 spin_unlock_bh(&ecm_db_lock);
5467 return mi->host;
5468}
5469EXPORT_SYMBOL(ecm_db_mapping_host_get_and_ref);
5470
5471/*
5472 * ecm_db_node_iface_get_and_ref()
5473 */
5474struct ecm_db_iface_instance *ecm_db_node_iface_get_and_ref(struct ecm_db_node_instance *ni)
5475{
5476 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5477
5478 spin_lock_bh(&ecm_db_lock);
5479 _ecm_db_iface_ref(ni->iface);
5480 spin_unlock_bh(&ecm_db_lock);
5481 return ni->iface;
5482}
5483EXPORT_SYMBOL(ecm_db_node_iface_get_and_ref);
Ben Menchaca84f36632014-02-28 20:57:38 +00005484
5485/*
5486 * ecm_db_mapping_connections_total_count_get()
5487 * Return the total number of connections (NAT and non-NAT) this mapping has
5488 */
5489int ecm_db_mapping_connections_total_count_get(struct ecm_db_mapping_instance *mi)
5490{
5491 int count;
5492
5493 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305494
Ben Menchaca84f36632014-02-28 20:57:38 +00005495 spin_lock_bh(&ecm_db_lock);
5496 count = mi->from + mi->to + mi->nat_from + mi->nat_to;
5497 DEBUG_ASSERT(count >= 0, "%p: Count overflow from: %d, to: %d, nat_from: %d, nat_to: %d\n", mi, mi->from, mi->to, mi->nat_from, mi->nat_to);
5498 spin_unlock_bh(&ecm_db_lock);
5499 return count;
5500}
5501EXPORT_SYMBOL(ecm_db_mapping_connections_total_count_get);
5502
5503/*
5504 * ecm_db_connection_mapping_from_get_and_ref()
5505 * Return a reference to the from mapping of the connection
5506 */
5507struct ecm_db_mapping_instance *ecm_db_connection_mapping_from_get_and_ref(struct ecm_db_connection_instance *ci)
5508{
5509 struct ecm_db_mapping_instance *mi;
5510
5511 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305512
Ben Menchaca84f36632014-02-28 20:57:38 +00005513 spin_lock_bh(&ecm_db_lock);
5514 mi = ci->mapping_from;
5515 _ecm_db_mapping_ref(mi);
5516 spin_unlock_bh(&ecm_db_lock);
5517 return mi;
5518}
5519EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref);
5520
5521/*
5522 * ecm_db_connection_mapping_nat_from_get_and_ref()
5523 * Return a reference to the from NAT mapping of the connection
5524 */
5525struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_from_get_and_ref(struct ecm_db_connection_instance *ci)
5526{
5527 struct ecm_db_mapping_instance *mi;
5528
5529 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305530
Ben Menchaca84f36632014-02-28 20:57:38 +00005531 spin_lock_bh(&ecm_db_lock);
5532 mi = ci->mapping_nat_from;
5533 _ecm_db_mapping_ref(mi);
5534 spin_unlock_bh(&ecm_db_lock);
5535 return mi;
5536}
5537EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref);
5538
5539/*
5540 * ecm_db_connection_mapping_to_get_and_ref()
5541 * Return a reference to the from mapping of the connection
5542 */
5543struct ecm_db_mapping_instance *ecm_db_connection_mapping_to_get_and_ref(struct ecm_db_connection_instance *ci)
5544{
5545 struct ecm_db_mapping_instance *mi;
5546
5547 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305548
Ben Menchaca84f36632014-02-28 20:57:38 +00005549 spin_lock_bh(&ecm_db_lock);
5550 mi = ci->mapping_to;
5551 _ecm_db_mapping_ref(mi);
5552 spin_unlock_bh(&ecm_db_lock);
5553 return mi;
5554}
5555EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref);
5556
5557/*
5558 * ecm_db_connection_mapping_to_nat_get_and_ref()
5559 * Return a reference to the from NAT mapping of the connection
5560 */
5561struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_to_get_and_ref(struct ecm_db_connection_instance *ci)
5562{
5563 struct ecm_db_mapping_instance *mi;
5564
5565 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305566
Ben Menchaca84f36632014-02-28 20:57:38 +00005567 spin_lock_bh(&ecm_db_lock);
5568 mi = ci->mapping_nat_to;
5569 _ecm_db_mapping_ref(mi);
5570 spin_unlock_bh(&ecm_db_lock);
5571 return mi;
5572}
5573EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref);
5574
5575/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005576 * ecm_db_timer_groups_check()
5577 * Check for expired group entries, returns the number that have expired
5578 */
5579static uint32_t ecm_db_timer_groups_check(uint32_t time_now)
5580{
5581 ecm_db_timer_group_t i;
5582 uint32_t expired = 0;
5583
5584 DEBUG_TRACE("Timer groups check start %u\n", time_now);
5585
5586 /*
5587 * Examine all timer groups for expired entries.
5588 */
5589 for (i = 0; i < ECM_DB_TIMER_GROUPS_MAX; ++i) {
5590 struct ecm_db_timer_group *timer_group;
5591
5592 /*
5593 * The group tail tracks the oldest entry so that is what we examine.
5594 */
5595 timer_group = &ecm_db_timer_groups[i];
5596 spin_lock_bh(&ecm_db_lock);
5597 while (timer_group->tail) {
5598 struct ecm_db_timer_group_entry *tge;
5599
5600 tge = timer_group->tail;
5601 if (tge->timeout > time_now) {
5602 /*
5603 * Not expired - and no further will be as they are in order
5604 */
5605 break;
5606 }
5607
5608 /*
5609 * Has expired - remove the entry from the list and invoke the callback
5610 * NOTE: We know the entry is at the tail of the group
5611 */
5612 if (tge->prev) {
5613 tge->prev->next = NULL;
5614 } else {
5615 /*
5616 * First in the group
5617 */
5618 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p got %p\n", timer_group, tge, timer_group->head);
5619 timer_group->head = NULL;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305620 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005621 timer_group->tail = tge->prev;
5622 tge->group = ECM_DB_TIMER_GROUPS_MAX;
5623 spin_unlock_bh(&ecm_db_lock);
5624 expired++;
5625 DEBUG_TRACE("%p: Expired\n", tge);
5626 tge->fn(tge->arg);
5627 spin_lock_bh(&ecm_db_lock);
5628 }
5629 spin_unlock_bh(&ecm_db_lock);
5630 }
5631
5632 spin_lock_bh(&ecm_db_lock);
5633 time_now = ecm_db_time;
5634 spin_unlock_bh(&ecm_db_lock);
5635 DEBUG_TRACE("Timer groups check end %u, expired count %u\n", time_now, expired);
5636 return expired;
5637}
5638
5639/*
5640 * ecm_db_connection_classifier_assign()
5641 * Assign a classifier to the connection assigned classifier list.
5642 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005643 * This adds the classifier in the ci->assignments list in ascending priority order according to the classifier type.
5644 * Only assigned classifiers are in this list, allowing fast retrival of current assignments, avoiding the need to skip over unassigned classifiers.
Ben Menchaca84f36632014-02-28 20:57:38 +00005645 * Because there is only one of each type of classifier the classifier is also recorded in an array, the position in which is its type value.
5646 * This allows fast lookup based on type too.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005647 * Further, the connection is recorded in the classifier type assignment array too, this permits iterating of all connections that are assigned to a TYPE of classifier.
Ben Menchaca84f36632014-02-28 20:57:38 +00005648 */
5649void ecm_db_connection_classifier_assign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *new_ca)
5650{
5651 struct ecm_classifier_instance *ca;
5652 struct ecm_classifier_instance *ca_prev;
5653 ecm_classifier_type_t new_ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005654#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005655 struct ecm_db_connection_classifier_type_assignment *ta;
5656 struct ecm_db_connection_classifier_type_assignment_list *tal;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005657#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005658
Ben Menchaca84f36632014-02-28 20:57:38 +00005659 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5660
5661 /*
5662 * Get the type (which is also used as the priority)
5663 */
5664 new_ca_type = new_ca->type_get(new_ca);
5665
5666 /*
5667 * Connection holds ref to the classifier
5668 */
5669 new_ca->ref(new_ca);
5670
5671 /*
5672 * Find place to insert the classifier
5673 */
5674 spin_lock_bh(&ecm_db_lock);
5675 ca = ci->assignments;
5676 ca_prev = NULL;
5677 while (ca) {
5678 ecm_classifier_type_t ca_type;
5679 ca_type = ca->type_get(ca);
5680
5681 /*
5682 * If new ca is less important that the current assigned classifier insert here
5683 */
5684 if (new_ca_type < ca_type) {
5685 break;
5686 }
5687 ca_prev = ca;
5688 ca = ca->ca_next;
5689 }
5690
5691 /*
5692 * Insert new_ca before ca and after ca_prev.
5693 */
5694 new_ca->ca_prev = ca_prev;
5695 if (ca_prev) {
5696 ca_prev->ca_next = new_ca;
5697 } else {
5698 DEBUG_ASSERT(ci->assignments == ca, "%p: Bad assigmnment list, expecting: %p, got: %p\n", ci, ca, ci->assignments);
5699 ci->assignments = new_ca;
5700 }
5701
5702 new_ca->ca_next = ca;
5703 if (ca) {
5704 ca->ca_prev = new_ca;
5705 }
5706
5707 /*
5708 * Insert based on type too
5709 */
5710 DEBUG_ASSERT(ci->assignments_by_type[new_ca_type] == NULL, "%p: Only one of each type: %d may be registered, new: %p, existing, %p\n",
5711 ci, new_ca_type, new_ca, ci->assignments_by_type[new_ca_type]);
5712 ci->assignments_by_type[new_ca_type] = new_ca;
5713
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005714#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005715 /*
5716 * Add the connection into the type assignment list too.
5717 */
5718 ta = &ci->type_assignment[new_ca_type];
5719 if (ta->pending_unassign) {
5720 /*
5721 * The connection is pending unassignment / removal from list, but since it has been
5722 * re-assigned to the same type of classifier we can just clear the flag and avoid the removal.
5723 * NOTE: pending_unassign is only ever true if the iteration count is non-zero i.e. iteration is in progress.
5724 */
5725 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5726 DEBUG_ASSERT(ta->iteration_count != 0, "%p: Bad pending_unassign: type: %d, Iteration count zero\n", ci, new_ca_type);
5727 ta->pending_unassign = false;
5728 spin_unlock_bh(&ecm_db_lock);
5729 return;
5730 }
5731
5732 /*
5733 * iteration_count should be zero as there should not be a duplicate assignment of the same type.
5734 * This is because if iteration_count was non-zero then pending_unassign should have been true.
5735 */
5736 DEBUG_ASSERT(ta->iteration_count == 0, "%p: Type: %d, Iteration count not zero: %d\n", ci, new_ca_type, ta->iteration_count);
5737
5738 /*
5739 * Insert the connection into the classifier type assignment list, at the head
5740 */
5741 tal = &ecm_db_connection_classifier_type_assignments[new_ca_type];
5742 ta->next = tal->type_assignments_list;
5743 ta->prev = NULL;
5744
5745 /*
5746 * If there is an existing head, it is no longer the head
5747 */
5748 if (tal->type_assignments_list) {
5749 struct ecm_db_connection_classifier_type_assignment *talh;
5750 talh = &tal->type_assignments_list->type_assignment[new_ca_type];
5751 talh->prev = ci;
5752 }
5753
5754 /*
5755 * Set new head
5756 */
5757 tal->type_assignments_list = ci;
5758
5759 /*
5760 * Set magic
5761 */
5762 DEBUG_SET_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC);
5763
5764 /*
5765 * Increment assignment count
5766 */
5767 tal->type_assignment_count++;
5768 DEBUG_ASSERT(tal->type_assignment_count > 0, "Bad iteration count: %d\n", tal->type_assignment_count);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005769#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005770 spin_unlock_bh(&ecm_db_lock);
5771}
5772EXPORT_SYMBOL(ecm_db_connection_classifier_assign);
5773
5774/*
5775 * ecm_db_connection_classifier_assignments_get_and_ref()
5776 * Populate the given array with references to the currently assigned classifiers.
5777 *
5778 * This function returns the number of assignments starting from [0].
5779 * [0] is the lowest priority classifier, [return_val - 1] is the highest priority.
5780 * Release each classifier when you are done, for convenience use ecm_db_connection_assignments_release().
5781 *
5782 * NOTE: The array also contains the default classifier too which of course will always be at [0]
5783 *
5784 * WARNING: The array MUST be of size ECM_CLASSIFIER_TYPES.
5785 */
5786int ecm_db_connection_classifier_assignments_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *assignments[])
5787{
5788 int aci_count;
5789 struct ecm_classifier_instance *aci;
5790 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5791
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005792 aci_count = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00005793 spin_lock_bh(&ecm_db_lock);
5794 aci = ci->assignments;
5795 while (aci) {
5796 aci->ref(aci);
5797 assignments[aci_count++] = aci;
5798 aci = aci->ca_next;
5799 }
5800 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005801 DEBUG_ASSERT(aci_count >= 1, "%p: Must have at least default classifier!\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005802 return aci_count;
5803}
5804EXPORT_SYMBOL(ecm_db_connection_classifier_assignments_get_and_ref);
5805
5806/*
5807 * ecm_db_connection_assignments_release()
5808 * Release references to classifiers in the assignments array
5809 */
5810void ecm_db_connection_assignments_release(int assignment_count, struct ecm_classifier_instance *assignments[])
5811{
5812 int i;
5813 for (i = 0; i < assignment_count; ++i) {
5814 struct ecm_classifier_instance *aci = assignments[i];
5815 if (aci) {
5816 aci->deref(aci);
5817 }
5818 }
5819}
5820EXPORT_SYMBOL(ecm_db_connection_assignments_release);
5821
5822/*
5823 * ecm_db_connection_assigned_classifier_find_and_ref()
5824 * Return a ref to classifier of the requested type, if found
5825 */
5826struct ecm_classifier_instance *ecm_db_connection_assigned_classifier_find_and_ref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t type)
5827{
5828 struct ecm_classifier_instance *ca;
5829 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5830 spin_lock_bh(&ecm_db_lock);
5831 ca = ci->assignments_by_type[type];
5832 if (ca) {
5833 ca->ref(ca);
5834 }
5835 spin_unlock_bh(&ecm_db_lock);
5836 return ca;
5837}
5838EXPORT_SYMBOL(ecm_db_connection_assigned_classifier_find_and_ref);
5839
5840/*
5841 * ecm_db_connection_classifier_unassign()
5842 * Unassign a classifier
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005843 *
5844 * The default classifier cannot be unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005845 */
5846void ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci)
5847{
5848 ecm_classifier_type_t ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005849#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005850 struct ecm_db_connection_classifier_type_assignment *ta;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005851#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005852 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5853
5854 DEBUG_ASSERT(cci->type_get(cci) != ECM_CLASSIFIER_TYPE_DEFAULT, "%p: Cannot unassign default", ci);
5855
Ben Menchaca84f36632014-02-28 20:57:38 +00005856 /*
5857 * Get the type
5858 */
5859 ca_type = cci->type_get(cci);
5860
5861 DEBUG_TRACE("%p: Unassign type: %d, classifier: %p\n", ci, ca_type, cci);
5862
5863 spin_lock_bh(&ecm_db_lock);
5864
5865 /*
5866 * Remove from assignments_by_type
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005867 * NOTE: It is possible that in SMP this classifier has already been unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005868 */
Gareth Williamsee0a38a2014-06-05 15:41:20 +01005869 if (ci->assignments_by_type[ca_type] == NULL) {
5870 spin_unlock_bh(&ecm_db_lock);
5871 DEBUG_TRACE("%p: Classifier type: %d already unassigned\n", ci, ca_type);
5872 return;
5873 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005874 ci->assignments_by_type[ca_type] = NULL;
5875
5876 /*
5877 * Link out of assignments list
5878 */
5879 if (cci->ca_prev) {
5880 cci->ca_prev->ca_next = cci->ca_next;
5881 } else {
5882 DEBUG_ASSERT(ci->assignments == cci, "%p: Bad assigmnment list, expecting: %p, got: %p", ci, cci, ci->assignments);
5883 ci->assignments = cci->ca_next;
5884 }
5885 if (cci->ca_next) {
5886 cci->ca_next->ca_prev = cci->ca_prev;
5887 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005888
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005889#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005890 /*
5891 * Remove from the classifier type assignment list
5892 */
5893 ta = &ci->type_assignment[ca_type];
5894 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5895 if (ta->iteration_count > 0) {
5896 /*
5897 * The list entry is being iterated outside of db lock being held.
5898 * We cannot remove this entry since it would mess up iteration.
5899 * Set the pending flag to be actioned another time
5900 */
5901 ta->pending_unassign = true;
5902 spin_unlock_bh(&ecm_db_lock);
5903 cci->deref(cci);
5904 return;
5905 }
5906
5907 /*
5908 * Remove the list entry
5909 */
5910 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
5911 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005912#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005913 spin_unlock_bh(&ecm_db_lock);
5914 cci->deref(cci);
5915}
5916EXPORT_SYMBOL(ecm_db_connection_classifier_unassign);
5917
5918/*
5919 * ecm_db_connection_classifier_default_get_and_ref()
5920 * Get a reference to default classifier associated with this connection
5921 */
5922struct ecm_classifier_default_instance *ecm_db_connection_classifier_default_get_and_ref(struct ecm_db_connection_instance *ci)
5923{
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005924 struct ecm_classifier_default_instance *dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005925 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5926
5927 /*
5928 * No need to lock this object - it cannot change
5929 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005930 dci = (struct ecm_classifier_default_instance *)ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT];
5931 DEBUG_ASSERT(dci, "%p: No default classifier!\n", ci);
5932 dci->base.ref((struct ecm_classifier_instance *)dci);
5933 return dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005934}
5935EXPORT_SYMBOL(ecm_db_connection_classifier_default_get_and_ref);
5936
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005937#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00005938/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005939 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_first()
5940 * Return a reference to the first connection for which a classifier of the given type is associated with
5941 *
5942 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5943 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5944 */
5945struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ecm_classifier_type_t ca_type)
5946{
5947 struct ecm_db_connection_classifier_type_assignment_list *tal;
5948 struct ecm_db_connection_instance *ci;
5949
5950 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5951
5952 DEBUG_TRACE("Get and ref first connection assigned with classifier type: %d\n", ca_type);
5953
5954 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
5955 spin_lock_bh(&ecm_db_lock);
5956 ci = tal->type_assignments_list;
5957 while (ci) {
5958 struct ecm_db_connection_classifier_type_assignment *ta;
5959 ta = &ci->type_assignment[ca_type];
5960 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5961
5962 if (ta->pending_unassign) {
5963 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", ci, ca_type);
5964 ci = ta->next;
5965 continue;
5966 }
5967
5968 /*
5969 * Take reference to this connection.
5970 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
5971 * and the type assignment list entry maintains integrity.
5972 */
5973 _ecm_db_connection_ref(ci);
5974 ta->iteration_count++;
5975 DEBUG_ASSERT(ta->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
5976 spin_unlock_bh(&ecm_db_lock);
5977 return ci;
5978 }
5979 spin_unlock_bh(&ecm_db_lock);
5980 return NULL;
5981}
5982EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_first);
5983
5984/*
5985 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_next()
5986 * Return a reference to the next connection for which a classifier of the given type is associated with.
5987 *
5988 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5989 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5990 */
5991struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
5992{
5993 struct ecm_db_connection_classifier_type_assignment *ta;
5994 struct ecm_db_connection_instance *cin;
5995
5996 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5997 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5998
5999 DEBUG_TRACE("Get and ref next connection assigned with classifier type: %d and ci: %p\n", ca_type, ci);
6000
6001 spin_lock_bh(&ecm_db_lock);
6002 ta = &ci->type_assignment[ca_type];
6003 cin = ta->next;
6004 while (cin) {
6005 struct ecm_db_connection_classifier_type_assignment *tan;
6006
6007 tan = &cin->type_assignment[ca_type];
6008 DEBUG_CHECK_MAGIC(tan, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", tan, cin);
6009
6010 if (tan->pending_unassign) {
6011 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", cin, ca_type);
6012 cin = tan->next;
6013 continue;
6014 }
6015
6016 /*
6017 * Take reference to this connection.
6018 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
6019 * and the type assignment list entry maintains integrity.
6020 */
6021 _ecm_db_connection_ref(cin);
6022 tan->iteration_count++;
6023 DEBUG_ASSERT(tan->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", tan->iteration_count, ca_type, cin);
6024 spin_unlock_bh(&ecm_db_lock);
6025 return cin;
6026 }
6027 spin_unlock_bh(&ecm_db_lock);
6028 return NULL;
6029}
6030EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_next);
6031
6032/*
6033 * ecm_db_connection_by_classifier_type_assignment_deref()
6034 * Release a reference to a connection while iterating a classifier type assignment list
6035 */
6036void ecm_db_connection_by_classifier_type_assignment_deref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
6037{
6038 struct ecm_db_connection_classifier_type_assignment_list *tal;
6039 struct ecm_db_connection_classifier_type_assignment *ta;
6040
6041 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6042 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6043
6044 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
6045
6046 /*
6047 * Drop the iteration count
6048 */
6049 spin_lock_bh(&ecm_db_lock);
6050 ta = &ci->type_assignment[ca_type];
6051 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
6052 ta->iteration_count--;
6053 DEBUG_ASSERT(ta->iteration_count >= 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
6054
6055 /*
6056 * If there are no more iterations on-going and this is pending unassign then we can remove it from the assignments list
6057 */
6058 if (ta->pending_unassign && (ta->iteration_count == 0)) {
6059 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
6060 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
6061 }
6062 spin_unlock_bh(&ecm_db_lock);
6063 ecm_db_connection_deref(ci);
6064}
6065EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_deref);
6066
6067/*
6068 * ecm_db_connection_make_defunct_by_assignment_type()
6069 * Make defunct all connections that are currently assigned to a classifier of the given type
6070 */
6071void ecm_db_connection_make_defunct_by_assignment_type(ecm_classifier_type_t ca_type)
6072{
6073 struct ecm_db_connection_instance *ci;
6074
6075 DEBUG_INFO("Make defunct all assigned to type: %d\n", ca_type);
6076
6077 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6078 while (ci) {
6079 struct ecm_db_connection_instance *cin;
6080
6081 DEBUG_TRACE("%p: Make defunct: %d\n", ci, ca_type);
6082 ecm_db_connection_make_defunct(ci);
6083
6084 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6085 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6086 ci = cin;
6087 }
6088}
6089EXPORT_SYMBOL(ecm_db_connection_make_defunct_by_assignment_type);
6090
6091/*
6092 * ecm_db_connection_regenerate_by_assignment_type()
6093 * Cause regeneration all connections that are currently assigned to a classifier of the given type
6094 */
6095void ecm_db_connection_regenerate_by_assignment_type(ecm_classifier_type_t ca_type)
6096{
6097 struct ecm_db_connection_instance *ci;
6098
6099 DEBUG_INFO("Regenerate all assigned to type: %d\n", ca_type);
6100
6101 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6102 while (ci) {
6103 struct ecm_db_connection_instance *cin;
6104
6105 DEBUG_TRACE("%p: Re-generate: %d\n", ci, ca_type);
Xiaoping Faned6d37e2015-09-17 14:13:47 -07006106 ecm_db_connection_regenerate(ci);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006107
6108 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6109 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6110 ci = cin;
6111 }
6112}
6113EXPORT_SYMBOL(ecm_db_connection_regenerate_by_assignment_type);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006114#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006115
6116/*
Ben Menchaca84f36632014-02-28 20:57:38 +00006117 * ecm_db_connection_from_interfaces_get_and_ref()
6118 * Return the interface heirarchy from which this connection is established.
6119 *
6120 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6121 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6122 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6123 *
6124 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6125 */
6126int32_t ecm_db_connection_from_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6127{
6128 int32_t n;
6129 int32_t i;
6130 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6131
6132 spin_lock_bh(&ecm_db_lock);
6133 n = ci->from_interface_first;
6134 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6135 interfaces[i] = ci->from_interfaces[i];
6136 _ecm_db_iface_ref(interfaces[i]);
6137 }
6138 spin_unlock_bh(&ecm_db_lock);
6139 return n;
6140}
6141EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_and_ref);
6142
6143/*
6144 * ecm_db_connection_to_interfaces_get_and_ref()
6145 * Return the interface heirarchy to which this connection is established.
6146 *
6147 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6148 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6149 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6150 *
6151 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6152 */
6153int32_t ecm_db_connection_to_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6154{
6155 int32_t n;
6156 int32_t i;
6157 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6158
6159 spin_lock_bh(&ecm_db_lock);
6160 n = ci->to_interface_first;
6161 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6162 interfaces[i] = ci->to_interfaces[i];
6163 _ecm_db_iface_ref(interfaces[i]);
6164 }
6165 spin_unlock_bh(&ecm_db_lock);
6166 return n;
6167}
6168EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_and_ref);
6169
6170/*
6171 * ecm_db_connection_from_nat_interfaces_get_and_ref()
6172 * Return the interface heirarchy from (nat) which this connection is established.
6173 *
6174 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6175 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6176 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6177 *
6178 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6179 */
6180int32_t ecm_db_connection_from_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6181{
6182 int32_t n;
6183 int32_t i;
6184 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6185
6186 spin_lock_bh(&ecm_db_lock);
6187 n = ci->from_nat_interface_first;
6188 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6189 interfaces[i] = ci->from_nat_interfaces[i];
6190 _ecm_db_iface_ref(interfaces[i]);
6191 }
6192 spin_unlock_bh(&ecm_db_lock);
6193 return n;
6194}
6195EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_and_ref);
6196
6197/*
6198 * ecm_db_connection_to_nat_interfaces_get_and_ref()
6199 * Return the interface heirarchy to (nat) which this connection is established.
6200 *
6201 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6202 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6203 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6204 *
6205 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6206 */
6207int32_t ecm_db_connection_to_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6208{
6209 int32_t n;
6210 int32_t i;
6211 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6212
6213 spin_lock_bh(&ecm_db_lock);
6214 n = ci->to_nat_interface_first;
6215 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6216 interfaces[i] = ci->to_nat_interfaces[i];
6217 _ecm_db_iface_ref(interfaces[i]);
6218 }
6219 spin_unlock_bh(&ecm_db_lock);
6220 return n;
6221}
6222EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_and_ref);
6223
6224/*
6225 * ecm_db_connection_interfaces_deref()
6226 * Release all interfaces in the given interfaces heirarchy array.
6227 *
6228 * 'first' is the number returned by one of the ecm_db_connection_xx_interfaces_get_and_ref().
6229 * You should NOT have released any references to any of the interfaces in the array youself, this releases them all.
6230 */
6231void ecm_db_connection_interfaces_deref(struct ecm_db_iface_instance *interfaces[], int32_t first)
6232{
6233 int32_t i;
6234 DEBUG_ASSERT((first >= 0) && (first <= ECM_DB_IFACE_HEIRARCHY_MAX), "Bad first: %d\n", first);
6235
6236 for (i = first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6237 ecm_db_iface_deref(interfaces[i]);
6238 }
6239}
6240EXPORT_SYMBOL(ecm_db_connection_interfaces_deref);
6241
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306242#ifdef ECM_MULTICAST_ENABLE
6243/*
6244 * ecm_db_multicast_connection_to_interfaces_reset()
6245 * Reset the 'to' interfaces heirarchy with a new set of destination interfaces for
6246 * the multicast connection
6247 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306248int ecm_db_multicast_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces, int32_t *new_first)
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306249{
6250 struct ecm_db_iface_instance *ii_temp;
6251 struct ecm_db_iface_instance *ii_single;
6252 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306253 struct ecm_db_iface_instance *ii_db;
6254 struct ecm_db_iface_instance *ii_db_single;
6255 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306256 int32_t *nf_p;
6257 int32_t heirarchy_index;
6258 int32_t i;
6259 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6260
6261 /*
6262 * First remove all old interface hierarchies if any hierarchy
6263 * uphold in the ci->to_mcast_interfaces.
6264 */
6265 ecm_db_multicast_connection_to_interfaces_clear(ci);
6266
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306267 ci->to_mcast_interfaces = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
6268 if (!ci->to_mcast_interfaces) {
6269 DEBUG_WARN("%p: Memory is not available for to_mcast_interfaces\n", ci);
6270 return -1;
6271 }
6272
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306273 /*
6274 * Iterate the to interface list and add the new interface hierarchies
6275 */
6276 spin_lock_bh(&ecm_db_lock);
6277
6278 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6279 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
6280 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6281
6282 if (*nf_p == ECM_DB_IFACE_HEIRARCHY_MAX) {
6283 continue;
6284 }
6285
6286 for (i = *nf_p; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6287
6288 /*
6289 * Store valid dest interface list into DB connection
6290 */
6291 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6292 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306293
6294 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
6295 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, i);
6296 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
6297
6298 *ifaces_db = *ifaces;
6299 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306300 }
6301 }
6302
6303 /*
6304 * Update the first indices
6305 */
6306 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6307 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6308 ci->to_mcast_interface_first[heirarchy_index] = *nf_p;
6309 }
6310
6311 ci->to_mcast_interfaces_set = true;
6312 spin_unlock_bh(&ecm_db_lock);
6313
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306314 return 0;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306315}
6316EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_reset);
6317
6318/*
6319 * ecm_db_multicast_connection_to_interfaces_update()
6320 * Merge the latest valid multicast destination interfaces into DB Connection
6321 * instance. The new list holds the updated list of interfaces for the multicast
6322 * connection, due to JOIN updates.
6323 */
6324void ecm_db_multicast_connection_to_interfaces_update(struct ecm_db_connection_instance *ci,
6325 struct ecm_db_iface_instance *interfaces, int32_t *mc_join_first, int32_t *mc_join_valid_idx)
6326{
6327 struct ecm_db_iface_instance *ii_temp;
6328 struct ecm_db_iface_instance *ii_single;
6329 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306330 struct ecm_db_iface_instance *ii_db;
6331 struct ecm_db_iface_instance *ii_db_single;
6332 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306333 int32_t *join_first;
6334 int32_t *join_idx;
6335 int heirarchy_index;
6336 int32_t if_index;
6337 int32_t i;
6338
6339 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6340
6341 /*
6342 * Iterate the to interface list, adding in the new
6343 */
6344 spin_lock_bh(&ecm_db_lock);
6345 for (heirarchy_index = 0, if_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6346 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, if_index);
6347 join_first = ecm_db_multicast_if_first_get_at_index(mc_join_first, if_index);
6348 join_idx = ecm_db_multicast_if_num_get_at_index(mc_join_valid_idx, heirarchy_index);
6349
6350 if (*join_idx == 0) {
6351
6352 /*
6353 * No update for the interface at this index
6354 */
6355 continue;
6356 }
6357
6358 /*
6359 * This interface has joined the group. Add it to the list.
6360 */
6361 if (*join_first == ECM_DB_IFACE_HEIRARCHY_MAX) {
6362 if_index++;
6363 continue;
6364 }
6365
6366 ci->to_mcast_interface_first[heirarchy_index] = *join_first;
6367 for (i = *join_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6368
6369 /*
6370 * Store valid dest interface list into DB connection
6371 */
6372 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6373 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306374 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
6375 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, i);
6376 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
6377 *ifaces_db = *ifaces;
6378 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306379 }
6380 if_index++;
6381 }
6382 spin_unlock_bh(&ecm_db_lock);
6383 return;
6384}
6385EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_update);
6386#endif
6387
Ben Menchaca84f36632014-02-28 20:57:38 +00006388/*
6389 * ecm_db_connection_from_interfaces_reset()
6390 * Reset the from interfaces heirarchy with a new set of interfaces
6391 *
6392 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6393 * This is deliberate - it's stating that there is no list :-)
6394 */
6395void ecm_db_connection_from_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6396{
6397 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6398 int32_t old_first;
6399 int32_t i;
6400 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6401
6402 /*
6403 * Iterate the from interface list, removing the old and adding in the new
6404 */
6405 spin_lock_bh(&ecm_db_lock);
6406 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6407 /*
6408 * Put any previous interface into the old list
6409 */
6410 old[i] = ci->from_interfaces[i];
6411 ci->from_interfaces[i] = NULL;
6412 if (i < new_first) {
6413 continue;
6414 }
6415 ci->from_interfaces[i] = interfaces[i];
6416 _ecm_db_iface_ref(ci->from_interfaces[i]);
6417 }
6418
6419 /*
6420 * Get old first and update to new first
6421 */
6422 old_first = ci->from_interface_first;
6423 ci->from_interface_first = new_first;
6424 ci->from_interface_set = true;
6425 spin_unlock_bh(&ecm_db_lock);
6426
6427 /*
6428 * Release old
6429 */
6430 ecm_db_connection_interfaces_deref(old, old_first);
6431}
6432EXPORT_SYMBOL(ecm_db_connection_from_interfaces_reset);
6433
6434/*
6435 * ecm_db_connection_to_interfaces_reset()
6436 * Reset the to interfaces heirarchy with a new set of interfaces
6437 *
6438 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6439 * This is deliberate - it's stating that there is no list :-)
6440 */
6441void ecm_db_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6442{
6443 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6444 int32_t old_first;
6445 int32_t i;
6446 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6447
6448 /*
6449 * Iterate the to interface list, removing the old and adding in the new
6450 */
6451 spin_lock_bh(&ecm_db_lock);
6452 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6453 /*
6454 * Put any previous interface into the old list
6455 */
6456 old[i] = ci->to_interfaces[i];
6457 ci->to_interfaces[i] = NULL;
6458 if (i < new_first) {
6459 continue;
6460 }
6461 ci->to_interfaces[i] = interfaces[i];
6462 _ecm_db_iface_ref(ci->to_interfaces[i]);
6463 }
6464
6465 /*
6466 * Get old first and update to new first
6467 */
6468 old_first = ci->to_interface_first;
6469 ci->to_interface_first = new_first;
6470 ci->to_interface_set = true;
6471 spin_unlock_bh(&ecm_db_lock);
6472
6473 /*
6474 * Release old
6475 */
6476 ecm_db_connection_interfaces_deref(old, old_first);
6477}
6478EXPORT_SYMBOL(ecm_db_connection_to_interfaces_reset);
6479
6480/*
6481 * ecm_db_connection_from_nat_interfaces_reset()
6482 * Reset the from NAT interfaces heirarchy with a new set of interfaces
6483 *
6484 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6485 * This is deliberate - it's stating that there is no list :-)
6486 */
6487void ecm_db_connection_from_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6488{
6489 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6490 int32_t old_first;
6491 int32_t i;
6492 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6493
6494 /*
6495 * Iterate the from nat interface list, removing the old and adding in the new
6496 */
6497 spin_lock_bh(&ecm_db_lock);
6498 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6499 /*
6500 * Put any previous interface into the old list
6501 */
6502 old[i] = ci->from_nat_interfaces[i];
6503 ci->from_nat_interfaces[i] = NULL;
6504 if (i < new_first) {
6505 continue;
6506 }
6507 ci->from_nat_interfaces[i] = interfaces[i];
6508 _ecm_db_iface_ref(ci->from_nat_interfaces[i]);
6509 }
6510
6511 /*
6512 * Get old first and update to new first
6513 */
6514 old_first = ci->from_nat_interface_first;
6515 ci->from_nat_interface_first = new_first;
6516 ci->from_nat_interface_set = true;
6517 spin_unlock_bh(&ecm_db_lock);
6518
6519 /*
6520 * Release old
6521 */
6522 ecm_db_connection_interfaces_deref(old, old_first);
6523}
6524EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_reset);
6525
6526/*
6527 * ecm_db_connection_to_nat_interfaces_reset()
6528 * Reset the to NAT interfaces heirarchy with a new set of interfaces.
6529 *
6530 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6531 * This is deliberate - it's stating that there is no list :-)
6532 */
6533void ecm_db_connection_to_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6534{
6535 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6536 int32_t old_first;
6537 int32_t i;
6538 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6539
6540 /*
6541 * Iterate the to nat interface list, removing the old and adding in the new
6542 */
6543 spin_lock_bh(&ecm_db_lock);
6544 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6545 /*
6546 * Put any previous interface into the old list
6547 */
6548 old[i] = ci->to_nat_interfaces[i];
6549 ci->to_nat_interfaces[i] = NULL;
6550 if (i < new_first) {
6551 continue;
6552 }
6553 ci->to_nat_interfaces[i] = interfaces[i];
6554 _ecm_db_iface_ref(ci->to_nat_interfaces[i]);
6555 }
6556
6557 /*
6558 * Get old first and update to new first
6559 */
6560 old_first = ci->to_nat_interface_first;
6561 ci->to_nat_interface_first = new_first;
6562 ci->to_nat_interface_set = true;
6563 spin_unlock_bh(&ecm_db_lock);
6564
6565 /*
6566 * Release old
6567 */
6568 ecm_db_connection_interfaces_deref(old, old_first);
6569}
6570EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_reset);
6571
6572/*
6573 * ecm_db_connection_to_nat_interfaces_get_count()
6574 * Return the number of interfaces in the list
6575 */
6576int32_t ecm_db_connection_to_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6577{
6578 int32_t first;
6579 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6580 spin_lock_bh(&ecm_db_lock);
6581 first = ci->to_nat_interface_first;
6582 spin_unlock_bh(&ecm_db_lock);
6583 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6584}
6585EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_count);
6586
6587/*
6588 * ecm_db_connection_from_nat_interfaces_get_count()
6589 * Return the number of interfaces in the list
6590 */
6591int32_t ecm_db_connection_from_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6592{
6593 int32_t first;
6594 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6595 spin_lock_bh(&ecm_db_lock);
6596 first = ci->from_nat_interface_first;
6597 spin_unlock_bh(&ecm_db_lock);
6598 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6599}
6600EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_count);
6601
6602/*
6603 * ecm_db_connection_to_interfaces_get_count()
6604 * Return the number of interfaces in the list
6605 */
6606int32_t ecm_db_connection_to_interfaces_get_count(struct ecm_db_connection_instance *ci)
6607{
6608 int32_t first;
6609 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6610 spin_lock_bh(&ecm_db_lock);
6611 first = ci->to_interface_first;
6612 spin_unlock_bh(&ecm_db_lock);
6613 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6614}
6615EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_count);
6616
6617/*
6618 * ecm_db_connection_from_interfaces_get_count()
6619 * Return the number of interfaces in the list
6620 */
6621int32_t ecm_db_connection_from_interfaces_get_count(struct ecm_db_connection_instance *ci)
6622{
6623 int32_t first;
6624 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6625 spin_lock_bh(&ecm_db_lock);
6626 first = ci->from_interface_first;
6627 spin_unlock_bh(&ecm_db_lock);
6628 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6629}
6630EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_count);
6631
6632/*
6633 * ecm_db_connection_to_interfaces_set_check()
6634 * Returns true if the interface list has been set - even if set to an empty list!
6635 */
6636bool ecm_db_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
6637{
6638 bool set;
6639
6640 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6641 spin_lock_bh(&ecm_db_lock);
6642 set = ci->to_interface_set;
6643 spin_unlock_bh(&ecm_db_lock);
6644 return set;
6645}
6646EXPORT_SYMBOL(ecm_db_connection_to_interfaces_set_check);
6647
6648/*
6649 * ecm_db_connection_from_interfaces_set_check()
6650 * Returns true if the interface list has been set - even if set to an empty list!
6651 */
6652bool ecm_db_connection_from_interfaces_set_check(struct ecm_db_connection_instance *ci)
6653{
6654 bool set;
6655
6656 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6657 spin_lock_bh(&ecm_db_lock);
6658 set = ci->from_interface_set;
6659 spin_unlock_bh(&ecm_db_lock);
6660 return set;
6661}
6662EXPORT_SYMBOL(ecm_db_connection_from_interfaces_set_check);
6663
6664/*
6665 * ecm_db_connection_to_nat_interfaces_set_check()
6666 * Returns true if the interface list has been set - even if set to an empty list!
6667 */
6668bool ecm_db_connection_to_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6669{
6670 bool set;
6671
6672 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6673 spin_lock_bh(&ecm_db_lock);
6674 set = ci->to_nat_interface_set;
6675 spin_unlock_bh(&ecm_db_lock);
6676 return set;
6677}
6678EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_set_check);
6679
6680/*
6681 * ecm_db_connection_from_nat_interfaces_set_check()
6682 * Returns true if the interface list has been set - even if set to an empty list!
6683 */
6684bool ecm_db_connection_from_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6685{
6686 bool set;
6687
6688 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6689 spin_lock_bh(&ecm_db_lock);
6690 set = ci->from_nat_interface_set;
6691 spin_unlock_bh(&ecm_db_lock);
6692 return set;
6693}
6694EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_set_check);
6695
6696/*
6697 * ecm_db_connection_from_interfaces_clear()
6698 * Clear down the interfaces list, marking the list as not set
6699 */
6700void ecm_db_connection_from_interfaces_clear(struct ecm_db_connection_instance *ci)
6701{
6702 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6703 int32_t discard_first;
6704 int32_t i;
6705
6706 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6707
6708 spin_lock_bh(&ecm_db_lock);
6709 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6710 discard[i] = ci->from_interfaces[i];
6711 }
6712
6713 discard_first = ci->from_interface_first;
6714 ci->from_interface_set = false;
6715 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6716 spin_unlock_bh(&ecm_db_lock);
6717
6718 /*
6719 * Release previous
6720 */
6721 ecm_db_connection_interfaces_deref(discard, discard_first);
6722}
6723EXPORT_SYMBOL(ecm_db_connection_from_interfaces_clear);
6724
6725/*
6726 * ecm_db_connection_from_nat_interfaces_clear()
6727 * Clear down the interfaces list, marking the list as not set
6728 */
6729void ecm_db_connection_from_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
6730{
6731 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6732 int32_t discard_first;
6733 int32_t i;
6734
6735 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6736
6737 spin_lock_bh(&ecm_db_lock);
6738 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6739 discard[i] = ci->from_nat_interfaces[i];
6740 }
6741
6742 discard_first = ci->from_nat_interface_first;
6743 ci->from_nat_interface_set = false;
6744 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6745 spin_unlock_bh(&ecm_db_lock);
6746
6747 /*
6748 * Release previous
6749 */
6750 ecm_db_connection_interfaces_deref(discard, discard_first);
6751}
6752EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_clear);
6753
6754/*
6755 * ecm_db_connection_to_interfaces_clear()
6756 * Clear down the interfaces list, marking the list as not set
6757 */
6758void ecm_db_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
6759{
6760 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6761 int32_t discard_first;
6762 int32_t i;
6763
6764 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6765
6766 spin_lock_bh(&ecm_db_lock);
6767 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6768 discard[i] = ci->to_interfaces[i];
6769 }
6770
6771 discard_first = ci->to_interface_first;
6772 ci->to_interface_set = false;
6773 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6774 spin_unlock_bh(&ecm_db_lock);
6775
6776 /*
6777 * Release previous
6778 */
6779 ecm_db_connection_interfaces_deref(discard, discard_first);
6780}
6781EXPORT_SYMBOL(ecm_db_connection_to_interfaces_clear);
6782
6783/*
6784 * ecm_db_connection_to_nat_interfaces_clear()
6785 * Clear down the interfaces list, marking the list as not set
6786 */
6787void ecm_db_connection_to_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
6788{
6789 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6790 int32_t discard_first;
6791 int32_t i;
6792
6793 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6794
6795 spin_lock_bh(&ecm_db_lock);
6796 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6797 discard[i] = ci->to_nat_interfaces[i];
6798 }
6799
6800 discard_first = ci->to_nat_interface_first;
6801 ci->to_nat_interface_set = false;
6802 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6803 spin_unlock_bh(&ecm_db_lock);
6804
6805 /*
6806 * Release previous
6807 */
6808 ecm_db_connection_interfaces_deref(discard, discard_first);
6809}
6810EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_clear);
6811
6812/*
6813 * ecm_db_connection_add()
6814 * Add the connection into the database.
6815 *
6816 * NOTE: The parameters are DIRECTIONAL in terms of which mapping established the connection.
6817 * NOTE: Dir confirms if this is an egressing or ingressing connection. This applies to firewalling front ends mostly. If INGRESS then mapping_from is the WAN side. If EGRESS then mapping_to is the WAN side.
6818 */
6819void ecm_db_connection_add(struct ecm_db_connection_instance *ci,
6820 struct ecm_front_end_connection_instance *feci,
Ben Menchaca84f36632014-02-28 20:57:38 +00006821 struct ecm_db_mapping_instance *mapping_from, struct ecm_db_mapping_instance *mapping_to,
6822 struct ecm_db_mapping_instance *mapping_nat_from, struct ecm_db_mapping_instance *mapping_nat_to,
Gareth Williams90f2a282014-08-27 15:56:25 +01006823 struct ecm_db_node_instance *from_node, struct ecm_db_node_instance *to_node,
6824 struct ecm_db_node_instance *from_nat_node, struct ecm_db_node_instance *to_nat_node,
Gareth Williams3e5b37f2015-05-13 10:04:12 +01006825 int ip_version,
Ben Menchaca84f36632014-02-28 20:57:38 +00006826 int protocol, ecm_db_direction_t dir,
6827 ecm_db_connection_final_callback_t final,
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07006828 ecm_db_connection_defunct_callback_t defunct,
Ben Menchaca84f36632014-02-28 20:57:38 +00006829 ecm_db_timer_group_t tg, bool is_routed,
6830 void *arg)
6831{
6832 ecm_db_connection_hash_t hash_index;
6833 ecm_db_connection_serial_hash_t serial_hash_index;
6834 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00006835#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00006836 struct ecm_db_iface_instance *iface_from;
6837 struct ecm_db_iface_instance *iface_to;
6838 struct ecm_db_iface_instance *iface_nat_from;
6839 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00006840#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00006841
6842 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6843 DEBUG_CHECK_MAGIC(mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_from);
6844 DEBUG_CHECK_MAGIC(mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_to);
6845 DEBUG_CHECK_MAGIC(mapping_nat_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_from);
6846 DEBUG_CHECK_MAGIC(mapping_nat_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_to);
Gareth Williams90f2a282014-08-27 15:56:25 +01006847 DEBUG_CHECK_MAGIC(from_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_node);
6848 DEBUG_CHECK_MAGIC(to_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_node);
6849 DEBUG_CHECK_MAGIC(from_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_nat_node);
6850 DEBUG_CHECK_MAGIC(to_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_nat_node);
Ben Menchaca84f36632014-02-28 20:57:38 +00006851 DEBUG_ASSERT((protocol >= 0) && (protocol <= 255), "%p: invalid protocol number %d\n", ci, protocol);
6852
6853 spin_lock_bh(&ecm_db_lock);
6854 DEBUG_ASSERT(!(ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED), "%p: inserted\n", ci);
6855 spin_unlock_bh(&ecm_db_lock);
6856
6857 /*
6858 * Record owner arg and callbacks
6859 */
6860 ci->final = final;
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07006861 ci->defunct = defunct;
Ben Menchaca84f36632014-02-28 20:57:38 +00006862 ci->arg = arg;
6863
6864 /*
6865 * Take reference to the front end
6866 */
6867 feci->ref(feci);
6868 ci->feci = feci;
6869
6870 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006871 * Ensure default classifier has been assigned this is a must to ensure minimum level of classification
Ben Menchaca84f36632014-02-28 20:57:38 +00006872 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006873 DEBUG_ASSERT(ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT], "%p: No default classifier assigned\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006874
6875 /*
6876 * Connection takes references to the mappings
6877 */
6878 ecm_db_mapping_ref(mapping_from);
6879 ecm_db_mapping_ref(mapping_to);
6880 ci->mapping_from = mapping_from;
6881 ci->mapping_to = mapping_to;
6882
6883 ecm_db_mapping_ref(mapping_nat_from);
6884 ecm_db_mapping_ref(mapping_nat_to);
6885 ci->mapping_nat_from = mapping_nat_from;
6886 ci->mapping_nat_to = mapping_nat_to;
6887
6888 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01006889 * Take references to the nodes
6890 */
6891 ci->from_node = from_node;
6892 ecm_db_node_ref(from_node);
6893 ci->to_node = to_node;
6894 ecm_db_node_ref(to_node);
6895
6896 ci->from_nat_node = from_nat_node;
6897 ecm_db_node_ref(from_nat_node);
6898 ci->to_nat_node = to_nat_node;
6899 ecm_db_node_ref(to_nat_node);
6900
6901 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00006902 * Set the protocol and routed flag
6903 */
Gareth Williams3e5b37f2015-05-13 10:04:12 +01006904 ci->ip_version = ip_version;
Ben Menchaca84f36632014-02-28 20:57:38 +00006905 ci->protocol = protocol;
6906 ci->is_routed = is_routed;
6907
6908 /*
6909 * Set direction of connection
6910 */
6911 ci->direction = dir;
6912
6913 /*
6914 * Identify which hash chain this connection will go into
6915 */
6916 hash_index = ecm_db_connection_generate_hash_index(mapping_from->host->address, mapping_from->port, mapping_to->host->address, mapping_to->port, protocol);
6917 ci->hash_index = hash_index;
6918
6919 /*
6920 * Identify which serial hash chain this connection will go into
6921 */
6922 serial_hash_index = ecm_db_connection_generate_serial_hash_index(ci->serial);
6923 ci->serial_hash_index = serial_hash_index;
6924
6925 /*
6926 * Now we need to lock
6927 */
6928 spin_lock_bh(&ecm_db_lock);
6929
6930 /*
6931 * Increment protocol counter stats
6932 */
6933 ecm_db_connection_count_by_protocol[protocol]++;
6934 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[protocol] > 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[protocol]);
6935
Ben Menchaca84f36632014-02-28 20:57:38 +00006936 /*
6937 * Set time
6938 */
6939 ci->time_added = ecm_db_time;
6940
6941 /*
6942 * Add connection into the global list
6943 */
6944 ci->prev = NULL;
6945 ci->next = ecm_db_connections;
6946 if (ecm_db_connections) {
6947 ecm_db_connections->prev = ci;
6948 }
6949 ecm_db_connections = ci;
6950
6951 /*
6952 * Add this connection into the connections hash table
6953 */
6954 ci->flags |= ECM_DB_CONNECTION_FLAGS_INSERTED;
6955
6956 /*
Gareth Williamsb5903892015-03-20 15:13:07 +00006957 * Insert connection into the connections hash table
Ben Menchaca84f36632014-02-28 20:57:38 +00006958 */
6959 ci->hash_next = ecm_db_connection_table[hash_index];
6960 if (ecm_db_connection_table[hash_index]) {
6961 ecm_db_connection_table[hash_index]->hash_prev = ci;
6962 }
6963 ecm_db_connection_table[hash_index] = ci;
6964 ecm_db_connection_table_lengths[hash_index]++;
6965 DEBUG_ASSERT(ecm_db_connection_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[hash_index]);
6966
6967 /*
6968 * Insert connection into the connections serial hash table
6969 */
6970 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
6971 if (ecm_db_connection_serial_table[serial_hash_index]) {
6972 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
6973 }
6974 ecm_db_connection_serial_table[serial_hash_index] = ci;
6975 ecm_db_connection_serial_table_lengths[serial_hash_index]++;
6976 DEBUG_ASSERT(ecm_db_connection_serial_table_lengths[serial_hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_serial_table_lengths[serial_hash_index]);
6977
Gareth Williamsb5903892015-03-20 15:13:07 +00006978#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00006979 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01006980 * Add this connection into the FROM node
6981 */
6982 ci->node_from_prev = NULL;
6983 ci->node_from_next = from_node->from_connections;
6984 if (from_node->from_connections) {
6985 from_node->from_connections->node_from_prev = ci;
6986 }
6987 from_node->from_connections = ci;
6988 from_node->from_connections_count++;
6989 DEBUG_ASSERT(from_node->from_connections_count > 0, "%p: invalid count\n", ci);
6990
6991 /*
6992 * Add this connection into the TO node
6993 */
6994 ci->node_to_prev = NULL;
6995 ci->node_to_next = to_node->to_connections;
6996 if (to_node->to_connections) {
6997 to_node->to_connections->node_to_prev = ci;
6998 }
6999 to_node->to_connections = ci;
7000 to_node->to_connections_count++;
7001 DEBUG_ASSERT(to_node->to_connections_count > 0, "%p: invalid count\n", ci);
7002
7003 /*
7004 * Add this connection into the FROM NAT node
7005 */
7006 ci->node_from_nat_prev = NULL;
7007 ci->node_from_nat_next = from_nat_node->from_nat_connections;
7008 if (from_nat_node->from_nat_connections) {
7009 from_nat_node->from_nat_connections->node_from_nat_prev = ci;
7010 }
7011 from_nat_node->from_nat_connections = ci;
7012 from_nat_node->from_nat_connections_count++;
7013 DEBUG_ASSERT(from_nat_node->from_nat_connections_count > 0, "%p: invalid count\n", ci);
7014
7015 /*
7016 * Add this connection into the TO NAT node
7017 */
7018 ci->node_to_nat_prev = NULL;
7019 ci->node_to_nat_next = to_nat_node->to_nat_connections;
7020 if (to_nat_node->to_nat_connections) {
7021 to_nat_node->to_nat_connections->node_to_nat_prev = ci;
7022 }
7023 to_nat_node->to_nat_connections = ci;
7024 to_nat_node->to_nat_connections_count++;
7025 DEBUG_ASSERT(to_nat_node->to_nat_connections_count > 0, "%p: invalid count\n", ci);
7026
7027 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007028 * Add this connection into the FROM mapping
7029 */
7030 ci->from_prev = NULL;
7031 ci->from_next = mapping_from->from_connections;
7032 if (mapping_from->from_connections) {
7033 mapping_from->from_connections->from_prev = ci;
7034 }
7035 mapping_from->from_connections = ci;
7036
7037 /*
7038 * Add this connection into the TO mapping
7039 */
7040 ci->to_prev = NULL;
7041 ci->to_next = mapping_to->to_connections;
7042 if (mapping_to->to_connections) {
7043 mapping_to->to_connections->to_prev = ci;
7044 }
7045 mapping_to->to_connections = ci;
7046
7047 /*
7048 * Add this connection into the FROM NAT mapping
7049 */
7050 ci->from_nat_prev = NULL;
7051 ci->from_nat_next = mapping_nat_from->from_nat_connections;
7052 if (mapping_nat_from->from_nat_connections) {
7053 mapping_nat_from->from_nat_connections->from_nat_prev = ci;
7054 }
7055 mapping_nat_from->from_nat_connections = ci;
7056
7057 /*
7058 * Add this connection into the TO NAT mapping
7059 */
7060 ci->to_nat_prev = NULL;
7061 ci->to_nat_next = mapping_nat_to->to_nat_connections;
7062 if (mapping_nat_to->to_nat_connections) {
7063 mapping_nat_to->to_nat_connections->to_nat_prev = ci;
7064 }
7065 mapping_nat_to->to_nat_connections = ci;
7066
7067 /*
7068 * Add this connection into the FROM iface list of connections
7069 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7070 * due to the heirarchy of dependencies being kept by the database.
7071 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007072 iface_from = from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007073 ci->iface_from_prev = NULL;
7074 ci->iface_from_next = iface_from->from_connections;
7075 if (iface_from->from_connections) {
7076 iface_from->from_connections->iface_from_prev = ci;
7077 }
7078 iface_from->from_connections = ci;
7079
7080 /*
7081 * Add this connection into the TO iface list of connections
7082 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7083 * due to the heirarchy of dependencies being kept by the database.
7084 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007085 iface_to = to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007086 ci->iface_to_prev = NULL;
7087 ci->iface_to_next = iface_to->to_connections;
7088 if (iface_to->to_connections) {
7089 iface_to->to_connections->iface_to_prev = ci;
7090 }
7091 iface_to->to_connections = ci;
7092
7093 /*
7094 * Add this connection into the FROM NAT iface list of connections
7095 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7096 * due to the heirarchy of dependencies being kept by the database.
7097 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007098 iface_nat_from = from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007099 ci->iface_from_nat_prev = NULL;
7100 ci->iface_from_nat_next = iface_nat_from->from_nat_connections;
7101 if (iface_nat_from->from_nat_connections) {
7102 iface_nat_from->from_nat_connections->iface_from_nat_prev = ci;
7103 }
7104 iface_nat_from->from_nat_connections = ci;
7105
7106 /*
7107 * Add this connection into the TO NAT iface list of connections
7108 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7109 * due to the heirarchy of dependencies being kept by the database.
7110 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007111 iface_nat_to = to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007112 ci->iface_to_nat_prev = NULL;
7113 ci->iface_to_nat_next = iface_nat_to->to_nat_connections;
7114 if (iface_nat_to->to_nat_connections) {
7115 iface_nat_to->to_nat_connections->iface_to_nat_prev = ci;
7116 }
7117 iface_nat_to->to_nat_connections = ci;
Gareth Williamsb5903892015-03-20 15:13:07 +00007118#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01007119
Ben Menchaca84f36632014-02-28 20:57:38 +00007120 /*
7121 * NOTE: The interface heirarchy lists are deliberately left empty - these are completed
7122 * by the front end if it is appropriate to do so.
7123 */
7124
7125 /*
7126 * Update the counters in the mapping
7127 */
7128 if (protocol == IPPROTO_UDP) {
7129 mapping_from->udp_from++;
7130 mapping_to->udp_to++;
7131 mapping_nat_from->udp_nat_from++;
7132 mapping_nat_to->udp_nat_to++;
7133 } else if (protocol == IPPROTO_TCP) {
7134 mapping_from->tcp_from++;
7135 mapping_to->tcp_to++;
7136 mapping_nat_from->tcp_nat_from++;
7137 mapping_nat_to->tcp_nat_to++;
7138 }
7139
7140 mapping_from->from++;
7141 mapping_to->to++;
7142 mapping_nat_from->nat_from++;
7143 mapping_nat_to->nat_to++;
7144
7145 /*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307146 * Set the generation number to match global
Ben Menchaca84f36632014-02-28 20:57:38 +00007147 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307148 ci->generation = ecm_db_connection_generation;
Ben Menchaca84f36632014-02-28 20:57:38 +00007149
7150 spin_unlock_bh(&ecm_db_lock);
7151
7152 /*
7153 * Throw add event to the listeners
7154 */
7155 DEBUG_TRACE("%p: Throw connection added event\n", ci);
7156 li = ecm_db_listeners_get_and_ref_first();
7157 while (li) {
7158 struct ecm_db_listener_instance *lin;
7159 if (li->connection_added) {
7160 li->connection_added(li->arg, ci);
7161 }
7162
7163 /*
7164 * Get next listener
7165 */
7166 lin = ecm_db_listener_get_and_ref_next(li);
7167 ecm_db_listener_deref(li);
7168 li = lin;
7169 }
7170
7171 /*
7172 * Set timer group. 'ref' the connection to ensure it persists for the timer.
7173 */
7174 ecm_db_connection_ref(ci);
7175 ecm_db_timer_group_entry_set(&ci->defunct_timer, tg);
7176}
7177EXPORT_SYMBOL(ecm_db_connection_add);
7178
7179/*
7180 * ecm_db_mapping_add()
7181 * Add a mapping instance into the database
7182 *
7183 * NOTE: The mapping will take a reference to the host instance.
7184 */
7185void ecm_db_mapping_add(struct ecm_db_mapping_instance *mi, struct ecm_db_host_instance *hi, int port,
7186 ecm_db_mapping_final_callback_t final, void *arg)
7187{
7188 ecm_db_mapping_hash_t hash_index;
7189 struct ecm_db_listener_instance *li;
7190
7191 spin_lock_bh(&ecm_db_lock);
7192 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
7193 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007194 DEBUG_ASSERT(!(mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED), "%p: inserted\n", mi);
7195 DEBUG_ASSERT((hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: not inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007196 DEBUG_ASSERT(!mi->tcp_from && !mi->tcp_to && !mi->udp_from && !mi->udp_to, "%p: protocol count errors\n", mi);
7197#ifdef ECM_DB_XREF_ENABLE
7198 DEBUG_ASSERT(mi->from_connections == NULL, "%p: connections not null\n", mi);
7199 DEBUG_ASSERT(mi->to_connections == NULL, "%p: connections not null\n", mi);
7200 DEBUG_ASSERT(!mi->from && !mi->to && !mi->nat_from && !mi->nat_to, "%p: connection count errors\n", mi);
7201#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007202 spin_unlock_bh(&ecm_db_lock);
7203
7204 mi->arg = arg;
7205 mi->final = final;
7206
7207 /*
7208 * Compute hash table position for insertion
7209 */
7210 hash_index = ecm_db_mapping_generate_hash_index(hi->address, port);
7211 mi->hash_index = hash_index;
7212
7213 /*
7214 * Record port
7215 */
7216 mi->port = port;
7217
7218 /*
7219 * Mapping takes a ref to the host
7220 */
7221 ecm_db_host_ref(hi);
7222 mi->host = hi;
7223
7224 /*
7225 * Set time
7226 */
7227 spin_lock_bh(&ecm_db_lock);
7228 mi->time_added = ecm_db_time;
7229
7230 /*
7231 * Record the mapping is inserted
7232 */
7233 mi->flags |= ECM_DB_MAPPING_FLAGS_INSERTED;
7234
7235 /*
7236 * Add into the global list
7237 */
7238 mi->prev = NULL;
7239 mi->next = ecm_db_mappings;
7240 if (ecm_db_mappings) {
7241 ecm_db_mappings->prev = mi;
7242 }
7243 ecm_db_mappings = mi;
7244
7245 /*
7246 * Insert mapping into the mappings hash table
7247 */
7248 mi->hash_next = ecm_db_mapping_table[hash_index];
7249 if (ecm_db_mapping_table[hash_index]) {
7250 ecm_db_mapping_table[hash_index]->hash_prev = mi;
7251 }
7252 ecm_db_mapping_table[hash_index] = mi;
7253 ecm_db_mapping_table_lengths[hash_index]++;
7254 DEBUG_ASSERT(ecm_db_mapping_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_mapping_table_lengths[hash_index]);
7255
Gareth Williamsb5903892015-03-20 15:13:07 +00007256#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007257 /*
7258 * Insert mapping into the host mapping list
7259 */
7260 mi->mapping_prev = NULL;
7261 mi->mapping_next = hi->mappings;
7262 if (hi->mappings) {
7263 hi->mappings->mapping_prev = mi;
7264 }
7265 hi->mappings = mi;
7266 hi->mapping_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007267#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007268 spin_unlock_bh(&ecm_db_lock);
7269
7270 /*
7271 * Throw add event to the listeners
7272 */
7273 DEBUG_TRACE("%p: Throw mapping added event\n", mi);
7274 li = ecm_db_listeners_get_and_ref_first();
7275 while (li) {
7276 struct ecm_db_listener_instance *lin;
7277 if (li->mapping_added) {
7278 li->mapping_added(li->arg, mi);
7279 }
7280
7281 /*
7282 * Get next listener
7283 */
7284 lin = ecm_db_listener_get_and_ref_next(li);
7285 ecm_db_listener_deref(li);
7286 li = lin;
7287 }
7288}
7289EXPORT_SYMBOL(ecm_db_mapping_add);
7290
7291/*
7292 * ecm_db_host_add()
7293 * Add a host instance into the database
7294 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007295void ecm_db_host_add(struct ecm_db_host_instance *hi, ip_addr_t address, bool on_link, ecm_db_host_final_callback_t final, void *arg)
Ben Menchaca84f36632014-02-28 20:57:38 +00007296{
7297 ecm_db_host_hash_t hash_index;
7298 struct ecm_db_listener_instance *li;
7299
7300 spin_lock_bh(&ecm_db_lock);
7301 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007302 DEBUG_ASSERT(!(hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007303#ifdef ECM_DB_XREF_ENABLE
7304 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
7305#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007306 spin_unlock_bh(&ecm_db_lock);
7307
7308 hi->arg = arg;
7309 hi->final = final;
7310 ECM_IP_ADDR_COPY(hi->address, address);
7311 hi->on_link = on_link;
7312
7313 /*
7314 * Compute hash index into which host will be added
7315 */
7316 hash_index = ecm_db_host_generate_hash_index(address);
7317 hi->hash_index = hash_index;
7318
7319 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007320 * Add into the global list
7321 */
7322 spin_lock_bh(&ecm_db_lock);
7323 hi->flags |= ECM_DB_HOST_FLAGS_INSERTED;
7324 hi->prev = NULL;
7325 hi->next = ecm_db_hosts;
7326 if (ecm_db_hosts) {
7327 ecm_db_hosts->prev = hi;
7328 }
7329 ecm_db_hosts = hi;
7330
7331 /*
7332 * Add host into the hash table
7333 */
7334 hi->hash_next = ecm_db_host_table[hash_index];
7335 if (ecm_db_host_table[hash_index]) {
7336 ecm_db_host_table[hash_index]->hash_prev = hi;
7337 }
7338 ecm_db_host_table[hash_index] = hi;
7339 ecm_db_host_table_lengths[hash_index]++;
7340 DEBUG_ASSERT(ecm_db_host_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hash_index]);
7341
7342 /*
7343 * Set time of add
7344 */
7345 hi->time_added = ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00007346 spin_unlock_bh(&ecm_db_lock);
7347
7348 /*
7349 * Throw add event to the listeners
7350 */
7351 DEBUG_TRACE("%p: Throw host added event\n", hi);
7352 li = ecm_db_listeners_get_and_ref_first();
7353 while (li) {
7354 struct ecm_db_listener_instance *lin;
7355 if (li->host_added) {
7356 li->host_added(li->arg, hi);
7357 }
7358
7359 /*
7360 * Get next listener
7361 */
7362 lin = ecm_db_listener_get_and_ref_next(li);
7363 ecm_db_listener_deref(li);
7364 li = lin;
7365 }
7366}
7367EXPORT_SYMBOL(ecm_db_host_add);
7368
7369/*
7370 * ecm_db_node_add()
7371 * Add a node instance into the database
7372 */
7373void ecm_db_node_add(struct ecm_db_node_instance *ni, struct ecm_db_iface_instance *ii, uint8_t *address,
7374 ecm_db_node_final_callback_t final, void *arg)
7375{
7376 ecm_db_node_hash_t hash_index;
7377 struct ecm_db_listener_instance *li;
7378
7379 spin_lock_bh(&ecm_db_lock);
7380 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
7381 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7382 DEBUG_ASSERT(address, "%p: address null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00007383 DEBUG_ASSERT((ni->iface == NULL), "%p: iface not null\n", ni);
7384 DEBUG_ASSERT(!(ni->flags & ECM_DB_NODE_FLAGS_INSERTED), "%p: inserted\n", ni);
7385#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01007386 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
7387 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
7388 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
7389 DEBUG_ASSERT((ni->to_nat_connections == NULL) && (ni->to_nat_connections_count == 0), "%p: to_nat_connections not null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00007390#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007391 spin_unlock_bh(&ecm_db_lock);
7392
7393 memcpy(ni->address, address, ETH_ALEN);
7394 ni->arg = arg;
7395 ni->final = final;
7396
7397 /*
7398 * Compute hash chain for insertion
7399 */
7400 hash_index = ecm_db_node_generate_hash_index(address);
7401 ni->hash_index = hash_index;
7402
7403 /*
7404 * Node takes a ref to the iface
7405 */
7406 ecm_db_iface_ref(ii);
7407 ni->iface = ii;
7408
7409 /*
7410 * Add into the global list
7411 */
7412 spin_lock_bh(&ecm_db_lock);
7413 ni->flags |= ECM_DB_NODE_FLAGS_INSERTED;
7414 ni->prev = NULL;
7415 ni->next = ecm_db_nodes;
7416 if (ecm_db_nodes) {
7417 ecm_db_nodes->prev = ni;
7418 }
7419 ecm_db_nodes = ni;
7420
7421 /*
7422 * Insert into the hash chain
7423 */
7424 ni->hash_next = ecm_db_node_table[hash_index];
7425 if (ecm_db_node_table[hash_index]) {
7426 ecm_db_node_table[hash_index]->hash_prev = ni;
7427 }
7428 ecm_db_node_table[hash_index] = ni;
7429 ecm_db_node_table_lengths[hash_index]++;
7430 DEBUG_ASSERT(ecm_db_node_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[hash_index]);
7431
7432 /*
7433 * Set time of add
7434 */
7435 ni->time_added = ecm_db_time;
7436
Gareth Williamsb5903892015-03-20 15:13:07 +00007437#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007438 /*
7439 * Insert node into the iface nodes list
7440 */
7441 ni->node_prev = NULL;
7442 ni->node_next = ii->nodes;
7443 if (ii->nodes) {
7444 ii->nodes->node_prev = ni;
7445 }
7446 ii->nodes = ni;
7447 ii->node_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007448#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007449 spin_unlock_bh(&ecm_db_lock);
7450
7451 /*
7452 * Throw add event to the listeners
7453 */
7454 DEBUG_TRACE("%p: Throw node added event\n", ni);
7455 li = ecm_db_listeners_get_and_ref_first();
7456 while (li) {
7457 struct ecm_db_listener_instance *lin;
7458 if (li->node_added) {
7459 li->node_added(li->arg, ni);
7460 }
7461
7462 /*
7463 * Get next listener
7464 */
7465 lin = ecm_db_listener_get_and_ref_next(li);
7466 ecm_db_listener_deref(li);
7467 li = lin;
7468 }
7469}
7470EXPORT_SYMBOL(ecm_db_node_add);
7471
Gareth Williamsd5618a82015-05-20 11:13:32 +01007472/*
7473 * ecm_db_adv_stats_state_write()
7474 * Write out advanced stats state
7475 */
7476static int ecm_db_adv_stats_state_write(struct ecm_state_file_instance *sfi,uint64_t from_data_total, uint64_t to_data_total,
7477 uint64_t from_packet_total, uint64_t to_packet_total, uint64_t from_data_total_dropped,
7478 uint64_t to_data_total_dropped, uint64_t from_packet_total_dropped, uint64_t to_packet_total_dropped)
7479{
7480 int result;
7481
7482 if ((result = ecm_state_prefix_add(sfi, "adv_stats"))) {
7483 return result;
7484 }
7485
7486 if ((result = ecm_state_write(sfi, "from_data_total", "%llu", from_data_total))) {
7487 return result;
7488 }
7489 if ((result = ecm_state_write(sfi, "to_data_total", "%llu", to_data_total))) {
7490 return result;
7491 }
7492 if ((result = ecm_state_write(sfi, "from_packet_total", "%llu", from_packet_total))) {
7493 return result;
7494 }
7495 if ((result = ecm_state_write(sfi, "to_packet_total", "%llu", to_packet_total))) {
7496 return result;
7497 }
7498 if ((result = ecm_state_write(sfi, "from_data_total_dropped", "%llu", from_data_total_dropped))) {
7499 return result;
7500 }
7501 if ((result = ecm_state_write(sfi, "to_data_total_dropped", "%llu", to_data_total_dropped))) {
7502 return result;
7503 }
7504 if ((result = ecm_state_write(sfi, "from_packet_total_dropped", "%llu", from_packet_total_dropped))) {
7505 return result;
7506 }
7507 if ((result = ecm_state_write(sfi, "to_packet_total_dropped", "%llu", to_packet_total_dropped))) {
7508 return result;
7509 }
7510
7511 return ecm_state_prefix_remove(sfi);
7512}
7513
Gareth Williamsf98d4192015-03-11 16:55:41 +00007514#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007515/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007516 * ecm_db_iface_state_get_base()
7517 * Get the basic state for an interface object
Ben Menchaca84f36632014-02-28 20:57:38 +00007518 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007519static int ecm_db_iface_state_get_base(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007520{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007521 int result;
Gareth Williamsb5903892015-03-20 15:13:07 +00007522#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007523 int node_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00007524#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007525 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00007526 int32_t interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007527 int32_t ae_interface_identifier;
Gareth Williams85331c92015-03-11 20:39:18 +00007528 char name[IFNAMSIZ];
7529 int32_t mtu;
7530 ecm_db_iface_type_t type;
7531#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007532 uint64_t from_data_total;
7533 uint64_t to_data_total;
7534 uint64_t from_packet_total;
7535 uint64_t to_packet_total;
7536 uint64_t from_data_total_dropped;
7537 uint64_t to_data_total_dropped;
7538 uint64_t from_packet_total_dropped;
7539 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00007540#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007541
7542 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7543 DEBUG_TRACE("%p: Open iface msg\n", ii);
7544
Gareth Williamsd5618a82015-05-20 11:13:32 +01007545 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
7546 return result;
7547 }
7548
Gareth Williamsb5903892015-03-20 15:13:07 +00007549#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007550 node_count = ecm_db_iface_node_count_get(ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00007551#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007552 time_added = ii->time_added;
Ben Menchaca84f36632014-02-28 20:57:38 +00007553 type = ii->type;
Gareth Williamsd5618a82015-05-20 11:13:32 +01007554 interface_identifier = ii->interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007555 ae_interface_identifier = ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00007556 spin_lock_bh(&ecm_db_lock);
7557 strcpy(name, ii->name);
7558 mtu = ii->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00007559 spin_unlock_bh(&ecm_db_lock);
7560
Gareth Williams85331c92015-03-11 20:39:18 +00007561#ifdef ECM_DB_ADVANCED_STATS_ENABLE
7562 ecm_db_iface_data_stats_get(ii, &from_data_total, &to_data_total,
7563 &from_packet_total, &to_packet_total,
7564 &from_data_total_dropped, &to_data_total_dropped,
7565 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williamsd5618a82015-05-20 11:13:32 +01007566
7567 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
7568 from_packet_total, to_packet_total, from_data_total_dropped,
7569 to_data_total_dropped, from_packet_total_dropped,
7570 to_packet_total_dropped))) {
7571 return result;
7572 }
Gareth Williams85331c92015-03-11 20:39:18 +00007573#endif
7574
Gareth Williamsd5618a82015-05-20 11:13:32 +01007575 if ((result = ecm_state_write(sfi, "type", "%d", type))) {
7576 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007577 }
7578
Gareth Williamsd5618a82015-05-20 11:13:32 +01007579 if ((result = ecm_state_write(sfi, "name", "%s", name))) {
7580 return result;
7581 }
7582
7583 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
7584 return result;
7585 }
7586
7587 if ((result = ecm_state_write(sfi, "mtu", "%d", mtu))) {
7588 return result;
7589 }
7590
7591 if ((result = ecm_state_write(sfi, "interface_identifier", "%d", interface_identifier))) {
7592 return result;
7593 }
7594
Murat Sezgin91c5d712015-06-12 15:16:22 -07007595 if ((result = ecm_state_write(sfi, "ae_interface_identifier", "%d", ae_interface_identifier))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01007596 return result;
7597 }
7598
7599#ifdef ECM_DB_XREF_ENABLE
7600 if ((result = ecm_state_write(sfi, "nodes", "%d", node_count))) {
7601 return result;
7602 }
7603#endif
7604
7605 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007606}
7607
7608/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007609 * ecm_db_iface_ethernet_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007610 * Return interface type specific state
7611 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007612static int ecm_db_iface_ethernet_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007613{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007614 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007615 uint8_t address[ETH_ALEN];
7616
7617 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7618 spin_lock_bh(&ecm_db_lock);
7619 memcpy(address, ii->type_info.ethernet.address, ETH_ALEN);
7620 spin_unlock_bh(&ecm_db_lock);
7621
Gareth Williamsd5618a82015-05-20 11:13:32 +01007622 if ((result = ecm_state_prefix_add(sfi, "ethernet"))) {
7623 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007624 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007625
Gareth Williamsd5618a82015-05-20 11:13:32 +01007626 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7627 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007628 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007629
Gareth Williamsd5618a82015-05-20 11:13:32 +01007630 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7631 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007632 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007633
7634 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007635}
7636
Murat Sezgin910c9662015-03-11 16:15:06 -07007637#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007638/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007639 * ecm_db_iface_lag_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007640 * Return interface type specific state
7641 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007642static int ecm_db_iface_lag_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007643{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007644 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007645 uint8_t address[ETH_ALEN];
7646
7647 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7648 spin_lock_bh(&ecm_db_lock);
7649 memcpy(address, ii->type_info.lag.address, ETH_ALEN);
7650 spin_unlock_bh(&ecm_db_lock);
7651
Gareth Williamsd5618a82015-05-20 11:13:32 +01007652 if ((result = ecm_state_prefix_add(sfi, "lag"))) {
7653 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007654 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007655 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7656 return result;
7657 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007658
Gareth Williamsd5618a82015-05-20 11:13:32 +01007659 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7660 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007661 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007662
Gareth Williamsd5618a82015-05-20 11:13:32 +01007663 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007664}
Murat Sezgin910c9662015-03-11 16:15:06 -07007665#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007666
7667/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007668 * ecm_db_iface_bridge_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007669 * Return interface type specific state
7670 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007671static int ecm_db_iface_bridge_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007672{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007673 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007674 uint8_t address[ETH_ALEN];
7675
7676 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7677 spin_lock_bh(&ecm_db_lock);
7678 memcpy(address, ii->type_info.bridge.address, ETH_ALEN);
7679 spin_unlock_bh(&ecm_db_lock);
7680
Gareth Williamsd5618a82015-05-20 11:13:32 +01007681 if ((result = ecm_state_prefix_add(sfi, "bridge"))) {
7682 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007683 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007684 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7685 return result;
7686 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007687
Gareth Williamsd5618a82015-05-20 11:13:32 +01007688 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7689 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007690 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007691
Gareth Williamsd5618a82015-05-20 11:13:32 +01007692 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007693}
7694
Murat Sezgin37fb3952015-03-10 16:45:13 -07007695#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007696/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007697 * ecm_db_iface_vlan_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007698 * Return interface type specific state
7699 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007700static int ecm_db_iface_vlan_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007701{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007702 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007703 uint8_t address[ETH_ALEN];
7704 uint16_t vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307705 uint16_t vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007706
7707 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7708 spin_lock_bh(&ecm_db_lock);
7709 memcpy(address, ii->type_info.vlan.address, ETH_ALEN);
7710 vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307711 vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007712 spin_unlock_bh(&ecm_db_lock);
7713
Gareth Williamsd5618a82015-05-20 11:13:32 +01007714 if ((result = ecm_state_prefix_add(sfi, "vlan"))) {
7715 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007716 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007717 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7718 return result;
7719 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007720
Gareth Williamsd5618a82015-05-20 11:13:32 +01007721 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7722 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007723 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007724 if ((result = ecm_state_write(sfi, "tag", "%x", vlan_tag))) {
7725 return result;
7726 }
7727 if ((result = ecm_state_write(sfi, "tpid", "%x", vlan_tpid))) {
7728 return result;
7729 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007730
Gareth Williamsd5618a82015-05-20 11:13:32 +01007731 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007732}
Murat Sezgin37fb3952015-03-10 16:45:13 -07007733#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007734
ratheesh kannotha32fdd12015-09-09 08:02:58 +05307735#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007736/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007737 * ecm_db_iface_pppoe_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007738 * Return interface type specific state
7739 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007740static int ecm_db_iface_pppoe_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007741{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007742 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007743 uint16_t pppoe_session_id;
7744 uint8_t remote_mac[ETH_ALEN];
7745
7746 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7747 spin_lock_bh(&ecm_db_lock);
7748 pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
7749 memcpy(remote_mac, ii->type_info.pppoe.remote_mac, ETH_ALEN);
7750 spin_unlock_bh(&ecm_db_lock);
7751
Gareth Williamsd5618a82015-05-20 11:13:32 +01007752 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
7753 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007754 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007755 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7756 return result;
7757 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007758
Gareth Williamsd5618a82015-05-20 11:13:32 +01007759 if ((result = ecm_state_write(sfi, "remote_max", "%pM", remote_mac))) {
7760 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007761 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007762 if ((result = ecm_state_write(sfi, "session_id", "%u", pppoe_session_id))) {
7763 return result;
7764 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007765
Gareth Williamsd5618a82015-05-20 11:13:32 +01007766 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007767}
Murat Sezginaad635c2015-03-06 16:11:41 -08007768#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007769
ratheesh kannotha32fdd12015-09-09 08:02:58 +05307770#ifdef ECM_INTERFACE_L2TPV2_ENABLE
7771
7772/*
7773 * ecm_db_iface_pppol2tpv2_state_get()
7774 * Return interface type specific state
7775 */
7776static int ecm_db_iface_pppol2tpv2_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
7777{
7778 int result;
7779 struct ecm_db_interface_info_pppol2tpv2 type_info;
7780
7781 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7782 spin_lock_bh(&ecm_db_lock);
7783 memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
7784 spin_unlock_bh(&ecm_db_lock);
7785
7786 if ((result = ecm_state_prefix_add(sfi, "pppol2tpv2"))) {
7787 return result;
7788 }
7789
7790 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7791 return result;
7792 }
7793
7794 if ((result = ecm_state_write(sfi, "local_tunnel_id", "%u", type_info.l2tp.tunnel.tunnel_id))) {
7795 return result;
7796 }
7797
7798 if ((result = ecm_state_write(sfi, "local_session_id", "%u", type_info.l2tp.session.session_id))) {
7799 return result;
7800 }
7801
7802 if ((result = ecm_state_write(sfi, "peer_tunnnel_id", "%u", type_info.l2tp.tunnel.peer_tunnel_id))) {
7803 return result;
7804 }
7805
7806 if ((result = ecm_state_write(sfi, "peer_session_id", "%u", type_info.l2tp.session.peer_session_id))) {
7807 return result;
7808 }
7809
7810 return ecm_state_prefix_remove(sfi);
7811}
7812
7813#endif
7814
Ben Menchaca84f36632014-02-28 20:57:38 +00007815/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007816 * ecm_db_iface_unknown_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007817 * Return interface type specific state
7818 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007819static int ecm_db_iface_unknown_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007820{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007821 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007822 uint32_t os_specific_ident;
7823
7824 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7825 spin_lock_bh(&ecm_db_lock);
7826 os_specific_ident = ii->type_info.unknown.os_specific_ident;
7827 spin_unlock_bh(&ecm_db_lock);
7828
Gareth Williamsd5618a82015-05-20 11:13:32 +01007829 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
7830 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007831 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007832 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7833 return result;
7834 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007835
Gareth Williamsd5618a82015-05-20 11:13:32 +01007836 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7837 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007838 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007839
Gareth Williamsd5618a82015-05-20 11:13:32 +01007840 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007841}
7842
7843/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007844 * ecm_db_iface_loopback_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007845 * Return interface type specific state
7846 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007847static int ecm_db_iface_loopback_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007848{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007849 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007850 uint32_t os_specific_ident;
7851
7852 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7853 spin_lock_bh(&ecm_db_lock);
7854 os_specific_ident = ii->type_info.loopback.os_specific_ident;
7855 spin_unlock_bh(&ecm_db_lock);
7856
Gareth Williamsd5618a82015-05-20 11:13:32 +01007857 if ((result = ecm_state_prefix_add(sfi, "loopback"))) {
7858 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007859 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007860 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7861 return result;
7862 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007863
Gareth Williamsd5618a82015-05-20 11:13:32 +01007864 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7865 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007866 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007867
Gareth Williamsd5618a82015-05-20 11:13:32 +01007868 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007869}
7870
Murat Sezgin69a27532015-03-12 14:09:40 -07007871#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007872/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007873 * ecm_db_iface_ipsec_tunnel_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007874 * Return interface type specific state
7875 *
7876 * GGG TODO Output state on ipsec tunnel specific data
7877 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007878static int ecm_db_iface_ipsec_tunnel_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Ben Menchaca84f36632014-02-28 20:57:38 +00007879{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007880 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007881 uint32_t os_specific_ident;
7882
7883 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7884 spin_lock_bh(&ecm_db_lock);
7885 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7886 spin_unlock_bh(&ecm_db_lock);
7887
Gareth Williamsd5618a82015-05-20 11:13:32 +01007888 if ((result = ecm_state_prefix_add(sfi, "ipsec"))) {
7889 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007890 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007891 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7892 return result;
7893 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007894
Gareth Williamsd5618a82015-05-20 11:13:32 +01007895 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7896 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007897 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007898
Gareth Williamsd5618a82015-05-20 11:13:32 +01007899 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007900}
Murat Sezgin69a27532015-03-12 14:09:40 -07007901#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007902
Gareth Williamsf98d4192015-03-11 16:55:41 +00007903#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00007904#ifdef ECM_IPV6_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00007905/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007906 * ecm_db_iface_tunipip6_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00007907 * Return interface type specific state
7908 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007909static int ecm_db_iface_tunipip6_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00007910{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007911 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007912 uint32_t os_specific_ident;
7913
7914 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7915 spin_lock_bh(&ecm_db_lock);
7916 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7917 spin_unlock_bh(&ecm_db_lock);
7918
Gareth Williamsd5618a82015-05-20 11:13:32 +01007919 if ((result = ecm_state_prefix_add(sfi, "tunipip6"))) {
7920 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007921 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007922 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7923 return result;
7924 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007925
Gareth Williamsd5618a82015-05-20 11:13:32 +01007926 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7927 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007928 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007929
Gareth Williamsd5618a82015-05-20 11:13:32 +01007930 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00007931}
7932#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00007933#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00007934
7935#ifdef ECM_INTERFACE_SIT_ENABLE
7936/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007937 * ecm_db_iface_sit_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00007938 * Return interface type specific state
7939 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007940static int ecm_db_iface_sit_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00007941{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007942 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007943 uint32_t os_specific_ident;
7944
7945 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7946 spin_lock_bh(&ecm_db_lock);
7947 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7948 spin_unlock_bh(&ecm_db_lock);
7949
Gareth Williamsd5618a82015-05-20 11:13:32 +01007950 if ((result = ecm_state_prefix_add(sfi, "sit"))) {
7951 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007952 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007953 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7954 return result;
7955 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007956
Gareth Williamsd5618a82015-05-20 11:13:32 +01007957 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7958 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007959 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007960
Gareth Williamsd5618a82015-05-20 11:13:32 +01007961 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00007962}
7963#endif
7964
7965/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007966 * ecm_db_iface_state_get()
7967 * Obtain state for the interface.
Gareth Williamsf98d4192015-03-11 16:55:41 +00007968 *
7969 * State specific to the interface type will be returned.
7970 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007971int ecm_db_iface_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_iface_instance *ii)
Gareth Williamsf98d4192015-03-11 16:55:41 +00007972{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007973 int result;
7974
Gareth Williamsf98d4192015-03-11 16:55:41 +00007975 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsd5618a82015-05-20 11:13:32 +01007976
7977 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
7978 return result;
7979 }
7980
7981 if ((result = ii->state_get(ii, sfi))) {
7982 return result;
7983 }
7984
7985 return ecm_state_prefix_remove(sfi);
7986
Gareth Williamsf98d4192015-03-11 16:55:41 +00007987}
Gareth Williamsd5618a82015-05-20 11:13:32 +01007988EXPORT_SYMBOL(ecm_db_iface_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00007989
7990/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007991 * ecm_db_connection_heirarchy_state_get()
7992 * Output state for an interface heirarchy list.
Gareth Williamsf98d4192015-03-11 16:55:41 +00007993 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007994static int ecm_db_connection_heirarchy_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_iface_instance *interfaces[], int32_t first_interface)
Gareth Williamsf98d4192015-03-11 16:55:41 +00007995{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007996 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007997 int count;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007998 int i;
Gareth Williamsd5618a82015-05-20 11:13:32 +01007999 int j;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008000
Gareth Williamsd5618a82015-05-20 11:13:32 +01008001 count = ECM_DB_IFACE_HEIRARCHY_MAX - first_interface;
8002 if ((result = ecm_state_write(sfi, "interface_count", "%d", count))) {
8003 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008004 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008005
8006 /*
8007 * Iterate the interface heirarchy list and output the information
8008 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008009 for (i = first_interface, j = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i, ++j) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008010 struct ecm_db_iface_instance *ii = interfaces[i];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008011 DEBUG_TRACE("Output interface @ %d: %p\n", i, ii);
8012
8013 if ((result = ecm_state_prefix_index_add(sfi, j))) {
8014 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008015 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008016 result = ii->state_get(ii, sfi);
8017 if (result) {
8018 return result;
8019 }
8020 if ((result = ecm_state_prefix_remove(sfi))) {
8021 return result;
8022 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008023 }
8024
Gareth Williamsd5618a82015-05-20 11:13:32 +01008025 return 0;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008026}
8027
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308028#ifdef ECM_MULTICAST_ENABLE
8029/*
8030 * ecm_db_multicast_to_interfaces_xml_state_get()
8031 * Obtain XML state for the multicast destination interfaces list
8032 */
8033static int ecm_db_multicast_to_interfaces_xml_state_get(struct ecm_db_connection_instance *ci, struct ecm_state_file_instance *sfi)
8034{
8035 struct ecm_db_iface_instance *mc_ifaces;
8036 struct ecm_db_iface_instance *mc_ifaces_single[ECM_DB_IFACE_HEIRARCHY_MAX];
8037 struct ecm_db_iface_instance *ii_temp;
8038 int32_t *mc_ifaces_first;
8039 int32_t *ifaces_first;
8040 int32_t heirarchy_index;
8041 int ret;
8042
8043 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &mc_ifaces, &mc_ifaces_first);
8044 if (ret == 0) {
Shyam Sunder3af86a52015-08-28 18:04:10 +05308045 return ret;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308046 }
8047
8048 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
8049
8050 ii_temp = ecm_db_multicast_if_heirarchy_get(mc_ifaces, heirarchy_index);
8051 ecm_db_multicast_copy_if_heirarchy(mc_ifaces_single, ii_temp);
8052 ifaces_first = ecm_db_multicast_if_first_get_at_index(mc_ifaces_first, heirarchy_index);
8053
8054 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
8055 ret = ecm_db_connection_heirarchy_state_get(sfi, mc_ifaces_single, *ifaces_first);
8056 if (ret) {
8057 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8058 return ret;
8059 }
8060
8061 }
8062 }
8063 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8064
8065 return ret;
8066}
8067#endif
8068
Gareth Williamsf98d4192015-03-11 16:55:41 +00008069/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008070 * ecm_db_connection_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008071 * Prepare a connection message
8072 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008073int ecm_db_connection_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_connection_instance *ci)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008074{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008075 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008076 long int expires_in;
8077 int sport;
8078 int sport_nat;
8079 char snode_address[25];
8080 char snode_address_nat[25];
8081 char sip_address[50];
8082 char sip_address_nat[50];
8083 char dnode_address[25];
8084 char dnode_address_nat[25];
8085 int dport;
8086 int dport_nat;
8087 char dip_address[50];
8088 char dip_address_nat[50];
8089 ecm_db_direction_t direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008090 int ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008091 int protocol;
8092 bool is_routed;
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308093 uint32_t regen_success;
8094 uint32_t regen_fail;
8095 uint16_t regen_required;
8096 uint16_t regen_occurances;
8097 bool regen_in_progress;
8098 uint16_t generation;
8099 uint16_t global_generation;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008100 uint32_t time_added;
8101 uint32_t serial;
8102 uint64_t from_data_total;
8103 uint64_t to_data_total;
8104 uint64_t from_packet_total;
8105 uint64_t to_packet_total;
8106 uint64_t from_data_total_dropped;
8107 uint64_t to_data_total_dropped;
8108 uint64_t from_packet_total_dropped;
8109 uint64_t to_packet_total_dropped;
8110 struct ecm_db_host_instance *hi;
8111 struct ecm_db_node_instance *ni;
8112 int aci_index;
8113 int aci_count;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308114 ip_addr_t __attribute__((unused)) group_ip;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008115 struct ecm_front_end_connection_instance *feci;
8116 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
8117 int32_t first_interface;
8118 struct ecm_db_iface_instance *interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
8119
8120 DEBUG_TRACE("Prep conn msg for %p\n", ci);
8121
8122 /*
8123 * Identify expiration
8124 */
8125 spin_lock_bh(&ecm_db_lock);
8126 if (ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX) {
8127 expires_in = -1;
8128 } else {
8129 expires_in = (long int)(ci->defunct_timer.timeout - ecm_db_time);
8130 if (expires_in <= 0) {
8131 expires_in = 0;
8132 }
8133 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308134
8135 regen_success = ci->regen_success;
8136 regen_fail = ci->regen_fail;
8137 regen_required = ci->regen_required;
8138 regen_occurances = ci->regen_occurances;
8139 regen_in_progress = ci->regen_in_progress;
8140 generation = ci->generation;
8141 global_generation = ecm_db_connection_generation;
8142
Gareth Williamsf98d4192015-03-11 16:55:41 +00008143 spin_unlock_bh(&ecm_db_lock);
8144
8145 /*
8146 * Extract information from the connection for inclusion into the message
8147 */
8148 sport = ci->mapping_from->port;
8149 sport_nat = ci->mapping_nat_from->port;
8150 dport = ci->mapping_to->port;
8151 dport_nat = ci->mapping_nat_to->port;
8152
8153 hi = ci->mapping_to->host;
8154 ecm_ip_addr_to_string(dip_address, hi->address);
8155 ni = ci->to_node;
8156 sprintf(dnode_address, "%pM", ni->address);
8157 hi = ci->mapping_nat_to->host;
8158 ecm_ip_addr_to_string(dip_address_nat, hi->address);
8159
8160 hi = ci->mapping_from->host;
8161 ecm_ip_addr_to_string(sip_address, hi->address);
8162 ni = ci->from_node;
8163 sprintf(snode_address, "%pM", ni->address);
8164 hi = ci->mapping_nat_from->host;
8165 ecm_ip_addr_to_string(sip_address_nat, hi->address);
8166
8167 ni = ci->to_nat_node;
8168 sprintf(dnode_address_nat, "%pM", ni->address);
8169
8170 ni = ci->from_nat_node;
8171 sprintf(snode_address_nat, "%pM", ni->address);
8172
8173 direction = ci->direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008174 ip_version = ci->ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008175 protocol = ci->protocol;
8176 is_routed = ci->is_routed;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008177 time_added = ci->time_added;
8178 serial = ci->serial;
8179 ecm_db_connection_data_stats_get(ci, &from_data_total, &to_data_total,
8180 &from_packet_total, &to_packet_total,
8181 &from_data_total_dropped, &to_data_total_dropped,
8182 &from_packet_total_dropped, &to_packet_total_dropped);
8183
Gareth Williamsd5618a82015-05-20 11:13:32 +01008184 if ((result = ecm_state_prefix_add(sfi, "conn"))) {
8185 return result;
8186 }
8187 if ((result = ecm_state_prefix_index_add(sfi, serial))) {
8188 return result;
8189 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008190
Gareth Williamsd5618a82015-05-20 11:13:32 +01008191 if ((result = ecm_state_write(sfi, "serial", "%u", serial))) {
8192 return result;
8193 }
8194
8195 if ((result = ecm_state_write(sfi, "sip_address", "%s", sip_address))) {
8196 return result;
8197 }
8198
8199 if ((result = ecm_state_write(sfi, "sip_address_nat", "%s", sip_address_nat))) {
8200 return result;
8201 }
8202
8203 if ((result = ecm_state_write(sfi, "sport", "%d", sport))) {
8204 return result;
8205 }
8206
8207 if ((result = ecm_state_write(sfi, "sport_nat", "%d", sport_nat))) {
8208 return result;
8209 }
8210
8211 if ((result = ecm_state_write(sfi, "snode_address", "%s", snode_address))) {
8212 return result;
8213 }
8214
8215 if ((result = ecm_state_write(sfi, "snode_address_nat", "%s", snode_address_nat))) {
8216 return result;
8217 }
8218
8219 if ((result = ecm_state_write(sfi, "dip_address", "%s", dip_address))) {
8220 return result;
8221 }
8222
8223 if ((result = ecm_state_write(sfi, "dip_address_nat", "%s", dip_address_nat))) {
8224 return result;
8225 }
8226
8227 if ((result = ecm_state_write(sfi, "dport", "%d", dport))) {
8228 return result;
8229 }
8230
8231 if ((result = ecm_state_write(sfi, "dport_nat", "%d", dport_nat))) {
8232 return result;
8233 }
8234
8235 if ((result = ecm_state_write(sfi, "dnode_address", "%s", dnode_address))) {
8236 return result;
8237 }
8238
8239 if ((result = ecm_state_write(sfi, "dnode_address_nat", "%s", dnode_address_nat))) {
8240 return result;
8241 }
8242
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008243 if ((result = ecm_state_write(sfi, "ip_version", "%d", ip_version))) {
8244 return result;
8245 }
8246
Gareth Williamsd5618a82015-05-20 11:13:32 +01008247 if ((result = ecm_state_write(sfi, "protocol", "%d", protocol))) {
8248 return result;
8249 }
8250
8251 if ((result = ecm_state_write(sfi, "is_routed", "%d", is_routed))) {
8252 return result;
8253 }
8254
8255 if ((result = ecm_state_write(sfi, "expires", "%ld", expires_in))) {
8256 return result;
8257 }
8258
8259 if ((result = ecm_state_write(sfi, "direction", "%d", direction))) {
8260 return result;
8261 }
8262
8263 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8264 return result;
8265 }
8266
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308267 if ((result = ecm_state_write(sfi, "regen_success", "%u", regen_success))) {
8268 return result;
8269 }
8270 if ((result = ecm_state_write(sfi, "regen_fail", "%u", regen_fail))) {
8271 return result;
8272 }
8273 if ((result = ecm_state_write(sfi, "regen_required", "%u", regen_required))) {
8274 return result;
8275 }
8276 if ((result = ecm_state_write(sfi, "regen_occurances", "%u", regen_occurances))) {
8277 return result;
8278 }
8279 if ((result = ecm_state_write(sfi, "regen_in_progress", "%u", regen_in_progress))) {
8280 return result;
8281 }
8282 if ((result = ecm_state_write(sfi, "generation", "%u/%u", generation, global_generation))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01008283 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008284 }
8285
8286 /*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008287 * NOTE: These advanced stats are not conditional compiled.
8288 * Connections always contain these stats
Gareth Williamsf98d4192015-03-11 16:55:41 +00008289 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008290 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8291 from_packet_total, to_packet_total, from_data_total_dropped,
8292 to_data_total_dropped, from_packet_total_dropped,
8293 to_packet_total_dropped))) {
8294 return result;
8295 }
8296
8297 if ((result = ecm_state_prefix_add(sfi, "from_interfaces"))) {
8298 return result;
8299 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008300 first_interface = ecm_db_connection_from_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008301 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008302 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008303 if (result) {
8304 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008305 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008306 if ((result = ecm_state_prefix_remove(sfi))) {
8307 return result;
8308 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008309
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308310#ifdef ECM_MULTICAST_ENABLE
8311 ecm_db_connection_to_address_get(ci, group_ip);
8312 if (ecm_ip_addr_is_multicast(group_ip)) {
8313 if ((result = ecm_state_prefix_add(sfi, "to_mc_interfaces"))) {
8314 return result;
8315 }
8316
8317 if ((result = ecm_db_multicast_to_interfaces_xml_state_get(ci, sfi))) {
8318 return result;
8319 }
8320
8321 if ((result = ecm_state_prefix_remove(sfi))) {
8322 return result;
8323 }
8324 }
8325 else {
8326 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8327 return result;
8328 }
8329
8330 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
8331 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8332 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8333 if (result) {
8334 return result;
8335 }
8336
8337 if ((result = ecm_state_prefix_remove(sfi))) {
8338 return result;
8339 }
8340 }
8341#else
Gareth Williamsd5618a82015-05-20 11:13:32 +01008342 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8343 return result;
8344 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008345 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008346 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008347 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008348 if (result) {
8349 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008350 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008351 if ((result = ecm_state_prefix_remove(sfi))) {
8352 return result;
8353 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308354#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008355
Gareth Williamsd5618a82015-05-20 11:13:32 +01008356 if ((result = ecm_state_prefix_add(sfi, "from_nat_interfaces"))) {
8357 return result;
8358 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008359 first_interface = ecm_db_connection_from_nat_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008360 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008361 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008362 if (result) {
8363 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008364 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008365 if ((result = ecm_state_prefix_remove(sfi))) {
8366 return result;
8367 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008368
Gareth Williamsd5618a82015-05-20 11:13:32 +01008369 if ((result = ecm_state_prefix_add(sfi, "to_nat_interfaces"))) {
8370 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008371 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008372 first_interface = ecm_db_connection_to_nat_interfaces_get_and_ref(ci, interfaces);
8373 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8374 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8375 if (result) {
8376 return result;
8377 }
8378 if ((result = ecm_state_prefix_remove(sfi))) {
8379 return result;
8380 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008381
8382 /*
8383 * Output front end state
8384 */
8385 feci = ecm_db_connection_front_end_get_and_ref(ci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008386 result = feci->state_get(feci, sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008387 feci->deref(feci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008388 if (result) {
8389 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008390 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008391
8392 if ((result = ecm_state_prefix_add(sfi, "classifiers"))) {
8393 return result;
8394 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008395
8396 /*
8397 * Grab references to the assigned classifiers so we can produce state for them
8398 */
8399 aci_count = ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
8400
8401 /*
8402 * Iterate the assigned classifiers and provide a state record for each
8403 */
8404 for (aci_index = 0; aci_index < aci_count; ++aci_index) {
8405 struct ecm_classifier_instance *aci;
8406
8407 aci = assignments[aci_index];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008408 result = aci->state_get(aci, sfi);
8409 if (result) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008410 ecm_db_connection_assignments_release(aci_count, assignments);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008411 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008412 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008413 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008414
Gareth Williamsf98d4192015-03-11 16:55:41 +00008415 ecm_db_connection_assignments_release(aci_count, assignments);
8416
Gareth Williamsd5618a82015-05-20 11:13:32 +01008417 if ((result = ecm_state_prefix_remove(sfi))) {
8418 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008419 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008420
8421 if ((result = ecm_state_prefix_remove(sfi))) {
8422 return result;
8423 }
8424
8425 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008426}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008427EXPORT_SYMBOL(ecm_db_connection_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008428
8429/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008430 * ecm_db_mapping_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008431 * Prepare a mapping message
8432 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008433int ecm_db_mapping_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_mapping_instance *mi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008434{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008435 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008436 int port;
8437 char address[25];
8438 int tcp_from;
8439 int tcp_to;
8440 int udp_from;
8441 int udp_to;
8442 int from;
8443 int to;
8444 int tcp_nat_from;
8445 int tcp_nat_to;
8446 int udp_nat_from;
8447 int udp_nat_to;
8448 int nat_from;
8449 int nat_to;
8450 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008451 struct ecm_db_host_instance *hi;
8452#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008453 uint64_t from_data_total;
8454 uint64_t to_data_total;
8455 uint64_t from_packet_total;
8456 uint64_t to_packet_total;
8457 uint64_t from_data_total_dropped;
8458 uint64_t to_data_total_dropped;
8459 uint64_t from_packet_total_dropped;
8460 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008461#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008462
8463 DEBUG_TRACE("Prep mapping msg for %p\n", mi);
8464
8465 /*
8466 * Create a small xml stats element for our mapping.
8467 * Extract information from the mapping for inclusion into the message
8468 */
8469 ecm_db_mapping_port_count_get(mi, &tcp_from, &tcp_to, &udp_from, &udp_to, &from, &to,
8470 &tcp_nat_from, &tcp_nat_to, &udp_nat_from, &udp_nat_to, &nat_from, &nat_to);
8471 port = mi->port;
8472 time_added = mi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008473 hi = mi->host;
8474 ecm_ip_addr_to_string(address, hi->address);
8475
8476#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008477 ecm_db_mapping_data_stats_get(mi, &from_data_total, &to_data_total,
8478 &from_packet_total, &to_packet_total,
8479 &from_data_total_dropped, &to_data_total_dropped,
8480 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008481#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008482
Gareth Williamsd5618a82015-05-20 11:13:32 +01008483 if ((result = ecm_state_prefix_add(sfi, "mapping"))) {
8484 return result;
8485 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008486
Gareth Williamsd5618a82015-05-20 11:13:32 +01008487 if ((result = ecm_state_write(sfi, "port", "%d", port))) {
8488 return result;
8489 }
8490
8491 if ((result = ecm_state_write(sfi, "from", "%d", from))) {
8492 return result;
8493 }
8494
8495 if ((result = ecm_state_write(sfi, "to", "%d", to))) {
8496 return result;
8497 }
8498
8499 if ((result = ecm_state_write(sfi, "tcp_from", "%d", tcp_from))) {
8500 return result;
8501 }
8502
8503 if ((result = ecm_state_write(sfi, "tcp_to", "%d", tcp_to))) {
8504 return result;
8505 }
8506
8507 if ((result = ecm_state_write(sfi, "udp_from", "%d", udp_from))) {
8508 return result;
8509 }
8510
8511 if ((result = ecm_state_write(sfi, "udp_to", "%d", udp_to))) {
8512 return result;
8513 }
8514
8515 if ((result = ecm_state_write(sfi, "nat_from", "%d", nat_from))) {
8516 return result;
8517 }
8518
8519 if ((result = ecm_state_write(sfi, "nat_to", "%d", nat_to))) {
8520 return result;
8521 }
8522
8523 if ((result = ecm_state_write(sfi, "tcp_nat_from", "%d", tcp_nat_from))) {
8524 return result;
8525 }
8526
8527 if ((result = ecm_state_write(sfi, "tcp_nat_to", "%d", tcp_nat_to))) {
8528 return result;
8529 }
8530
8531 if ((result = ecm_state_write(sfi, "udp_nat_from", "%d", udp_nat_from))) {
8532 return result;
8533 }
8534
8535 if ((result = ecm_state_write(sfi, "udp_nat_to", "%d", udp_nat_to))) {
8536 return result;
8537 }
8538
8539 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8540 return result;
8541 }
8542
8543 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8544 return result;
8545 }
8546
8547#ifdef ECM_DB_ADVANCED_STATS_ENABLE
8548 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8549 from_packet_total, to_packet_total, from_data_total_dropped,
8550 to_data_total_dropped, from_packet_total_dropped,
8551 to_packet_total_dropped))) {
8552 return result;
8553 }
8554#endif
8555
8556 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008557}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008558EXPORT_SYMBOL(ecm_db_mapping_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008559
8560/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008561 * ecm_db_host_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008562 * Prepare a host message
8563 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008564int ecm_db_host_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_host_instance *hi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008565{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008566 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008567 char address[50];
Gareth Williamsb5903892015-03-20 15:13:07 +00008568#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008569 int mapping_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00008570#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008571 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008572 bool on_link;
8573#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008574 uint64_t from_data_total;
8575 uint64_t to_data_total;
8576 uint64_t from_packet_total;
8577 uint64_t to_packet_total;
8578 uint64_t from_data_total_dropped;
8579 uint64_t to_data_total_dropped;
8580 uint64_t from_packet_total_dropped;
8581 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008582#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008583
8584 DEBUG_TRACE("Prep host msg for %p\n", hi);
8585
8586 /*
8587 * Create a small xml stats element for our host.
8588 * Extract information from the host for inclusion into the message
8589 */
Gareth Williamsb5903892015-03-20 15:13:07 +00008590#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008591 mapping_count = ecm_db_host_mapping_count_get(hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00008592#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008593 ecm_ip_addr_to_string(address, hi->address);
8594 time_added = hi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008595 on_link = hi->on_link;
8596
8597#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008598 ecm_db_host_data_stats_get(hi, &from_data_total, &to_data_total,
8599 &from_packet_total, &to_packet_total,
8600 &from_data_total_dropped, &to_data_total_dropped,
8601 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008602#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008603
Gareth Williamsd5618a82015-05-20 11:13:32 +01008604 if ((result = ecm_state_prefix_add(sfi, "host"))) {
8605 return result;
8606 }
8607
8608 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8609 return result;
8610 }
8611 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8612 return result;
8613 }
8614 if ((result = ecm_state_write(sfi, "on_link", "%d", on_link))) {
8615 return result;
8616 }
8617
Gareth Williamsb5903892015-03-20 15:13:07 +00008618#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008619 if ((result = ecm_state_write(sfi, "mappings", "%d", mapping_count))) {
8620 return result;
8621 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008622#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008623
Gareth Williams85331c92015-03-11 20:39:18 +00008624#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008625 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8626 from_packet_total, to_packet_total, from_data_total_dropped,
8627 to_data_total_dropped, from_packet_total_dropped,
8628 to_packet_total_dropped))) {
8629 return result;
8630 }
Gareth Williams85331c92015-03-11 20:39:18 +00008631#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008632
8633 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008634}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008635EXPORT_SYMBOL(ecm_db_host_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008636
8637/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008638 * ecm_db_node_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008639 * Prepare a node message
8640 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008641int ecm_db_node_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_node_instance *ni)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008642{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008643 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008644 char address[25];
Gareth Williamsb5903892015-03-20 15:13:07 +00008645#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008646 int from_connections_count;
8647 int to_connections_count;
8648 int from_nat_connections_count;
8649 int to_nat_connections_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00008650#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008651 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008652#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008653 uint64_t from_data_total;
8654 uint64_t to_data_total;
8655 uint64_t from_packet_total;
8656 uint64_t to_packet_total;
8657 uint64_t from_data_total_dropped;
8658 uint64_t to_data_total_dropped;
8659 uint64_t from_packet_total_dropped;
8660 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008661#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008662
8663 DEBUG_TRACE("Prep node msg for %p\n", ni);
8664
8665 /*
8666 * Create a small xml stats block for our managed node, like:
8667 * <node address="" hosts="" time_added="" from_data_total="" to_data_total="" />
8668 *
8669 * Extract information from the node for inclusion into the message
8670 */
Gareth Williamsb5903892015-03-20 15:13:07 +00008671#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008672 spin_lock_bh(&ecm_db_lock);
8673 from_connections_count = ni->from_connections_count;
8674 to_connections_count = ni->to_connections_count;
8675 from_nat_connections_count = ni->from_nat_connections_count;
8676 to_nat_connections_count = ni->to_nat_connections_count;
8677 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsb5903892015-03-20 15:13:07 +00008678#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008679 time_added = ni->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008680 sprintf(address, "%pM", ni->address);
8681
8682#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008683 ecm_db_node_data_stats_get(ni, &from_data_total, &to_data_total,
8684 &from_packet_total, &to_packet_total,
8685 &from_data_total_dropped, &to_data_total_dropped,
8686 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008687
8688#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008689
Gareth Williamsd5618a82015-05-20 11:13:32 +01008690 if ((result = ecm_state_prefix_add(sfi, "node"))) {
8691 return result;
8692 }
8693 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8694 return result;
8695 }
8696 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8697 return result;
8698 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008699#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008700 if ((result = ecm_state_write(sfi, "from_connections_count", "%d", from_connections_count))) {
8701 return result;
8702 }
8703 if ((result = ecm_state_write(sfi, "to_connections_count", "%d", to_connections_count))) {
8704 return result;
8705 }
8706 if ((result = ecm_state_write(sfi, "from_nat_connections_count", "%d", from_nat_connections_count))) {
8707 return result;
8708 }
8709 if ((result = ecm_state_write(sfi, "to_nat_connections_count", "%d", to_nat_connections_count))) {
8710 return result;
8711 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008712#endif
Gareth Williams85331c92015-03-11 20:39:18 +00008713#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008714 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8715 from_packet_total, to_packet_total, from_data_total_dropped,
8716 to_data_total_dropped, from_packet_total_dropped,
8717 to_packet_total_dropped))) {
8718 return result;
8719 }
Gareth Williams85331c92015-03-11 20:39:18 +00008720#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008721 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008722}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008723EXPORT_SYMBOL(ecm_db_node_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008724
8725/*
8726 * ecm_db_connection_hash_table_lengths_get()
8727 * Return hash table length
8728 */
8729int ecm_db_connection_hash_table_lengths_get(int index)
8730{
8731 int length;
8732
8733 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
8734 spin_lock_bh(&ecm_db_lock);
8735 length = ecm_db_connection_table_lengths[index];
8736 spin_unlock_bh(&ecm_db_lock);
8737 return length;
8738}
8739EXPORT_SYMBOL(ecm_db_connection_hash_table_lengths_get);
8740
8741/*
8742 * ecm_db_connection_hash_index_get_next()
8743 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8744 */
8745int ecm_db_connection_hash_index_get_next(int index)
8746{
8747 index++;
8748 if (index >= ECM_DB_CONNECTION_SERIAL_HASH_SLOTS) {
8749 return -1;
8750 }
8751 return index;
8752}
8753EXPORT_SYMBOL(ecm_db_connection_hash_index_get_next);
8754
8755/*
8756 * ecm_db_connection_hash_index_get_first()
8757 * Return first hash index
8758 */
8759int ecm_db_connection_hash_index_get_first(void)
8760{
8761 return 0;
8762}
8763EXPORT_SYMBOL(ecm_db_connection_hash_index_get_first);
8764
8765/*
8766 * ecm_db_mapping_hash_table_lengths_get()
8767 * Return hash table length
8768 */
8769int ecm_db_mapping_hash_table_lengths_get(int index)
8770{
8771 int length;
8772
8773 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
8774 spin_lock_bh(&ecm_db_lock);
8775 length = ecm_db_mapping_table_lengths[index];
8776 spin_unlock_bh(&ecm_db_lock);
8777 return length;
8778}
8779EXPORT_SYMBOL(ecm_db_mapping_hash_table_lengths_get);
8780
8781/*
8782 * ecm_db_mapping_hash_index_get_next()
8783 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8784 */
8785int ecm_db_mapping_hash_index_get_next(int index)
8786{
8787 index++;
8788 if (index >= ECM_DB_MAPPING_HASH_SLOTS) {
8789 return -1;
8790 }
8791 return index;
8792}
8793EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_next);
8794
8795/*
8796 * ecm_db_mapping_hash_index_get_first()
8797 * Return first hash index
8798 */
8799int ecm_db_mapping_hash_index_get_first(void)
8800{
8801 return 0;
8802}
8803EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_first);
8804
8805/*
8806 * ecm_db_host_hash_table_lengths_get()
8807 * Return hash table length
8808 */
8809int ecm_db_host_hash_table_lengths_get(int index)
8810{
8811 int length;
8812
8813 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_HOST_HASH_SLOTS), "Bad protocol: %d\n", index);
8814 spin_lock_bh(&ecm_db_lock);
8815 length = ecm_db_host_table_lengths[index];
8816 spin_unlock_bh(&ecm_db_lock);
8817 return length;
8818}
8819EXPORT_SYMBOL(ecm_db_host_hash_table_lengths_get);
8820
8821/*
8822 * ecm_db_host_hash_index_get_next()
8823 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8824 */
8825int ecm_db_host_hash_index_get_next(int index)
8826{
8827 index++;
8828 if (index >= ECM_DB_HOST_HASH_SLOTS) {
8829 return -1;
8830 }
8831 return index;
8832}
8833EXPORT_SYMBOL(ecm_db_host_hash_index_get_next);
8834
8835/*
8836 * ecm_db_host_hash_index_get_first()
8837 * Return first hash index
8838 */
8839int ecm_db_host_hash_index_get_first(void)
8840{
8841 return 0;
8842}
8843EXPORT_SYMBOL(ecm_db_host_hash_index_get_first);
8844
8845/*
8846 * ecm_db_node_hash_table_lengths_get()
8847 * Return hash table length
8848 */
8849int ecm_db_node_hash_table_lengths_get(int index)
8850{
8851 int length;
8852
8853 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_NODE_HASH_SLOTS), "Bad protocol: %d\n", index);
8854 spin_lock_bh(&ecm_db_lock);
8855 length = ecm_db_node_table_lengths[index];
8856 spin_unlock_bh(&ecm_db_lock);
8857 return length;
8858}
8859EXPORT_SYMBOL(ecm_db_node_hash_table_lengths_get);
8860
8861/*
8862 * ecm_db_node_hash_index_get_next()
8863 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8864 */
8865int ecm_db_node_hash_index_get_next(int index)
8866{
8867 index++;
8868 if (index >= ECM_DB_NODE_HASH_SLOTS) {
8869 return -1;
8870 }
8871 return index;
8872}
8873EXPORT_SYMBOL(ecm_db_node_hash_index_get_next);
8874
8875/*
8876 * ecm_db_node_hash_index_get_first()
8877 * Return first hash index
8878 */
8879int ecm_db_node_hash_index_get_first(void)
8880{
8881 return 0;
8882}
8883EXPORT_SYMBOL(ecm_db_node_hash_index_get_first);
8884
8885/*
8886 * ecm_db_iface_hash_table_lengths_get()
8887 * Return hash table length
8888 */
8889int ecm_db_iface_hash_table_lengths_get(int index)
8890{
8891 int length;
8892
8893 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_IFACE_HASH_SLOTS), "Bad protocol: %d\n", index);
8894 spin_lock_bh(&ecm_db_lock);
8895 length = ecm_db_iface_table_lengths[index];
8896 spin_unlock_bh(&ecm_db_lock);
8897 return length;
8898}
8899EXPORT_SYMBOL(ecm_db_iface_hash_table_lengths_get);
8900
8901/*
8902 * ecm_db_iface_hash_index_get_next()
8903 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8904 */
8905int ecm_db_iface_hash_index_get_next(int index)
8906{
8907 index++;
8908 if (index >= ECM_DB_IFACE_HASH_SLOTS) {
8909 return -1;
8910 }
8911 return index;
8912}
8913EXPORT_SYMBOL(ecm_db_iface_hash_index_get_next);
8914
8915/*
8916 * ecm_db_iface_hash_index_get_first()
8917 * Return first hash index
8918 */
8919int ecm_db_iface_hash_index_get_first(void)
8920{
8921 return 0;
8922}
8923EXPORT_SYMBOL(ecm_db_iface_hash_index_get_first);
8924
8925/*
8926 * ecm_db_protocol_get_next()
8927 * Given a number, return the next one OR return -1 for no more protocol numbers to return.
8928 */
8929int ecm_db_protocol_get_next(int protocol)
8930{
8931 protocol++;
8932 if (protocol >= ECM_DB_PROTOCOL_COUNT) {
8933 return -1;
8934 }
8935 return protocol;
8936}
8937EXPORT_SYMBOL(ecm_db_protocol_get_next);
8938
8939/*
8940 * ecm_db_protocol_get_first()
8941 * Return first protocol number
8942 */
8943int ecm_db_protocol_get_first(void)
8944{
8945 return 0;
8946}
8947EXPORT_SYMBOL(ecm_db_protocol_get_first);
8948#endif
8949
8950/*
8951 * ecm_db_iface_add_ethernet()
8952 * Add a iface instance into the database
8953 */
8954void ecm_db_iface_add_ethernet(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07008955 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00008956 ecm_db_iface_final_callback_t final, void *arg)
8957{
8958 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07008959 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008960 struct ecm_db_listener_instance *li;
8961 struct ecm_db_interface_info_ethernet *type_info;
8962
8963 spin_lock_bh(&ecm_db_lock);
8964 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8965 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00008966#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008967 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00008968#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008969 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
8970 DEBUG_ASSERT(name, "%p: no name given\n", ii);
8971 spin_unlock_bh(&ecm_db_lock);
8972
8973 /*
8974 * Record general info
8975 */
8976 ii->type = ECM_DB_IFACE_TYPE_ETHERNET;
8977#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008978 ii->state_get = ecm_db_iface_ethernet_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008979#endif
8980 ii->arg = arg;
8981 ii->final = final;
8982 strcpy(ii->name, name);
8983 ii->mtu = mtu;
8984 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07008985 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008986
8987 /*
8988 * Type specific info
8989 */
8990 type_info = &ii->type_info.ethernet;
8991 memcpy(type_info->address, address, ETH_ALEN);
8992
8993 /*
8994 * Compute hash chain for insertion
8995 */
8996 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
8997 ii->hash_index = hash_index;
8998
Murat Sezgin91c5d712015-06-12 15:16:22 -07008999 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9000 ii->iface_id_hash_index = iface_id_hash_index;
9001
Gareth Williamsf98d4192015-03-11 16:55:41 +00009002 /*
9003 * Add into the global list
9004 */
9005 spin_lock_bh(&ecm_db_lock);
9006 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9007 ii->prev = NULL;
9008 ii->next = ecm_db_interfaces;
9009 if (ecm_db_interfaces) {
9010 ecm_db_interfaces->prev = ii;
9011 }
9012 ecm_db_interfaces = ii;
9013
9014 /*
9015 * Insert into chain
9016 */
9017 ii->hash_next = ecm_db_iface_table[hash_index];
9018 if (ecm_db_iface_table[hash_index]) {
9019 ecm_db_iface_table[hash_index]->hash_prev = ii;
9020 }
9021 ecm_db_iface_table[hash_index] = ii;
9022 ecm_db_iface_table_lengths[hash_index]++;
9023 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9024
9025 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9026
9027 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009028 * Insert into interface identifier chain
9029 */
9030 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9031 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9032 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9033 }
9034 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9035 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9036 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9037
9038 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009039 * Set time of addition
9040 */
9041 ii->time_added = ecm_db_time;
9042 spin_unlock_bh(&ecm_db_lock);
9043
9044 /*
9045 * Throw add event to the listeners
9046 */
9047 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9048 li = ecm_db_listeners_get_and_ref_first();
9049 while (li) {
9050 struct ecm_db_listener_instance *lin;
9051 if (li->iface_added) {
9052 li->iface_added(li->arg, ii);
9053 }
9054
9055 /*
9056 * Get next listener
9057 */
9058 lin = ecm_db_listener_get_and_ref_next(li);
9059 ecm_db_listener_deref(li);
9060 li = lin;
9061 }
9062}
9063EXPORT_SYMBOL(ecm_db_iface_add_ethernet);
9064
9065#ifdef ECM_INTERFACE_BOND_ENABLE
9066/*
9067 * ecm_db_iface_add_lag()
9068 * Add a iface instance into the database
9069 */
9070void ecm_db_iface_add_lag(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009071 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009072 ecm_db_iface_final_callback_t final, void *arg)
9073{
9074 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009075 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009076 struct ecm_db_listener_instance *li;
9077 struct ecm_db_interface_info_lag *type_info;
9078
9079 spin_lock_bh(&ecm_db_lock);
9080 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9081 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009082#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009083 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009084#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009085 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9086 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9087 spin_unlock_bh(&ecm_db_lock);
9088
9089 /*
9090 * Record general info
9091 */
9092 ii->type = ECM_DB_IFACE_TYPE_LAG;
9093#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009094 ii->state_get = ecm_db_iface_lag_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009095#endif
9096 ii->arg = arg;
9097 ii->final = final;
9098 strcpy(ii->name, name);
9099 ii->mtu = mtu;
9100 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009101 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009102
9103 /*
9104 * Type specific info
9105 */
9106 type_info = &ii->type_info.lag;
9107 memcpy(type_info->address, address, ETH_ALEN);
9108
9109 /*
9110 * Compute hash chain for insertion
9111 */
9112 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9113 ii->hash_index = hash_index;
9114
Murat Sezgin91c5d712015-06-12 15:16:22 -07009115 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9116 ii->iface_id_hash_index = iface_id_hash_index;
9117
Gareth Williamsf98d4192015-03-11 16:55:41 +00009118 /*
9119 * Add into the global list
9120 */
9121 spin_lock_bh(&ecm_db_lock);
9122 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9123 ii->prev = NULL;
9124 ii->next = ecm_db_interfaces;
9125 if (ecm_db_interfaces) {
9126 ecm_db_interfaces->prev = ii;
9127 }
9128 ecm_db_interfaces = ii;
9129
9130 /*
9131 * Insert into chain
9132 */
9133 ii->hash_next = ecm_db_iface_table[hash_index];
9134 if (ecm_db_iface_table[hash_index]) {
9135 ecm_db_iface_table[hash_index]->hash_prev = ii;
9136 }
9137 ecm_db_iface_table[hash_index] = ii;
9138 ecm_db_iface_table_lengths[hash_index]++;
9139 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9140
9141 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9142
9143 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009144 * Insert into interface identifier chain
9145 */
9146 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9147 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9148 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9149 }
9150 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9151 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9152 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9153
9154 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009155 * Set time of addition
9156 */
9157 ii->time_added = ecm_db_time;
9158 spin_unlock_bh(&ecm_db_lock);
9159
9160 /*
9161 * Throw add event to the listeners
9162 */
9163 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9164 li = ecm_db_listeners_get_and_ref_first();
9165 while (li) {
9166 struct ecm_db_listener_instance *lin;
9167 if (li->iface_added) {
9168 li->iface_added(li->arg, ii);
9169 }
9170
9171 /*
9172 * Get next listener
9173 */
9174 lin = ecm_db_listener_get_and_ref_next(li);
9175 ecm_db_listener_deref(li);
9176 li = lin;
9177 }
9178}
9179EXPORT_SYMBOL(ecm_db_iface_add_lag);
9180#endif
9181
9182/*
9183 * ecm_db_iface_add_bridge()
9184 * Add a iface instance into the database
9185 */
9186void ecm_db_iface_add_bridge(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009187 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009188 ecm_db_iface_final_callback_t final, void *arg)
9189{
9190 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009191 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009192 struct ecm_db_listener_instance *li;
9193 struct ecm_db_interface_info_bridge *type_info;
9194
9195 spin_lock_bh(&ecm_db_lock);
9196 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9197 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009198#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009199 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009200#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009201 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9202 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9203 spin_unlock_bh(&ecm_db_lock);
9204
9205 /*
9206 * Record general info
9207 */
9208 ii->type = ECM_DB_IFACE_TYPE_BRIDGE;
9209#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009210 ii->state_get = ecm_db_iface_bridge_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009211#endif
9212 ii->arg = arg;
9213 ii->final = final;
9214 strcpy(ii->name, name);
9215 ii->mtu = mtu;
9216 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009217 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009218
9219 /*
9220 * Type specific info
9221 */
9222 type_info = &ii->type_info.bridge;
9223 memcpy(type_info->address, address, ETH_ALEN);
9224
9225 /*
9226 * Compute hash chain for insertion
9227 */
9228 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9229 ii->hash_index = hash_index;
9230
Murat Sezgin91c5d712015-06-12 15:16:22 -07009231 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9232 ii->iface_id_hash_index = iface_id_hash_index;
9233
Gareth Williamsf98d4192015-03-11 16:55:41 +00009234 /*
9235 * Add into the global list
9236 */
9237 spin_lock_bh(&ecm_db_lock);
9238 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9239 ii->prev = NULL;
9240 ii->next = ecm_db_interfaces;
9241 if (ecm_db_interfaces) {
9242 ecm_db_interfaces->prev = ii;
9243 }
9244 ecm_db_interfaces = ii;
9245
9246 /*
9247 * Insert into chain
9248 */
9249 ii->hash_next = ecm_db_iface_table[hash_index];
9250 if (ecm_db_iface_table[hash_index]) {
9251 ecm_db_iface_table[hash_index]->hash_prev = ii;
9252 }
9253 ecm_db_iface_table[hash_index] = ii;
9254 ecm_db_iface_table_lengths[hash_index]++;
9255 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9256
9257 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9258
9259 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009260 * Insert into interface identifier chain
9261 */
9262 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9263 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9264 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9265 }
9266 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9267 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9268 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9269
9270 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009271 * Set time of addition
9272 */
9273 ii->time_added = ecm_db_time;
9274 spin_unlock_bh(&ecm_db_lock);
9275
9276 /*
9277 * Throw add event to the listeners
9278 */
9279 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9280 li = ecm_db_listeners_get_and_ref_first();
9281 while (li) {
9282 struct ecm_db_listener_instance *lin;
9283 if (li->iface_added) {
9284 li->iface_added(li->arg, ii);
9285 }
9286
9287 /*
9288 * Get next listener
9289 */
9290 lin = ecm_db_listener_get_and_ref_next(li);
9291 ecm_db_listener_deref(li);
9292 li = lin;
9293 }
9294}
9295EXPORT_SYMBOL(ecm_db_iface_add_bridge);
9296
9297#ifdef ECM_INTERFACE_VLAN_ENABLE
9298/*
9299 * ecm_db_iface_add_vlan()
9300 * Add a iface instance into the database
9301 */
9302void ecm_db_iface_add_vlan(struct ecm_db_iface_instance *ii, uint8_t *address, uint16_t vlan_tag, uint16_t vlan_tpid, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009303 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009304 ecm_db_iface_final_callback_t final, void *arg)
9305{
9306 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009307 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009308 struct ecm_db_listener_instance *li;
9309 struct ecm_db_interface_info_vlan *type_info;
9310
9311 spin_lock_bh(&ecm_db_lock);
9312 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9313 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009314#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009315 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009316#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009317 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9318 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9319 spin_unlock_bh(&ecm_db_lock);
9320
9321 /*
9322 * Record general info
9323 */
9324 ii->type = ECM_DB_IFACE_TYPE_VLAN;
9325#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009326 ii->state_get = ecm_db_iface_vlan_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009327#endif
9328 ii->arg = arg;
9329 ii->final = final;
9330 strcpy(ii->name, name);
9331 ii->mtu = mtu;
9332 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009333 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009334
9335 /*
9336 * Type specific info
9337 */
9338 type_info = &ii->type_info.vlan;
9339 type_info->vlan_tag = vlan_tag;
9340 type_info->vlan_tpid = vlan_tpid;
9341 memcpy(type_info->address, address, ETH_ALEN);
9342
9343 /*
9344 * Compute hash chain for insertion
9345 */
9346 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9347 ii->hash_index = hash_index;
9348
Murat Sezgin91c5d712015-06-12 15:16:22 -07009349 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9350 ii->iface_id_hash_index = iface_id_hash_index;
9351
Gareth Williamsf98d4192015-03-11 16:55:41 +00009352 /*
9353 * Add into the global list
9354 */
9355 spin_lock_bh(&ecm_db_lock);
9356 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9357 ii->prev = NULL;
9358 ii->next = ecm_db_interfaces;
9359 if (ecm_db_interfaces) {
9360 ecm_db_interfaces->prev = ii;
9361 }
9362 ecm_db_interfaces = ii;
9363
9364 /*
9365 * Insert into chain
9366 */
9367 ii->hash_next = ecm_db_iface_table[hash_index];
9368 if (ecm_db_iface_table[hash_index]) {
9369 ecm_db_iface_table[hash_index]->hash_prev = ii;
9370 }
9371 ecm_db_iface_table[hash_index] = ii;
9372 ecm_db_iface_table_lengths[hash_index]++;
9373 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9374
9375 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9376
9377 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009378 * Insert into interface identifier chain
9379 */
9380 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9381 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9382 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9383 }
9384 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9385 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9386 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9387
9388 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009389 * Set time of addition
9390 */
9391 ii->time_added = ecm_db_time;
9392 spin_unlock_bh(&ecm_db_lock);
9393
9394 /*
9395 * Throw add event to the listeners
9396 */
9397 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9398 li = ecm_db_listeners_get_and_ref_first();
9399 while (li) {
9400 struct ecm_db_listener_instance *lin;
9401 if (li->iface_added) {
9402 li->iface_added(li->arg, ii);
9403 }
9404
9405 /*
9406 * Get next listener
9407 */
9408 lin = ecm_db_listener_get_and_ref_next(li);
9409 ecm_db_listener_deref(li);
9410 li = lin;
9411 }
9412}
9413EXPORT_SYMBOL(ecm_db_iface_add_vlan);
9414#endif
9415
ratheesh kannotha32fdd12015-09-09 08:02:58 +05309416#ifdef ECM_INTERFACE_PPPOE_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009417/*
9418 * ecm_db_iface_add_pppoe()
9419 * Add a iface instance into the database
9420 */
9421void ecm_db_iface_add_pppoe(struct ecm_db_iface_instance *ii, uint16_t pppoe_session_id, uint8_t *remote_mac,
9422 char *name, int32_t mtu, int32_t interface_identifier,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009423 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009424 void *arg)
9425{
9426 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009427 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009428 struct ecm_db_listener_instance *li;
9429 struct ecm_db_interface_info_pppoe *type_info;
9430
9431 spin_lock_bh(&ecm_db_lock);
9432 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009433#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009434 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009435#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009436 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9437 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9438 spin_unlock_bh(&ecm_db_lock);
9439
9440 /*
9441 * Record general info
9442 */
9443 ii->type = ECM_DB_IFACE_TYPE_PPPOE;
9444#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009445 ii->state_get = ecm_db_iface_pppoe_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009446#endif
9447 ii->arg = arg;
9448 ii->final = final;
9449 strcpy(ii->name, name);
9450 ii->mtu = mtu;
9451 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009452 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009453
9454 /*
9455 * Type specific info
9456 */
9457 type_info = &ii->type_info.pppoe;
9458 type_info->pppoe_session_id = pppoe_session_id;
9459 memcpy(type_info->remote_mac, remote_mac, ETH_ALEN);
9460
9461 /*
9462 * Compute hash chain for insertion
9463 */
9464 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
9465 ii->hash_index = hash_index;
9466
Murat Sezgin91c5d712015-06-12 15:16:22 -07009467 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9468 ii->iface_id_hash_index = iface_id_hash_index;
9469
Gareth Williamsf98d4192015-03-11 16:55:41 +00009470 /*
9471 * Add into the global list
9472 */
9473 spin_lock_bh(&ecm_db_lock);
9474 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9475 ii->prev = NULL;
9476 ii->next = ecm_db_interfaces;
9477 if (ecm_db_interfaces) {
9478 ecm_db_interfaces->prev = ii;
9479 }
9480 ecm_db_interfaces = ii;
9481
9482 /*
9483 * Insert into chain
9484 */
9485 ii->hash_next = ecm_db_iface_table[hash_index];
9486 if (ecm_db_iface_table[hash_index]) {
9487 ecm_db_iface_table[hash_index]->hash_prev = ii;
9488 }
9489 ecm_db_iface_table[hash_index] = ii;
9490 ecm_db_iface_table_lengths[hash_index]++;
9491 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9492
9493 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9494
9495 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009496 * Insert into interface identifier chain
9497 */
9498 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9499 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9500 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9501 }
9502 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9503 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9504 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9505
9506 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009507 * Set time of addition
9508 */
9509 ii->time_added = ecm_db_time;
9510 spin_unlock_bh(&ecm_db_lock);
9511
9512 /*
9513 * Throw add event to the listeners
9514 */
9515 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9516 li = ecm_db_listeners_get_and_ref_first();
9517 while (li) {
9518 struct ecm_db_listener_instance *lin;
9519 if (li->iface_added) {
9520 li->iface_added(li->arg, ii);
9521 }
9522
9523 /*
9524 * Get next listener
9525 */
9526 lin = ecm_db_listener_get_and_ref_next(li);
9527 ecm_db_listener_deref(li);
9528 li = lin;
9529 }
9530}
9531EXPORT_SYMBOL(ecm_db_iface_add_pppoe);
9532#endif
9533
ratheesh kannotha32fdd12015-09-09 08:02:58 +05309534#ifdef ECM_INTERFACE_L2TPV2_ENABLE
9535/*
9536 * ecm_db_iface_add_pppol2tpv2()
9537 * Add a iface instance into the database
9538 */
9539void ecm_db_iface_add_pppol2tpv2(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info,
9540 char *name, int32_t mtu, int32_t interface_identifier,
9541 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
9542 void *arg)
9543{
9544 ecm_db_iface_hash_t hash_index;
9545 ecm_db_iface_id_hash_t iface_id_hash_index;
9546 struct ecm_db_listener_instance *li;
9547 struct ecm_db_interface_info_pppol2tpv2 *type_info;
9548
9549 spin_lock_bh(&ecm_db_lock);
9550 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9551#ifdef ECM_DB_XREF_ENABLE
9552 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
9553#endif
9554 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9555 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9556 spin_unlock_bh(&ecm_db_lock);
9557
9558 /*
9559 * Record general info
9560 */
9561 ii->type = ECM_DB_IFACE_TYPE_PPPOL2TPV2;
9562#ifdef ECM_STATE_OUTPUT_ENABLE
9563 ii->state_get = ecm_db_iface_pppol2tpv2_state_get;
9564#endif
9565 ii->arg = arg;
9566 ii->final = final;
9567 strlcpy(ii->name, name, IFNAMSIZ);
9568 ii->mtu = mtu;
9569 ii->interface_identifier = interface_identifier;
9570 ii->ae_interface_identifier = ae_interface_identifier;
9571
9572 /*
9573 * Type specific info
9574 */
9575 type_info = &ii->type_info.pppol2tpv2;
9576 memcpy(type_info, pppol2tpv2_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
9577
9578 /*
9579 * Compute hash chain for insertion
9580 */
9581 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id,
9582 type_info->l2tp.session.session_id);
9583 ii->hash_index = hash_index;
9584
9585 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9586 ii->iface_id_hash_index = iface_id_hash_index;
9587 /*
9588 * Add into the global list
9589 */
9590 spin_lock_bh(&ecm_db_lock);
9591 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9592 ii->prev = NULL;
9593 ii->next = ecm_db_interfaces;
9594 if (ecm_db_interfaces) {
9595 ecm_db_interfaces->prev = ii;
9596 }
9597 ecm_db_interfaces = ii;
9598
9599 /*
9600 * Insert into chain
9601 */
9602 ii->hash_next = ecm_db_iface_table[hash_index];
9603 if (ecm_db_iface_table[hash_index]) {
9604 ecm_db_iface_table[hash_index]->hash_prev = ii;
9605 }
9606 ecm_db_iface_table[hash_index] = ii;
9607 ecm_db_iface_table_lengths[hash_index]++;
9608 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9609
9610 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9611
9612 /*
9613 * Insert into interface identifier chain
9614 */
9615 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9616 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9617 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9618 }
9619 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9620 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9621 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9622
9623 /*
9624 * Set time of addition
9625 */
9626 ii->time_added = ecm_db_time;
9627 spin_unlock_bh(&ecm_db_lock);
9628
9629 /*
9630 * Throw add event to the listeners
9631 */
9632 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9633 li = ecm_db_listeners_get_and_ref_first();
9634 while (li) {
9635 struct ecm_db_listener_instance *lin;
9636 if (li->iface_added) {
9637 li->iface_added(li->arg, ii);
9638 }
9639
9640 /*
9641 * Get next listener
9642 */
9643 lin = ecm_db_listener_get_and_ref_next(li);
9644 ecm_db_listener_deref(li);
9645 li = lin;
9646 }
9647}
9648EXPORT_SYMBOL(ecm_db_iface_add_pppol2tpv2);
9649
9650#endif
9651
Ben Menchaca84f36632014-02-28 20:57:38 +00009652/*
9653 * ecm_db_iface_add_unknown()
9654 * Add a iface instance into the database
9655 */
9656void ecm_db_iface_add_unknown(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009657 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +00009658 ecm_db_iface_final_callback_t final, void *arg)
9659{
9660 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009661 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +00009662 struct ecm_db_listener_instance *li;
9663 struct ecm_db_interface_info_unknown *type_info;
9664
9665 spin_lock_bh(&ecm_db_lock);
9666 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009667#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00009668 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009669#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009670 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9671 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9672 spin_unlock_bh(&ecm_db_lock);
9673
9674 /*
9675 * Record general info
9676 */
9677 ii->type = ECM_DB_IFACE_TYPE_UNKNOWN;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009678#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009679 ii->state_get = ecm_db_iface_unknown_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009680#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009681 ii->arg = arg;
9682 ii->final = final;
9683 strcpy(ii->name, name);
9684 ii->mtu = mtu;
9685 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009686 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00009687
9688 /*
9689 * Type specific info
9690 */
9691 type_info = &ii->type_info.unknown;
9692 type_info->os_specific_ident = os_specific_ident;
9693
9694 /*
9695 * Compute hash chain for insertion
9696 */
9697 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
9698 ii->hash_index = hash_index;
9699
Murat Sezgin91c5d712015-06-12 15:16:22 -07009700 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9701 ii->iface_id_hash_index = iface_id_hash_index;
9702
Ben Menchaca84f36632014-02-28 20:57:38 +00009703 /*
9704 * Add into the global list
9705 */
9706 spin_lock_bh(&ecm_db_lock);
9707 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9708 ii->prev = NULL;
9709 ii->next = ecm_db_interfaces;
9710 if (ecm_db_interfaces) {
9711 ecm_db_interfaces->prev = ii;
9712 }
9713 ecm_db_interfaces = ii;
9714
9715 /*
9716 * Insert into chain
9717 */
9718 ii->hash_next = ecm_db_iface_table[hash_index];
9719 if (ecm_db_iface_table[hash_index]) {
9720 ecm_db_iface_table[hash_index]->hash_prev = ii;
9721 }
9722 ecm_db_iface_table[hash_index] = ii;
9723 ecm_db_iface_table_lengths[hash_index]++;
9724 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9725
9726 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9727
9728 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009729 * Insert into interface identifier chain
9730 */
9731 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9732 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9733 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9734 }
9735 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9736 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9737 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9738
9739 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00009740 * Set time of addition
9741 */
9742 ii->time_added = ecm_db_time;
9743 spin_unlock_bh(&ecm_db_lock);
9744
9745 /*
9746 * Throw add event to the listeners
9747 */
9748 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9749 li = ecm_db_listeners_get_and_ref_first();
9750 while (li) {
9751 struct ecm_db_listener_instance *lin;
9752 if (li->iface_added) {
9753 li->iface_added(li->arg, ii);
9754 }
9755
9756 /*
9757 * Get next listener
9758 */
9759 lin = ecm_db_listener_get_and_ref_next(li);
9760 ecm_db_listener_deref(li);
9761 li = lin;
9762 }
9763}
9764EXPORT_SYMBOL(ecm_db_iface_add_unknown);
9765
9766/*
9767 * ecm_db_iface_add_loopback()
9768 * Add a iface instance into the database
9769 */
9770void ecm_db_iface_add_loopback(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009771 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +00009772 ecm_db_iface_final_callback_t final, void *arg)
9773{
9774 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009775 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +00009776 struct ecm_db_listener_instance *li;
9777 struct ecm_db_interface_info_loopback *type_info;
9778
9779 spin_lock_bh(&ecm_db_lock);
9780 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009781#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00009782 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009783#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009784 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9785 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9786 spin_unlock_bh(&ecm_db_lock);
9787
9788 /*
9789 * Record general info
9790 */
9791 ii->type = ECM_DB_IFACE_TYPE_LOOPBACK;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009792#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009793 ii->state_get = ecm_db_iface_loopback_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009794#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009795 ii->arg = arg;
9796 ii->final = final;
9797 strcpy(ii->name, name);
9798 ii->mtu = mtu;
9799 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009800 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00009801
9802 /*
9803 * Type specific info
9804 */
9805 type_info = &ii->type_info.loopback;
9806 type_info->os_specific_ident = os_specific_ident;
9807
9808 /*
9809 * Compute hash chain for insertion
9810 */
9811 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
9812 ii->hash_index = hash_index;
9813
Murat Sezgin91c5d712015-06-12 15:16:22 -07009814 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9815 ii->iface_id_hash_index = iface_id_hash_index;
9816
Ben Menchaca84f36632014-02-28 20:57:38 +00009817 /*
9818 * Add into the global list
9819 */
9820 spin_lock_bh(&ecm_db_lock);
9821 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9822 ii->prev = NULL;
9823 ii->next = ecm_db_interfaces;
9824 if (ecm_db_interfaces) {
9825 ecm_db_interfaces->prev = ii;
9826 }
9827 ecm_db_interfaces = ii;
9828
9829 /*
9830 * Insert into chain
9831 */
9832 ii->hash_next = ecm_db_iface_table[hash_index];
9833 if (ecm_db_iface_table[hash_index]) {
9834 ecm_db_iface_table[hash_index]->hash_prev = ii;
9835 }
9836 ecm_db_iface_table[hash_index] = ii;
9837 ecm_db_iface_table_lengths[hash_index]++;
9838 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9839
9840 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9841
9842 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009843 * Insert into interface identifier chain
9844 */
9845 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9846 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9847 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9848 }
9849 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9850 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9851 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9852
9853 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00009854 * Set time of addition
9855 */
9856 ii->time_added = ecm_db_time;
9857 spin_unlock_bh(&ecm_db_lock);
9858
9859 /*
9860 * Throw add event to the listeners
9861 */
9862 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9863 li = ecm_db_listeners_get_and_ref_first();
9864 while (li) {
9865 struct ecm_db_listener_instance *lin;
9866 if (li->iface_added) {
9867 li->iface_added(li->arg, ii);
9868 }
9869
9870 /*
9871 * Get next listener
9872 */
9873 lin = ecm_db_listener_get_and_ref_next(li);
9874 ecm_db_listener_deref(li);
9875 li = lin;
9876 }
9877}
9878EXPORT_SYMBOL(ecm_db_iface_add_loopback);
9879
Murat Sezginbde55f92015-03-11 16:44:11 -07009880#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00009881/*
Zhu Ken56477be2014-08-05 17:50:28 +08009882 * ecm_db_iface_sit_daddr_is_null()
9883 * The sit addr is null or not
9884 */
9885bool ecm_db_iface_sit_daddr_is_null(struct ecm_db_iface_instance *ii)
9886{
9887 return ii->type_info.sit.daddr[0] == 0;
9888}
9889EXPORT_SYMBOL(ecm_db_iface_sit_daddr_is_null);
9890
9891/*
Ben Menchaca84f36632014-02-28 20:57:38 +00009892 * ecm_db_iface_add_sit()
9893 * Add a iface instance into the database
9894 */
9895void ecm_db_iface_add_sit(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_sit *type_info, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009896 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +00009897 ecm_db_iface_final_callback_t final, void *arg)
9898{
9899 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009900 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +00009901 struct ecm_db_listener_instance *li;
9902
9903 spin_lock_bh(&ecm_db_lock);
9904 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009905#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00009906 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009907#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009908 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9909 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9910 spin_unlock_bh(&ecm_db_lock);
9911
9912 /*
9913 * Record general info
9914 */
9915 ii->type = ECM_DB_IFACE_TYPE_SIT;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009916#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009917 ii->state_get = ecm_db_iface_sit_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009918#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009919 ii->arg = arg;
9920 ii->final = final;
9921 strcpy(ii->name, name);
9922 ii->mtu = mtu;
9923 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009924 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00009925
9926 /*
9927 * Type specific info to be copied
9928 */
9929 ii->type_info.sit = *type_info;
9930
9931 /*
9932 * Compute hash chain for insertion
9933 */
9934 hash_index = ecm_db_iface_generate_hash_index_sit(type_info->saddr, type_info->daddr);
9935 ii->hash_index = hash_index;
9936
Murat Sezgin91c5d712015-06-12 15:16:22 -07009937 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9938 ii->iface_id_hash_index = iface_id_hash_index;
9939
Ben Menchaca84f36632014-02-28 20:57:38 +00009940 /*
9941 * Add into the global list
9942 */
9943 spin_lock_bh(&ecm_db_lock);
9944 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9945 ii->prev = NULL;
9946 ii->next = ecm_db_interfaces;
9947 if (ecm_db_interfaces) {
9948 ecm_db_interfaces->prev = ii;
9949 }
9950 ecm_db_interfaces = ii;
9951
9952 /*
9953 * Insert into chain
9954 */
9955 ii->hash_next = ecm_db_iface_table[hash_index];
9956 if (ecm_db_iface_table[hash_index]) {
9957 ecm_db_iface_table[hash_index]->hash_prev = ii;
9958 }
9959 ecm_db_iface_table[hash_index] = ii;
9960 ecm_db_iface_table_lengths[hash_index]++;
9961 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9962
9963 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
9964
9965 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009966 * Insert into interface identifier chain
9967 */
9968 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9969 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9970 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9971 }
9972 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9973 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9974 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
9975
9976 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00009977 * Set time of addition
9978 */
9979 ii->time_added = ecm_db_time;
9980 spin_unlock_bh(&ecm_db_lock);
9981
9982 /*
9983 * Throw add event to the listeners
9984 */
9985 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9986 li = ecm_db_listeners_get_and_ref_first();
9987 while (li) {
9988 struct ecm_db_listener_instance *lin;
9989 if (li->iface_added) {
9990 li->iface_added(li->arg, ii);
9991 }
9992
9993 /*
9994 * Get next listener
9995 */
9996 lin = ecm_db_listener_get_and_ref_next(li);
9997 ecm_db_listener_deref(li);
9998 li = lin;
9999 }
10000}
10001EXPORT_SYMBOL(ecm_db_iface_add_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -070010002#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010003
Murat Sezginc1402562015-03-12 12:32:20 -070010004#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +000010005#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010006/*
10007 * ecm_db_iface_add_tunipip6()
10008 * Add a iface instance into the database
10009 */
10010void ecm_db_iface_add_tunipip6(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_tunipip6 *type_info, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -070010011 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010012 ecm_db_iface_final_callback_t final, void *arg)
10013{
10014 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010015 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010016 struct ecm_db_listener_instance *li;
10017
10018 spin_lock_bh(&ecm_db_lock);
10019 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010020#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010021 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010022#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010023 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10024 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10025 spin_unlock_bh(&ecm_db_lock);
10026
10027 /*
10028 * Record general info
10029 */
10030 ii->type = ECM_DB_IFACE_TYPE_TUNIPIP6;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010031#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010032 ii->state_get = ecm_db_iface_tunipip6_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010033#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010034 ii->arg = arg;
10035 ii->final = final;
10036 strcpy(ii->name, name);
10037 ii->mtu = mtu;
10038 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010039 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010040
10041 /*
10042 * Type specific info to be copied
10043 */
10044 ii->type_info.tunipip6 = *type_info;
10045
10046 /*
10047 * Compute hash chain for insertion
10048 */
10049 hash_index = ecm_db_iface_generate_hash_index_tunipip6(type_info->saddr, type_info->daddr);
10050 ii->hash_index = hash_index;
10051
Murat Sezgin91c5d712015-06-12 15:16:22 -070010052 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10053 ii->iface_id_hash_index = iface_id_hash_index;
10054
Ben Menchaca84f36632014-02-28 20:57:38 +000010055 /*
10056 * Add into the global list
10057 */
10058 spin_lock_bh(&ecm_db_lock);
10059 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10060 ii->prev = NULL;
10061 ii->next = ecm_db_interfaces;
10062 if (ecm_db_interfaces) {
10063 ecm_db_interfaces->prev = ii;
10064 }
10065 ecm_db_interfaces = ii;
10066
10067 /*
10068 * Insert into chain
10069 */
10070 ii->hash_next = ecm_db_iface_table[hash_index];
10071 if (ecm_db_iface_table[hash_index]) {
10072 ecm_db_iface_table[hash_index]->hash_prev = ii;
10073 }
10074 ecm_db_iface_table[hash_index] = ii;
10075 ecm_db_iface_table_lengths[hash_index]++;
10076 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10077
10078 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10079
10080 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010081 * Insert into interface identifier chain
10082 */
10083 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10084 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10085 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10086 }
10087 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10088 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10089 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10090
10091 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010092 * Set time of addition
10093 */
10094 ii->time_added = ecm_db_time;
10095 spin_unlock_bh(&ecm_db_lock);
10096
10097 /*
10098 * Throw add event to the listeners
10099 */
10100 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10101 li = ecm_db_listeners_get_and_ref_first();
10102 while (li) {
10103 struct ecm_db_listener_instance *lin;
10104 if (li->iface_added) {
10105 li->iface_added(li->arg, ii);
10106 }
10107
10108 /*
10109 * Get next listener
10110 */
10111 lin = ecm_db_listener_get_and_ref_next(li);
10112 ecm_db_listener_deref(li);
10113 li = lin;
10114 }
10115}
10116EXPORT_SYMBOL(ecm_db_iface_add_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -070010117#endif
Gareth Williams8ac34292015-03-17 14:06:58 +000010118#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010119
Murat Sezgin69a27532015-03-12 14:09:40 -070010120#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010121/*
10122 * ecm_db_iface_add_ipsec_tunnel()
10123 * Add a iface instance into the database
10124 *
10125 * GGG TODO This needs to take ipsec tunnel endpoint information etc. something very appropriate for ipsec tunnels, anyhow.
10126 */
10127void ecm_db_iface_add_ipsec_tunnel(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
Murat Sezgin91c5d712015-06-12 15:16:22 -070010128 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010129 ecm_db_iface_final_callback_t final, void *arg)
10130{
10131 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010132 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010133 struct ecm_db_listener_instance *li;
10134 struct ecm_db_interface_info_ipsec_tunnel *type_info;
10135
10136 spin_lock_bh(&ecm_db_lock);
10137 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010138#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010139 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010140#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010141 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10142 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10143 spin_unlock_bh(&ecm_db_lock);
10144
10145 /*
10146 * Record general info
10147 */
Ankit Dhanuka60683c52014-06-09 17:43:38 +053010148 ii->type = ECM_DB_IFACE_TYPE_IPSEC_TUNNEL;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010149#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010150 ii->state_get = ecm_db_iface_ipsec_tunnel_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010151#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010152 ii->arg = arg;
10153 ii->final = final;
10154 strcpy(ii->name, name);
10155 ii->mtu = mtu;
10156 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010157 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010158
10159 /*
10160 * Type specific info
10161 */
10162 type_info = &ii->type_info.ipsec_tunnel;
10163 type_info->os_specific_ident = os_specific_ident;
10164
10165 /*
10166 * Compute hash chain for insertion
10167 */
10168 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
10169 ii->hash_index = hash_index;
10170
Murat Sezgin91c5d712015-06-12 15:16:22 -070010171 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10172 ii->iface_id_hash_index = iface_id_hash_index;
10173
Ben Menchaca84f36632014-02-28 20:57:38 +000010174 /*
10175 * Add into the global list
10176 */
10177 spin_lock_bh(&ecm_db_lock);
10178 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10179 ii->prev = NULL;
10180 ii->next = ecm_db_interfaces;
10181 if (ecm_db_interfaces) {
10182 ecm_db_interfaces->prev = ii;
10183 }
10184 ecm_db_interfaces = ii;
10185
10186 /*
10187 * Insert into chain
10188 */
10189 ii->hash_next = ecm_db_iface_table[hash_index];
10190 if (ecm_db_iface_table[hash_index]) {
10191 ecm_db_iface_table[hash_index]->hash_prev = ii;
10192 }
10193 ecm_db_iface_table[hash_index] = ii;
10194 ecm_db_iface_table_lengths[hash_index]++;
10195 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10196
10197 DEBUG_INFO("%p: interface inserted at hash index %u, hash prev is %p, type: %d\n", ii, ii->hash_index, ii->hash_prev, ii->type);
10198
10199 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010200 * Insert into interface identifier chain
10201 */
10202 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10203 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10204 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10205 }
10206 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10207 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10208 DEBUG_ASSERT(ecm_db_iface_id_table_lengths[iface_id_hash_index] > 0, "%p: invalid iface id table len %d\n", ii, ecm_db_iface_id_table_lengths[iface_id_hash_index]);
10209
10210 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010211 * Set time of addition
10212 */
10213 ii->time_added = ecm_db_time;
10214 spin_unlock_bh(&ecm_db_lock);
10215
10216 /*
10217 * Throw add event to the listeners
10218 */
10219 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10220 li = ecm_db_listeners_get_and_ref_first();
10221 while (li) {
10222 struct ecm_db_listener_instance *lin;
10223 if (li->iface_added) {
10224 li->iface_added(li->arg, ii);
10225 }
10226
10227 /*
10228 * Get next listener
10229 */
10230 lin = ecm_db_listener_get_and_ref_next(li);
10231 ecm_db_listener_deref(li);
10232 li = lin;
10233 }
10234}
10235EXPORT_SYMBOL(ecm_db_iface_add_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -070010236#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010237
10238/*
10239 * ecm_db_listener_add()
10240 * Add a listener instance into the database.
10241 */
10242void ecm_db_listener_add(struct ecm_db_listener_instance *li,
10243 ecm_db_iface_listener_added_callback_t iface_added,
10244 ecm_db_iface_listener_removed_callback_t iface_removed,
10245 ecm_db_node_listener_added_callback_t node_added,
10246 ecm_db_node_listener_removed_callback_t node_removed,
10247 ecm_db_host_listener_added_callback_t host_added,
10248 ecm_db_host_listener_removed_callback_t host_removed,
10249 ecm_db_mapping_listener_added_callback_t mapping_added,
10250 ecm_db_mapping_listener_removed_callback_t mapping_removed,
10251 ecm_db_connection_listener_added_callback_t connection_added,
10252 ecm_db_connection_listener_removed_callback_t connection_removed,
10253 ecm_db_listener_final_callback_t final,
10254 void *arg)
10255{
10256 spin_lock_bh(&ecm_db_lock);
10257 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed\n", li);
10258 DEBUG_ASSERT(!(li->flags & ECM_DB_LISTENER_FLAGS_INSERTED), "%p: inserted\n", li);
10259 spin_unlock_bh(&ecm_db_lock);
10260
10261 li->arg = arg;
10262 li->final = final;
10263 li->iface_added = iface_added;
10264 li->iface_removed = iface_removed;
10265 li->node_added = node_added;
10266 li->node_removed = node_removed;
10267 li->host_added = host_added;
10268 li->host_removed = host_removed;
10269 li->mapping_added = mapping_added;
10270 li->mapping_removed = mapping_removed;
10271 li->connection_added = connection_added;
10272 li->connection_removed = connection_removed;
10273
10274 /*
10275 * Add instance into listener list
10276 */
10277 spin_lock_bh(&ecm_db_lock);
10278 li->flags |= ECM_DB_LISTENER_FLAGS_INSERTED;
10279 li->next = ecm_db_listeners;
10280 ecm_db_listeners = li;
10281 spin_unlock_bh(&ecm_db_lock);
10282}
10283EXPORT_SYMBOL(ecm_db_listener_add);
10284
10285/*
10286 * ecm_db_connection_alloc()
10287 * Allocate a connection instance
10288 */
10289struct ecm_db_connection_instance *ecm_db_connection_alloc(void)
10290{
10291 struct ecm_db_connection_instance *ci;
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010292 int __attribute__((unused)) i;
Ben Menchaca84f36632014-02-28 20:57:38 +000010293
10294 /*
10295 * Allocate the connection
10296 */
10297 ci = (struct ecm_db_connection_instance *)kzalloc(sizeof(struct ecm_db_connection_instance), GFP_ATOMIC | __GFP_NOWARN);
10298 if (!ci) {
10299 DEBUG_WARN("Connection alloc failed\n");
10300 return NULL;
10301 }
10302
10303 /*
10304 * Initialise the defunct timer entry
10305 */
10306 ecm_db_timer_group_entry_init(&ci->defunct_timer, ecm_db_connection_defunct_callback, ci);
10307
10308 /*
10309 * Refs is 1 for the creator of the connection
10310 */
10311 ci->refs = 1;
10312 DEBUG_SET_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC);
10313
10314 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010315 * Initialise the interfaces from/to lists.
10316 * Interfaces are added from end of array.
10317 */
10318 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10319 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10320 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10321 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10322
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010323#ifdef ECM_MULTICAST_ENABLE
10324 for (i = 0; i < ECM_DB_MULTICAST_IF_MAX; ++i) {
10325 ci->to_mcast_interface_first[i] = ECM_DB_IFACE_HEIRARCHY_MAX;
10326 }
10327#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010328 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010329 * If the master thread is terminating then we cannot create new instances
10330 */
10331 spin_lock_bh(&ecm_db_lock);
10332 if (ecm_db_terminate_pending) {
10333 spin_unlock_bh(&ecm_db_lock);
10334 DEBUG_WARN("Thread terminating\n");
10335 kfree(ci);
10336 return NULL;
10337 }
10338
10339 /*
10340 * Assign runtime unique serial
10341 */
10342 ci->serial = ecm_db_connection_serial++;
10343
Ben Menchaca84f36632014-02-28 20:57:38 +000010344 ecm_db_connection_count++;
10345 DEBUG_ASSERT(ecm_db_connection_count > 0, "%p: connection count wrap\n", ci);
10346 spin_unlock_bh(&ecm_db_lock);
10347
10348 DEBUG_TRACE("Connection created %p\n", ci);
10349 return ci;
10350}
10351EXPORT_SYMBOL(ecm_db_connection_alloc);
10352
10353/*
10354 * ecm_db_mapping_alloc()
10355 * Allocate a mapping instance
10356 */
10357struct ecm_db_mapping_instance *ecm_db_mapping_alloc(void)
10358{
10359 struct ecm_db_mapping_instance *mi;
10360
10361 mi = (struct ecm_db_mapping_instance *)kzalloc(sizeof(struct ecm_db_mapping_instance), GFP_ATOMIC | __GFP_NOWARN);
10362 if (!mi) {
10363 DEBUG_WARN("Alloc failed\n");
10364 return NULL;
10365 }
10366
10367 mi->refs = 1;
10368 DEBUG_SET_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC);
10369
10370 /*
10371 * Alloc operation must be atomic to ensure thread and module can be held
10372 */
10373 spin_lock_bh(&ecm_db_lock);
10374
10375 /*
10376 * If the event processing thread is terminating then we cannot create new instances
10377 */
10378 if (ecm_db_terminate_pending) {
10379 spin_unlock_bh(&ecm_db_lock);
10380 DEBUG_WARN("Thread terminating\n");
10381 kfree(mi);
10382 return NULL;
10383 }
10384
Ben Menchaca84f36632014-02-28 20:57:38 +000010385 ecm_db_mapping_count++;
10386 spin_unlock_bh(&ecm_db_lock);
10387
10388 DEBUG_TRACE("Mapping created %p\n", mi);
10389 return mi;
10390}
10391EXPORT_SYMBOL(ecm_db_mapping_alloc);
10392
Ben Menchaca84f36632014-02-28 20:57:38 +000010393/*
10394 * ecm_db_host_alloc()
10395 * Allocate a host instance
10396 */
10397struct ecm_db_host_instance *ecm_db_host_alloc(void)
10398{
10399 struct ecm_db_host_instance *hi;
10400 hi = (struct ecm_db_host_instance *)kzalloc(sizeof(struct ecm_db_host_instance), GFP_ATOMIC | __GFP_NOWARN);
10401 if (!hi) {
10402 DEBUG_WARN("Alloc failed\n");
10403 return NULL;
10404 }
10405
10406 hi->refs = 1;
10407 DEBUG_SET_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC);
10408
10409 /*
10410 * Alloc operation must be atomic to ensure thread and module can be held
10411 */
10412 spin_lock_bh(&ecm_db_lock);
10413
10414 /*
10415 * If the event processing thread is terminating then we cannot create new instances
10416 */
10417 if (ecm_db_terminate_pending) {
10418 spin_unlock_bh(&ecm_db_lock);
10419 DEBUG_WARN("Thread terminating\n");
10420 kfree(hi);
10421 return NULL;
10422 }
10423
Ben Menchaca84f36632014-02-28 20:57:38 +000010424 ecm_db_host_count++;
10425 spin_unlock_bh(&ecm_db_lock);
10426
10427 DEBUG_TRACE("Host created %p\n", hi);
10428 return hi;
10429}
10430EXPORT_SYMBOL(ecm_db_host_alloc);
10431
10432/*
10433 * ecm_db_node_alloc()
10434 * Allocate a node instance
10435 */
10436struct ecm_db_node_instance *ecm_db_node_alloc(void)
10437{
10438 struct ecm_db_node_instance *ni;
10439
10440 ni = (struct ecm_db_node_instance *)kzalloc(sizeof(struct ecm_db_node_instance), GFP_ATOMIC | __GFP_NOWARN);
10441 if (!ni) {
10442 DEBUG_WARN("Alloc failed\n");
10443 return NULL;
10444 }
10445
10446 ni->refs = 1;
10447 DEBUG_SET_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC);
10448
10449 /*
10450 * Alloc operation must be atomic to ensure thread and module can be held
10451 */
10452 spin_lock_bh(&ecm_db_lock);
10453
10454 /*
10455 * If the event processing thread is terminating then we cannot create new instances
10456 */
10457 if (ecm_db_terminate_pending) {
10458 spin_unlock_bh(&ecm_db_lock);
10459 DEBUG_WARN("Thread terminating\n");
10460 kfree(ni);
10461 return NULL;
10462 }
10463
Ben Menchaca84f36632014-02-28 20:57:38 +000010464 ecm_db_node_count++;
10465 spin_unlock_bh(&ecm_db_lock);
10466
10467 DEBUG_TRACE("Node created %p\n", ni);
10468 return ni;
10469}
10470EXPORT_SYMBOL(ecm_db_node_alloc);
10471
10472/*
10473 * ecm_db_iface_alloc()
10474 * Allocate a iface instance
10475 */
10476struct ecm_db_iface_instance *ecm_db_iface_alloc(void)
10477{
10478 struct ecm_db_iface_instance *ii;
10479
10480 ii = (struct ecm_db_iface_instance *)kzalloc(sizeof(struct ecm_db_iface_instance), GFP_ATOMIC | __GFP_NOWARN);
10481 if (!ii) {
10482 DEBUG_WARN("Alloc failed\n");
10483 return NULL;
10484 }
10485
10486 ii->refs = 1;
10487 DEBUG_SET_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC);
10488
10489 /*
10490 * Alloc operation must be atomic to ensure thread and module can be held
10491 */
10492 spin_lock_bh(&ecm_db_lock);
10493
10494 /*
10495 * If the event processing thread is terminating then we cannot create new instances
10496 */
10497 if (ecm_db_terminate_pending) {
10498 spin_unlock_bh(&ecm_db_lock);
10499 DEBUG_WARN("Thread terminating\n");
10500 kfree(ii);
10501 return NULL;
10502 }
10503
Ben Menchaca84f36632014-02-28 20:57:38 +000010504 ecm_db_iface_count++;
10505 spin_unlock_bh(&ecm_db_lock);
10506
10507 DEBUG_TRACE("iface created %p\n", ii);
10508 return ii;
10509}
10510EXPORT_SYMBOL(ecm_db_iface_alloc);
10511
10512/*
10513 * ecm_db_listener_alloc()
10514 * Allocate a listener instance
10515 */
10516struct ecm_db_listener_instance *ecm_db_listener_alloc(void)
10517{
10518 struct ecm_db_listener_instance *li;
10519
10520 li = (struct ecm_db_listener_instance *)kzalloc(sizeof(struct ecm_db_listener_instance), GFP_ATOMIC | __GFP_NOWARN);
10521 if (!li) {
10522 DEBUG_WARN("Alloc failed\n");
10523 return NULL;
10524 }
10525
10526 li->refs = 1;
10527 DEBUG_SET_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC);
10528
10529 /*
10530 * Alloc operation must be atomic to ensure thread and module can be held
10531 */
10532 spin_lock_bh(&ecm_db_lock);
10533
10534 /*
10535 * If the event processing thread is terminating then we cannot create new instances
10536 */
10537 if (ecm_db_terminate_pending) {
10538 spin_unlock_bh(&ecm_db_lock);
10539 DEBUG_WARN("Thread terminating\n");
10540 kfree(li);
10541 return NULL;
10542 }
10543
Ben Menchaca84f36632014-02-28 20:57:38 +000010544 ecm_db_listeners_count++;
10545 DEBUG_ASSERT(ecm_db_listeners_count > 0, "%p: listener count wrap\n", li);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010546 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +000010547
10548 DEBUG_TRACE("Listener created %p\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +000010549 return li;
10550}
10551EXPORT_SYMBOL(ecm_db_listener_alloc);
10552
Shyam Sunder1f037262015-05-18 20:04:13 +053010553#ifdef ECM_MULTICAST_ENABLE
10554/*
10555 * _ecm_db_multicast_tuple_instance_ref()
10556 * Increment tuple reference count by one
10557 */
10558static void _ecm_db_multicast_tuple_instance_ref(struct ecm_db_multicast_tuple_instance *ti)
10559{
10560 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10561 ti->refs++;
10562 DEBUG_TRACE("%p: ti ref %d\n", ti, ti->refs);
10563 DEBUG_ASSERT(ti->refs > 0, "%p: ref wrap\n", ti)
10564}
10565
10566/*
10567 * ecm_db_multicast_alloc_connection()
10568 * Allocate memory for the connection structure.
10569 */
10570struct ecm_db_multicast_tuple_instance *ecm_db_multicast_tuple_instance_alloc(ip_addr_t origin, ip_addr_t group, uint16_t src_port, uint16_t dst_port)
10571{
10572 struct ecm_db_multicast_tuple_instance *ti;
10573 ti = (struct ecm_db_multicast_tuple_instance *)kzalloc(sizeof(struct ecm_db_multicast_tuple_instance), GFP_ATOMIC | __GFP_NOWARN);
10574 if (!ti) {
10575 DEBUG_WARN("ti: Alloc failed\n");
10576 return NULL;
10577 }
10578 ti->src_port = src_port;
10579 ti->dst_port = dst_port;
10580 ECM_IP_ADDR_COPY(ti->src_ip, origin);
10581 ECM_IP_ADDR_COPY(ti->grp_ip, group);
10582 ti->proto = IPPROTO_UDP;
10583 ti->hash_index = ecm_db_multicast_generate_hash_index(group);
10584 ti->flags = 0;
10585 ti->refs = 1;
10586 ti->next = NULL;
10587 ti->prev = NULL;
10588 DEBUG_SET_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC);
10589
10590 return ti;
10591}
10592EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_alloc);
10593
10594/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010595 * ecm_db_multicast_connection_find_and_ref()
Shyam Sunder1f037262015-05-18 20:04:13 +053010596 * Called by MFC event update to fetch connection from the table
Shyam Sunder3af86a52015-08-28 18:04:10 +053010597 * This function takes a ref count for both tuple_instance and 'ci'
10598 * Call ecm_db_multicast_connection_deref function for deref both
10599 * 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053010600 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053010601struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_find_and_ref(ip_addr_t origin, ip_addr_t group)
Shyam Sunder1f037262015-05-18 20:04:13 +053010602{
10603 ecm_db_multicast_tuple_instance_hash_t hash_index;
10604 struct ecm_db_multicast_tuple_instance *ti;
10605
10606 /*
10607 * Compute the hash chain index
10608 */
10609 hash_index = ecm_db_multicast_generate_hash_index(group);
10610
10611 spin_lock_bh(&ecm_db_lock);
10612 ti = ecm_db_multicast_tuple_instance_table[hash_index];
10613
10614 /*
10615 * Traverse through the list and find the ti
10616 */
10617 while (ti) {
10618 if (!(ECM_IP_ADDR_MATCH(ti->src_ip, origin) && ECM_IP_ADDR_MATCH(ti->grp_ip, group))) {
10619 ti = ti->next;
10620 continue;
10621 }
10622
10623 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053010624 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053010625 spin_unlock_bh(&ecm_db_lock);
10626 DEBUG_TRACE("multicast tuple instance found %p\n", ti);
10627 return ti;
10628 }
10629
10630 spin_unlock_bh(&ecm_db_lock);
10631 DEBUG_TRACE("multicast tuple instance not found\n");
10632 return NULL;
10633}
Shyam Sunder3af86a52015-08-28 18:04:10 +053010634EXPORT_SYMBOL(ecm_db_multicast_connection_find_and_ref);
Shyam Sunder1f037262015-05-18 20:04:13 +053010635
10636/*
10637 * ecm_db_multicast_tuple_instance_deref()
10638 * Deref the reference count or
Shyam Sunder3af86a52015-08-28 18:04:10 +053010639 * Free the tuple_instance struct, when the multicast connection dies
Shyam Sunder1f037262015-05-18 20:04:13 +053010640 */
10641int ecm_db_multicast_tuple_instance_deref(struct ecm_db_multicast_tuple_instance *ti)
10642{
10643 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10644 spin_lock_bh(&ecm_db_lock);
10645 ti->refs--;
10646 DEBUG_TRACE("%p: ti deref %d\n", ti, ti->refs);
10647 DEBUG_ASSERT(ti->refs >= 0, "%p: ref wrap\n", ti);
10648
10649 if (ti->refs > 0) {
10650 int refs = ti->refs;
10651 spin_unlock_bh(&ecm_db_lock);
10652 return refs;
10653 }
10654
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010655 if (ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED) {
10656
10657 if (!ti->prev) {
10658 DEBUG_ASSERT(ecm_db_multicast_tuple_instance_table[ti->hash_index] == ti, "%p: hash table bad\n", ti);
10659 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti->next;
10660 } else {
10661 ti->prev->next = ti->next;
10662 }
10663
10664 if (ti->next) {
10665 ti->next->prev = ti->prev;
10666 }
Shyam Sunder1f037262015-05-18 20:04:13 +053010667 }
10668
Shyam Sunder1f037262015-05-18 20:04:13 +053010669 spin_unlock_bh(&ecm_db_lock);
Shyam Sunder1f037262015-05-18 20:04:13 +053010670 DEBUG_CLEAR_MAGIC(ti);
10671 kfree(ti);
10672
10673 return 0;
10674}
10675EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_deref);
10676
10677/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010678 * ecm_db_multicast_connection_deref()
10679 * Deref both 'ti' and 'ci'
10680 * call this function after ecm_db_multicast_connection_find_and_ref()
10681 */
10682void ecm_db_multicast_connection_deref(struct ecm_db_multicast_tuple_instance *ti)
10683{
10684 struct ecm_db_connection_instance *ci;
10685 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10686
10687 ci = ti->ci;
10688 ecm_db_multicast_tuple_instance_deref(ti);
10689 ecm_db_connection_deref(ci);
10690
10691}
10692EXPORT_SYMBOL(ecm_db_multicast_connection_deref);
10693
10694/*
Shyam Sunder1f037262015-05-18 20:04:13 +053010695 * ecm_db_multicast_tuple_instance_add()
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010696 * Add the tuple instance into the hash table. Also, attach the tuple instance
10697 * with connection instance.
10698 *
Shyam Sunder1f037262015-05-18 20:04:13 +053010699 * Note: This function takes a reference count and caller has to also call
10700 * ecm_db_multicast_tuple_instance_deref() after this function.
10701 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010702void ecm_db_multicast_tuple_instance_add(struct ecm_db_multicast_tuple_instance *ti, struct ecm_db_connection_instance *ci)
Shyam Sunder1f037262015-05-18 20:04:13 +053010703{
10704 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10705
10706 spin_lock_bh(&ecm_db_lock);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010707 DEBUG_ASSERT(!(ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED), "%p: inserted\n", ti);
10708
10709 /*
10710 * Attach the multicast tuple instance with the connection instance
10711 */
10712 ci->ti = ti;
Shyam Sunder3af86a52015-08-28 18:04:10 +053010713 ti->ci = ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053010714
10715 /*
10716 * Take a local reference to ti
10717 */
10718 _ecm_db_multicast_tuple_instance_ref(ti);
10719 ti->next = ecm_db_multicast_tuple_instance_table[ti->hash_index];
10720 if (ecm_db_multicast_tuple_instance_table[ti->hash_index]) {
10721 ecm_db_multicast_tuple_instance_table[ti->hash_index]->prev = ti;
10722 }
10723
10724 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010725
10726 ti->flags |= ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED;
Shyam Sunder1f037262015-05-18 20:04:13 +053010727 spin_unlock_bh(&ecm_db_lock);
10728
10729}
10730EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_add);
10731
10732/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010733 * ecm_db_multicast_connection_get_and_ref_first()
Shyam Sunder1f037262015-05-18 20:04:13 +053010734 * Return the first tuple instance from the table when given a group
Shyam Sunder3af86a52015-08-28 18:04:10 +053010735 * Also take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
10736 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053010737 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053010738struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_get_and_ref_first(ip_addr_t group)
Shyam Sunder1f037262015-05-18 20:04:13 +053010739{
10740 ecm_db_multicast_tuple_instance_hash_t hash_index;
10741 struct ecm_db_multicast_tuple_instance *ti;
10742
10743 hash_index = ecm_db_multicast_generate_hash_index(group);
10744
10745 spin_lock_bh(&ecm_db_lock);
10746 ti = ecm_db_multicast_tuple_instance_table[hash_index];
10747 if (ti) {
10748 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053010749 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053010750 }
10751 spin_unlock_bh(&ecm_db_lock);
10752
10753 return ti;
10754}
Shyam Sunder3af86a52015-08-28 18:04:10 +053010755EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_first);
Shyam Sunder1f037262015-05-18 20:04:13 +053010756
10757/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010758 * ecm_db_multicast_connection_get_and_ref_next()
10759 * Return the next tuple instance node and
10760 * take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
10761 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053010762 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053010763struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_get_and_ref_next(struct ecm_db_multicast_tuple_instance *ti)
Shyam Sunder1f037262015-05-18 20:04:13 +053010764{
10765 struct ecm_db_multicast_tuple_instance *tin;
10766 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10767 spin_lock_bh(&ecm_db_lock);
10768 tin = ti->next;
10769 if (tin) {
10770 _ecm_db_multicast_tuple_instance_ref(tin);
Shyam Sunder3af86a52015-08-28 18:04:10 +053010771 _ecm_db_connection_ref(tin->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053010772 }
10773 spin_unlock_bh(&ecm_db_lock);
10774 return tin;
10775}
Shyam Sunder3af86a52015-08-28 18:04:10 +053010776EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_next);
Shyam Sunder1f037262015-05-18 20:04:13 +053010777
10778/*
10779 * ecm_db_multicast_tuple_instance_source_ip_get()
10780 * This function return the source IP for a connection object
10781 */
10782void ecm_db_multicast_tuple_instance_source_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t origin)
10783{
10784 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10785 ECM_IP_ADDR_COPY(origin, ti->src_ip);
10786}
10787EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_source_ip_get);
10788
10789/*
Shyam Sunderf34c25b2015-06-11 21:14:50 +053010790 * ecm_db_multicast_tuple_instance_group_ip_get()
10791 * This function return the group IP for a connection object
10792 */
10793void ecm_db_multicast_tuple_instance_group_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t group)
10794{
10795 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10796 ECM_IP_ADDR_COPY(group, ti->grp_ip);
10797}
10798EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_group_ip_get);
10799
10800/*
Shyam Sunder1f037262015-05-18 20:04:13 +053010801 * ecm_db_multicast_tuple_instance_flags_get()
10802 * Return flags related to Multicast connection
10803 */
10804uint32_t ecm_db_multicast_tuple_instance_flags_get(struct ecm_db_multicast_tuple_instance *ti)
10805{
10806 uint32_t flags;
10807
10808 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
10809 spin_lock_bh(&ecm_db_lock);
10810 flags = ti->flags;
10811 spin_unlock_bh(&ecm_db_lock);
10812 return flags;
10813}
10814EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_get);
10815
10816/*
10817 * ecm_db_multicast_tuple_instance_flags_set()
10818 * Set the multicast connection flags
10819 */
10820void ecm_db_multicast_tuple_instance_flags_set(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
10821{
10822 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
10823
10824 spin_lock_bh(&ecm_db_lock);
10825 ti->flags |= flags;
10826 spin_unlock_bh(&ecm_db_lock);
10827}
10828EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_set);
10829
10830/*
10831 * ecm_db_multicast_tuple_instance_flags_clear()
10832 * Clear the multicast connection flags
10833 */
10834void ecm_db_multicast_tuple_instance_flags_clear(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
10835{
10836 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
10837
10838 spin_lock_bh(&ecm_db_lock);
10839 ti->flags &= ~flags;
10840 spin_unlock_bh(&ecm_db_lock);
10841}
10842EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_clear);
10843
10844/*
10845 * ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
10846 * Return the list of multicast destination interface heirarchies to which this connection is established.
10847 * The function returns the heirarchies using the 'interface' pointer passed to it. It also returns the first
10848 * index in the interface heirarchy for each of the heirarchies using the 'ifaces_first' pointer.
10849 *
10850 * NOTE: This function allocates the memory for the destination interface heirachy. This memory is expected to be
10851 * freed only by making a call to ecm_db_multicast_connection_interfaces_deref_all().
10852 *
10853 * The size of the buffer allocated for the heirarchies and pointed to by 'interfaces' is as large as
10854 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX.
10855 * Returns the number of interface heirarchies in the list as a return value.
10856 *
10857 * Each interface is referenced on return, be sure to release them using ecm_db_multicast_connection_interfaces_deref_all().
10858 */
10859int32_t ecm_db_multicast_connection_to_interfaces_get_and_ref_all(struct ecm_db_connection_instance *ci,
10860 struct ecm_db_iface_instance **interfaces, int32_t **ifaces_first)
10861{
10862 struct ecm_db_iface_instance *heirarchy_base;
10863 struct ecm_db_iface_instance *heirarchy_temp;
10864 struct ecm_db_iface_instance *ii_single;
10865 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010866 struct ecm_db_iface_instance *ii_db;
10867 struct ecm_db_iface_instance *ii_db_single;
10868 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053010869 int32_t *ii_first_base;
10870 int32_t *ii_first;
10871 int32_t heirarchy_index;
10872 int32_t ii_index;
10873 int32_t if_count = 0;
10874
10875 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
10876
10877 heirarchy_base = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
10878 if (!heirarchy_base) {
10879 DEBUG_WARN("%p: No memory for interface hierarchies \n", ci);
10880 return if_count;
10881 }
10882
10883 ii_first_base = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
10884 if (!ii_first_base) {
10885 DEBUG_WARN("%p: No memory for first interface \n", ci);
10886 kfree(heirarchy_base);
10887 return if_count;
10888 }
10889
10890 spin_lock_bh(&ecm_db_lock);
10891 if (!ci->to_mcast_interfaces_set) {
10892 spin_unlock_bh(&ecm_db_lock);
10893 kfree(ii_first_base);
10894 kfree(heirarchy_base);
10895 return if_count;
10896 }
10897
10898 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
10899
10900 heirarchy_temp = ecm_db_multicast_if_heirarchy_get(heirarchy_base, heirarchy_index);
10901
10902 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
10903 if_count++;
10904 }
10905
10906 for (ii_index = ci->to_mcast_interface_first[heirarchy_index]; ii_index < ECM_DB_IFACE_HEIRARCHY_MAX; ++ii_index) {
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010907 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
10908 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, ii_index);
10909 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053010910
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010911 /*
10912 * Take a reference count
10913 */
10914 _ecm_db_iface_ref(*ifaces_db);
10915
Shyam Sunder1f037262015-05-18 20:04:13 +053010916 ii_single = ecm_db_multicast_if_instance_get_at_index(heirarchy_temp, ii_index);
10917 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010918 *ifaces = *ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053010919 }
10920
10921 ii_first = ecm_db_multicast_if_first_get_at_index(ii_first_base, heirarchy_index);
10922 *ii_first = ci->to_mcast_interface_first[heirarchy_index];
10923 }
10924
10925 *interfaces = heirarchy_base;
10926 *ifaces_first = ii_first_base;
10927
10928 spin_unlock_bh(&ecm_db_lock);
10929 return if_count;
10930}
10931EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_get_and_ref_all);
10932
10933/*
10934 * ecm_db_multicast_connection_to_interfaces_set_check()
10935 * Returns true if the multicast destination interfaces list has been set.
10936 */
10937bool ecm_db_multicast_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
10938{
10939 bool set;
10940
10941 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
10942 spin_lock_bh(&ecm_db_lock);
10943 set = ci->to_mcast_interfaces_set;
10944 spin_unlock_bh(&ecm_db_lock);
10945 return set;
10946}
10947EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_set_check);
10948
10949/*
10950 * ecm_db_multicast_connection_to_interfaces_set_clear()
10951 * Clear the to_mcast_interfaces_set flag if the multicast destination interfaces list has been freed.
10952 */
10953static void _ecm_db_multicast_connection_to_interfaces_set_clear(struct ecm_db_connection_instance *ci)
10954{
10955 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053010956 ci->to_mcast_interfaces_set = false;
Shyam Sunder1f037262015-05-18 20:04:13 +053010957}
10958
10959/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010960 * ecm_db_multicast_connection_get_from_tuple()
Shyam Sunder1f037262015-05-18 20:04:13 +053010961 * Return the connection instance
10962 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053010963struct ecm_db_connection_instance *ecm_db_multicast_connection_get_from_tuple(struct ecm_db_multicast_tuple_instance *ti)
Shyam Sunder1f037262015-05-18 20:04:13 +053010964{
Shyam Sunder3af86a52015-08-28 18:04:10 +053010965 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10966 DEBUG_ASSERT(ti->ci, "%p: Bad multicast connection instance \n", ti);
10967
10968 return ti->ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053010969}
Shyam Sunder3af86a52015-08-28 18:04:10 +053010970EXPORT_SYMBOL(ecm_db_multicast_connection_get_from_tuple);
Shyam Sunder1f037262015-05-18 20:04:13 +053010971
10972/*
10973 * ecm_db_multicast_connection_to_interfaces_deref_all()
10974 * Deref all destination multicast interface heirarchies at once
10975 */
10976void ecm_db_multicast_connection_to_interfaces_deref_all(struct ecm_db_iface_instance *interfaces, int32_t *ifaces_first)
10977{
10978 struct ecm_db_iface_instance *ifaces_single;
10979 struct ecm_db_iface_instance *ii_temp[ECM_DB_IFACE_HEIRARCHY_MAX];
10980 int32_t *to_first;
10981 int heirarchy_index;
Shyam Sunder1f037262015-05-18 20:04:13 +053010982 DEBUG_ASSERT(interfaces, "Bad memory, multicast interfaces list has been already freed\n");
10983 DEBUG_ASSERT(ifaces_first, "Bad memory, multicast interfaces first has been already freed\n");
10984
10985 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
10986 to_first = ecm_db_multicast_if_first_get_at_index(ifaces_first, heirarchy_index);
10987 if (*to_first < ECM_DB_IFACE_HEIRARCHY_MAX) {
10988 ifaces_single = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
10989 ecm_db_multicast_copy_if_heirarchy(ii_temp, ifaces_single);
10990 ecm_db_connection_interfaces_deref(ii_temp, *to_first);
10991 }
10992 }
10993
10994 /*
10995 * Free the temporary memory allocated by ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
10996 */
10997 kfree(interfaces);
10998 kfree(ifaces_first);
10999
11000}
11001EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_deref_all);
11002
11003/*
11004 * _ecm_db_multicast_connection_to_interface_first_is_valid()
11005 * Check if destnation interfaces first list uphold a valid interface
11006 * first or all entries have discarded.
11007 */
11008static bool _ecm_db_multicast_connection_to_interface_first_is_valid(int32_t ifaces_first[])
11009{
11010 int heirarchy_index;
11011
11012 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11013 if (ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
11014 return true;
11015 }
11016 }
11017
11018 return false;
11019}
11020
11021/*
11022 * ecm_db_multicast_connection_to_interfaces_clear_at_index()
11023 * Dereference and clear a interface heirarchy at 'index' position
11024 */
11025void ecm_db_multicast_connection_to_interfaces_clear_at_index(struct ecm_db_connection_instance *ci, uint32_t index)
11026{
11027 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011028 struct ecm_db_iface_instance *ifaces_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053011029 int32_t discard_first;
Shyam Sunder1f037262015-05-18 20:04:13 +053011030
11031 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11032
11033 /*
11034 * Invalid Index Value
11035 */
11036 DEBUG_ASSERT((index < ECM_DB_MULTICAST_IF_MAX), "%p: Invalid index for multicast interface heirarchies list %u\n", ci, index);
11037
11038 spin_lock_bh(&ecm_db_lock);
11039 if (ci->to_mcast_interface_first[index] == ECM_DB_IFACE_HEIRARCHY_MAX) {
11040 spin_unlock_bh(&ecm_db_lock);
11041 return;
11042 }
11043
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011044 ifaces_db_single = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, index);
11045 ecm_db_multicast_copy_if_heirarchy(discard, ifaces_db_single);
Shyam Sunder1f037262015-05-18 20:04:13 +053011046
11047 discard_first = ci->to_mcast_interface_first[index];
11048 ci->to_mcast_interface_first[index] = ECM_DB_IFACE_HEIRARCHY_MAX;
11049
11050 /*
11051 * If this is the only valid interface hierarchy left in the list of destination
11052 * interface hierarchies then clear the ci->to_mcast_interfaces_set flag here before
11053 * deleting this.
11054 */
11055 if (!_ecm_db_multicast_connection_to_interface_first_is_valid(ci->to_mcast_interface_first)) {
11056 ci->to_mcast_interfaces_set = false;
11057 }
11058
11059 spin_unlock_bh(&ecm_db_lock);
11060
11061 ecm_db_connection_interfaces_deref(discard, discard_first);
11062}
11063EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear_at_index);
11064
11065/*
11066 * ecm_db_multicast_connection_to_interfaces_clear()
11067 * Deref and clear all destination multicast interface heirarchies
11068 */
11069void ecm_db_multicast_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
11070{
11071 int heirarchy_index;
11072 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11073
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011074 spin_lock_bh(&ecm_db_lock);
11075 if (!ci->to_mcast_interfaces) {
11076 spin_unlock_bh(&ecm_db_lock);
11077 return;
11078 }
11079
Shyam Sunder1f037262015-05-18 20:04:13 +053011080 _ecm_db_multicast_connection_to_interfaces_set_clear(ci);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011081 spin_unlock_bh(&ecm_db_lock);
11082
Shyam Sunder1f037262015-05-18 20:04:13 +053011083 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11084 ecm_db_multicast_connection_to_interfaces_clear_at_index(ci, heirarchy_index);
11085 }
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011086
11087 kfree(ci->to_mcast_interfaces);
11088 ci->to_mcast_interfaces = NULL;
Shyam Sunder1f037262015-05-18 20:04:13 +053011089}
11090EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear);
11091#endif
11092
Ben Menchaca84f36632014-02-28 20:57:38 +000011093/*
11094 * ecm_db_time_get()
11095 * Return database time, in seconds since the database started.
11096 */
11097uint32_t ecm_db_time_get(void)
11098{
11099 uint32_t time_now;
11100 spin_lock_bh(&ecm_db_lock);
11101 time_now = ecm_db_time;
11102 spin_unlock_bh(&ecm_db_lock);
11103 return time_now;
11104}
11105EXPORT_SYMBOL(ecm_db_time_get);
11106
11107/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011108 * ecm_db_get_defunct_all()
11109 * Reading this file returns the accumulated total of all objects
11110 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011111static ssize_t ecm_db_get_defunct_all(struct file *file,
11112 char __user *user_buf,
11113 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011114{
Murat Sezgin908ecb32015-05-10 20:54:36 -070011115 int ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011116 int num;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011117 char *buf;
11118
11119 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11120 if (!buf) {
11121 return -ENOMEM;
11122 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011123
11124 /*
11125 * Operate under our locks
11126 */
11127 spin_lock_bh(&ecm_db_lock);
11128 num = ecm_db_connection_count + ecm_db_mapping_count + ecm_db_host_count
11129 + ecm_db_node_count + ecm_db_iface_count;
11130 spin_unlock_bh(&ecm_db_lock);
11131
Murat Sezgin908ecb32015-05-10 20:54:36 -070011132 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
11133 if (ret < 0) {
11134 kfree(buf);
11135 return ret;
11136 }
11137
11138 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11139 kfree(buf);
11140 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011141}
11142
11143/*
11144 * ecm_db_set_defunct_all()
11145 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011146static ssize_t ecm_db_set_defunct_all(struct file *file,
11147 const char __user *user_buf,
11148 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011149{
11150 ecm_db_connection_defunct_all();
Murat Sezgin908ecb32015-05-10 20:54:36 -070011151 return sz;
Ben Menchaca84f36632014-02-28 20:57:38 +000011152}
11153
11154/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011155 * File operations for defunct_all.
11156 */
11157static struct file_operations ecm_db_defunct_all_fops = {
11158 .read = ecm_db_get_defunct_all,
11159 .write = ecm_db_set_defunct_all,
11160};
11161
11162/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011163 * ecm_db_get_connection_counts_simple()
11164 * Return total of connections for each simple protocol (tcp, udp, other). Primarily for use by the luci-bwc service.
11165 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011166static ssize_t ecm_db_get_connection_counts_simple(struct file *file,
11167 char __user *user_buf,
11168 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011169{
11170 int tcp_count;
11171 int udp_count;
11172 int other_count;
11173 int total_count;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011174 int ret;
11175 char *buf;
11176
11177 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11178 if (!buf) {
11179 return -ENOMEM;
11180 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011181
11182 /*
11183 * Get snapshot of the protocol counts
11184 */
11185 spin_lock_bh(&ecm_db_lock);
11186 tcp_count = ecm_db_connection_count_by_protocol[IPPROTO_TCP];
11187 udp_count = ecm_db_connection_count_by_protocol[IPPROTO_UDP];
11188 total_count = ecm_db_connection_count;
11189 other_count = total_count - (tcp_count + udp_count);
11190 spin_unlock_bh(&ecm_db_lock);
11191
Murat Sezgin908ecb32015-05-10 20:54:36 -070011192 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "tcp %d udp %d other %d total %d\n", tcp_count, udp_count, other_count, total_count);
11193 if (ret < 0) {
11194 kfree(buf);
11195 return -EFAULT;
11196 }
11197
11198 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11199 kfree(buf);
11200 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011201}
11202
Ben Menchaca84f36632014-02-28 20:57:38 +000011203/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011204 * File operations for simple connection counts.
Ben Menchaca84f36632014-02-28 20:57:38 +000011205 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011206static struct file_operations ecm_db_connection_count_simple_fops = {
11207 .read = ecm_db_get_connection_counts_simple,
Ben Menchaca84f36632014-02-28 20:57:38 +000011208};
11209
11210/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011211 * ecm_db_timer_callback()
11212 * Manage expiration of connections
11213 * NOTE: This is softirq context
11214 */
11215static void ecm_db_timer_callback(unsigned long data)
11216{
11217 uint32_t timer;
11218
11219 /*
11220 * Increment timer.
11221 */
11222 spin_lock_bh(&ecm_db_lock);
11223 timer = ++ecm_db_time;
11224 spin_unlock_bh(&ecm_db_lock);
11225 DEBUG_TRACE("Garbage timer tick %d\n", timer);
11226
11227 /*
11228 * Check timer groups
11229 */
11230 ecm_db_timer_groups_check(timer);
11231
11232 /*
11233 * Set the timer for the next second
11234 */
11235 ecm_db_timer.expires += HZ;
11236 if (ecm_db_timer.expires <= jiffies) {
11237 DEBUG_WARN("losing time %lu, jiffies = %lu\n", ecm_db_timer.expires, jiffies);
11238 ecm_db_timer.expires = jiffies + HZ;
11239 }
11240 add_timer(&ecm_db_timer);
11241}
Gareth Williamsd5618a82015-05-20 11:13:32 +010011242#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000011243/*
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011244 * ecm_db_node_from_connections_get_and_ref_first()
11245 * Obtain a ref to the first connection instance of "from list" of node, if any
11246 */
11247static inline struct ecm_db_connection_instance *ecm_db_node_from_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11248{
11249 struct ecm_db_connection_instance *ci;
11250 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11251 spin_lock_bh(&ecm_db_lock);
11252 ci = node->from_connections;
11253 if (ci) {
11254 _ecm_db_connection_ref(ci);
11255 }
11256 spin_unlock_bh(&ecm_db_lock);
11257 return ci;
11258}
11259
11260/*
11261 * ecm_db_node_from_connection_get_and_ref_next()
11262 * Return the next connection in the "from list" of given a connection
11263 */
11264static inline struct ecm_db_connection_instance *ecm_db_node_from_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11265{
11266 struct ecm_db_connection_instance *cin;
11267 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11268 spin_lock_bh(&ecm_db_lock);
11269 cin = ci->node_from_next;
11270 if (cin) {
11271 _ecm_db_connection_ref(cin);
11272 }
11273 spin_unlock_bh(&ecm_db_lock);
11274 return cin;
11275}
11276
11277/*
11278 * ecm_db_node_to_connections_get_and_ref_first()
11279 * Obtain a ref to the first connection instance of a "to list" of node, if any
11280 */
11281static inline struct ecm_db_connection_instance *ecm_db_node_to_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11282{
11283 struct ecm_db_connection_instance *ci;
11284 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11285 spin_lock_bh(&ecm_db_lock);
11286 ci = node->to_connections;
11287 if (ci) {
11288 _ecm_db_connection_ref(ci);
11289 }
11290 spin_unlock_bh(&ecm_db_lock);
11291 return ci;
11292}
11293
11294/*
11295 * ecm_db_node_to_connection_get_and_ref_next()
11296 * Return the next connection in the "to list" of given a connection
11297 */
11298static inline struct ecm_db_connection_instance *ecm_db_node_to_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11299{
11300 struct ecm_db_connection_instance *cin;
11301 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11302 spin_lock_bh(&ecm_db_lock);
11303 cin = ci->node_to_next;
11304 if (cin) {
11305 _ecm_db_connection_ref(cin);
11306 }
11307 spin_unlock_bh(&ecm_db_lock);
11308 return cin;
11309}
11310
11311/*
11312 * ecm_db_node_from_nat_connections_get_and_ref_first()
11313 * Obtain a ref to the first connection instance of a "from_nat list" of node, if any
11314 */
11315static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11316{
11317 struct ecm_db_connection_instance *ci;
11318 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11319 spin_lock_bh(&ecm_db_lock);
11320 ci = node->from_nat_connections;
11321 if (ci) {
11322 _ecm_db_connection_ref(ci);
11323 }
11324 spin_unlock_bh(&ecm_db_lock);
11325 return ci;
11326}
11327
11328/*
11329 * ecm_db_node_from_nat_connection_get_and_ref_next()
11330 * Return the next connection in the "from nat list" of given a connection
11331 */
11332static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11333{
11334 struct ecm_db_connection_instance *cin;
11335 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11336 spin_lock_bh(&ecm_db_lock);
11337 cin = ci->node_from_nat_next;
11338 if (cin) {
11339 _ecm_db_connection_ref(cin);
11340 }
11341 spin_unlock_bh(&ecm_db_lock);
11342 return cin;
11343}
11344
11345/*
11346 * ecm_db_node_to_nat_connections_get_and_ref_first()
11347 * Obtain a ref to the first connection instance of a "to_nat list" of node, if any
11348 */
11349static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11350{
11351 struct ecm_db_connection_instance *ci;
11352 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11353 spin_lock_bh(&ecm_db_lock);
11354 ci = node->to_nat_connections;
11355 if (ci) {
11356 _ecm_db_connection_ref(ci);
11357 }
11358 spin_unlock_bh(&ecm_db_lock);
11359 return ci;
11360}
11361
11362/*
11363 * ecm_db_node_to_nat_connection_get_and_ref_next()
11364 * Return the next connection in the "to nat list" of given a connection
11365 */
11366static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11367{
11368 struct ecm_db_connection_instance *cin;
11369 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11370 spin_lock_bh(&ecm_db_lock);
11371 cin = ci->node_to_nat_next;
11372 if (cin) {
11373 _ecm_db_connection_ref(cin);
11374 }
11375 spin_unlock_bh(&ecm_db_lock);
11376 return cin;
11377}
11378
11379/*
11380 * ecm_db_connection_decelerate_and_defunct()
11381 * decelerate and defunct a connection
11382 */
11383static inline void ecm_db_connection_decelerate_and_defunct(struct ecm_db_connection_instance *ci)
11384{
11385 struct ecm_front_end_connection_instance *feci = NULL;
11386
11387 if(unlikely(!ci)) {
11388 DEBUG_WARN("%p: ecm db connection instance pointer is null\n", ci);
11389 return;
11390 }
11391
11392 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11393
11394 feci = ecm_db_connection_front_end_get_and_ref(ci);
11395
11396 feci->decelerate(feci);
11397 feci->deref(feci);
11398 ecm_db_connection_make_defunct(ci);
11399}
11400
11401/*
11402 * ecm_db_traverse_node_from_connection_list_and_decelerate()
11403 * traverse from_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11404 * for each entry
11405 */
11406void ecm_db_traverse_node_from_connection_list_and_decelerate(struct ecm_db_node_instance *node)
11407{
11408 struct ecm_db_connection_instance *ci = NULL;
11409
11410 /*
11411 * Iterate all from connections
11412 */
11413 ci = ecm_db_node_from_connections_get_and_ref_first(node);
11414 while (ci) {
11415 struct ecm_db_connection_instance *cin;
11416
11417 DEBUG_TRACE("%p: defunct\n", ci);
11418 ecm_db_connection_decelerate_and_defunct(ci);
11419
11420 cin = ecm_db_node_from_connection_get_and_ref_next(ci);
11421 ecm_db_connection_deref(ci);
11422 ci = cin;
11423 }
11424 DEBUG_INFO("%p: Defuncting node's from connection list complete\n", node);
11425}
11426
11427/*
11428 * ecm_db_traverse_node_to_connection_list_and_decelerate()
11429 * traverse to_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11430 * for each entry
11431 */
11432void ecm_db_traverse_node_to_connection_list_and_decelerate(struct ecm_db_node_instance *node)
11433{
11434 struct ecm_db_connection_instance *ci = NULL;
11435
11436 /*
11437 * Iterate all to connections
11438 */
11439 ci = ecm_db_node_to_connections_get_and_ref_first(node);
11440 while (ci) {
11441 struct ecm_db_connection_instance *cin;
11442
11443 DEBUG_TRACE("%p: defunct\n", ci);
11444 ecm_db_connection_decelerate_and_defunct(ci);
11445
11446 cin = ecm_db_node_to_connection_get_and_ref_next(ci);
11447 ecm_db_connection_deref(ci);
11448 ci = cin;
11449 }
11450 DEBUG_INFO("%p: Defuncting node's to connection list complete\n", node);
11451}
11452
11453/*
11454 * ecm_db_traverse_node_from_nat_connection_list_and_decelerate()
11455 * traverse from_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11456 * for each entry
11457 */
11458void ecm_db_traverse_node_from_nat_connection_list_and_decelerate(struct ecm_db_node_instance *node)
11459{
11460 struct ecm_db_connection_instance *ci = NULL;
11461
11462 /*
11463 * Iterate all from nat connections
11464 */
11465 ci = ecm_db_node_from_nat_connections_get_and_ref_first(node);
11466 while (ci) {
11467 struct ecm_db_connection_instance *cin;
11468
11469 DEBUG_TRACE("%p: defunct\n", ci);
11470 ecm_db_connection_decelerate_and_defunct(ci);
11471
11472 cin = ecm_db_node_from_nat_connection_get_and_ref_next(ci);
11473 ecm_db_connection_deref(ci);
11474 ci = cin;
11475 }
11476 DEBUG_INFO("%p: Defuncting node's from nat connection list complete\n", node);
11477}
11478
11479/*
11480 * ecm_db_traverse_node_to_nat_connection_list_and_decelerate()
11481 * traverse to_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11482 * for each entry
11483 */
11484void ecm_db_traverse_node_to_nat_connection_list_and_decelerate(struct ecm_db_node_instance *node)
11485{
11486 struct ecm_db_connection_instance *ci = NULL;
11487
11488 /*
11489 * Iterate all to nat connections
11490 */
11491 ci = ecm_db_node_to_nat_connections_get_and_ref_first(node);
11492 while (ci) {
11493 struct ecm_db_connection_instance *cin;
11494
11495 DEBUG_TRACE("%p: defunct\n", ci);
11496 ecm_db_connection_decelerate_and_defunct(ci);
11497
11498 cin = ecm_db_node_to_nat_connection_get_and_ref_next(ci);
11499 ecm_db_connection_deref(ci);
11500 ci = cin;
11501 }
11502 DEBUG_INFO("%p: Defuncting to node's nat connection list complete\n", node);
11503}
Murat Sezgin8c345822015-05-27 15:35:38 -070011504#endif
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011505/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011506 * ecm_db_init()
Ben Menchaca84f36632014-02-28 20:57:38 +000011507 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011508int ecm_db_init(struct dentry *dentry)
Ben Menchaca84f36632014-02-28 20:57:38 +000011509{
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011510 DEBUG_INFO("ECM Module init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +000011511
Murat Sezgin908ecb32015-05-10 20:54:36 -070011512 ecm_db_dentry = debugfs_create_dir("ecm_db", dentry);
11513 if (!ecm_db_dentry) {
11514 DEBUG_ERROR("Failed to create ecm db directory in debugfs\n");
11515 return -1;
11516 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011517
11518 /*
Gareth Williams54d15d92015-04-24 19:28:27 +010011519 * Get a random seed for jhash()
11520 */
11521 get_random_bytes(&ecm_db_jhash_rnd, sizeof(ecm_db_jhash_rnd));
11522 DEBUG_INFO("jhash random seed: %u\n", ecm_db_jhash_rnd);
11523
Murat Sezgin908ecb32015-05-10 20:54:36 -070011524 if (!debugfs_create_u32("connection_count", S_IRUGO, ecm_db_dentry,
11525 (u32 *)&ecm_db_connection_count)) {
11526 DEBUG_ERROR("Failed to create ecm db connection count file in debugfs\n");
11527 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000011528 }
11529
Murat Sezgin908ecb32015-05-10 20:54:36 -070011530 if (!debugfs_create_u32("host_count", S_IRUGO, ecm_db_dentry,
11531 (u32 *)&ecm_db_host_count)) {
11532 DEBUG_ERROR("Failed to create ecm db host count file in debugfs\n");
11533 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000011534 }
11535
Murat Sezgin908ecb32015-05-10 20:54:36 -070011536 if (!debugfs_create_u32("mapping_count", S_IRUGO, ecm_db_dentry,
11537 (u32 *)&ecm_db_mapping_count)) {
11538 DEBUG_ERROR("Failed to create ecm db mapping count file in debugfs\n");
11539 goto init_cleanup;
11540 }
11541
11542 if (!debugfs_create_u32("node_count", S_IRUGO, ecm_db_dentry,
11543 (u32 *)&ecm_db_node_count)) {
11544 DEBUG_ERROR("Failed to create ecm db node count file in debugfs\n");
11545 goto init_cleanup;
11546 }
11547
11548 if (!debugfs_create_u32("iface_count", S_IRUGO, ecm_db_dentry,
11549 (u32 *)&ecm_db_iface_count)) {
11550 DEBUG_ERROR("Failed to create ecm db iface count file in debugfs\n");
11551 goto init_cleanup;
11552 }
11553
11554 if (!debugfs_create_file("defunct_all", S_IRUGO | S_IWUSR, ecm_db_dentry,
11555 NULL, &ecm_db_defunct_all_fops)) {
11556 DEBUG_ERROR("Failed to create ecm db defunct_all file in debugfs\n");
11557 goto init_cleanup;
11558 }
11559
11560 if (!debugfs_create_file("connection_count_simple", S_IRUGO, ecm_db_dentry,
11561 NULL, &ecm_db_connection_count_simple_fops)) {
11562 DEBUG_ERROR("Failed to create ecm db connection count simple file in debugfs\n");
11563 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000011564 }
11565
11566 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000011567 * Set a timer to manage cleanup of expired connections
11568 */
11569 init_timer(&ecm_db_timer);
11570 ecm_db_timer.function = ecm_db_timer_callback;
11571 ecm_db_timer.data = 0;
11572 ecm_db_timer.expires = jiffies + HZ;
11573 add_timer(&ecm_db_timer);
11574
11575 /*
11576 * Initialise timer groups with time values
11577 */
11578 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].time = ECM_DB_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
11579 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
11580 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_GENERIC_TIMEOUT;
11581 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT;
11582 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].time = ECM_DB_CONNECTION_IGMP_TIMEOUT;
11583 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT;
11584 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
11585 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT;
11586 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
11587 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT;
11588 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].time = ECM_DB_CONNECTION_ICMP_TIMEOUT;
11589 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT;
11590 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].time = ECM_DB_CONNECTION_TCP_SHORT_TIMEOUT;
11591 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT;
11592 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].time = ECM_DB_CONNECTION_TCP_RST_TIMEOUT;
11593 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT;
11594 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
11595 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT;
11596 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].time = ECM_DB_CONNECTION_PPTP_DATA_TIMEOUT;
11597 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT;
11598 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].time = ECM_DB_CONNECTION_RTCP_TIMEOUT;
11599 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT;
11600 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
11601 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT;
11602 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_FAST_TIMEOUT;
11603 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT;
11604 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_SLOW_TIMEOUT;
11605 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT;
11606 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].time = ECM_DB_CONNECTION_DNS_TIMEOUT;
11607 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT;
11608 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].time = ECM_DB_CONNECTION_FTP_TIMEOUT;
11609 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT;
11610 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].time = ECM_DB_CONNECTION_BITTORRENT_TIMEOUT;
11611 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT;
11612
11613 /*
11614 * H323 timeout value is 8 hours (8h * 60m * 60s == 28800 seconds).
11615 */
11616 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].time = ECM_DB_CONNECTION_H323_TIMEOUT;
11617 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT;
11618
11619 /*
11620 * IKE Timeout (seconds) = 15 hours
11621 */
11622 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].time = ECM_DB_CONNECTION_IKE_TIMEOUT;
11623 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT;
11624
11625 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].time = ECM_DB_CONNECTION_ESP_TIMEOUT;
11626 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT;
11627 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].time = ECM_DB_CONNECTION_ESP_PENDING_TIMEOUT;
11628 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT;
11629
11630 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].time = ECM_DB_CONNECTION_SDP_TIMEOUT;
11631 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT;
11632 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].time = ECM_DB_CONNECTION_SIP_TIMEOUT;
11633 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT;
11634
11635 /*
11636 * Reset connection by protocol counters
11637 */
11638 memset(ecm_db_connection_count_by_protocol, 0, sizeof(ecm_db_connection_count_by_protocol));
11639
Gareth Williamsb39e7c22015-03-25 10:15:33 +000011640#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010011641 /*
11642 * Reset classifier type assignment lists
11643 */
11644 memset(ecm_db_connection_classifier_type_assignments, 0, sizeof(ecm_db_connection_classifier_type_assignments));
Gareth Williamsb39e7c22015-03-25 10:15:33 +000011645#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011646 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +000011647
Murat Sezgin908ecb32015-05-10 20:54:36 -070011648init_cleanup:
Ben Menchaca84f36632014-02-28 20:57:38 +000011649
Murat Sezgin908ecb32015-05-10 20:54:36 -070011650 debugfs_remove_recursive(ecm_db_dentry);
11651 return -1;
Ben Menchaca84f36632014-02-28 20:57:38 +000011652}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011653EXPORT_SYMBOL(ecm_db_init);
Ben Menchaca84f36632014-02-28 20:57:38 +000011654
11655/*
11656 * ecm_db_exit()
11657 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011658void ecm_db_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +000011659{
11660 DEBUG_INFO("ECM DB Module exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011661
11662 spin_lock_bh(&ecm_db_lock);
11663 ecm_db_terminate_pending = true;
11664 spin_unlock_bh(&ecm_db_lock);
11665
11666 ecm_db_connection_defunct_all();
11667
11668 /*
11669 * Destroy garbage timer
11670 * Timer must be cancelled outside of holding db lock - if the
11671 * timer callback runs on another CPU we would deadlock
11672 * as we would wait for the callback to finish and it would wait
11673 * indefinately for the lock to be released!
11674 */
11675 del_timer_sync(&ecm_db_timer);
Murat Sezgin1f381852014-11-20 09:51:07 -080011676
Murat Sezgin908ecb32015-05-10 20:54:36 -070011677 /*
11678 * Remove the debugfs files recursively.
11679 */
11680 if (ecm_db_dentry) {
11681 debugfs_remove_recursive(ecm_db_dentry);
Murat Sezgin1f381852014-11-20 09:51:07 -080011682 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011683}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011684EXPORT_SYMBOL(ecm_db_exit);