blob: 280e54731f5215139227ca109d1d9179249cf2c2 [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>
Murat Sezgin1134fb82015-10-06 14:03:49 -070035#include <net/ip6_route.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000036#include <linux/inet.h>
37#include <linux/in.h>
38#include <linux/udp.h>
39#include <linux/tcp.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000040#include <linux/netfilter_ipv4.h>
41#include <linux/netfilter_bridge.h>
42#include <net/netfilter/nf_conntrack.h>
43#include <net/netfilter/nf_conntrack_helper.h>
44#include <net/netfilter/nf_conntrack_l4proto.h>
45#include <net/netfilter/nf_conntrack_l3proto.h>
46#include <net/netfilter/nf_conntrack_core.h>
47#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
48#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
49
50/*
51 * Debug output levels
52 * 0 = OFF
53 * 1 = ASSERTS / ERRORS
54 * 2 = 1 + WARN
55 * 3 = 2 + INFO
56 * 4 = 3 + TRACE
57 */
58#define DEBUG_LEVEL ECM_DB_DEBUG_LEVEL
59
Ben Menchaca84f36632014-02-28 20:57:38 +000060#include "ecm_types.h"
61#include "ecm_db_types.h"
Gareth Williamsd5618a82015-05-20 11:13:32 +010062#include "ecm_state.h"
Ben Menchaca84f36632014-02-28 20:57:38 +000063#include "ecm_tracker.h"
64#include "ecm_classifier.h"
65#include "ecm_front_end_types.h"
66#include "ecm_classifier_default.h"
67#include "ecm_db.h"
68
69/*
70 * Magic numbers
71 */
72#define ECM_DB_CONNECTION_INSTANCE_MAGIC 0xff23
73#define ECM_DB_HOST_INSTANCE_MAGIC 0x2873
74#define ECM_DB_MAPPING_INSTANCE_MAGIC 0x8765
75#define ECM_DB_LISTENER_INSTANCE_MAGIC 0x9876
76#define ECM_DB_NODE_INSTANCE_MAGIC 0x3312
77#define ECM_DB_IFACE_INSTANCE_MAGIC 0xAEF1
Gareth Williamsb39e7c22015-03-25 10:15:33 +000078#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010079#define ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC 0xAEF4
Gareth Williamsb39e7c22015-03-25 10:15:33 +000080#endif
Shyam Sunder1f037262015-05-18 20:04:13 +053081#ifdef ECM_MULTICAST_ENABLE
82#define ECM_DB_MULTICAST_INSTANCE_MAGIC 0xc34a
83#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000084
85/*
86 * Global lists.
87 * All instances are inserted into global list - this allows easy iteration of all instances of a particular type.
88 * The list is doubly linked for fast removal. The list is in no particular order.
89 */
90struct ecm_db_connection_instance *ecm_db_connections = NULL;
91struct ecm_db_mapping_instance *ecm_db_mappings = NULL;
92struct ecm_db_host_instance *ecm_db_hosts = NULL;
93struct ecm_db_node_instance *ecm_db_nodes = NULL;
94struct ecm_db_iface_instance *ecm_db_interfaces = NULL;
95
96/*
97 * Connection hash table
98 */
99#define ECM_DB_CONNECTION_HASH_SLOTS 32768
100static struct ecm_db_connection_instance *ecm_db_connection_table[ECM_DB_CONNECTION_HASH_SLOTS];
101 /* Slots of the connection hash table */
102static int ecm_db_connection_table_lengths[ECM_DB_CONNECTION_HASH_SLOTS];
103 /* Tracks how long each chain is */
104static int ecm_db_connection_count = 0; /* Number of connections allocated */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100105static int ecm_db_connection_serial = 0; /* Serial number - ensures each connection has a unique serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000106 * Serial numbers are used mainly by classifiers that keep their own state
107 * and can 'link' their state to the right connection using a serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000108 * The serial number is also used as a soft linkage to other subsystems such as NA.
109 */
110typedef uint32_t ecm_db_connection_hash_t;
111
112/*
113 * Connection serial number hash table
114 */
115#define ECM_DB_CONNECTION_SERIAL_HASH_SLOTS 32768
116static struct ecm_db_connection_instance *ecm_db_connection_serial_table[ECM_DB_CONNECTION_SERIAL_HASH_SLOTS];
117 /* Slots of the connection serial hash table */
118static int ecm_db_connection_serial_table_lengths[ECM_DB_CONNECTION_SERIAL_HASH_SLOTS];
119 /* Tracks how long each chain is */
120typedef uint32_t ecm_db_connection_serial_hash_t;
121
122/*
123 * Mapping hash table
124 */
125#define ECM_DB_MAPPING_HASH_SLOTS 32768
126static struct ecm_db_mapping_instance *ecm_db_mapping_table[ECM_DB_MAPPING_HASH_SLOTS];
127 /* Slots of the mapping hash table */
128static int ecm_db_mapping_table_lengths[ECM_DB_MAPPING_HASH_SLOTS];
129 /* Tracks how long each chain is */
130static int ecm_db_mapping_count = 0; /* Number of mappings allocated */
131typedef uint32_t ecm_db_mapping_hash_t;
132
133/*
134 * Host hash table
135 */
136#define ECM_DB_HOST_HASH_SLOTS 32768
137static struct ecm_db_host_instance *ecm_db_host_table[ECM_DB_HOST_HASH_SLOTS];
138 /* Slots of the host hash table */
139static int ecm_db_host_table_lengths[ECM_DB_HOST_HASH_SLOTS];
140 /* Tracks how long each chain is */
141static int ecm_db_host_count = 0; /* Number of hosts allocated */
142typedef uint32_t ecm_db_host_hash_t;
143
144/*
145 * Node hash table
146 */
147#define ECM_DB_NODE_HASH_SLOTS 32768
148static struct ecm_db_node_instance *ecm_db_node_table[ECM_DB_NODE_HASH_SLOTS];
149 /* Slots of the node hash table */
150static int ecm_db_node_table_lengths[ECM_DB_NODE_HASH_SLOTS];
151 /* Tracks how long each chain is */
152static int ecm_db_node_count = 0; /* Number of nodes allocated */
153typedef uint32_t ecm_db_node_hash_t;
154
155/*
156 * Interface hash table
157 */
158#define ECM_DB_IFACE_HASH_SLOTS 8
159static struct ecm_db_iface_instance *ecm_db_iface_table[ECM_DB_IFACE_HASH_SLOTS];
160 /* Slots of the interface hash table */
161static int ecm_db_iface_table_lengths[ECM_DB_IFACE_HASH_SLOTS];
162 /* Tracks how long each chain is */
163static int ecm_db_iface_count = 0; /* Number of interfaces allocated */
164typedef uint32_t ecm_db_iface_hash_t;
165
Murat Sezgin91c5d712015-06-12 15:16:22 -0700166#define ECM_DB_IFACE_ID_HASH_SLOTS 8
167static struct ecm_db_iface_instance *ecm_db_iface_id_table[ECM_DB_IFACE_ID_HASH_SLOTS];
168 /* Slots of the interface id hash table */
169static int ecm_db_iface_id_table_lengths[ECM_DB_IFACE_ID_HASH_SLOTS];
170 /* Tracks how long each chain is */
171typedef uint32_t ecm_db_iface_id_hash_t;
172
Ben Menchaca84f36632014-02-28 20:57:38 +0000173/*
174 * Listeners
175 */
176static int ecm_db_listeners_count = 0; /* Number of listeners allocated */
177static struct ecm_db_listener_instance *ecm_db_listeners = NULL;
178 /* Event listeners */
179
Gareth Williamsf98d4192015-03-11 16:55:41 +0000180#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000181/*
Gareth Williamsd5618a82015-05-20 11:13:32 +0100182 * ecm_db_iface_state_get_method_t
183 * Used to obtain interface state
Ben Menchaca84f36632014-02-28 20:57:38 +0000184 */
Gareth Williamsd5618a82015-05-20 11:13:32 +0100185typedef 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 +0000186#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000187
188/*
189 * struct ecm_db_iface_instance
190 */
191struct ecm_db_iface_instance {
192 struct ecm_db_iface_instance *next; /* Next instance in global list */
193 struct ecm_db_iface_instance *prev; /* Previous instance in global list */
194 struct ecm_db_iface_instance *hash_next; /* Next Interface in the chain of Interfaces */
195 struct ecm_db_iface_instance *hash_prev; /* previous Interface in the chain of Interfaces */
196 ecm_db_iface_type_t type; /* RO: Type of interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000197 uint32_t time_added; /* RO: DB time stamp when the Interface was added into the database */
198
199 int32_t interface_identifier; /* RO: The operating system dependent identifier of this interface */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700200 int32_t ae_interface_identifier; /* RO: The accel engine identifier of this interface */
Ben Menchaca84f36632014-02-28 20:57:38 +0000201 char name[IFNAMSIZ]; /* Name of interface */
202 int32_t mtu; /* Interface MTU */
203
Murat Sezgin91c5d712015-06-12 15:16:22 -0700204 struct ecm_db_iface_instance *iface_id_hash_next; /* Next interface in the chain of interface id table */
205 struct ecm_db_iface_instance *iface_id_hash_prev; /* Previous interface in the chain of interface id table */
206 ecm_db_iface_id_hash_t iface_id_hash_index; /* Hash index value of chains */
207
Gareth Williams85331c92015-03-11 20:39:18 +0000208#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000209 uint64_t from_data_total; /* Total of data sent by this Interface */
210 uint64_t to_data_total; /* Total of data sent to this Interface */
211 uint64_t from_packet_total; /* Total of packets sent by this Interface */
212 uint64_t to_packet_total; /* Total of packets sent to this Interface */
213 uint64_t from_data_total_dropped;
214 uint64_t to_data_total_dropped;
215 uint64_t from_packet_total_dropped;
216 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000217#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000218
Gareth Williamsb5903892015-03-20 15:13:07 +0000219#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000220 /*
221 * For convenience interfaces keep lists of connections that have been established
222 * from them and to them.
223 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
224 * Interfaces keep this information for rapid iteration of connections e.g. when an interface 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700225 * can defunct all associated connections or destroy any accel engine rules.
Ben Menchaca84f36632014-02-28 20:57:38 +0000226 */
227 struct ecm_db_connection_instance *from_connections; /* list of connections made from this interface */
228 struct ecm_db_connection_instance *to_connections; /* list of connections made to this interface */
229
230 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this interface */
231 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this interface */
232
233 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000234 * Normally only the node refers to the interfaces which it is reachable upon.
235 * The interface also keeps a list of all nodes that can be reached.
236 */
237 struct ecm_db_node_instance *nodes; /* Nodes associated with this Interface */
238 int node_count; /* Number of Nodes in the nodes list */
239#endif
240
241 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000242 * Interface specific information.
243 * type identifies which information is applicable.
244 */
245 union {
246 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700247#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000248 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
Murat Sezgin37fb3952015-03-10 16:45:13 -0700249#endif
Murat Sezgin910c9662015-03-11 16:15:06 -0700250#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000251 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
Murat Sezgin910c9662015-03-11 16:15:06 -0700252#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000253 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530254#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000255 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
Murat Sezginaad635c2015-03-06 16:11:41 -0800256#endif
ratheesh kannotha32fdd12015-09-09 08:02:58 +0530257#ifdef ECM_INTERFACE_L2TPV2_ENABLE
258 struct ecm_db_interface_info_pppol2tpv2 pppol2tpv2; /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
259#endif
Shyam Sunder23f2e542015-09-28 14:56:49 +0530260#ifdef ECM_INTERFACE_PPTP_ENABLE
261 struct ecm_db_interface_info_pptp pptp; /* type == ECM_DB_IFACE_TYPE_PPTP */
262#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000263 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
264 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
Murat Sezgin69a27532015-03-12 14:09:40 -0700265#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000266 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
Murat Sezgin69a27532015-03-12 14:09:40 -0700267#endif
Murat Sezginbde55f92015-03-11 16:44:11 -0700268#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000269 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT (6-in-4) */
Murat Sezginbde55f92015-03-11 16:44:11 -0700270#endif
Murat Sezginc1402562015-03-12 12:32:20 -0700271#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +0000272#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000273 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 -0700274#endif
Gareth Williams8ac34292015-03-17 14:06:58 +0000275#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000276 } type_info;
277
Gareth Williamsf98d4192015-03-11 16:55:41 +0000278#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +0100279 ecm_db_iface_state_get_method_t state_get; /* Type specific method to return state */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000280#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000281
282 ecm_db_iface_final_callback_t final; /* Callback to owner when object is destroyed */
283 void *arg; /* Argument returned to owner in callbacks */
284 uint32_t flags;
285 int refs; /* Integer to trap we never go negative */
286 ecm_db_iface_hash_t hash_index;
287#if (DEBUG_LEVEL > 0)
288 uint16_t magic;
289#endif
290};
291
292/*
293 * Interface flags
294 */
295#define ECM_DB_IFACE_FLAGS_INSERTED 1 /* Interface is inserted into connection database tables */
296
297/*
298 * struct ecm_db_node_instance
299 */
300struct ecm_db_node_instance {
301 struct ecm_db_node_instance *next; /* Next instance in global list */
302 struct ecm_db_node_instance *prev; /* Previous instance in global list */
Gareth Williams90f2a282014-08-27 15:56:25 +0100303 struct ecm_db_node_instance *hash_next; /* Next node in the chain of nodes */
304 struct ecm_db_node_instance *hash_prev; /* previous node in the chain of nodes */
Ben Menchaca84f36632014-02-28 20:57:38 +0000305 uint8_t address[ETH_ALEN]; /* RO: MAC Address of this node */
Gareth Williams90f2a282014-08-27 15:56:25 +0100306
Gareth Williamsb5903892015-03-20 15:13:07 +0000307#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +0100308 /*
309 * For convenience nodes keep lists of connections that have been established from them and to them.
310 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
311 * Nodes keep this information for rapid iteration of connections e.g. when a node 'goes down' we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700312 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williams90f2a282014-08-27 15:56:25 +0100313 */
314 struct ecm_db_connection_instance *from_connections; /* list of connections made from this node */
315 struct ecm_db_connection_instance *to_connections; /* list of connections made to this node */
316 int from_connections_count; /* Number of connections in the from_connections list */
317 int to_connections_count; /* Number of connections in the to_connections list */
318
319 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this node */
320 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this node */
321 int from_nat_connections_count; /* Number of connections in the from_nat_connections list */
322 int to_nat_connections_count; /* Number of connections in the to_nat_connections list */
323
Gareth Williamsb5903892015-03-20 15:13:07 +0000324 /*
325 * Nodes reachable from an interface are stored in a linked list maintained by that interface.
326 * This is so, given an interface, you can examine all nodes reachable from it.
327 */
328 struct ecm_db_node_instance *node_next; /* The next node within the same iface nodes list */
329 struct ecm_db_node_instance *node_prev; /* The previous node within the same iface nodes list */
330#endif
331
Ben Menchaca84f36632014-02-28 20:57:38 +0000332 uint32_t time_added; /* RO: DB time stamp when the node was added into the database */
333
Gareth Williams85331c92015-03-11 20:39:18 +0000334#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000335 uint64_t from_data_total; /* Total of data sent by this node */
336 uint64_t to_data_total; /* Total of data sent to this node */
337 uint64_t from_packet_total; /* Total of packets sent by this node */
338 uint64_t to_packet_total; /* Total of packets sent to this node */
339 uint64_t from_data_total_dropped;
340 uint64_t to_data_total_dropped;
341 uint64_t from_packet_total_dropped;
342 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000343#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000344
345 struct ecm_db_iface_instance *iface; /* The interface to which this node relates */
Ben Menchaca84f36632014-02-28 20:57:38 +0000346
347 ecm_db_node_final_callback_t final; /* Callback to owner when object is destroyed */
348 void *arg; /* Argument returned to owner in callbacks */
349 uint8_t flags;
350 int refs; /* Integer to trap we never go negative */
351 ecm_db_node_hash_t hash_index;
352#if (DEBUG_LEVEL > 0)
353 uint16_t magic;
354#endif
355};
356
357/*
358 * Node flags
359 */
360#define ECM_DB_NODE_FLAGS_INSERTED 1 /* Node is inserted into connection database tables */
361
362/*
363 * struct ecm_db_host_instance
364 */
365struct ecm_db_host_instance {
366 struct ecm_db_host_instance *next; /* Next instance in global list */
367 struct ecm_db_host_instance *prev; /* Previous instance in global list */
368 struct ecm_db_host_instance *hash_next; /* Next host in the chain of hosts */
369 struct ecm_db_host_instance *hash_prev; /* previous host in the chain of hosts */
370 ip_addr_t address; /* RO: IPv4/v6 Address of this host */
371 bool on_link; /* RO: false when this host is reached via a gateway */
Gareth Williamsb5903892015-03-20 15:13:07 +0000372 uint32_t time_added; /* RO: DB time stamp when the host was added into the database */
373
374#ifdef ECM_DB_XREF_ENABLE
375 /*
376 * Normally the mapping refers to the host it requires.
377 * However the host also keeps a list of all mappings that are associated with it.
378 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000379 struct ecm_db_mapping_instance *mappings; /* Mappings made on this host */
380 int mapping_count; /* Number of mappings in the mapping list */
Gareth Williamsb5903892015-03-20 15:13:07 +0000381#endif
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530382
Gareth Williams85331c92015-03-11 20:39:18 +0000383#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000384 uint64_t from_data_total; /* Total of data sent by this host */
385 uint64_t to_data_total; /* Total of data sent to this host */
386 uint64_t from_packet_total; /* Total of packets sent by this host */
387 uint64_t to_packet_total; /* Total of packets sent to this host */
388 uint64_t from_data_total_dropped;
389 uint64_t to_data_total_dropped;
390 uint64_t from_packet_total_dropped;
391 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000392#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000393
394 ecm_db_host_final_callback_t final; /* Callback to owner when object is destroyed */
395 void *arg; /* Argument returned to owner in callbacks */
396 uint32_t flags;
397 int refs; /* Integer to trap we never go negative */
398 ecm_db_host_hash_t hash_index;
399#if (DEBUG_LEVEL > 0)
400 uint16_t magic;
401#endif
402};
403
404/*
405 * Host flags
406 */
407#define ECM_DB_HOST_FLAGS_INSERTED 1 /* Host is inserted into connection database tables */
408
409/*
410 * struct ecm_db_mapping_instance
411 */
412struct ecm_db_mapping_instance {
413 struct ecm_db_mapping_instance *next; /* Next instance in global list */
414 struct ecm_db_mapping_instance *prev; /* Previous instance in global list */
415
416 struct ecm_db_mapping_instance *hash_next; /* Next mapping in the chain of mappings */
417 struct ecm_db_mapping_instance *hash_prev; /* previous mapping in the chain of mappings */
418
419 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
420 struct ecm_db_host_instance *host; /* The host to which this mapping relates */
421 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 +0000422
Gareth Williamsb5903892015-03-20 15:13:07 +0000423#ifdef ECM_DB_XREF_ENABLE
424 /*
425 * For convenience mappings keep lists of connections that have been established from them and to them.
426 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
427 * Mappings keep this information for rapid iteration of connections e.g. given a mapping we
Murat Sezgin91c5d712015-06-12 15:16:22 -0700428 * can defunct all associated connections or destroy any accel engine rules.
Gareth Williamsb5903892015-03-20 15:13:07 +0000429 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000430 struct ecm_db_connection_instance *from_connections; /* list of connections made from this host mapping */
431 struct ecm_db_connection_instance *to_connections; /* list of connections made to this host mapping */
432
433 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this host mapping */
434 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this host mapping */
435
436 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000437 * While a mapping refers to the host it requires.
438 * The host also keeps a list of all mappings that are associated with it, this is that list linkage.
439 */
440 struct ecm_db_mapping_instance *mapping_next; /* Next mapping in the list of mappings for the host */
441 struct ecm_db_mapping_instance *mapping_prev; /* previous mapping in the list of mappings for the host */
442#endif
443
444 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000445 * Connection counts
446 */
447 int tcp_from;
448 int tcp_to;
449 int udp_from;
450 int udp_to;
451 int tcp_nat_from;
452 int tcp_nat_to;
453 int udp_nat_from;
454 int udp_nat_to;
455
456 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000457 * Connection counts
Ben Menchaca84f36632014-02-28 20:57:38 +0000458 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000459 int from; /* Number of connections made from */
460 int to; /* Number of connections made to */
461 int nat_from; /* Number of connections made from (nat) */
462 int nat_to; /* Number of connections made to (nat) */
Ben Menchaca84f36632014-02-28 20:57:38 +0000463
Gareth Williams85331c92015-03-11 20:39:18 +0000464#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000465 /*
466 * Data totals
467 */
468 uint64_t from_data_total; /* Total of data sent by this mapping */
469 uint64_t to_data_total; /* Total of data sent to this mapping */
470 uint64_t from_packet_total; /* Total of packets sent by this mapping */
471 uint64_t to_packet_total; /* Total of packets sent to this mapping */
472 uint64_t from_data_total_dropped;
473 uint64_t to_data_total_dropped;
474 uint64_t from_packet_total_dropped;
475 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +0000476#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000477
478 ecm_db_mapping_final_callback_t final; /* Callback to owner when object is destroyed */
479 void *arg; /* Argument returned to owner in callbacks */
480 uint32_t flags;
481 int refs; /* Integer to trap we never go negative */
482 ecm_db_mapping_hash_t hash_index;
483#if (DEBUG_LEVEL > 0)
484 uint16_t magic;
485#endif
486};
487
488/*
489 * Mapping flags
490 */
491#define ECM_DB_MAPPING_FLAGS_INSERTED 1 /* Mapping is inserted into connection database tables */
492
493/*
494 * struct ecm_db_timer_group
495 * A timer group - all group members within the same group have the same TTL reset value.
496 *
497 * Expiry of entries occurs from tail to head.
498 */
499struct ecm_db_timer_group {
500 struct ecm_db_timer_group_entry *head; /* Most recently used entry in this timer group */
501 struct ecm_db_timer_group_entry *tail; /* Least recently used entry in this timer group. */
502 uint32_t time; /* Time in seconds a group entry will be given to live when 'touched' */
503 ecm_db_timer_group_t tg; /* RO: The group id */
504#if (DEBUG_LEVEL > 0)
505 uint16_t magic;
506#endif
507};
508
509/*
510 * Timers and cleanup
511 */
512static uint32_t ecm_db_time = 0; /* Time in seconds since start */
513static struct ecm_db_timer_group ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_MAX];
514 /* Timer groups */
515static struct timer_list ecm_db_timer; /* Timer to drive timer groups */
516
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000517#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +0000518/*
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000519 * Classifier TYPE assignment lists.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100520 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000521 * For each type of classifier a list is kept of all connections assigned a classifier of that type.
522 * This permits a classifier type to rapidly retrieve all connections with classifiers assigned to it of that type.
523 *
524 * NOTE: This is in addition to the basic functionality whereby a connection keeps a list of classifier instances
525 * that are assigned to it in descending order of priority.
526 */
527
528/*
529 * struct ecm_db_connection_classifier_type_assignment
530 * List linkage
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100531 */
532struct ecm_db_connection_classifier_type_assignment {
533 struct ecm_db_connection_instance *next; /* Next connection assigned to a classifier of this type */
534 struct ecm_db_connection_instance *prev; /* Previous connection assigned to a classifier of this type */
535 int iteration_count; /* >0 if something is examining this list entry and it may not be unlinked. The connection will persist. */
536 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 */
537#if (DEBUG_LEVEL > 0)
538 uint16_t magic;
539#endif
540};
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000541
542/*
543 * struct ecm_db_connection_classifier_type_assignment_list
544 * A list, one for each classifier type.
545 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100546struct ecm_db_connection_classifier_type_assignment_list {
547 struct ecm_db_connection_instance *type_assignments_list;
548 /* Lists of connections assigned to this type of classifier */
549 int32_t type_assignment_count; /* Number of connections in the list */
550} ecm_db_connection_classifier_type_assignments[ECM_CLASSIFIER_TYPES];
551 /* Each classifier type has a list of connections that are assigned to classifier instances of that type */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000552#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100553
554/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000555 * struct ecm_db_connection_instance
556 */
557struct ecm_db_connection_instance {
558 struct ecm_db_connection_instance *next; /* Next instance in global list */
559 struct ecm_db_connection_instance *prev; /* Previous instance in global list */
560
561 struct ecm_db_connection_instance *hash_next; /* Next connection in chain */
562 struct ecm_db_connection_instance *hash_prev; /* Previous connection in chain */
563 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 +0530564
Ben Menchaca84f36632014-02-28 20:57:38 +0000565 struct ecm_db_connection_instance *serial_hash_next; /* Next connection in serial hash chain */
566 struct ecm_db_connection_instance *serial_hash_prev; /* Previous connection in serial hash chain */
567 ecm_db_connection_hash_t serial_hash_index; /* The hash table slot whose chain of connections this is inserted into */
568
569 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
570
Gareth Williams3e5b37f2015-05-13 10:04:12 +0100571 int ip_version; /* RO: The version of IP protocol this connection was established for */
Ben Menchaca84f36632014-02-28 20:57:38 +0000572 int protocol; /* RO: Protocol of the connection */
573 ecm_db_direction_t direction; /* RO: 'Direction' of connection establishment. */
574 bool is_routed; /* RO: True when connection is routed, false when not */
575
576 /*
577 * Connection endpoint mapping
578 */
579 struct ecm_db_mapping_instance *mapping_from; /* The connection was established from this mapping */
580 struct ecm_db_mapping_instance *mapping_to; /* The connection was established to this mapping */
Ben Menchaca84f36632014-02-28 20:57:38 +0000581
582 /*
583 * Connection endpoint mapping for NAT purposes
584 * NOTE: For non-NAT connections these would be identical to the endpoint mappings.
585 */
586 struct ecm_db_mapping_instance *mapping_nat_from; /* The connection was established from this mapping */
587 struct ecm_db_mapping_instance *mapping_nat_to; /* The connection was established to this mapping */
Gareth Williamsb5903892015-03-20 15:13:07 +0000588
589 /*
590 * From / To Node (NAT and non-NAT).
591 * Connections keep references to the nodes upon which they operate.
592 * Gut feeling would tell us this is unusual since it should be the case that
593 * the HOST refer to the node, e.g. IP address to a MAC address.
594 * However there are some 'interesting' usage models where the same IP address may appear
595 * from different nodes / MAC addresses because of this the unique element here is the connection
596 * and so we record the node information directly here.
597 */
598 struct ecm_db_node_instance *from_node; /* Node from which this connection was established */
599 struct ecm_db_node_instance *to_node; /* Node to which this connection was established */
600 struct ecm_db_node_instance *from_nat_node; /* Node from which this connection was established */
601 struct ecm_db_node_instance *to_nat_node; /* Node to which this connection was established */
602
603#ifdef ECM_DB_XREF_ENABLE
604 /*
605 * The connection has references to the mappings (both nat and non-nat) as required above.
606 * Also mappings keep lists of connections made to/from them so that they may be iterated
607 * to determine associated connections in each direction/situation (e.g. "defuncting all connections made to/from a mapping").
608 */
609 struct ecm_db_connection_instance *from_next; /* Next connection made from the same mapping */
610 struct ecm_db_connection_instance *from_prev; /* Previous connection made from the same mapping */
611 struct ecm_db_connection_instance *to_next; /* Next connection made to the same mapping */
612 struct ecm_db_connection_instance *to_prev; /* Previous connection made to the same mapping */
613
Ben Menchaca84f36632014-02-28 20:57:38 +0000614 struct ecm_db_connection_instance *from_nat_next; /* Next connection made from the same mapping */
615 struct ecm_db_connection_instance *from_nat_prev; /* Previous connection made from the same mapping */
616 struct ecm_db_connection_instance *to_nat_next; /* Next connection made to the same mapping */
617 struct ecm_db_connection_instance *to_nat_prev; /* Previous connection made to the same mapping */
618
619 /*
620 * Connection endpoint interface
Gareth Williamsb5903892015-03-20 15:13:07 +0000621 * GGG TODO Deprecated - use interface lists instead.
622 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000623 */
624 struct ecm_db_connection_instance *iface_from_next; /* Next connection made from the same interface */
625 struct ecm_db_connection_instance *iface_from_prev; /* Previous connection made from the same interface */
626 struct ecm_db_connection_instance *iface_to_next; /* Next connection made to the same interface */
627 struct ecm_db_connection_instance *iface_to_prev; /* Previous connection made to the same interface */
628
629 /*
630 * Connection endpoint interface for NAT purposes
631 * NOTE: For non-NAT connections these would be identical to the endpoint interface.
Gareth Williamsb5903892015-03-20 15:13:07 +0000632 * GGG TODO Deprecated - use interface lists instead.
633 * To be removed when interface heirarchies are implemented to provide the same functionality.
Ben Menchaca84f36632014-02-28 20:57:38 +0000634 */
635 struct ecm_db_connection_instance *iface_from_nat_next; /* Next connection made from the same interface */
636 struct ecm_db_connection_instance *iface_from_nat_prev; /* Previous connection made from the same interface */
637 struct ecm_db_connection_instance *iface_to_nat_next; /* Next connection made to the same interface */
638 struct ecm_db_connection_instance *iface_to_nat_prev; /* Previous connection made to the same interface */
639
640 /*
Gareth Williamsb5903892015-03-20 15:13:07 +0000641 * As well as keeping a reference to the node which this connection uses the nodes
642 * also keep lists of connections made from/to them.
643 */
644 struct ecm_db_connection_instance *node_from_next; /* Next connection in the nodes from_connections list */
645 struct ecm_db_connection_instance *node_from_prev; /* Prev connection in the nodes from_connections list */
646 struct ecm_db_connection_instance *node_to_next; /* Next connection in the nodes to_connections list */
647 struct ecm_db_connection_instance *node_to_prev; /* Prev connection in the nodes to_connections list */
648
649 struct ecm_db_connection_instance *node_from_nat_next; /* Next connection in the nodes from_nat_connections list */
650 struct ecm_db_connection_instance *node_from_nat_prev; /* Prev connection in the nodes from_nat_connections list */
651 struct ecm_db_connection_instance *node_to_nat_next; /* Next connection in the nodes to_nat_connections list */
652 struct ecm_db_connection_instance *node_to_nat_prev; /* Prev connection in the nodes to_nat_connections list */
653#endif
654
655 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000656 * From / To interfaces list
657 */
658 struct ecm_db_iface_instance *from_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
659 /* The outermost to innnermost interface this connection is using in the from path.
660 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
661 */
662 int32_t from_interface_first; /* The index of the first interface in the list */
663 bool from_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
664 struct ecm_db_iface_instance *to_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
665 /* The outermost to innnermost interface this connection is using in the to path */
666 int32_t to_interface_first; /* The index of the first interface in the list */
667 bool to_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
668
669 /*
670 * From / To NAT interfaces list
Gareth Williams90f2a282014-08-27 15:56:25 +0100671 * GGG TODO Not sure if NAT interface lists are necessary or appropriate or practical.
672 * Needs to be assessed if it gives any clear benefit and possibly remove these if not.
Ben Menchaca84f36632014-02-28 20:57:38 +0000673 */
674 struct ecm_db_iface_instance *from_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
675 /* The outermost to innnermost interface this connection is using in the from path.
676 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
677 */
678 int32_t from_nat_interface_first; /* The index of the first interface in the list */
679 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. */
680 struct ecm_db_iface_instance *to_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
681 /* The outermost to innnermost interface this connection is using in the to path */
682 int32_t to_nat_interface_first; /* The index of the first interface in the list */
683 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. */
684
Shyam Sunder1f037262015-05-18 20:04:13 +0530685#ifdef ECM_MULTICAST_ENABLE
686 /*
687 * Destination Multicast interfaces list
688 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +0530689 struct ecm_db_iface_instance *to_mcast_interfaces;
690 /* The outermost to innnermost interfaces this connection is using in multicast path.
691 * The size of the buffer allocated for the to_mcast_interfaces heirarchies is as large as
692 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX. */
Shyam Sunder1f037262015-05-18 20:04:13 +0530693 int32_t to_mcast_interface_first[ECM_DB_MULTICAST_IF_MAX];
694 /* The indexes of the first interfaces in the destinaiton interface list */
695 struct ecm_db_multicast_tuple_instance *ti; /* Multicast Connection instance */
696 bool to_mcast_interfaces_set; /* Flag to indicate if the destination interface list is currently empty or not */
697#endif
Ben Menchaca84f36632014-02-28 20:57:38 +0000698 /*
699 * Time values in seconds
700 */
701 struct ecm_db_timer_group_entry defunct_timer; /* Used to defunct the connection on inactivity */
702
703 /*
704 * Byte and packet counts
705 */
706 uint64_t from_data_total; /* Totals of data as sent by the 'from' side of this connection */
707 uint64_t to_data_total; /* Totals of data as sent by the 'to' side of this connection */
708 uint64_t from_packet_total; /* Totals of packets as sent by the 'from' side of this connection */
709 uint64_t to_packet_total; /* Totals of packets as sent by the 'to' side of this connection */
710 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 */
711 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 */
712 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 */
713 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 */
714
715 /*
716 * Classifiers attached to this connection
717 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000718 struct ecm_classifier_instance *assignments; /* A list of all classifiers that are still assigned to this connection.
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000719 * When a connection is created, one instance of every type of classifier is assigned to the connection.
Ben Menchaca84f36632014-02-28 20:57:38 +0000720 * Classifiers are added in ascending order of priority - so the most important processes a packet last.
721 * Classifiers may drop out of this list (become unassigned) at any time.
722 */
723 struct ecm_classifier_instance *assignments_by_type[ECM_CLASSIFIER_TYPES];
724 /* All assignments are also recorded in this array, since there can be only one of each type, this array allows
725 * rapid retrieval of a classifier type, saving having to iterate the assignments list.
726 */
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000727
728#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100729 struct ecm_db_connection_classifier_type_assignment type_assignment[ECM_CLASSIFIER_TYPES];
Gareth Williamsb39e7c22015-03-25 10:15:33 +0000730 /*
731 * Each classifier TYPE has a list of connections that are assigned to it.
732 * This permits a classifier TYPE to rapidly retrieve all connections associated with it.
733 */
734#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100735
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530736 /*
737 * Re-generation.
738 * When system or classifier state changes, affected connections may need to have their state re-generated.
739 * This ensures that a connection does not continue to operate on stale state which could affect the sanity of acceleration rules.
740 * A connection needs to be re-generated when its regen_required is > 0.
741 * When a re-generation is completed successfully the counter is decremented.
742 * The counter ensures that any further changes of state while re-generation is under way is not missed.
743 * While a connection needs re-generation (regen_required > 0), acceleration should not be permitted.
744 * It may not always be practical to flag individual connections for re-generation (time consuming with large numbers of connections).
745 * The "generation" is a numerical counter comparison against the global "ecm_db_connection_generation".
746 * This ecm_db_connection_generation can be incremented causing a numerical difference between the connections counter and this global.
747 * This is enough to flag that a re-generation is needed.
748 * Further, it is possible that re-generation may be required DURING a rule construction. Since constructing a rule
749 * can require lengthy non-atomic processes there needs to be a way to ensure that changes during construction of a rule are caught.
750 * The regen_occurances is a counter that is incremented whenever regen_required is also incremented.
751 * However it is never decremented. This permits the caller to obtain this count before a non-atomic procedure and then afterwards.
752 * If there is any change in the counter value there is a change of generation! And the operation should be aborted.
753 */
754 bool regen_in_progress; /* The connection is under regeneration right now and is used to provide atomic re-generation in SMP */
755 uint16_t regen_required; /* The connection needs to be re-generated when > 0 */
756 uint16_t regen_occurances; /* Total number of regens required */
757 uint16_t generation; /* Used to detect when a re-evaluation of this connection is necessary by comparing with ecm_db_connection_generation */
758 uint32_t regen_success; /* Tracks how many times re-generation was successfully completed */
759 uint32_t regen_fail; /* Tracks how many times re-generation failed */
760
Ben Menchaca84f36632014-02-28 20:57:38 +0000761 struct ecm_front_end_connection_instance *feci; /* Front end instance specific to this connection */
762
Murat Sezgin7f6cdf62014-09-11 13:41:06 -0700763 ecm_db_connection_defunct_callback_t defunct; /* Callback to be called when connection has become defunct */
Ben Menchaca84f36632014-02-28 20:57:38 +0000764 ecm_db_connection_final_callback_t final; /* Callback to owner when object is destroyed */
765 void *arg; /* Argument returned to owner in callbacks */
766
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100767 uint32_t serial; /* RO: Serial number for the connection - unique for run lifetime */
Ben Menchaca84f36632014-02-28 20:57:38 +0000768 uint32_t flags;
769 int refs; /* Integer to trap we never go negative */
770#if (DEBUG_LEVEL > 0)
771 uint16_t magic;
772#endif
773};
774
775/*
776 * Connection flags
777 */
778#define ECM_DB_CONNECTION_FLAGS_INSERTED 1 /* Connection is inserted into connection database tables */
779
780/*
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530781 * struct ecm_db_listener_instance
Ben Menchaca84f36632014-02-28 20:57:38 +0000782 * listener instances
783 */
784struct ecm_db_listener_instance {
785 struct ecm_db_listener_instance *next;
786 struct ecm_db_listener_instance *event_next;
787 uint32_t flags;
788 void *arg;
789 int refs; /* Integer to trap we never go negative */
790 ecm_db_mapping_final_callback_t final; /* Final callback for this instance */
791
792 ecm_db_iface_listener_added_callback_t iface_added;
793 ecm_db_iface_listener_removed_callback_t iface_removed;
794 ecm_db_node_listener_added_callback_t node_added;
795 ecm_db_node_listener_removed_callback_t node_removed;
796 ecm_db_host_listener_added_callback_t host_added;
797 ecm_db_host_listener_removed_callback_t host_removed;
798 ecm_db_mapping_listener_added_callback_t mapping_added;
799 ecm_db_mapping_listener_removed_callback_t mapping_removed;
800 ecm_db_connection_listener_added_callback_t connection_added;
801 ecm_db_connection_listener_removed_callback_t connection_removed;
802#if (DEBUG_LEVEL > 0)
803 uint16_t magic;
804#endif
805};
806
807/*
808 * Listener flags
809 */
Gareth Williamsb5903892015-03-20 15:13:07 +0000810#define ECM_DB_LISTENER_FLAGS_INSERTED 1 /* Is inserted into database */
Ben Menchaca84f36632014-02-28 20:57:38 +0000811
Shyam Sunder1f037262015-05-18 20:04:13 +0530812#ifdef ECM_MULTICAST_ENABLE
813/*
814 * struct ecm_db_multicast_tuple_instance
815 * Tuple information for an accelerated multicast connection.
816 * This tuple information is further used to find an attached
817 * connection for the multicast flow.
818 */
819struct ecm_db_multicast_tuple_instance {
820 struct ecm_db_multicast_tuple_instance *next; /* Next instance in global list */
821 struct ecm_db_multicast_tuple_instance *prev; /* Previous instance in global list */
Shyam Sunder3af86a52015-08-28 18:04:10 +0530822 struct ecm_db_connection_instance *ci; /* Pointer to the DB Connection Instance */
Shyam Sunder1f037262015-05-18 20:04:13 +0530823 uint16_t src_port; /* RO: IPv4/v6 Source Port */
824 uint16_t dst_port; /* RO: IPv4/v6 Destination Port */
825 ip_addr_t src_ip; /* RO: IPv4/v6 Source Address */
826 ip_addr_t grp_ip; /* RO: IPv4/v6 Multicast Group Address */
827 uint32_t flags; /* Flags for this instance node */
828 uint32_t hash_index; /* Hash index of this node */
829 int proto; /* RO: Protocol */
830 int refs; /* Integer to trap we never go negative */
831#if (DEBUG_LEVEL > 0)
832 uint16_t magic; /* Magic value for debug */
833#endif
834};
835
836#define ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS 16
837typedef uint32_t ecm_db_multicast_tuple_instance_hash_t;
838
839/*
840 * Multicast connection tuple table
841 * This table is used to lookup a complete tuple for multicast connections
842 * using the multicast group address
843 */
844static struct ecm_db_multicast_tuple_instance *ecm_db_multicast_tuple_instance_table[ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS];
845#endif
846
Ben Menchaca84f36632014-02-28 20:57:38 +0000847/*
848 * Simple stats
849 */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000850#define ECM_DB_PROTOCOL_COUNT 256
851static 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 +0000852
853/*
854 * Locking of the database - concurrency control
855 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700856static DEFINE_SPINLOCK(ecm_db_lock); /* Protect the table from SMP access. */
Ben Menchaca84f36632014-02-28 20:57:38 +0000857
858/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530859 * Connection state validity
860 * 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 +0000861 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +0530862static 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 +0000863
864/*
Murat Sezgin908ecb32015-05-10 20:54:36 -0700865 * Debugfs dentry object.
Ben Menchaca84f36632014-02-28 20:57:38 +0000866 */
Murat Sezgin908ecb32015-05-10 20:54:36 -0700867static struct dentry *ecm_db_dentry;
Ben Menchaca84f36632014-02-28 20:57:38 +0000868
869/*
870 * Management thread control
871 */
872static bool ecm_db_terminate_pending = false; /* When true the user has requested termination */
Ben Menchaca84f36632014-02-28 20:57:38 +0000873
874/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000875 * ecm_db_interface_type_names[]
876 * Array that maps the interface type to a string
877 */
878static char *ecm_db_interface_type_names[ECM_DB_IFACE_TYPE_COUNT] = {
879 "ETHERNET",
880 "PPPoE",
881 "LINK-AGGREGATION",
882 "VLAN",
883 "BRIDGE",
884 "LOOPBACK",
885 "IPSEC_TUNNEL",
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530886 "UNKNOWN",
Murat Sezginb3cc8792014-06-06 19:16:51 -0700887 "SIT",
888 "TUNIPIP6",
Shyam Sunder23f2e542015-09-28 14:56:49 +0530889 "PPPoL2TPV2",
890 "PPTP"
Ben Menchaca84f36632014-02-28 20:57:38 +0000891};
892
893/*
Gareth Williams54d15d92015-04-24 19:28:27 +0100894 * Random seed used during hash calculations
895 */
896static uint32_t ecm_db_jhash_rnd __read_mostly;
897
898/*
Gareth Williamsf28ba5f2015-02-13 11:07:28 +0000899 * ecm_db_connection_count_get()
900 * Return the connection count
901 */
902int ecm_db_connection_count_get(void)
903{
904 int count;
905
906 spin_lock_bh(&ecm_db_lock);
907 count = ecm_db_connection_count;
908 spin_unlock_bh(&ecm_db_lock);
909 return count;
910}
911EXPORT_SYMBOL(ecm_db_connection_count_get);
912
913/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000914 * ecm_db_interface_type_to_string()
915 * Return a string buffer containing the type name of the interface
916 */
917char *ecm_db_interface_type_to_string(ecm_db_iface_type_t type)
918{
919 DEBUG_ASSERT((type >= 0) && (type < ECM_DB_IFACE_TYPE_COUNT), "Invalid type: %d\n", type);
920 return ecm_db_interface_type_names[(int)type];
921}
922EXPORT_SYMBOL(ecm_db_interface_type_to_string);
923
924/*
Gareth Williamsf98d4192015-03-11 16:55:41 +0000925 * ecm_db_connection_count_by_protocol_get()
926 * Return # connections for the given protocol
927 */
928int ecm_db_connection_count_by_protocol_get(int protocol)
929{
930 int count;
931
932 DEBUG_ASSERT((protocol >= 0) && (protocol < ECM_DB_PROTOCOL_COUNT), "Bad protocol: %d\n", protocol);
933 spin_lock_bh(&ecm_db_lock);
934 count = ecm_db_connection_count_by_protocol[protocol];
935 spin_unlock_bh(&ecm_db_lock);
936 return count;
937}
938EXPORT_SYMBOL(ecm_db_connection_count_by_protocol_get);
939
940/*
Murat Sezgin91c5d712015-06-12 15:16:22 -0700941 * ecm_db_iface_ae_interface_identifier_get()
942 * Return the accel engine interface number of this ecm interface
Ben Menchaca84f36632014-02-28 20:57:38 +0000943 */
Murat Sezgin91c5d712015-06-12 15:16:22 -0700944int32_t ecm_db_iface_ae_interface_identifier_get(struct ecm_db_iface_instance *ii)
Ben Menchaca84f36632014-02-28 20:57:38 +0000945{
946 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
Murat Sezgin91c5d712015-06-12 15:16:22 -0700947 return ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +0000948}
Murat Sezgin91c5d712015-06-12 15:16:22 -0700949EXPORT_SYMBOL(ecm_db_iface_ae_interface_identifier_get);
Ben Menchaca84f36632014-02-28 20:57:38 +0000950
951/*
Kiran Kumar C. S. K451b62e2014-05-19 20:34:06 +0530952 * ecm_db_iface_interface_identifier_get()
953 * Return the interface number of this ecm interface
954 */
955int32_t ecm_db_iface_interface_identifier_get(struct ecm_db_iface_instance *ii)
956{
957 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
958 return ii->interface_identifier;
959}
960EXPORT_SYMBOL(ecm_db_iface_interface_identifier_get);
961
962/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000963 * ecm_db_iface_mtu_reset()
964 * Reset the mtu
965 */
966int32_t ecm_db_iface_mtu_reset(struct ecm_db_iface_instance *ii, int32_t mtu)
967{
968 int32_t mtu_old;
969 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
970 spin_lock_bh(&ecm_db_lock);
971 mtu_old = ii->mtu;
972 ii->mtu = mtu;
973 spin_unlock_bh(&ecm_db_lock);
974 DEBUG_INFO("%p: Mtu change from %d to %d\n", ii, mtu_old, mtu);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530975
Ben Menchaca84f36632014-02-28 20:57:38 +0000976 return mtu_old;
977}
978EXPORT_SYMBOL(ecm_db_iface_mtu_reset);
979
980/*
981 * ecm_db_connection_front_end_get_and_ref()
982 * Return ref to the front end instance of the connection
983 */
984struct ecm_front_end_connection_instance *ecm_db_connection_front_end_get_and_ref(struct ecm_db_connection_instance *ci)
985{
986 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
987 ci->feci->ref(ci->feci);
988 return ci->feci;
989}
990EXPORT_SYMBOL(ecm_db_connection_front_end_get_and_ref);
991
992/*
993 * ecm_db_connection_defunct_callback()
994 * Invoked by the expiration of the defunct_timer contained in a connection instance
995 */
996static void ecm_db_connection_defunct_callback(void *arg)
997{
998 struct ecm_db_connection_instance *ci = (struct ecm_db_connection_instance *)arg;
999 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1000
1001 DEBUG_INFO("%p: defunct timer expired\n", ci);
Gareth Williams2bfb0b82015-01-15 16:31:15 +00001002
1003 if (ci->defunct) {
1004 ci->defunct(ci->feci);
1005 }
1006
Ben Menchaca84f36632014-02-28 20:57:38 +00001007 ecm_db_connection_deref(ci);
1008}
1009
1010/*
1011 * ecm_db_connection_defunct_timer_reset()
1012 * 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.
1013 */
1014bool ecm_db_connection_defunct_timer_reset(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg)
1015{
1016 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1017 return ecm_db_timer_group_entry_reset(&ci->defunct_timer, tg);
1018}
1019EXPORT_SYMBOL(ecm_db_connection_defunct_timer_reset);
1020
1021/*
1022 * ecm_db_connection_defunct_timer_touch()
1023 * Update the connections defunct timer to stop it timing out. Returns false if the connection defunct timer has expired.
1024 */
1025bool ecm_db_connection_defunct_timer_touch(struct ecm_db_connection_instance *ci)
1026{
1027 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1028 return ecm_db_timer_group_entry_touch(&ci->defunct_timer);
1029}
1030EXPORT_SYMBOL(ecm_db_connection_defunct_timer_touch);
1031
1032/*
1033 * ecm_db_connection_timer_group_get()
1034 * Return the timer group id
1035 */
1036ecm_db_timer_group_t ecm_db_connection_timer_group_get(struct ecm_db_connection_instance *ci)
1037{
1038 ecm_db_timer_group_t tg;
1039 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1040
1041 spin_lock_bh(&ecm_db_lock);
1042 tg = ci->defunct_timer.group;
1043 spin_unlock_bh(&ecm_db_lock);
1044 return tg;
1045}
1046EXPORT_SYMBOL(ecm_db_connection_timer_group_get);
1047
1048/*
1049 * ecm_db_connection_make_defunct()
1050 * Make connection defunct.
1051 */
1052void ecm_db_connection_make_defunct(struct ecm_db_connection_instance *ci)
1053{
1054 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07001055
1056 if (ci->defunct) {
1057 ci->defunct(ci->feci);
1058 }
1059
Ben Menchaca84f36632014-02-28 20:57:38 +00001060 if (ecm_db_timer_group_entry_remove(&ci->defunct_timer)) {
1061 ecm_db_connection_deref(ci);
1062 }
1063}
1064EXPORT_SYMBOL(ecm_db_connection_make_defunct);
1065
1066/*
1067 * ecm_db_connection_data_totals_update()
1068 * Update the total data (and packets) sent/received by the given host
1069 */
1070void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1071{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001072 int32_t i;
1073
Ben Menchaca84f36632014-02-28 20:57:38 +00001074 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1075
1076 spin_lock_bh(&ecm_db_lock);
1077
1078 if (is_from) {
1079 /*
1080 * Update totals sent by the FROM side of connection
1081 */
1082 ci->from_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001083 ci->from_packet_total += packets;
1084#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001085 ci->mapping_from->from_data_total += size;
1086 ci->mapping_from->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001087 ci->from_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001088 ci->mapping_from->from_packet_total += packets;
1089 ci->mapping_from->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001090 ci->from_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001091
1092 /*
1093 * Data from the host is essentially TO the interface on which the host is reachable
1094 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001095 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1096 ci->from_interfaces[i]->to_data_total += size;
1097 ci->from_interfaces[i]->to_packet_total += packets;
1098 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001099
1100 /*
1101 * Update totals sent TO the other side of the connection
1102 */
1103 ci->mapping_to->to_data_total += size;
1104 ci->mapping_to->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001105 ci->to_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001106 ci->mapping_to->to_packet_total += packets;
1107 ci->mapping_to->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001108 ci->to_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001109
1110 /*
1111 * Sending to the other side means FROM the interface we reach that host
1112 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001113 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1114 ci->to_interfaces[i]->from_data_total += size;
1115 ci->to_interfaces[i]->from_packet_total += packets;
1116 }
Gareth Williams85331c92015-03-11 20:39:18 +00001117#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001118 spin_unlock_bh(&ecm_db_lock);
1119 return;
1120 }
1121
1122 /*
1123 * Update totals sent by the TO side of this connection
1124 */
1125 ci->to_data_total += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001126 ci->to_packet_total += packets;
1127#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001128 ci->mapping_to->from_data_total += size;
1129 ci->mapping_to->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001130 ci->to_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001131 ci->mapping_to->from_packet_total += packets;
1132 ci->mapping_to->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001133 ci->to_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001134
1135 /*
1136 * Data from the host is essentially TO the interface on which the host is reachable
1137 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001138 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1139 ci->to_interfaces[i]->to_data_total += size;
1140 ci->to_interfaces[i]->to_packet_total += packets;
1141 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001142
1143 /*
1144 * Update totals sent TO the other side of the connection
1145 */
1146 ci->mapping_from->to_data_total += size;
1147 ci->mapping_from->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001148 ci->from_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001149 ci->mapping_from->to_packet_total += packets;
1150 ci->mapping_from->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001151 ci->from_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001152
1153 /*
1154 * Sending to the other side means FROM the interface we reach that host
1155 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001156 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1157 ci->from_interfaces[i]->from_data_total += size;
1158 ci->from_interfaces[i]->from_packet_total += packets;
1159 }
Gareth Williams85331c92015-03-11 20:39:18 +00001160#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001161 spin_unlock_bh(&ecm_db_lock);
1162}
1163EXPORT_SYMBOL(ecm_db_connection_data_totals_update);
1164
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301165#ifdef ECM_MULTICAST_ENABLE
1166/*
1167 * ecm_db_multicast_connection_data_totals_update()
1168 * Update the total bytes and packets sent/received by the multicast connection
1169 * TODO: This function is almost similar to unicast connection_data_totals_update() except few
1170 * lines of code. The next merge should have a common logic for both unicast and multicast.
1171 */
1172void ecm_db_multicast_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1173{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001174 int32_t i;
1175
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301176 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1177
1178 spin_lock_bh(&ecm_db_lock);
1179
1180 if (is_from) {
1181 /*
1182 * Update totals sent by the FROM side of connection
1183 */
1184 ci->from_data_total += size;
1185 ci->from_packet_total += packets;
1186#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1187 ci->mapping_from->from_data_total += size;
1188 ci->mapping_from->host->from_data_total += size;
1189 ci->from_node->from_data_total += size;
1190 ci->mapping_from->from_packet_total += packets;
1191 ci->mapping_from->host->from_packet_total += packets;
1192 ci->from_node->from_packet_total += packets;
1193
1194 /*
1195 * Data from the host is essentially TO the interface on which the host is reachable
1196 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001197 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1198 ci->from_interfaces[i]->to_data_total += size;
1199 ci->from_interfaces[i]->to_packet_total += packets;
1200 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301201
1202 /*
1203 * Update totals sent TO the other side of the connection
1204 */
1205 ci->mapping_to->to_data_total += size;
1206 ci->mapping_to->host->to_data_total += size;
1207 ci->to_node->to_data_total += size;
1208 ci->mapping_to->to_packet_total += packets;
1209 ci->mapping_to->host->to_packet_total += packets;
1210 ci->to_node->to_packet_total += packets;
1211#endif
1212 spin_unlock_bh(&ecm_db_lock);
1213 return;
1214 }
1215
1216 /*
1217 * Update totals sent by the TO side of this connection
1218 */
1219 ci->to_data_total += size;
1220 ci->to_packet_total += packets;
1221#ifdef ECM_DB_ADVANCED_STATS_ENABLE
1222 ci->mapping_to->from_data_total += size;
1223 ci->mapping_to->host->from_data_total += size;
1224 ci->to_node->from_data_total += size;
1225 ci->mapping_to->from_packet_total += packets;
1226 ci->mapping_to->host->from_packet_total += packets;
1227 ci->to_node->from_packet_total += packets;
1228
1229 /*
1230 * Update totals sent TO the other side of the connection
1231 */
1232 ci->mapping_from->to_data_total += size;
1233 ci->mapping_from->host->to_data_total += size;
1234 ci->from_node->to_data_total += size;
1235 ci->mapping_from->to_packet_total += packets;
1236 ci->mapping_from->host->to_packet_total += packets;
1237 ci->from_node->to_packet_total += packets;
1238
1239 /*
1240 * Sending to the other side means FROM the interface we reach that host
1241 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001242 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1243 ci->from_interfaces[i]->from_data_total += size;
1244 ci->from_interfaces[i]->from_packet_total += packets;
1245 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05301246#endif
1247 spin_unlock_bh(&ecm_db_lock);
1248}
1249EXPORT_SYMBOL(ecm_db_multicast_connection_data_totals_update);
1250
1251/*
1252 * ecm_db_multicast_connection_interface_heirarchy_stats_update()
1253 * Traverse through the multicast destination interface heirarchy and update the stats (data and packets).
1254 */
1255void ecm_db_multicast_connection_interface_heirarchy_stats_update(struct ecm_db_connection_instance *ci, uint64_t size, uint64_t packets)
1256{
1257 struct ecm_db_iface_instance *to_mc_ifaces;
1258 struct ecm_db_iface_instance *ii;
1259 struct ecm_db_iface_instance **ifaces;
1260 struct ecm_db_iface_instance *ii_temp;
1261 int32_t *to_mc_ifaces_first;
1262 int heirarchy_index;
1263 int ret;
1264
1265 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &to_mc_ifaces, &to_mc_ifaces_first);
1266 if (ret == 0) {
1267 DEBUG_WARN("%p: no interfaces in to_multicast_interfaces list!\n", ci);
1268 return;
1269 }
1270
1271 spin_lock_bh(&ecm_db_lock);
1272 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
1273
1274 if (to_mc_ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
1275 ii_temp = ecm_db_multicast_if_heirarchy_get(to_mc_ifaces, heirarchy_index);
1276 ii_temp = ecm_db_multicast_if_instance_get_at_index(ii_temp, ECM_DB_IFACE_HEIRARCHY_MAX - 1);
1277 ifaces = (struct ecm_db_iface_instance **)ii_temp;
1278 ii = *ifaces;
1279 ii->to_data_total += size;
1280 ii->to_packet_total += packets;
1281 }
1282 }
1283 spin_unlock_bh(&ecm_db_lock);
1284
1285 ecm_db_multicast_connection_to_interfaces_deref_all(to_mc_ifaces, to_mc_ifaces_first);
1286}
1287EXPORT_SYMBOL(ecm_db_multicast_connection_interface_heirarchy_stats_update);
1288#endif
1289
Ben Menchaca84f36632014-02-28 20:57:38 +00001290/*
1291 * ecm_db_connection_data_totals_update_dropped()
1292 * Update the total data (and packets) sent by the given host but which we dropped
1293 */
1294void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1295{
Murat Sezginf6814bc2015-08-20 11:31:41 -07001296 int32_t i;
1297
Ben Menchaca84f36632014-02-28 20:57:38 +00001298 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1299
1300 if (is_from) {
1301 /*
1302 * Update dropped totals sent by the FROM side
1303 */
1304 spin_lock_bh(&ecm_db_lock);
1305 ci->from_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001306 ci->from_packet_total_dropped += packets;
1307#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001308 ci->mapping_from->from_data_total_dropped += size;
1309 ci->mapping_from->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001310 ci->from_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001311 ci->mapping_from->from_packet_total_dropped += packets;
1312 ci->mapping_from->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001313 ci->from_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001314
1315 /*
1316 * Data from the host is essentially TO the interface on which the host is reachable
1317 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001318 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1319 ci->from_interfaces[i]->to_data_total_dropped += size;
1320 ci->from_interfaces[i]->to_packet_total_dropped += packets;
1321 }
Gareth Williams85331c92015-03-11 20:39:18 +00001322#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001323 spin_unlock_bh(&ecm_db_lock);
1324 return;
1325 }
1326
1327 /*
1328 * Update dropped totals sent by the TO side of this connection
1329 */
1330 spin_lock_bh(&ecm_db_lock);
1331 ci->to_data_total_dropped += size;
Gareth Williams85331c92015-03-11 20:39:18 +00001332 ci->to_packet_total_dropped += packets;
1333#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001334 ci->mapping_to->from_data_total_dropped += size;
1335 ci->mapping_to->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001336 ci->to_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001337 ci->mapping_to->from_packet_total_dropped += packets;
1338 ci->mapping_to->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001339 ci->to_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001340
1341 /*
1342 * Data from the host is essentially TO the interface on which the host is reachable
1343 */
Murat Sezginf6814bc2015-08-20 11:31:41 -07001344 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
1345 ci->to_interfaces[i]->to_data_total_dropped += size;
1346 ci->to_interfaces[i]->to_packet_total_dropped += packets;
1347 }
Gareth Williams85331c92015-03-11 20:39:18 +00001348#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001349 spin_unlock_bh(&ecm_db_lock);
1350}
1351EXPORT_SYMBOL(ecm_db_connection_data_totals_update_dropped);
1352
1353/*
1354 * ecm_db_connection_data_stats_get()
1355 * Return data stats for the instance
1356 */
1357void ecm_db_connection_data_stats_get(struct ecm_db_connection_instance *ci, uint64_t *from_data_total, uint64_t *to_data_total,
1358 uint64_t *from_packet_total, uint64_t *to_packet_total,
1359 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1360 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1361{
1362 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1363
1364 spin_lock_bh(&ecm_db_lock);
1365 if (from_data_total) {
1366 *from_data_total = ci->from_data_total;
1367 }
1368 if (to_data_total) {
1369 *to_data_total = ci->to_data_total;
1370 }
1371 if (from_packet_total) {
1372 *from_packet_total = ci->from_packet_total;
1373 }
1374 if (to_packet_total) {
1375 *to_packet_total = ci->to_packet_total;
1376 }
1377 if (from_data_total_dropped) {
1378 *from_data_total_dropped = ci->from_data_total_dropped;
1379 }
1380 if (to_data_total_dropped) {
1381 *to_data_total_dropped = ci->to_data_total_dropped;
1382 }
1383 if (from_packet_total_dropped) {
1384 *from_packet_total_dropped = ci->from_packet_total_dropped;
1385 }
1386 if (to_packet_total_dropped) {
1387 *to_packet_total_dropped = ci->to_packet_total_dropped;
1388 }
1389 spin_unlock_bh(&ecm_db_lock);
1390}
1391EXPORT_SYMBOL(ecm_db_connection_data_stats_get);
1392
Gareth Williams85331c92015-03-11 20:39:18 +00001393#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001394/*
1395 * ecm_db_mapping_data_stats_get()
1396 * Return data stats for the instance
1397 */
1398void ecm_db_mapping_data_stats_get(struct ecm_db_mapping_instance *mi, uint64_t *from_data_total, uint64_t *to_data_total,
1399 uint64_t *from_packet_total, uint64_t *to_packet_total,
1400 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1401 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1402{
1403 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1404 spin_lock_bh(&ecm_db_lock);
1405 if (from_data_total) {
1406 *from_data_total = mi->from_data_total;
1407 }
1408 if (to_data_total) {
1409 *to_data_total = mi->to_data_total;
1410 }
1411 if (from_packet_total) {
1412 *from_packet_total = mi->from_packet_total;
1413 }
1414 if (to_packet_total) {
1415 *to_packet_total = mi->to_packet_total;
1416 }
1417 if (from_data_total_dropped) {
1418 *from_data_total_dropped = mi->from_data_total_dropped;
1419 }
1420 if (to_data_total_dropped) {
1421 *to_data_total_dropped = mi->to_data_total_dropped;
1422 }
1423 if (from_packet_total_dropped) {
1424 *from_packet_total_dropped = mi->from_packet_total_dropped;
1425 }
1426 if (to_packet_total_dropped) {
1427 *to_packet_total_dropped = mi->to_packet_total_dropped;
1428 }
1429 spin_unlock_bh(&ecm_db_lock);
1430}
1431EXPORT_SYMBOL(ecm_db_mapping_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001432#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001433
Gareth Williams85331c92015-03-11 20:39:18 +00001434#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001435/*
1436 * ecm_db_host_data_stats_get()
1437 * Return data stats for the instance
1438 */
1439void ecm_db_host_data_stats_get(struct ecm_db_host_instance *hi, uint64_t *from_data_total, uint64_t *to_data_total,
1440 uint64_t *from_packet_total, uint64_t *to_packet_total,
1441 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1442 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1443{
1444 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1445 spin_lock_bh(&ecm_db_lock);
1446 if (from_data_total) {
1447 *from_data_total = hi->from_data_total;
1448 }
1449 if (to_data_total) {
1450 *to_data_total = hi->to_data_total;
1451 }
1452 if (from_packet_total) {
1453 *from_packet_total = hi->from_packet_total;
1454 }
1455 if (to_packet_total) {
1456 *to_packet_total = hi->to_packet_total;
1457 }
1458 if (from_data_total_dropped) {
1459 *from_data_total_dropped = hi->from_data_total_dropped;
1460 }
1461 if (to_data_total_dropped) {
1462 *to_data_total_dropped = hi->to_data_total_dropped;
1463 }
1464 if (from_packet_total_dropped) {
1465 *from_packet_total_dropped = hi->from_packet_total_dropped;
1466 }
1467 if (to_packet_total_dropped) {
1468 *to_packet_total_dropped = hi->to_packet_total_dropped;
1469 }
1470 spin_unlock_bh(&ecm_db_lock);
1471}
1472EXPORT_SYMBOL(ecm_db_host_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001473#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001474
Gareth Williams85331c92015-03-11 20:39:18 +00001475#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001476/*
1477 * ecm_db_node_data_stats_get()
1478 * Return data stats for the instance
1479 */
1480void ecm_db_node_data_stats_get(struct ecm_db_node_instance *ni, uint64_t *from_data_total, uint64_t *to_data_total,
1481 uint64_t *from_packet_total, uint64_t *to_packet_total,
1482 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1483 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1484{
1485 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1486 spin_lock_bh(&ecm_db_lock);
1487 if (from_data_total) {
1488 *from_data_total = ni->from_data_total;
1489 }
1490 if (to_data_total) {
1491 *to_data_total = ni->to_data_total;
1492 }
1493 if (from_packet_total) {
1494 *from_packet_total = ni->from_packet_total;
1495 }
1496 if (to_packet_total) {
1497 *to_packet_total = ni->to_packet_total;
1498 }
1499 if (from_data_total_dropped) {
1500 *from_data_total_dropped = ni->from_data_total_dropped;
1501 }
1502 if (to_data_total_dropped) {
1503 *to_data_total_dropped = ni->to_data_total_dropped;
1504 }
1505 if (from_packet_total_dropped) {
1506 *from_packet_total_dropped = ni->from_packet_total_dropped;
1507 }
1508 if (to_packet_total_dropped) {
1509 *to_packet_total_dropped = ni->to_packet_total_dropped;
1510 }
1511 spin_unlock_bh(&ecm_db_lock);
1512}
1513EXPORT_SYMBOL(ecm_db_node_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001514#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001515
Gareth Williams85331c92015-03-11 20:39:18 +00001516#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00001517/*
1518 * ecm_db_iface_data_stats_get()
1519 * Return data stats for the instance
1520 */
1521void ecm_db_iface_data_stats_get(struct ecm_db_iface_instance *ii, uint64_t *from_data_total, uint64_t *to_data_total,
1522 uint64_t *from_packet_total, uint64_t *to_packet_total,
1523 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1524 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1525{
1526 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1527 spin_lock_bh(&ecm_db_lock);
1528 if (from_data_total) {
1529 *from_data_total = ii->from_data_total;
1530 }
1531 if (to_data_total) {
1532 *to_data_total = ii->to_data_total;
1533 }
1534 if (from_packet_total) {
1535 *from_packet_total = ii->from_packet_total;
1536 }
1537 if (to_packet_total) {
1538 *to_packet_total = ii->to_packet_total;
1539 }
1540 if (from_data_total_dropped) {
1541 *from_data_total_dropped = ii->from_data_total_dropped;
1542 }
1543 if (to_data_total_dropped) {
1544 *to_data_total_dropped = ii->to_data_total_dropped;
1545 }
1546 if (from_packet_total_dropped) {
1547 *from_packet_total_dropped = ii->from_packet_total_dropped;
1548 }
1549 if (to_packet_total_dropped) {
1550 *to_packet_total_dropped = ii->to_packet_total_dropped;
1551 }
1552 spin_unlock_bh(&ecm_db_lock);
1553}
1554EXPORT_SYMBOL(ecm_db_iface_data_stats_get);
Gareth Williams85331c92015-03-11 20:39:18 +00001555#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00001556
1557/*
1558 * ecm_db_connection_serial_get()
1559 * Return serial
1560 */
1561uint32_t ecm_db_connection_serial_get(struct ecm_db_connection_instance *ci)
1562{
1563 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1564 return ci->serial;
1565}
1566EXPORT_SYMBOL(ecm_db_connection_serial_get);
1567
1568/*
1569 * ecm_db_connection_from_address_get()
1570 * Return ip address address
1571 */
1572void ecm_db_connection_from_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1573{
1574 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1575 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1576 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1577 ECM_IP_ADDR_COPY(addr, ci->mapping_from->host->address);
1578}
1579EXPORT_SYMBOL(ecm_db_connection_from_address_get);
1580
1581/*
1582 * ecm_db_connection_from_address_nat_get()
1583 * Return NAT ip address address
1584 */
1585void ecm_db_connection_from_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1586{
1587 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1588 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1589 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1590 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_from->host->address);
1591}
1592EXPORT_SYMBOL(ecm_db_connection_from_address_nat_get);
1593
1594/*
1595 * ecm_db_connection_to_address_get()
1596 * Return ip address address
1597 */
1598void ecm_db_connection_to_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1599{
1600 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1601 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1602 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1603 ECM_IP_ADDR_COPY(addr, ci->mapping_to->host->address);
1604}
1605EXPORT_SYMBOL(ecm_db_connection_to_address_get);
1606
1607/*
1608 * ecm_db_connection_to_address_nat_get()
1609 * Return NAT ip address address
1610 */
1611void ecm_db_connection_to_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1612{
1613 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1614 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1615 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1616 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_to->host->address);
1617}
1618EXPORT_SYMBOL(ecm_db_connection_to_address_nat_get);
1619
1620/*
1621 * ecm_db_connection_to_port_get()
1622 * Return port
1623 */
1624int ecm_db_connection_to_port_get(struct ecm_db_connection_instance *ci)
1625{
1626 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1627 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1628 return ci->mapping_to->port;
1629}
1630EXPORT_SYMBOL(ecm_db_connection_to_port_get);
1631
1632/*
1633 * ecm_db_connection_to_port_nat_get()
1634 * Return port
1635 */
1636int ecm_db_connection_to_port_nat_get(struct ecm_db_connection_instance *ci)
1637{
1638 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1639 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1640 return ci->mapping_nat_to->port;
1641}
1642EXPORT_SYMBOL(ecm_db_connection_to_port_nat_get);
1643
1644/*
1645 * ecm_db_connection_from_port_get()
1646 * Return port
1647 */
1648int ecm_db_connection_from_port_get(struct ecm_db_connection_instance *ci)
1649{
1650 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1651 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1652 return ci->mapping_from->port;
1653}
1654EXPORT_SYMBOL(ecm_db_connection_from_port_get);
1655
1656/*
1657 * ecm_db_connection_from_port_nat_get()
1658 * Return port
1659 */
1660int ecm_db_connection_from_port_nat_get(struct ecm_db_connection_instance *ci)
1661{
1662 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1663 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1664 return ci->mapping_nat_from->port;
1665}
1666EXPORT_SYMBOL(ecm_db_connection_from_port_nat_get);
1667
1668/*
1669 * ecm_db_connection_to_node_address_get()
1670 * Return address of the node used when sending packets to the 'to' side.
1671 */
1672void ecm_db_connection_to_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1673{
1674 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001675 memcpy(address_buffer, ci->to_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001676}
1677EXPORT_SYMBOL(ecm_db_connection_to_node_address_get);
1678
1679/*
1680 * ecm_db_connection_from_node_address_get()
1681 * Return address of the node used when sending packets to the 'from' side.
1682 */
1683void ecm_db_connection_from_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1684{
1685 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001686 memcpy(address_buffer, ci->from_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001687}
1688EXPORT_SYMBOL(ecm_db_connection_from_node_address_get);
1689
1690/*
1691 * ecm_db_connection_to_nat_node_address_get()
1692 * Return address of the node used when sending packets to the 'to' NAT side.
1693 */
1694void ecm_db_connection_to_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1695{
1696 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001697 memcpy(address_buffer, ci->to_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001698}
1699EXPORT_SYMBOL(ecm_db_connection_to_nat_node_address_get);
1700
1701/*
1702 * ecm_db_connection_from_nat_node_address_get()
1703 * Return address of the node used when sending packets to the 'from' NAT side.
1704 */
1705void ecm_db_connection_from_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1706{
1707 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001708 memcpy(address_buffer, ci->from_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001709}
1710EXPORT_SYMBOL(ecm_db_connection_from_nat_node_address_get);
1711
1712/*
1713 * ecm_db_connection_to_iface_name_get()
1714 * Return name of interface on which the 'to' side may be reached
1715 */
1716void ecm_db_connection_to_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1717{
1718 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001719 strcpy(name_buffer, ci->to_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001720}
1721EXPORT_SYMBOL(ecm_db_connection_to_iface_name_get);
1722
1723/*
1724 * ecm_db_connection_from_iface_name_get()
1725 * Return name of interface on which the 'from' side may be reached
1726 */
1727void ecm_db_connection_from_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1728{
1729 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001730 strcpy(name_buffer, ci->from_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001731}
1732EXPORT_SYMBOL(ecm_db_connection_from_iface_name_get);
1733
1734/*
1735 * ecm_db_connection_to_iface_mtu_get()
1736 * Return MTU of interface on which the 'to' side may be reached
1737 */
1738int ecm_db_connection_to_iface_mtu_get(struct ecm_db_connection_instance *ci)
1739{
1740 int mtu;
1741 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1742 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001743 mtu = ci->to_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001744 spin_unlock_bh(&ecm_db_lock);
1745 return mtu;
1746}
1747EXPORT_SYMBOL(ecm_db_connection_to_iface_mtu_get);
1748
1749/*
1750 * ecm_db_connection_to_iface_type_get()
1751 * Return type of interface on which the 'to' side may be reached
1752 */
1753ecm_db_iface_type_t ecm_db_connection_to_iface_type_get(struct ecm_db_connection_instance *ci)
1754{
1755 ecm_db_iface_type_t type;
1756
1757 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1758 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001759 type = ci->to_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001760 spin_unlock_bh(&ecm_db_lock);
1761 return type;
1762}
1763EXPORT_SYMBOL(ecm_db_connection_to_iface_type_get);
1764
1765/*
1766 * ecm_db_connection_from_iface_mtu_get()
1767 * Return MTU of interface on which the 'from' side may be reached
1768 */
1769int ecm_db_connection_from_iface_mtu_get(struct ecm_db_connection_instance *ci)
1770{
1771 int mtu;
1772 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1773 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001774 mtu = ci->from_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001775 spin_unlock_bh(&ecm_db_lock);
1776 return mtu;
1777}
1778EXPORT_SYMBOL(ecm_db_connection_from_iface_mtu_get);
1779
1780/*
1781 * ecm_db_connection_from_iface_type_get()
1782 * Return type of interface on which the 'from' side may be reached
1783 */
1784ecm_db_iface_type_t ecm_db_connection_from_iface_type_get(struct ecm_db_connection_instance *ci)
1785{
1786 ecm_db_iface_type_t type;
1787
1788 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1789 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001790 type = ci->from_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001791 spin_unlock_bh(&ecm_db_lock);
1792 return type;
1793}
1794EXPORT_SYMBOL(ecm_db_connection_from_iface_type_get);
1795
1796/*
1797 * ecm_db_connection_iface_type_get()
1798 * Return type of interface
1799 */
1800ecm_db_iface_type_t ecm_db_connection_iface_type_get(struct ecm_db_iface_instance *ii)
1801{
1802 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1803 return ii->type;
1804}
1805EXPORT_SYMBOL(ecm_db_connection_iface_type_get);
1806
1807/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301808 * ecm_db_connection_regeneration_occurrances_get()
1809 * Get the number of regeneration occurrances that have occurred since the connection was created.
Ben Menchaca84f36632014-02-28 20:57:38 +00001810 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301811uint16_t ecm_db_connection_regeneration_occurrances_get(struct ecm_db_connection_instance *ci)
1812{
1813 uint16_t occurances;
1814 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1815
1816 spin_lock_bh(&ecm_db_lock);
1817 occurances = ci->regen_occurances;
1818 spin_unlock_bh(&ecm_db_lock);
1819 return occurances;
1820}
1821EXPORT_SYMBOL(ecm_db_connection_regeneration_occurrances_get);
1822
1823/*
1824 * ecm_db_conection_regeneration_completed()
1825 * Re-generation was completed successfully
1826 */
1827void ecm_db_conection_regeneration_completed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001828{
1829 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1830
1831 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301832
1833 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1834 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1835
1836 /*
1837 * Decrement the required counter by 1.
1838 * This may mean that regeneration is still required due to another change occuring _during_ re-generation.
1839 */
1840 ci->regen_required--;
1841 ci->regen_in_progress = false;
1842 ci->regen_success++;
1843 spin_unlock_bh(&ecm_db_lock);
1844}
1845EXPORT_SYMBOL(ecm_db_conection_regeneration_completed);
1846
1847/*
1848 * ecm_db_conection_regeneration_failed()
1849 * Re-generation failed
1850 */
1851void ecm_db_conection_regeneration_failed(struct ecm_db_connection_instance *ci)
1852{
1853 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1854
1855 spin_lock_bh(&ecm_db_lock);
1856
1857 DEBUG_ASSERT(ci->regen_in_progress, "%p: Bad call", ci);
1858 DEBUG_ASSERT(ci->regen_required > 0, "%p: Bad call", ci);
1859
1860 /*
1861 * Re-generation is no longer in progress BUT we leave the regen
1862 * counter as it is so as to indicate re-generation is still needed
1863 */
1864 ci->regen_in_progress = false;
1865 ci->regen_fail++;
1866 spin_unlock_bh(&ecm_db_lock);
1867}
1868EXPORT_SYMBOL(ecm_db_conection_regeneration_failed);
1869
1870/*
1871 * ecm_db_connection_regeneration_required_check()
1872 * Returns true if the connection needs to be re-generated.
1873 *
1874 * If re-generation is needed this will mark the connection to indicate that re-generation is needed AND in progress.
1875 * If the return code is TRUE the caller MUST handle the re-generation.
1876 * Upon re-generation completion you must call ecm_db_conection_regeneration_completed() or ecm_db_conection_regeneration_failed().
1877 */
1878bool ecm_db_connection_regeneration_required_check(struct ecm_db_connection_instance *ci)
1879{
1880 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1881
1882 /*
1883 * Check the global generation counter for changes
1884 */
1885 spin_lock_bh(&ecm_db_lock);
1886 if (ci->generation != ecm_db_connection_generation) {
1887 /*
1888 * Re-generation is needed
1889 */
1890 ci->regen_occurances++;
1891 ci->regen_required++;
1892
1893 /*
1894 * Record that we have seen this change
1895 */
1896 ci->generation = ecm_db_connection_generation;
1897 }
1898
1899 /*
1900 * If re-generation is in progress then something is handling re-generation already
1901 * so we tell the caller that it cannot handle re-generation.
1902 */
1903 if (ci->regen_in_progress) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001904 spin_unlock_bh(&ecm_db_lock);
1905 return false;
1906 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301907
1908 /*
1909 * Is re-generation required?
1910 */
1911 if (ci->regen_required == 0) {
1912 spin_unlock_bh(&ecm_db_lock);
1913 return false;
1914 }
1915
1916 /*
1917 * Flag that re-generation is in progress and tell the caller to handle re-generation
1918 */
1919 ci->regen_in_progress = true;
Ben Menchaca84f36632014-02-28 20:57:38 +00001920 spin_unlock_bh(&ecm_db_lock);
1921 return true;
1922}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301923EXPORT_SYMBOL(ecm_db_connection_regeneration_required_check);
Ben Menchaca84f36632014-02-28 20:57:38 +00001924
1925/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301926 * ecm_db_connection_regeneration_required_peek()
1927 * Returns true if the connection needs to be regenerated.
Ben Menchaca84f36632014-02-28 20:57:38 +00001928 *
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301929 * NOTE: The caller MUST NOT handle re-generation, the caller may use this indication
1930 * to determine the sanity of the connection state and whether acceleration is permitted.
Ben Menchaca84f36632014-02-28 20:57:38 +00001931 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301932bool ecm_db_connection_regeneration_required_peek(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001933{
1934 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1935
1936 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301937
1938 /*
1939 * Check the global generation counter for changes (record any change now)
1940 */
1941 if (ci->generation != ecm_db_connection_generation) {
1942 /*
1943 * Re-generation is needed, flag the connection as needing re-generation now.
1944 */
1945 ci->regen_occurances++;
1946 ci->regen_required++;
1947
1948 /*
1949 * Record that we have seen this change
1950 */
1951 ci->generation = ecm_db_connection_generation;
1952 }
1953 if (ci->regen_required == 0) {
Ben Menchaca84f36632014-02-28 20:57:38 +00001954 spin_unlock_bh(&ecm_db_lock);
1955 return false;
1956 }
1957 spin_unlock_bh(&ecm_db_lock);
1958 return true;
1959}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301960EXPORT_SYMBOL(ecm_db_connection_regeneration_required_peek);
Ben Menchaca84f36632014-02-28 20:57:38 +00001961
1962/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301963 * ecm_db_connection_regeneration_needed()
1964 * Cause a specific connection to require re-generation
1965 *
1966 * NOTE: This only flags that re-generation is needed.
1967 * The connection will typically be re-generated when ecm_db_connection_regeneration_required_check() is invoked.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01001968 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301969void ecm_db_connection_regeneration_needed(struct ecm_db_connection_instance *ci)
Ben Menchaca84f36632014-02-28 20:57:38 +00001970{
1971 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1972
1973 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301974 ci->regen_occurances++;
1975 ci->regen_required++;
Ben Menchaca84f36632014-02-28 20:57:38 +00001976 spin_unlock_bh(&ecm_db_lock);
1977}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301978EXPORT_SYMBOL(ecm_db_connection_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00001979
1980/*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301981 * ecm_db_regeneration_needed()
1982 * Bump the global generation index to cause a re-generation of all connections state.
Ben Menchaca84f36632014-02-28 20:57:38 +00001983 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301984void ecm_db_regeneration_needed(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00001985{
1986 spin_lock_bh(&ecm_db_lock);
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301987 ecm_db_connection_generation++;
Ben Menchaca84f36632014-02-28 20:57:38 +00001988 spin_unlock_bh(&ecm_db_lock);
1989}
Tushar Mathurd38cacd2015-07-28 12:19:10 +05301990EXPORT_SYMBOL(ecm_db_regeneration_needed);
Ben Menchaca84f36632014-02-28 20:57:38 +00001991
1992/*
Xiaoping Faned6d37e2015-09-17 14:13:47 -07001993 * ecm_db_connection_regenerate()
1994 * Re-generate a specific connection
1995 */
1996void ecm_db_connection_regenerate(struct ecm_db_connection_instance *ci)
1997{
1998 struct ecm_front_end_connection_instance *feci;
1999
2000 DEBUG_TRACE("Regenerate connection: %p\n", ci);
2001
2002 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2003
2004 /*
2005 * Notify front end to regenerate a connection.
2006 */
2007 feci = ecm_db_connection_front_end_get_and_ref(ci);
2008 feci->regenerate(feci, ci);
2009 feci->deref(feci);
2010}
2011EXPORT_SYMBOL(ecm_db_connection_regenerate);
2012
2013/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002014 * ecm_db_connection_direction_get()
2015 * Return direction of the connection.
2016 *
2017 * NOTE: an EGRESS connection means that packets being sent to mapping_to should have qos applied.
2018 * INGRESS means that packets being sent to mapping_from should have qos applied.
2019 */
2020ecm_db_direction_t ecm_db_connection_direction_get(struct ecm_db_connection_instance *ci)
2021{
2022 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2023 return ci->direction;
2024}
2025EXPORT_SYMBOL(ecm_db_connection_direction_get);
2026
2027/*
2028 * ecm_db_mapping_port_count_get()
2029 * Return port count stats for a mapping.
2030 */
2031void ecm_db_mapping_port_count_get(struct ecm_db_mapping_instance *mi,
2032 int *tcp_from, int *tcp_to, int *udp_from, int *udp_to, int *from, int *to,
2033 int *tcp_nat_from, int *tcp_nat_to, int *udp_nat_from, int *udp_nat_to, int *nat_from, int *nat_to)
2034{
2035 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2036
2037 spin_lock_bh(&ecm_db_lock);
2038
2039 *tcp_from = mi->tcp_from;
2040 *tcp_to = mi->tcp_to;
2041 *udp_from = mi->udp_from;
2042 *udp_to = mi->udp_to;
2043 *from = mi->from;
2044 *to = mi->to;
2045
2046 *tcp_nat_from = mi->tcp_nat_from;
2047 *tcp_nat_to = mi->tcp_nat_to;
2048 *udp_nat_from = mi->udp_nat_from;
2049 *udp_nat_to = mi->udp_nat_to;
2050 *nat_from = mi->nat_from;
2051 *nat_to = mi->nat_to;
2052
2053 spin_unlock_bh(&ecm_db_lock);
2054}
2055EXPORT_SYMBOL(ecm_db_mapping_port_count_get);
2056
2057/*
2058 * ecm_db_connection_is_routed_get()
2059 * Return whether connection is a routed path or not
2060 */
2061bool ecm_db_connection_is_routed_get(struct ecm_db_connection_instance *ci)
2062{
2063 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2064 return ci->is_routed;
2065}
2066EXPORT_SYMBOL(ecm_db_connection_is_routed_get);
2067
2068/*
2069 * ecm_db_connection_protocol_get()
2070 * Return protocol of connection
2071 */
2072int ecm_db_connection_protocol_get(struct ecm_db_connection_instance *ci)
2073{
2074 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2075 return ci->protocol;
2076}
2077EXPORT_SYMBOL(ecm_db_connection_protocol_get);
2078
2079/*
Gareth Williams3e5b37f2015-05-13 10:04:12 +01002080 * ecm_db_connection_ip_version_get()
2081 * Return IP version of connection
2082 */
2083int ecm_db_connection_ip_version_get(struct ecm_db_connection_instance *ci)
2084{
2085 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2086 return ci->ip_version;
2087}
2088EXPORT_SYMBOL(ecm_db_connection_ip_version_get);
2089
2090/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002091 * ecm_db_host_address_get()
2092 * Return address of host
2093 */
2094void ecm_db_host_address_get(struct ecm_db_host_instance *hi, ip_addr_t addr)
2095{
2096 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2097 ECM_IP_ADDR_COPY(addr, hi->address);
2098}
2099EXPORT_SYMBOL(ecm_db_host_address_get);
2100
2101/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002102 * ecm_db_host_on_link_get()
2103 * Return on link status of host
2104 */
2105bool ecm_db_host_on_link_get(struct ecm_db_host_instance *hi)
2106{
2107 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2108 return hi->on_link;
2109}
2110EXPORT_SYMBOL(ecm_db_host_on_link_get);
2111
2112/*
2113 * ecm_db_mapping_adress_get()
2114 * Return address
2115 */
2116void ecm_db_mapping_adress_get(struct ecm_db_mapping_instance *mi, ip_addr_t addr)
2117{
2118 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2119 ECM_IP_ADDR_COPY(addr, mi->host->address);
2120}
2121EXPORT_SYMBOL(ecm_db_mapping_adress_get);
2122
2123/*
2124 * ecm_db_mapping_port_get()
2125 * Return port
2126 */
2127int ecm_db_mapping_port_get(struct ecm_db_mapping_instance *mi)
2128{
2129 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2130 return mi->port;
2131}
2132EXPORT_SYMBOL(ecm_db_mapping_port_get);
2133
2134/*
2135 * ecm_db_node_adress_get()
2136 * Return address
2137 */
2138void ecm_db_node_adress_get(struct ecm_db_node_instance *ni, uint8_t *address_buffer)
2139{
2140 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2141 memcpy(address_buffer, ni->address, ETH_ALEN);
2142}
2143EXPORT_SYMBOL(ecm_db_node_adress_get);
2144
2145/*
2146 * _ecm_db_timer_group_entry_remove()
2147 * Remove the entry from its timer group, returns false if the entry has already expired.
2148 */
2149static bool _ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2150{
2151 struct ecm_db_timer_group *timer_group;
2152
2153 /*
2154 * If not in a timer group then it is already removed
2155 */
2156 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2157 return false;
2158 }
2159
2160 /*
2161 * Remove the connection from its current group
2162 */
2163 timer_group = &ecm_db_timer_groups[tge->group];
2164
2165 /*
2166 * Somewhere in the list?
2167 */
2168 if (tge->prev) {
2169 tge->prev->next = tge->next;
2170 } else {
2171 /*
2172 * First in the group
2173 */
2174 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p, got %p\n", timer_group, tge, timer_group->head);
2175 timer_group->head = tge->next;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302176 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002177
2178 if (tge->next) {
2179 tge->next->prev = tge->prev;
2180 } else {
2181 /*
2182 * No next so this must be the last item - we need to adjust the tail pointer
2183 */
2184 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2185 timer_group->tail = tge->prev;
2186 }
2187
2188 /*
2189 * No longer a part of a timer group
2190 */
2191 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2192 return true;
2193}
2194
2195/*
2196 * ecm_db_timer_group_entry_remove()
2197 * Remove the connection from its timer group, returns false if the entry has already expired.
2198 */
2199bool ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
2200{
2201 bool res;
2202 spin_lock_bh(&ecm_db_lock);
2203 res = _ecm_db_timer_group_entry_remove(tge);
2204 spin_unlock_bh(&ecm_db_lock);
2205 return res;
2206}
2207EXPORT_SYMBOL(ecm_db_timer_group_entry_remove);
2208
2209/*
2210 * _ecm_db_timer_group_entry_set()
2211 * Set the timer group to which this entry will be a member
2212 */
2213void _ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2214{
2215 struct ecm_db_timer_group *timer_group;
2216
2217 DEBUG_ASSERT(tge->group == ECM_DB_TIMER_GROUPS_MAX, "%p: already set\n", tge);
2218
2219 /*
2220 * Set group
2221 */
2222 tge->group = tg;
2223 timer_group = &ecm_db_timer_groups[tge->group];
2224 tge->timeout = timer_group->time + ecm_db_time;
2225
2226 /*
2227 * Insert into a timer group at the head (as this is now touched)
2228 */
2229 tge->prev = NULL;
2230 tge->next = timer_group->head;
2231 if (!timer_group->head) {
2232 /*
2233 * As there is no head there is also no tail so we need to set that
2234 */
2235 timer_group->tail = tge;
2236 } else {
2237 /*
2238 * As there is a head already there must be a tail. Since we insert before
2239 * the current head we don't adjust the tail.
2240 */
2241 timer_group->head->prev = tge;
2242 }
2243 timer_group->head = tge;
2244}
2245
2246/*
2247 * ecm_db_timer_group_entry_reset()
2248 * Re-set the timer group to which this entry will be a member.
2249 *
2250 * Returns false if the timer cannot be reset because it has expired
2251 */
2252bool ecm_db_timer_group_entry_reset(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2253{
2254 spin_lock_bh(&ecm_db_lock);
2255
2256 /*
2257 * Remove it from its current group, if any
2258 */
2259 if (!_ecm_db_timer_group_entry_remove(tge)) {
2260 spin_unlock_bh(&ecm_db_lock);
2261 return false;
2262 }
2263
2264 /*
2265 * Set new group
2266 */
2267 _ecm_db_timer_group_entry_set(tge, tg);
2268 spin_unlock_bh(&ecm_db_lock);
2269 return true;
2270}
2271EXPORT_SYMBOL(ecm_db_timer_group_entry_reset);
2272
2273/*
2274 * ecm_db_timer_group_entry_set()
2275 * Set the timer group to which this entry will be a member
2276 */
2277void ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
2278{
2279 spin_lock_bh(&ecm_db_lock);
2280 _ecm_db_timer_group_entry_set(tge, tg);
2281 spin_unlock_bh(&ecm_db_lock);
2282}
2283EXPORT_SYMBOL(ecm_db_timer_group_entry_set);
2284
2285/*
2286 * ecm_db_timer_group_entry_init()
2287 * Initialise a timer entry ready for setting
2288 */
2289void ecm_db_timer_group_entry_init(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_entry_callback_t fn, void *arg)
2290{
2291 memset(tge, 0, sizeof(struct ecm_db_timer_group_entry));
2292 tge->group = ECM_DB_TIMER_GROUPS_MAX;
2293 tge->arg = arg;
2294 tge->fn = fn;
2295}
2296EXPORT_SYMBOL(ecm_db_timer_group_entry_init);
2297
2298/*
2299 * ecm_db_timer_group_entry_touch()
2300 * Update the timeout, if the timer is not running this has no effect.
2301 * It returns false if the timer is not running.
2302 */
2303bool ecm_db_timer_group_entry_touch(struct ecm_db_timer_group_entry *tge)
2304{
2305 struct ecm_db_timer_group *timer_group;
2306
2307 spin_lock_bh(&ecm_db_lock);
2308
2309 /*
2310 * If not in a timer group then do nothing
2311 */
2312 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
2313 spin_unlock_bh(&ecm_db_lock);
2314 return false;
2315 }
2316
2317 /*
2318 * Update time to live
2319 */
2320 timer_group = &ecm_db_timer_groups[tge->group];
2321
2322 /*
2323 * Link out of its current position.
2324 */
2325 if (!tge->prev) {
2326 /*
2327 * Already at the head, just update the time
2328 */
2329 tge->timeout = timer_group->time + ecm_db_time;
2330 spin_unlock_bh(&ecm_db_lock);
2331 return true;
2332 }
2333
2334 /*
2335 * tge->prev is not null, so:
2336 * 1) it is in a timer list
2337 * 2) is not at the head of the list
2338 * 3) there is a head already (so more than one item on the list)
2339 * 4) there is a prev pointer.
2340 * Somewhere in the group list - unlink it.
2341 */
2342 tge->prev->next = tge->next;
2343
2344 if (tge->next) {
2345 tge->next->prev = tge->prev;
2346 } else {
2347 /*
2348 * Since there is no next this must be the tail
2349 */
2350 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
2351 timer_group->tail = tge->prev;
2352 }
2353
2354 /*
2355 * Link in to head.
2356 */
Sol Kavy213e45d2014-06-05 18:04:07 -07002357 tge->timeout = timer_group->time + ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00002358 tge->prev = NULL;
2359 tge->next = timer_group->head;
2360 timer_group->head->prev = tge;
2361 timer_group->head = tge;
2362 spin_unlock_bh(&ecm_db_lock);
2363 return true;
2364}
2365EXPORT_SYMBOL(ecm_db_timer_group_entry_touch);
2366
2367/*
2368 * _ecm_db_connection_ref()
2369 */
2370static void _ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2371{
2372 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2373 ci->refs++;
2374 DEBUG_TRACE("%p: connection ref %d\n", ci, ci->refs);
2375 DEBUG_ASSERT(ci->refs > 0, "%p: ref wrap\n", ci);
2376}
2377
2378/*
2379 * ecm_db_connection_ref()
2380 */
2381void ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
2382{
2383 spin_lock_bh(&ecm_db_lock);
2384 _ecm_db_connection_ref(ci);
2385 spin_unlock_bh(&ecm_db_lock);
2386}
2387EXPORT_SYMBOL(ecm_db_connection_ref);
2388
2389/*
2390 * _ecm_db_mapping_ref()
2391 */
2392static void _ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2393{
2394 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
2395 mi->refs++;
2396 DEBUG_TRACE("%p: mapping ref %d\n", mi, mi->refs);
2397 DEBUG_ASSERT(mi->refs > 0, "%p: ref wrap\n", mi);
2398}
2399
2400/*
2401 * ecm_db_mapping_ref()
2402 */
2403void ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
2404{
2405 spin_lock_bh(&ecm_db_lock);
2406 _ecm_db_mapping_ref(mi);
2407 spin_unlock_bh(&ecm_db_lock);
2408}
2409EXPORT_SYMBOL(ecm_db_mapping_ref);
2410
2411/*
2412 * _ecm_db_host_ref()
2413 */
2414static void _ecm_db_host_ref(struct ecm_db_host_instance *hi)
2415{
2416 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
2417 hi->refs++;
2418 DEBUG_TRACE("%p: host ref %d\n", hi, hi->refs);
2419 DEBUG_ASSERT(hi->refs > 0, "%p: ref wrap\n", hi);
2420}
2421
2422/*
2423 * ecm_db_host_ref()
2424 */
2425void ecm_db_host_ref(struct ecm_db_host_instance *hi)
2426{
2427 spin_lock_bh(&ecm_db_lock);
2428 _ecm_db_host_ref(hi);
2429 spin_unlock_bh(&ecm_db_lock);
2430}
2431EXPORT_SYMBOL(ecm_db_host_ref);
2432
2433/*
2434 * _ecm_db_node_ref()
2435 */
2436static void _ecm_db_node_ref(struct ecm_db_node_instance *ni)
2437{
2438 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
2439 ni->refs++;
2440 DEBUG_TRACE("%p: node ref %d\n", ni, ni->refs);
2441 DEBUG_ASSERT(ni->refs > 0, "%p: ref wrap\n", ni);
2442}
2443
2444/*
2445 * ecm_db_node_ref()
2446 */
2447void ecm_db_node_ref(struct ecm_db_node_instance *ni)
2448{
2449 spin_lock_bh(&ecm_db_lock);
2450 _ecm_db_node_ref(ni);
2451 spin_unlock_bh(&ecm_db_lock);
2452}
2453EXPORT_SYMBOL(ecm_db_node_ref);
2454
2455/*
2456 * _ecm_db_iface_ref()
2457 */
2458static void _ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2459{
2460 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
2461 ii->refs++;
2462 DEBUG_TRACE("%p: iface ref %d\n", ii, ii->refs);
2463 DEBUG_ASSERT(ii->refs > 0, "%p: ref wrap\n", ii);
2464}
2465
2466/*
2467 * ecm_db_iface_ref()
2468 */
2469void ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2470{
2471 spin_lock_bh(&ecm_db_lock);
2472 _ecm_db_iface_ref(ii);
2473 spin_unlock_bh(&ecm_db_lock);
2474}
2475EXPORT_SYMBOL(ecm_db_iface_ref);
2476
2477/*
2478 * _ecm_db_listener_ref()
2479 */
2480static void _ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2481{
2482 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2483 li->refs++;
2484 DEBUG_ASSERT(li->refs > 0, "%p: ref wrap\n", li);
2485}
2486
2487/*
2488 * ecm_db_listener_ref()
2489 */
2490void ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2491{
2492 spin_lock_bh(&ecm_db_lock);
2493 _ecm_db_listener_ref(li);
2494 spin_unlock_bh(&ecm_db_lock);
2495}
2496EXPORT_SYMBOL(ecm_db_listener_ref);
2497
2498/*
2499 * ecm_db_connections_get_and_ref_first()
2500 * Obtain a ref to the first connection instance, if any
2501 */
Gareth Williamsf98d4192015-03-11 16:55:41 +00002502struct ecm_db_connection_instance *ecm_db_connections_get_and_ref_first(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00002503{
2504 struct ecm_db_connection_instance *ci;
2505 spin_lock_bh(&ecm_db_lock);
2506 ci = ecm_db_connections;
2507 if (ci) {
2508 _ecm_db_connection_ref(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302509 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002510 spin_unlock_bh(&ecm_db_lock);
2511 return ci;
2512}
2513EXPORT_SYMBOL(ecm_db_connections_get_and_ref_first);
2514
2515/*
2516 * ecm_db_connection_get_and_ref_next()
2517 * Return the next connection in the list given a connection
2518 */
2519struct ecm_db_connection_instance *ecm_db_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
2520{
2521 struct ecm_db_connection_instance *cin;
2522 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2523 spin_lock_bh(&ecm_db_lock);
2524 cin = ci->next;
2525 if (cin) {
2526 _ecm_db_connection_ref(cin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302527 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002528 spin_unlock_bh(&ecm_db_lock);
2529 return cin;
2530}
2531EXPORT_SYMBOL(ecm_db_connection_get_and_ref_next);
2532
2533/*
2534 * ecm_db_mappings_get_and_ref_first()
2535 * Obtain a ref to the first mapping instance, if any
2536 */
2537struct ecm_db_mapping_instance *ecm_db_mappings_get_and_ref_first(void)
2538{
2539 struct ecm_db_mapping_instance *mi;
2540 spin_lock_bh(&ecm_db_lock);
2541 mi = ecm_db_mappings;
2542 if (mi) {
2543 _ecm_db_mapping_ref(mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302544 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002545 spin_unlock_bh(&ecm_db_lock);
2546 return mi;
2547}
2548EXPORT_SYMBOL(ecm_db_mappings_get_and_ref_first);
2549
2550/*
2551 * ecm_db_mapping_get_and_ref_next()
2552 * Return the next mapping in the list given a mapping
2553 */
2554struct ecm_db_mapping_instance *ecm_db_mapping_get_and_ref_next(struct ecm_db_mapping_instance *mi)
2555{
2556 struct ecm_db_mapping_instance *min;
2557 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2558 spin_lock_bh(&ecm_db_lock);
2559 min = mi->next;
2560 if (min) {
2561 _ecm_db_mapping_ref(min);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302562 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002563 spin_unlock_bh(&ecm_db_lock);
2564 return min;
2565}
2566EXPORT_SYMBOL(ecm_db_mapping_get_and_ref_next);
2567
2568/*
2569 * ecm_db_hosts_get_and_ref_first()
2570 * Obtain a ref to the first host instance, if any
2571 */
2572struct ecm_db_host_instance *ecm_db_hosts_get_and_ref_first(void)
2573{
2574 struct ecm_db_host_instance *hi;
2575 spin_lock_bh(&ecm_db_lock);
2576 hi = ecm_db_hosts;
2577 if (hi) {
2578 _ecm_db_host_ref(hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302579 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002580 spin_unlock_bh(&ecm_db_lock);
2581 return hi;
2582}
2583EXPORT_SYMBOL(ecm_db_hosts_get_and_ref_first);
2584
2585/*
2586 * ecm_db_host_get_and_ref_next()
2587 * Return the next host in the list given a host
2588 */
2589struct ecm_db_host_instance *ecm_db_host_get_and_ref_next(struct ecm_db_host_instance *hi)
2590{
2591 struct ecm_db_host_instance *hin;
2592 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2593 spin_lock_bh(&ecm_db_lock);
2594 hin = hi->next;
2595 if (hin) {
2596 _ecm_db_host_ref(hin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302597 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002598 spin_unlock_bh(&ecm_db_lock);
2599 return hin;
2600}
2601EXPORT_SYMBOL(ecm_db_host_get_and_ref_next);
2602
2603/*
2604 * ecm_db_listeners_get_and_ref_first()
2605 * Obtain a ref to the first listener instance, if any
2606 */
2607static struct ecm_db_listener_instance *ecm_db_listeners_get_and_ref_first(void)
2608{
2609 struct ecm_db_listener_instance *li;
2610 spin_lock_bh(&ecm_db_lock);
2611 li = ecm_db_listeners;
2612 if (li) {
2613 _ecm_db_listener_ref(li);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302614 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002615 spin_unlock_bh(&ecm_db_lock);
2616 return li;
2617}
2618
2619/*
2620 * ecm_db_listener_get_and_ref_next()
2621 * Return the next listener in the list given a listener
2622 */
2623static struct ecm_db_listener_instance *ecm_db_listener_get_and_ref_next(struct ecm_db_listener_instance *li)
2624{
2625 struct ecm_db_listener_instance *lin;
2626 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2627 spin_lock_bh(&ecm_db_lock);
2628 lin = li->next;
2629 if (lin) {
2630 _ecm_db_listener_ref(lin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302631 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002632 spin_unlock_bh(&ecm_db_lock);
2633 return lin;
2634}
2635
2636/*
2637 * ecm_db_nodes_get_and_ref_first()
2638 * Obtain a ref to the first node instance, if any
2639 */
2640struct ecm_db_node_instance *ecm_db_nodes_get_and_ref_first(void)
2641{
2642 struct ecm_db_node_instance *ni;
2643 spin_lock_bh(&ecm_db_lock);
2644 ni = ecm_db_nodes;
2645 if (ni) {
2646 _ecm_db_node_ref(ni);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302647 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002648 spin_unlock_bh(&ecm_db_lock);
2649 return ni;
2650}
2651EXPORT_SYMBOL(ecm_db_nodes_get_and_ref_first);
2652
2653/*
2654 * ecm_db_node_get_and_ref_next()
2655 * Return the next node in the list given a node
2656 */
2657struct ecm_db_node_instance *ecm_db_node_get_and_ref_next(struct ecm_db_node_instance *ni)
2658{
2659 struct ecm_db_node_instance *nin;
2660 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2661 spin_lock_bh(&ecm_db_lock);
2662 nin = ni->next;
2663 if (nin) {
2664 _ecm_db_node_ref(nin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302665 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002666 spin_unlock_bh(&ecm_db_lock);
2667 return nin;
2668}
2669EXPORT_SYMBOL(ecm_db_node_get_and_ref_next);
2670
2671/*
2672 * ecm_db_interfaces_get_and_ref_first()
2673 * Obtain a ref to the first iface instance, if any
2674 */
2675struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void)
2676{
2677 struct ecm_db_iface_instance *ii;
2678 spin_lock_bh(&ecm_db_lock);
2679 ii = ecm_db_interfaces;
2680 if (ii) {
2681 _ecm_db_iface_ref(ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302682 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002683 spin_unlock_bh(&ecm_db_lock);
2684 return ii;
2685}
2686EXPORT_SYMBOL(ecm_db_interfaces_get_and_ref_first);
2687
2688/*
2689 * ecm_db_interface_get_and_ref_next()
2690 * Return the next iface in the list given a iface
2691 */
2692struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii)
2693{
2694 struct ecm_db_iface_instance *iin;
2695 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
2696 spin_lock_bh(&ecm_db_lock);
2697 iin = ii->next;
2698 if (iin) {
2699 _ecm_db_iface_ref(iin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302700 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002701 spin_unlock_bh(&ecm_db_lock);
2702 return iin;
2703}
2704EXPORT_SYMBOL(ecm_db_interface_get_and_ref_next);
2705
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002706#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002707/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002708 * _ecm_db_classifier_type_assignment_remove()
2709 * Remove the connection from the classifier type assignment list (of the given type)
2710 */
2711static void _ecm_db_classifier_type_assignment_remove(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
2712{
2713 struct ecm_db_connection_classifier_type_assignment *ta;
2714 struct ecm_db_connection_classifier_type_assignment_list *tal;
2715
2716 DEBUG_TRACE("%p: Classifier type assignment remove: %d\n", ci, ca_type);
2717 ta = &ci->type_assignment[ca_type];
2718 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p\n", ta, ci);
2719 DEBUG_ASSERT(ta->iteration_count == 0, "%p: iteration count: %d, type: %d\n", ci, ta->iteration_count, ca_type);
2720
2721 if (ta->next) {
2722 struct ecm_db_connection_classifier_type_assignment *tan = &ta->next->type_assignment[ca_type];
2723 DEBUG_ASSERT(tan->prev == ci, "Bad list, expecting: %p, got: %p\n", ci, tan->prev);
2724 tan->prev = ta->prev;
2725 }
2726
2727 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
2728 if (ta->prev) {
2729 struct ecm_db_connection_classifier_type_assignment *tap = &ta->prev->type_assignment[ca_type];
2730 DEBUG_ASSERT(tap->next == ci, "Bad list, expecting: %p, got: %p\n", ci, tap->next);
2731 tap->next = ta->next;
2732 } else {
2733 /*
2734 * Set new head of list
2735 */
2736 DEBUG_ASSERT(tal->type_assignments_list == ci, "Bad head, expecting %p, got %p, type: %d\n", ci, tal->type_assignments_list, ca_type);
2737 tal->type_assignments_list = ta->next;
2738 }
2739 ta->next = NULL;
2740 ta->prev = NULL;
2741 ta->pending_unassign = false;
2742
2743 /*
2744 * Decrement assignment count
2745 */
2746 tal->type_assignment_count--;
2747 DEBUG_ASSERT(tal->type_assignment_count >= 0, "Bad type assignment count: %d, type: %d\n", tal->type_assignment_count, ca_type);
2748
2749 DEBUG_CLEAR_MAGIC(ta);
2750}
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002751#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002752
2753/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002754 * ecm_db_connection_deref()
2755 * Release reference to connection. Connection is removed from database on final deref and destroyed.
2756 */
2757int ecm_db_connection_deref(struct ecm_db_connection_instance *ci)
2758{
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002759#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002760 ecm_classifier_type_t ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002761#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002762 int32_t i;
2763
2764 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2765
2766 spin_lock_bh(&ecm_db_lock);
2767 ci->refs--;
2768 DEBUG_TRACE("%p: connection deref %d\n", ci, ci->refs);
2769 DEBUG_ASSERT(ci->refs >= 0, "%p: ref wrap\n", ci);
2770
2771 if (ci->refs > 0) {
2772 int refs = ci->refs;
2773 spin_unlock_bh(&ecm_db_lock);
2774 return refs;
2775 }
2776
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002777#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002778 /*
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002779 * Unlink from the "assignments by classifier type" lists.
ratheesh kannoth37e35b02015-03-26 11:25:02 +05302780 *
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002781 * This is done whether the connection is inserted into the database or not - this is because
2782 * classifier assignments take place before adding into the db.
2783 *
2784 * NOTE: We know that the ci is not being iterated in any of these lists because otherwise
2785 * ci would be being held as part of iteration and so we would not be here!
2786 * Equally we know that if the assignments_by_type[] element is non-null then it must also be in the relevant list too.
2787 */
2788 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
2789 if (!ci->assignments_by_type[ca_type]) {
2790 /*
2791 * No assignment of this type, so would not be in the classifier type assignments list
2792 */
2793 continue;
2794 }
2795 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
2796 }
Gareth Williamsb39e7c22015-03-25 10:15:33 +00002797#endif
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002798
2799 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002800 * Remove from database if inserted
2801 */
2802 if (!ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED) {
2803 spin_unlock_bh(&ecm_db_lock);
2804 } else {
2805 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00002806#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002807 struct ecm_db_iface_instance *iface_from;
2808 struct ecm_db_iface_instance *iface_to;
2809 struct ecm_db_iface_instance *iface_nat_from;
2810 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00002811#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00002812
2813 /*
2814 * Remove it from the connection hash table
2815 */
2816 if (!ci->hash_prev) {
2817 DEBUG_ASSERT(ecm_db_connection_table[ci->hash_index] == ci, "%p: hash table bad\n", ci);
2818 ecm_db_connection_table[ci->hash_index] = ci->hash_next;
2819 } else {
2820 ci->hash_prev->hash_next = ci->hash_next;
2821 }
2822 if (ci->hash_next) {
2823 ci->hash_next->hash_prev = ci->hash_prev;
2824 }
2825 ecm_db_connection_table_lengths[ci->hash_index]--;
2826 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]);
2827
2828 /*
2829 * Remove it from the connection serial hash table
2830 */
2831 if (!ci->serial_hash_prev) {
2832 DEBUG_ASSERT(ecm_db_connection_serial_table[ci->serial_hash_index] == ci, "%p: hash table bad\n", ci);
2833 ecm_db_connection_serial_table[ci->serial_hash_index] = ci->serial_hash_next;
2834 } else {
2835 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
2836 }
2837 if (ci->serial_hash_next) {
2838 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
2839 }
2840 ecm_db_connection_serial_table_lengths[ci->serial_hash_index]--;
2841 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]);
2842
2843 /*
2844 * Remove from the global list
2845 */
2846 if (!ci->prev) {
2847 DEBUG_ASSERT(ecm_db_connections == ci, "%p: conn table bad\n", ci);
2848 ecm_db_connections = ci->next;
2849 } else {
2850 ci->prev->next = ci->next;
2851 }
2852 if (ci->next) {
2853 ci->next->prev = ci->prev;
2854 }
2855
Gareth Williamsb5903892015-03-20 15:13:07 +00002856#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00002857 /*
2858 * Remove connection from the "from" mapping connection list
2859 */
2860 if (!ci->from_prev) {
2861 DEBUG_ASSERT(ci->mapping_from->from_connections == ci, "%p: from conn table bad\n", ci);
2862 ci->mapping_from->from_connections = ci->from_next;
2863 } else {
2864 ci->from_prev->from_next = ci->from_next;
2865 }
2866 if (ci->from_next) {
2867 ci->from_next->from_prev = ci->from_prev;
2868 }
2869
2870 /*
2871 * Remove connection from the "to" mapping connection list
2872 */
2873 if (!ci->to_prev) {
2874 DEBUG_ASSERT(ci->mapping_to->to_connections == ci, "%p: to conn table bad\n", ci);
2875 ci->mapping_to->to_connections = ci->to_next;
2876 } else {
2877 ci->to_prev->to_next = ci->to_next;
2878 }
2879 if (ci->to_next) {
2880 ci->to_next->to_prev = ci->to_prev;
2881 }
2882
2883 /*
2884 * Remove connection from the "from" NAT mapping connection list
2885 */
2886 if (!ci->from_nat_prev) {
2887 DEBUG_ASSERT(ci->mapping_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2888 ci->mapping_nat_from->from_nat_connections = ci->from_nat_next;
2889 } else {
2890 ci->from_nat_prev->from_nat_next = ci->from_nat_next;
2891 }
2892 if (ci->from_nat_next) {
2893 ci->from_nat_next->from_nat_prev = ci->from_nat_prev;
2894 }
2895
2896 /*
2897 * Remove connection from the "to" NAT mapping connection list
2898 */
2899 if (!ci->to_nat_prev) {
2900 DEBUG_ASSERT(ci->mapping_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2901 ci->mapping_nat_to->to_nat_connections = ci->to_nat_next;
2902 } else {
2903 ci->to_nat_prev->to_nat_next = ci->to_nat_next;
2904 }
2905 if (ci->to_nat_next) {
2906 ci->to_nat_next->to_nat_prev = ci->to_nat_prev;
2907 }
2908
2909 /*
2910 * Remove connection from the "from" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002911 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002912 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002913 iface_from = ci->from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002914 if (!ci->iface_from_prev) {
2915 DEBUG_ASSERT(iface_from->from_connections == ci, "%p: iface from conn table bad\n", ci);
2916 iface_from->from_connections = ci->iface_from_next;
2917 } else {
2918 ci->iface_from_prev->iface_from_next = ci->iface_from_next;
2919 }
2920 if (ci->iface_from_next) {
2921 ci->iface_from_next->iface_from_prev = ci->iface_from_prev;
2922 }
2923
2924 /*
2925 * Remove connection from the "to" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002926 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002927 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002928 iface_to = ci->to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002929 if (!ci->iface_to_prev) {
2930 DEBUG_ASSERT(iface_to->to_connections == ci, "%p: to conn table bad\n", ci);
2931 iface_to->to_connections = ci->iface_to_next;
2932 } else {
2933 ci->iface_to_prev->iface_to_next = ci->iface_to_next;
2934 }
2935 if (ci->iface_to_next) {
2936 ci->iface_to_next->iface_to_prev = ci->iface_to_prev;
2937 }
2938
2939 /*
2940 * Remove connection from the "from" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002941 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002942 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002943 iface_nat_from = ci->from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002944 if (!ci->iface_from_nat_prev) {
2945 DEBUG_ASSERT(iface_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2946 iface_nat_from->from_nat_connections = ci->iface_from_nat_next;
2947 } else {
2948 ci->iface_from_nat_prev->iface_from_nat_next = ci->iface_from_nat_next;
2949 }
2950 if (ci->iface_from_nat_next) {
2951 ci->iface_from_nat_next->iface_from_nat_prev = ci->iface_from_nat_prev;
2952 }
2953
2954 /*
2955 * Remove connection from the "to" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002956 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002957 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002958 iface_nat_to = ci->to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002959 if (!ci->iface_to_nat_prev) {
2960 DEBUG_ASSERT(iface_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2961 iface_nat_to->to_nat_connections = ci->iface_to_nat_next;
2962 } else {
2963 ci->iface_to_nat_prev->iface_to_nat_next = ci->iface_to_nat_next;
2964 }
2965 if (ci->iface_to_nat_next) {
2966 ci->iface_to_nat_next->iface_to_nat_prev = ci->iface_to_nat_prev;
2967 }
2968
2969 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01002970 * Remove connection from its "from node" node connection list
2971 */
2972 if (!ci->node_from_prev) {
2973 DEBUG_ASSERT(ci->from_node->from_connections == ci, "%p: from node conn table bad, got: %p\n", ci, ci->from_node->from_connections);
2974 ci->from_node->from_connections = ci->node_from_next;
2975 } else {
2976 ci->node_from_prev->node_from_next = ci->node_from_next;
2977 }
2978 if (ci->node_from_next) {
2979 ci->node_from_next->node_from_prev = ci->node_from_prev;
2980 }
2981 ci->from_node->from_connections_count--;
2982 DEBUG_ASSERT(ci->from_node->from_connections_count >= 0, "%p: bad count\n", ci);
2983
2984 /*
2985 * Remove connection from its "to node" node connection list
2986 */
2987 if (!ci->node_to_prev) {
2988 DEBUG_ASSERT(ci->to_node->to_connections == ci, "%p: to node conn table bad, got: %p\n", ci, ci->to_node->to_connections);
2989 ci->to_node->to_connections = ci->node_to_next;
2990 } else {
2991 ci->node_to_prev->node_to_next = ci->node_to_next;
2992 }
2993 if (ci->node_to_next) {
2994 ci->node_to_next->node_to_prev = ci->node_to_prev;
2995 }
2996 ci->to_node->to_connections_count--;
2997 DEBUG_ASSERT(ci->to_node->to_connections_count >= 0, "%p: bad count\n", ci);
2998
2999 /*
3000 * Remove connection from its "from nat node" node connection list
3001 */
3002 if (!ci->node_from_nat_prev) {
3003 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);
3004 ci->from_nat_node->from_nat_connections = ci->node_from_nat_next;
3005 } else {
3006 ci->node_from_nat_prev->node_from_nat_next = ci->node_from_nat_next;
3007 }
3008 if (ci->node_from_nat_next) {
3009 ci->node_from_nat_next->node_from_nat_prev = ci->node_from_nat_prev;
3010 }
3011 ci->from_nat_node->from_nat_connections_count--;
3012 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections_count >= 0, "%p: bad count\n", ci);
3013
3014 /*
3015 * Remove connection from its "to nat node" node connection list
3016 */
3017 if (!ci->node_to_nat_prev) {
3018 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);
3019 ci->to_nat_node->to_nat_connections = ci->node_to_nat_next;
3020 } else {
3021 ci->node_to_nat_prev->node_to_nat_next = ci->node_to_nat_next;
3022 }
3023 if (ci->node_to_nat_next) {
3024 ci->node_to_nat_next->node_to_nat_prev = ci->node_to_nat_prev;
3025 }
3026 ci->to_nat_node->to_nat_connections_count--;
3027 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections_count >= 0, "%p: bad count\n", ci);
Gareth Williamsb5903892015-03-20 15:13:07 +00003028#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01003029
3030 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003031 * Update the counters in the mappings
3032 */
3033 if (ci->protocol == IPPROTO_UDP) {
3034 ci->mapping_from->udp_from--;
3035 ci->mapping_to->udp_to--;
3036 ci->mapping_nat_from->udp_nat_from--;
3037 ci->mapping_nat_to->udp_nat_to--;
3038 } else if (ci->protocol == IPPROTO_TCP) {
3039 ci->mapping_from->tcp_from--;
3040 ci->mapping_to->tcp_to--;
3041 ci->mapping_nat_from->tcp_nat_from--;
3042 ci->mapping_nat_to->tcp_nat_to--;
3043 }
3044
3045 ci->mapping_from->from--;
3046 ci->mapping_to->to--;
3047 ci->mapping_nat_from->nat_from--;
3048 ci->mapping_nat_to->nat_to--;
3049
3050 /*
3051 * Assert that the defunt timer has been detached
3052 */
3053 DEBUG_ASSERT(ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX, "%p: unexpected timer group %d\n", ci, ci->defunct_timer.group);
3054
3055 /*
3056 * Decrement protocol counter stats
3057 */
3058 ecm_db_connection_count_by_protocol[ci->protocol]--;
3059 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 +01003060
Ben Menchaca84f36632014-02-28 20:57:38 +00003061 spin_unlock_bh(&ecm_db_lock);
3062
3063 /*
3064 * Throw removed event to listeners
3065 */
3066 DEBUG_TRACE("%p: Throw connection removed event\n", ci);
3067 li = ecm_db_listeners_get_and_ref_first();
3068 while (li) {
3069 struct ecm_db_listener_instance *lin;
3070 if (li->connection_removed) {
3071 li->connection_removed(li->arg, ci);
3072 }
3073
3074 /*
3075 * Get next listener
3076 */
3077 lin = ecm_db_listener_get_and_ref_next(li);
3078 ecm_db_listener_deref(li);
3079 li = lin;
3080 }
3081 }
3082
3083 /*
3084 * Throw final event
3085 */
3086 if (ci->final) {
3087 ci->final(ci->arg);
3088 }
3089
3090 /*
3091 * Release instances to the objects referenced by the connection
3092 */
3093 while (ci->assignments) {
3094 struct ecm_classifier_instance *classi = ci->assignments;
3095 ci->assignments = classi->ca_next;
3096 classi->deref(classi);
3097 }
3098
Ben Menchaca84f36632014-02-28 20:57:38 +00003099 if (ci->mapping_from) {
3100 ecm_db_mapping_deref(ci->mapping_from);
3101 }
3102 if (ci->mapping_to) {
3103 ecm_db_mapping_deref(ci->mapping_to);
3104 }
3105 if (ci->mapping_nat_from) {
3106 ecm_db_mapping_deref(ci->mapping_nat_from);
3107 }
3108 if (ci->mapping_nat_to) {
3109 ecm_db_mapping_deref(ci->mapping_nat_to);
3110 }
3111 if (ci->feci) {
3112 ci->feci->deref(ci->feci);
3113 }
Gareth Williams90f2a282014-08-27 15:56:25 +01003114 if (ci->from_node) {
3115 ecm_db_node_deref(ci->from_node);
3116 }
3117 if (ci->to_node) {
3118 ecm_db_node_deref(ci->to_node);
3119 }
3120 if (ci->from_nat_node) {
3121 ecm_db_node_deref(ci->from_nat_node);
3122 }
3123 if (ci->to_nat_node) {
3124 ecm_db_node_deref(ci->to_nat_node);
3125 }
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05303126#ifdef ECM_MULTICAST_ENABLE
3127 if (ci->ti) {
3128 ecm_db_multicast_tuple_instance_deref(ci->ti);
3129 }
3130#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003131 /*
3132 * Remove references to the interfaces in our heirarchy lists
3133 */
3134 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3135 DEBUG_TRACE("%p: from interface %d remove: %p\n", ci, i, ci->from_interfaces[i]);
3136 ecm_db_iface_deref(ci->from_interfaces[i]);
3137 }
3138 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3139 DEBUG_TRACE("%p: to interface %d remove: %p\n", ci, i, ci->to_interfaces[i]);
3140 ecm_db_iface_deref(ci->to_interfaces[i]);
3141 }
3142 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3143 DEBUG_TRACE("%p: from nat interface %d remove: %p\n", ci, i, ci->from_nat_interfaces[i]);
3144 ecm_db_iface_deref(ci->from_nat_interfaces[i]);
3145 }
3146 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
3147 DEBUG_TRACE("%p: to nat interface %d remove: %p\n", ci, i, ci->to_nat_interfaces[i]);
3148 ecm_db_iface_deref(ci->to_nat_interfaces[i]);
3149 }
3150
3151 /*
3152 * We can now destroy the instance
3153 */
3154 DEBUG_CLEAR_MAGIC(ci);
3155 kfree(ci);
3156
3157 /*
3158 * Decrease global connection count
3159 */
3160 spin_lock_bh(&ecm_db_lock);
3161 ecm_db_connection_count--;
3162 DEBUG_ASSERT(ecm_db_connection_count >= 0, "%p: connection count wrap\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00003163 spin_unlock_bh(&ecm_db_lock);
3164
Ben Menchaca84f36632014-02-28 20:57:38 +00003165 return 0;
3166}
3167EXPORT_SYMBOL(ecm_db_connection_deref);
3168
3169/*
3170 * ecm_db_mapping_deref()
3171 * Release ref to mapping, possibly removing it from the database and destroying it.
3172 */
3173int ecm_db_mapping_deref(struct ecm_db_mapping_instance *mi)
3174{
3175 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
3176
3177 spin_lock_bh(&ecm_db_lock);
3178 mi->refs--;
3179 DEBUG_TRACE("%p: mapping deref %d\n", mi, mi->refs);
3180 DEBUG_ASSERT(mi->refs >= 0, "%p: ref wrap\n", mi);
3181
3182 if (mi->refs > 0) {
3183 int refs = mi->refs;
3184 spin_unlock_bh(&ecm_db_lock);
3185 return refs;
3186 }
3187
Gareth Williamsb5903892015-03-20 15:13:07 +00003188 DEBUG_ASSERT(!mi->tcp_from && !mi->udp_from && !mi->from, "%p: from not zero: %d, %d, %d\n",
3189 mi, mi->tcp_from, mi->udp_from, mi->from);
3190 DEBUG_ASSERT(!mi->tcp_to && !mi->udp_to && !mi->to, "%p: to not zero: %d, %d, %d\n",
3191 mi, mi->tcp_to, mi->udp_to, mi->to);
3192 DEBUG_ASSERT(!mi->tcp_nat_from && !mi->udp_nat_from && !mi->nat_from, "%p: nat_from not zero: %d, %d, %d\n",
3193 mi, mi->tcp_nat_from, mi->udp_nat_from, mi->nat_from);
3194 DEBUG_ASSERT(!mi->tcp_nat_to && !mi->udp_nat_to && !mi->nat_to, "%p: nat_to not zero: %d, %d, %d\n",
3195 mi, mi->tcp_nat_to, mi->udp_nat_to, mi->nat_to);
3196
3197#ifdef ECM_DB_XREF_ENABLE
3198 DEBUG_ASSERT(!mi->from_connections, "%p: from not null: %p\n", mi, mi->from_connections);
3199 DEBUG_ASSERT(!mi->to_connections, "%p: to not null: %p\n", mi, mi->to_connections);
3200 DEBUG_ASSERT(!mi->from_nat_connections, "%p: nat_from not null: %p\n", mi, mi->from_nat_connections);
3201 DEBUG_ASSERT(!mi->to_nat_connections, "%p: nat_to not null: %p\n", mi, mi->to_nat_connections);
3202#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003203
3204 /*
3205 * Remove from database if inserted
3206 */
3207 if (!mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED) {
3208 spin_unlock_bh(&ecm_db_lock);
3209 } else {
3210 struct ecm_db_listener_instance *li;
3211
3212 /*
3213 * Remove from the global list
3214 */
3215 if (!mi->prev) {
3216 DEBUG_ASSERT(ecm_db_mappings == mi, "%p: mapping table bad\n", mi);
3217 ecm_db_mappings = mi->next;
3218 } else {
3219 mi->prev->next = mi->next;
3220 }
3221 if (mi->next) {
3222 mi->next->prev = mi->prev;
3223 }
3224
3225 /*
3226 * Unlink it from the mapping hash table
3227 */
3228 if (!mi->hash_prev) {
3229 DEBUG_ASSERT(ecm_db_mapping_table[mi->hash_index] == mi, "%p: hash table bad\n", mi);
3230 ecm_db_mapping_table[mi->hash_index] = mi->hash_next;
3231 } else {
3232 mi->hash_prev->hash_next = mi->hash_next;
3233 }
3234 if (mi->hash_next) {
3235 mi->hash_next->hash_prev = mi->hash_prev;
3236 }
3237 mi->hash_next = NULL;
3238 mi->hash_prev = NULL;
3239 ecm_db_mapping_table_lengths[mi->hash_index]--;
3240 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]);
3241
Gareth Williamsb5903892015-03-20 15:13:07 +00003242#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003243 /*
3244 * Unlink it from the host mapping list
3245 */
3246 if (!mi->mapping_prev) {
3247 DEBUG_ASSERT(mi->host->mappings == mi, "%p: mapping table bad\n", mi);
3248 mi->host->mappings = mi->mapping_next;
3249 } else {
3250 mi->mapping_prev->mapping_next = mi->mapping_next;
3251 }
3252 if (mi->mapping_next) {
3253 mi->mapping_next->mapping_prev = mi->mapping_prev;
3254 }
3255 mi->mapping_next = NULL;
3256 mi->mapping_prev = NULL;
3257
3258 mi->host->mapping_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003259#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003260 spin_unlock_bh(&ecm_db_lock);
3261
3262 /*
3263 * Throw removed event to listeners
3264 */
3265 DEBUG_TRACE("%p: Throw mapping removed event\n", mi);
3266 li = ecm_db_listeners_get_and_ref_first();
3267 while (li) {
3268 struct ecm_db_listener_instance *lin;
3269 if (li->mapping_removed) {
3270 li->mapping_removed(li->arg, mi);
3271 }
3272
3273 /*
3274 * Get next listener
3275 */
3276 lin = ecm_db_listener_get_and_ref_next(li);
3277 ecm_db_listener_deref(li);
3278 li = lin;
3279 }
3280 }
3281
3282 /*
3283 * Throw final event
3284 */
3285 if (mi->final) {
3286 mi->final(mi->arg);
3287 }
3288
3289 /*
3290 * Now release the host instance if the mapping had one
3291 */
3292 if (mi->host) {
3293 ecm_db_host_deref(mi->host);
3294 }
3295
3296 /*
3297 * We can now destroy the instance
3298 */
3299 DEBUG_CLEAR_MAGIC(mi);
3300 kfree(mi);
3301
3302 /*
3303 * Decrease global mapping count
3304 */
3305 spin_lock_bh(&ecm_db_lock);
3306 ecm_db_mapping_count--;
3307 DEBUG_ASSERT(ecm_db_mapping_count >= 0, "%p: mapping count wrap\n", mi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003308 spin_unlock_bh(&ecm_db_lock);
3309
Ben Menchaca84f36632014-02-28 20:57:38 +00003310 return 0;
3311}
3312EXPORT_SYMBOL(ecm_db_mapping_deref);
3313
3314/*
3315 * ecm_db_host_deref()
3316 * Release a ref to a host instance, possibly causing removal from the database and destruction of the instance
3317 */
3318int ecm_db_host_deref(struct ecm_db_host_instance *hi)
3319{
3320 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
3321
3322 spin_lock_bh(&ecm_db_lock);
3323 hi->refs--;
3324 DEBUG_TRACE("%p: host deref %d\n", hi, hi->refs);
3325 DEBUG_ASSERT(hi->refs >= 0, "%p: ref wrap\n", hi);
3326
3327 if (hi->refs > 0) {
3328 int refs = hi->refs;
3329 spin_unlock_bh(&ecm_db_lock);
3330 return refs;
3331 }
3332
Gareth Williamsb5903892015-03-20 15:13:07 +00003333#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003334 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00003335#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003336
3337 /*
3338 * Remove from database if inserted
3339 */
3340 if (!hi->flags & ECM_DB_HOST_FLAGS_INSERTED) {
3341 spin_unlock_bh(&ecm_db_lock);
3342 } else {
3343 struct ecm_db_listener_instance *li;
3344
3345 /*
3346 * Remove from the global list
3347 */
3348 if (!hi->prev) {
3349 DEBUG_ASSERT(ecm_db_hosts == hi, "%p: host table bad\n", hi);
3350 ecm_db_hosts = hi->next;
3351 } else {
3352 hi->prev->next = hi->next;
3353 }
3354 if (hi->next) {
3355 hi->next->prev = hi->prev;
3356 }
3357
3358 /*
3359 * Unlink it from the host hash table
3360 */
3361 if (!hi->hash_prev) {
3362 DEBUG_ASSERT(ecm_db_host_table[hi->hash_index] == hi, "%p: hash table bad\n", hi);
3363 ecm_db_host_table[hi->hash_index] = hi->hash_next;
3364 } else {
3365 hi->hash_prev->hash_next = hi->hash_next;
3366 }
3367 if (hi->hash_next) {
3368 hi->hash_next->hash_prev = hi->hash_prev;
3369 }
3370 hi->hash_next = NULL;
3371 hi->hash_prev = NULL;
3372 ecm_db_host_table_lengths[hi->hash_index]--;
3373 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]);
3374
Ben Menchaca84f36632014-02-28 20:57:38 +00003375 spin_unlock_bh(&ecm_db_lock);
3376
3377 /*
3378 * Throw removed event to listeners
3379 */
3380 DEBUG_TRACE("%p: Throw host removed event\n", hi);
3381 li = ecm_db_listeners_get_and_ref_first();
3382 while (li) {
3383 struct ecm_db_listener_instance *lin;
3384 if (li->host_removed) {
3385 li->host_removed(li->arg, hi);
3386 }
3387
3388 /*
3389 * Get next listener
3390 */
3391 lin = ecm_db_listener_get_and_ref_next(li);
3392 ecm_db_listener_deref(li);
3393 li = lin;
3394 }
3395 }
3396
3397 /*
3398 * Throw final event
3399 */
3400 if (hi->final) {
3401 hi->final(hi->arg);
3402 }
3403
3404 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00003405 * We can now destroy the instance
3406 */
3407 DEBUG_CLEAR_MAGIC(hi);
3408 kfree(hi);
3409
3410 /*
3411 * Decrease global host count
3412 */
3413 spin_lock_bh(&ecm_db_lock);
3414 ecm_db_host_count--;
3415 DEBUG_ASSERT(ecm_db_host_count >= 0, "%p: host count wrap\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00003416 spin_unlock_bh(&ecm_db_lock);
3417
Ben Menchaca84f36632014-02-28 20:57:38 +00003418 return 0;
3419}
3420EXPORT_SYMBOL(ecm_db_host_deref);
3421
3422/*
3423 * ecm_db_node_deref()
3424 * Deref a node. Removing it on the last ref and destroying it.
3425 */
3426int ecm_db_node_deref(struct ecm_db_node_instance *ni)
3427{
3428 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
3429
3430 spin_lock_bh(&ecm_db_lock);
3431 ni->refs--;
3432 DEBUG_TRACE("%p: node deref %d\n", ni, ni->refs);
3433 DEBUG_ASSERT(ni->refs >= 0, "%p: ref wrap\n", ni);
3434
3435 if (ni->refs > 0) {
3436 int refs = ni->refs;
3437 spin_unlock_bh(&ecm_db_lock);
3438 return refs;
3439 }
3440
Gareth Williamsb5903892015-03-20 15:13:07 +00003441#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01003442 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
3443 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
3444 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
3445 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 +00003446#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003447
3448 /*
3449 * Remove from database if inserted
3450 */
3451 if (!ni->flags & ECM_DB_NODE_FLAGS_INSERTED) {
3452 spin_unlock_bh(&ecm_db_lock);
3453 } else {
3454 struct ecm_db_listener_instance *li;
3455
3456 /*
3457 * Remove from the global list
3458 */
3459 if (!ni->prev) {
3460 DEBUG_ASSERT(ecm_db_nodes == ni, "%p: node table bad\n", ni);
3461 ecm_db_nodes = ni->next;
3462 } else {
3463 ni->prev->next = ni->next;
3464 }
3465 if (ni->next) {
3466 ni->next->prev = ni->prev;
3467 }
3468
3469 /*
3470 * Link out of hash table
3471 */
3472 if (!ni->hash_prev) {
3473 DEBUG_ASSERT(ecm_db_node_table[ni->hash_index] == ni, "%p: hash table bad\n", ni);
3474 ecm_db_node_table[ni->hash_index] = ni->hash_next;
3475 } else {
3476 ni->hash_prev->hash_next = ni->hash_next;
3477 }
3478 if (ni->hash_next) {
3479 ni->hash_next->hash_prev = ni->hash_prev;
3480 }
3481 ni->hash_next = NULL;
3482 ni->hash_prev = NULL;
3483 ecm_db_node_table_lengths[ni->hash_index]--;
3484 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]);
3485
Gareth Williamsb5903892015-03-20 15:13:07 +00003486#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003487 /*
3488 * Unlink it from the iface node list
3489 */
3490 if (!ni->node_prev) {
3491 DEBUG_ASSERT(ni->iface->nodes == ni, "%p: nodes table bad\n", ni);
3492 ni->iface->nodes = ni->node_next;
3493 } else {
3494 ni->node_prev->node_next = ni->node_next;
3495 }
3496 if (ni->node_next) {
3497 ni->node_next->node_prev = ni->node_prev;
3498 }
3499 ni->node_next = NULL;
3500 ni->node_prev = NULL;
3501 ni->iface->node_count--;
Gareth Williamsb5903892015-03-20 15:13:07 +00003502#endif
3503
Ben Menchaca84f36632014-02-28 20:57:38 +00003504 spin_unlock_bh(&ecm_db_lock);
3505
3506 /*
3507 * Throw removed event to listeners
3508 */
3509 DEBUG_TRACE("%p: Throw node removed event\n", ni);
3510 li = ecm_db_listeners_get_and_ref_first();
3511 while (li) {
3512 struct ecm_db_listener_instance *lin;
3513 if (li->node_removed) {
3514 li->node_removed(li->arg, ni);
3515 }
3516
3517 /*
3518 * Get next listener
3519 */
3520 lin = ecm_db_listener_get_and_ref_next(li);
3521 ecm_db_listener_deref(li);
3522 li = lin;
3523 }
3524 }
3525
3526 /*
3527 * Throw final event
3528 */
3529 if (ni->final) {
3530 ni->final(ni->arg);
3531 }
3532
3533 /*
3534 * Now release the iface instance if the node had one
3535 */
3536 if (ni->iface) {
3537 ecm_db_iface_deref(ni->iface);
3538 }
3539
3540 /*
3541 * We can now destroy the instance
3542 */
3543 DEBUG_CLEAR_MAGIC(ni);
3544 kfree(ni);
3545
3546 /*
3547 * Decrease global node count
3548 */
3549 spin_lock_bh(&ecm_db_lock);
3550 ecm_db_node_count--;
3551 DEBUG_ASSERT(ecm_db_node_count >= 0, "%p: node count wrap\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00003552 spin_unlock_bh(&ecm_db_lock);
3553
Ben Menchaca84f36632014-02-28 20:57:38 +00003554 return 0;
3555}
3556EXPORT_SYMBOL(ecm_db_node_deref);
3557
3558/*
3559 * ecm_db_iface_deref()
3560 * Deref a interface instance, removing it from the database on the last ref release
3561 */
3562int ecm_db_iface_deref(struct ecm_db_iface_instance *ii)
3563{
3564 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
3565
3566 /*
3567 * Decrement reference count
3568 */
3569 spin_lock_bh(&ecm_db_lock);
3570 ii->refs--;
3571 DEBUG_TRACE("%p: iface deref %d\n", ii, ii->refs);
3572 DEBUG_ASSERT(ii->refs >= 0, "%p: ref wrap\n", ii);
3573
3574 if (ii->refs > 0) {
3575 int refs = ii->refs;
3576 spin_unlock_bh(&ecm_db_lock);
3577 return refs;
3578 }
3579
Gareth Williamsb5903892015-03-20 15:13:07 +00003580#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003581 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00003582#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003583
3584 /*
3585 * Remove from database if inserted
3586 */
3587 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
3588 spin_unlock_bh(&ecm_db_lock);
3589 } else {
3590 struct ecm_db_listener_instance *li;
3591
3592 /*
3593 * Remove from the global list
3594 */
3595 if (!ii->prev) {
3596 DEBUG_ASSERT(ecm_db_interfaces == ii, "%p: interface table bad\n", ii);
3597 ecm_db_interfaces = ii->next;
3598 } else {
3599 ii->prev->next = ii->next;
3600 }
3601 if (ii->next) {
3602 ii->next->prev = ii->prev;
3603 }
3604
3605 /*
3606 * Link out of hash table
3607 */
3608 if (!ii->hash_prev) {
3609 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);
3610 ecm_db_iface_table[ii->hash_index] = ii->hash_next;
3611 } else {
3612 ii->hash_prev->hash_next = ii->hash_next;
3613 }
3614 if (ii->hash_next) {
3615 ii->hash_next->hash_prev = ii->hash_prev;
3616 }
3617 ii->hash_next = NULL;
3618 ii->hash_prev = NULL;
3619 ecm_db_iface_table_lengths[ii->hash_index]--;
3620 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 -07003621
3622 /*
3623 * Link out of interface identifier hash table
3624 */
3625 if (!ii->iface_id_hash_prev) {
3626 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);
3627 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
3628 } else {
3629 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
3630 }
3631 if (ii->iface_id_hash_next) {
3632 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
3633 }
3634 ii->iface_id_hash_next = NULL;
3635 ii->iface_id_hash_prev = NULL;
3636 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
3637 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 +00003638 spin_unlock_bh(&ecm_db_lock);
3639
3640 /*
3641 * Throw removed event to listeners
3642 */
3643 DEBUG_TRACE("%p: Throw iface removed event\n", ii);
3644 li = ecm_db_listeners_get_and_ref_first();
3645 while (li) {
3646 struct ecm_db_listener_instance *lin;
3647 if (li->iface_removed) {
3648 li->iface_removed(li->arg, ii);
3649 }
3650
3651 /*
3652 * Get next listener
3653 */
3654 lin = ecm_db_listener_get_and_ref_next(li);
3655 ecm_db_listener_deref(li);
3656 li = lin;
3657 }
3658 }
3659
3660 /*
3661 * Throw final event
3662 */
3663 if (ii->final) {
3664 ii->final(ii->arg);
3665 }
3666
3667 /*
3668 * We can now destroy the instance
3669 */
3670 DEBUG_CLEAR_MAGIC(ii);
3671 kfree(ii);
3672
3673 /*
3674 * Decrease global interface count
3675 */
3676 spin_lock_bh(&ecm_db_lock);
3677 ecm_db_iface_count--;
3678 DEBUG_ASSERT(ecm_db_iface_count >= 0, "%p: iface count wrap\n", ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00003679 spin_unlock_bh(&ecm_db_lock);
3680
Ben Menchaca84f36632014-02-28 20:57:38 +00003681 return 0;
3682}
3683EXPORT_SYMBOL(ecm_db_iface_deref);
3684
3685/*
3686 * ecm_db_listener_deref()
3687 * Release reference to listener.
3688 *
3689 * On final reference release listener shall be removed from the database.
3690 */
3691int ecm_db_listener_deref(struct ecm_db_listener_instance *li)
3692{
3693 struct ecm_db_listener_instance *cli;
3694 struct ecm_db_listener_instance **cli_prev;
3695
3696 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
3697
3698 spin_lock_bh(&ecm_db_lock);
3699 li->refs--;
3700 DEBUG_ASSERT(li->refs >= 0, "%p: ref wrap\n", li);
3701 if (li->refs > 0) {
3702 int refs;
3703 refs = li->refs;
3704 spin_unlock_bh(&ecm_db_lock);
3705 return refs;
3706 }
3707
3708 /*
3709 * Instance is to be removed and destroyed.
3710 * Link the listener out of the listener list.
3711 */
3712 cli = ecm_db_listeners;
3713 cli_prev = &ecm_db_listeners;
3714 while (cli) {
3715 if (cli == li) {
3716 *cli_prev = cli->next;
3717 break;
3718 }
3719 cli_prev = &cli->next;
3720 cli = cli->next;
3721 }
3722 DEBUG_ASSERT(cli, "%p: not found\n", li);
3723 spin_unlock_bh(&ecm_db_lock);
3724
3725 /*
3726 * Invoke final callback
3727 */
3728 if (li->final) {
3729 li->final(li->arg);
3730 }
3731 DEBUG_CLEAR_MAGIC(li);
3732 kfree(li);
3733
3734 /*
3735 * Decrease global listener count
3736 */
3737 spin_lock_bh(&ecm_db_lock);
3738 ecm_db_listeners_count--;
3739 DEBUG_ASSERT(ecm_db_listeners_count >= 0, "%p: listener count wrap\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00003740 spin_unlock_bh(&ecm_db_lock);
3741
Ben Menchaca84f36632014-02-28 20:57:38 +00003742 return 0;
3743}
3744EXPORT_SYMBOL(ecm_db_listener_deref);
3745
3746/*
3747 * ecm_db_connection_defunct_all()
3748 * Make defunct ALL connections.
3749 *
3750 * This API is typically used in shutdown situations commanded by the user.
3751 * NOTE: Ensure all front ends are stopped to avoid further connections being created while this is running.
3752 */
3753void ecm_db_connection_defunct_all(void)
3754{
3755 struct ecm_db_connection_instance *ci;
3756
3757 DEBUG_INFO("Defuncting all\n");
3758
3759 /*
3760 * Iterate all connections
3761 */
3762 ci = ecm_db_connections_get_and_ref_first();
3763 while (ci) {
3764 struct ecm_db_connection_instance *cin;
3765
3766 DEBUG_TRACE("%p: defunct\n", ci);
3767 ecm_db_connection_make_defunct(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303768
Ben Menchaca84f36632014-02-28 20:57:38 +00003769 cin = ecm_db_connection_get_and_ref_next(ci);
3770 ecm_db_connection_deref(ci);
3771 ci = cin;
3772 }
3773 DEBUG_INFO("Defuncting complete\n");
3774}
3775EXPORT_SYMBOL(ecm_db_connection_defunct_all);
3776
3777/*
3778 * ecm_db_connection_generate_hash_index()
3779 * Calculate the hash index.
3780 *
3781 * Note: The hash we produce is symmetric - i.e. we can swap the "from" and "to"
3782 * details without generating a different hash index!
3783 */
3784static 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)
3785{
Gareth Williams54d15d92015-04-24 19:28:27 +01003786 uint32_t hah1;
3787 uint32_t hah2;
3788 uint32_t ht1;
Ben Menchaca84f36632014-02-28 20:57:38 +00003789 uint32_t hash_val;
3790
3791 /*
3792 * The hash function only uses both host 1 address/port, host 2 address/port
3793 * and protocol fields.
3794 */
Gareth Williams54d15d92015-04-24 19:28:27 +01003795 ECM_IP_ADDR_HASH(hah1, host1_addr);
3796 ECM_IP_ADDR_HASH(hah2, host2_addr);
3797 ht1 = (u32)hah1 + host1_port + hah2 + host2_port + (uint32_t)protocol;
3798 hash_val = (uint32_t)jhash_1word(ht1, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003799 return (ecm_db_connection_hash_t)(hash_val & (ECM_DB_CONNECTION_HASH_SLOTS - 1));
3800}
3801
3802/*
3803 * ecm_db_connection_generate_serial_hash_index()
3804 * Calculate the serial hash index.
3805 */
3806static inline ecm_db_connection_serial_hash_t ecm_db_connection_generate_serial_hash_index(uint32_t serial)
3807{
Gareth Williams54d15d92015-04-24 19:28:27 +01003808 uint32_t hash_val;
3809 hash_val = (uint32_t)jhash_1word(serial, ecm_db_jhash_rnd);
3810
3811 return (ecm_db_connection_serial_hash_t)(hash_val & (ECM_DB_CONNECTION_SERIAL_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003812}
3813
Shyam Sunder1f037262015-05-18 20:04:13 +05303814#ifdef ECM_MULTICAST_ENABLE
3815/*
3816 * ecm_db_multicast_generate_hash_index()
3817 * Calculate the hash index given a multicast group address.
3818 */
3819static inline ecm_db_multicast_tuple_instance_hash_t ecm_db_multicast_generate_hash_index(ip_addr_t address)
3820{
3821 uint32_t temp;
3822 uint32_t hash_val;
3823
3824 if (ECM_IP_ADDR_IS_V4(address)){
3825 temp = (uint32_t)address[0];
3826 } else {
3827 temp = (uint32_t)address[3];
3828 }
3829
3830 hash_val = (uint32_t)jhash_1word(temp, ecm_db_jhash_rnd);
3831
3832 return (ecm_db_multicast_tuple_instance_hash_t)(hash_val & (ECM_DB_MULTICAST_TUPLE_INSTANCE_HASH_SLOTS - 1));
3833}
3834#endif
3835
Ben Menchaca84f36632014-02-28 20:57:38 +00003836/*
3837 * ecm_db_mapping_generate_hash_index()
3838 * Calculate the hash index.
3839 */
3840static inline ecm_db_mapping_hash_t ecm_db_mapping_generate_hash_index(ip_addr_t address, uint32_t port)
3841{
Gareth Williams54d15d92015-04-24 19:28:27 +01003842 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00003843 uint32_t hash_val;
3844
Gareth Williams54d15d92015-04-24 19:28:27 +01003845 ECM_IP_ADDR_HASH(tuple, address);
3846 hash_val = (uint32_t)jhash_2words(tuple, port, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003847 return (ecm_db_mapping_hash_t)(hash_val & (ECM_DB_MAPPING_HASH_SLOTS - 1));
3848}
3849
3850/*
3851 * ecm_db_host_generate_hash_index()
3852 * Calculate the hash index.
3853 */
3854static inline ecm_db_host_hash_t ecm_db_host_generate_hash_index(ip_addr_t address)
3855{
Gareth Williams54d15d92015-04-24 19:28:27 +01003856 uint32_t tuple;
Ben Menchaca84f36632014-02-28 20:57:38 +00003857 uint32_t hash_val;
3858
Gareth Williams54d15d92015-04-24 19:28:27 +01003859 ECM_IP_ADDR_HASH(tuple, address);
3860 hash_val = (uint32_t)jhash_1word(tuple, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003861 return (ecm_db_host_hash_t)(hash_val & (ECM_DB_HOST_HASH_SLOTS - 1));
3862}
3863
3864/*
3865 * ecm_db_node_generate_hash_index()
3866 * Calculate the hash index.
3867 */
3868static inline ecm_db_node_hash_t ecm_db_node_generate_hash_index(uint8_t *address)
3869{
3870 uint32_t hash_val;
3871
Gareth Williams54d15d92015-04-24 19:28:27 +01003872 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003873 hash_val &= (ECM_DB_NODE_HASH_SLOTS - 1);
3874
3875 return (ecm_db_node_hash_t)hash_val;
3876}
3877
Murat Sezgin91c5d712015-06-12 15:16:22 -07003878/*
3879 * ecm_db_iface_id_generate_hash_index()
3880 * Calculate the hash index based on interface identifier.
3881 */
3882static inline ecm_db_iface_id_hash_t ecm_db_iface_id_generate_hash_index(int32_t interface_id)
3883{
3884 uint32_t hash_val;
3885
3886 hash_val = (uint32_t)jhash_1word((uint32_t)interface_id, ecm_db_jhash_rnd);
3887 return (ecm_db_iface_id_hash_t)(hash_val & (ECM_DB_IFACE_ID_HASH_SLOTS - 1));
3888}
3889
Murat Sezginbde55f92015-03-11 16:44:11 -07003890#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003891/*
3892 * ecm_db_iface_generate_hash_index_sit()
3893 * Calculate the hash index.
3894 */
3895static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_sit(ip_addr_t saddr, ip_addr_t daddr)
3896{
Gareth Williams54d15d92015-04-24 19:28:27 +01003897 uint32_t tuple1;
3898 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00003899 uint32_t hash_val;
3900
Gareth Williams54d15d92015-04-24 19:28:27 +01003901 ECM_IP_ADDR_HASH(tuple1, saddr);
3902 ECM_IP_ADDR_HASH(tuple2, daddr);
3903 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003904 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3905}
Murat Sezginbde55f92015-03-11 16:44:11 -07003906#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003907
Murat Sezginc1402562015-03-12 12:32:20 -07003908#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00003909#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003910/*
3911 * ecm_db_iface_generate_hash_index_tunipip6()
3912 * Calculate the hash index.
3913 */
3914static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
3915{
Gareth Williams54d15d92015-04-24 19:28:27 +01003916 uint32_t tuple1;
3917 uint32_t tuple2;
Ben Menchaca84f36632014-02-28 20:57:38 +00003918 uint32_t hash_val;
3919
Gareth Williams54d15d92015-04-24 19:28:27 +01003920 ECM_IP_ADDR_HASH(tuple1, saddr);
3921 ECM_IP_ADDR_HASH(tuple2, daddr);
3922 hash_val = (uint32_t)jhash_2words(tuple1, tuple2, ecm_db_jhash_rnd);
Ben Menchaca84f36632014-02-28 20:57:38 +00003923 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3924}
Murat Sezginc1402562015-03-12 12:32:20 -07003925#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00003926#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003927
3928/*
3929 * ecm_db_iface_generate_hash_index_ethernet()
3930 * Calculate the hash index.
3931 */
3932static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ethernet(uint8_t *address)
3933{
Gareth Williams54d15d92015-04-24 19:28:27 +01003934 uint32_t hash_val;
3935 hash_val = (uint32_t)jhash(address, 6, ecm_db_jhash_rnd);
3936 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003937}
3938
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303939#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00003940/*
3941 * ecm_db_iface_generate_hash_index_pppoe()
3942 * Calculate the hash index.
3943 */
3944static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppoe(uint16_t pppoe_session_id)
3945{
Gareth Williams54d15d92015-04-24 19:28:27 +01003946 uint32_t hash_val;
3947 hash_val = (uint32_t)jhash_1word((uint32_t)pppoe_session_id, ecm_db_jhash_rnd);
3948 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003949}
Murat Sezginaad635c2015-03-06 16:11:41 -08003950#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003951
ratheesh kannotha32fdd12015-09-09 08:02:58 +05303952#ifdef ECM_INTERFACE_L2TPV2_ENABLE
3953/*
3954 * ecm_db_iface_generate_hash_index_pppol2tpv2()
3955 * Calculate the hash index.
3956 */
3957static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
3958{
3959 uint32_t hash_val;
3960 hash_val = (uint32_t)jhash_2words(pppol2tpv2_tunnel_id, pppol2tpv2_session_id, ecm_db_jhash_rnd);
3961 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3962}
3963
3964#endif
3965
Shyam Sunder23f2e542015-09-28 14:56:49 +05303966#ifdef ECM_INTERFACE_PPTP_ENABLE
3967/*
3968 * ecm_db_iface_generate_hash_index_pptp()
3969 * Calculate the hash index.
3970 */
3971static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pptp(uint16_t pptp_src_call_id, uint16_t pptp_dst_call_id)
3972{
3973 uint32_t hash_val;
3974 hash_val = (uint32_t)jhash_2words(pptp_src_call_id, pptp_dst_call_id, ecm_db_jhash_rnd);
3975 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3976}
3977#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00003978/*
3979 * ecm_db_iface_generate_hash_index_unknown()
3980 * Calculate the hash index.
3981 */
3982static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_unknown(uint32_t os_specific_ident)
3983{
Gareth Williams54d15d92015-04-24 19:28:27 +01003984 uint32_t hash_val;
3985 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
3986 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003987}
3988
3989/*
3990 * ecm_db_iface_generate_hash_index_loopback()
3991 * Calculate the hash index.
3992 */
3993static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_loopback(uint32_t os_specific_ident)
3994{
Gareth Williams54d15d92015-04-24 19:28:27 +01003995 uint32_t hash_val;
3996 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
3997 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00003998}
3999
Murat Sezgin69a27532015-03-12 14:09:40 -07004000#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004001/*
4002 * ecm_db_iface_generate_hash_index_ipsec_tunnel()
4003 * Calculate the hash index.
4004 * GGG TODO Flesh this out using actual tunnel endpoint keys
4005 */
4006static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ipsec_tunnel(uint32_t os_specific_ident)
4007{
Gareth Williams54d15d92015-04-24 19:28:27 +01004008 uint32_t hash_val;
4009 hash_val = (uint32_t)jhash_1word(os_specific_ident, ecm_db_jhash_rnd);
4010 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
Ben Menchaca84f36632014-02-28 20:57:38 +00004011}
Murat Sezgin69a27532015-03-12 14:09:40 -07004012#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004013
4014/*
4015 * ecm_db_host_find_and_ref()
4016 * Lookup and return a host reference if any
4017 */
4018struct ecm_db_host_instance *ecm_db_host_find_and_ref(ip_addr_t address)
4019{
4020 ecm_db_host_hash_t hash_index;
4021 struct ecm_db_host_instance *hi;
4022
4023 DEBUG_TRACE("Lookup host with addr " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(address));
4024
4025 /*
4026 * Compute the hash chain index and prepare to walk the chain
4027 */
4028 hash_index = ecm_db_host_generate_hash_index(address);
4029
4030 /*
4031 * Iterate the chain looking for a host with matching details
4032 */
4033 spin_lock_bh(&ecm_db_lock);
4034 hi = ecm_db_host_table[hash_index];
4035 while (hi) {
4036 if (!ECM_IP_ADDR_MATCH(hi->address, address)) {
4037 hi = hi->hash_next;
4038 continue;
4039 }
4040
4041 _ecm_db_host_ref(hi);
4042 spin_unlock_bh(&ecm_db_lock);
4043 DEBUG_TRACE("host found %p\n", hi);
4044 return hi;
4045 }
4046 spin_unlock_bh(&ecm_db_lock);
4047 DEBUG_TRACE("Host not found\n");
4048 return NULL;
4049}
4050EXPORT_SYMBOL(ecm_db_host_find_and_ref);
4051
4052/*
4053 * ecm_db_node_find_and_ref()
4054 * Lookup and return a node reference if any
4055 */
4056struct ecm_db_node_instance *ecm_db_node_find_and_ref(uint8_t *address)
4057{
4058 ecm_db_node_hash_t hash_index;
4059 struct ecm_db_node_instance *ni;
4060
4061 DEBUG_TRACE("Lookup node with addr %pM\n", address);
4062
4063 /*
4064 * Compute the hash chain index and prepare to walk the chain
4065 */
4066 hash_index = ecm_db_node_generate_hash_index(address);
4067
4068 /*
4069 * Iterate the chain looking for a host with matching details
4070 */
4071 spin_lock_bh(&ecm_db_lock);
4072 ni = ecm_db_node_table[hash_index];
4073 while (ni) {
4074 if (memcmp(ni->address, address, ETH_ALEN)) {
4075 ni = ni->hash_next;
4076 continue;
4077 }
4078
4079 _ecm_db_node_ref(ni);
4080 spin_unlock_bh(&ecm_db_lock);
4081 DEBUG_TRACE("node found %p\n", ni);
4082 return ni;
4083 }
4084 spin_unlock_bh(&ecm_db_lock);
4085 DEBUG_TRACE("Node not found\n");
4086 return NULL;
4087}
4088EXPORT_SYMBOL(ecm_db_node_find_and_ref);
4089
4090/*
4091 * ecm_db_iface_ethernet_address_get()
4092 * Obtain the ethernet address for an ethernet interface
4093 */
4094void ecm_db_iface_ethernet_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4095{
4096 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4097 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_ETHERNET, "%p: Bad type, expected ethernet, actual: %d\n", ii, ii->type);
4098 spin_lock_bh(&ecm_db_lock);
4099 memcpy(address, ii->type_info.ethernet.address, sizeof(ii->type_info.ethernet.address));
4100 spin_unlock_bh(&ecm_db_lock);
4101}
4102EXPORT_SYMBOL(ecm_db_iface_ethernet_address_get);
4103
4104/*
Gareth Williams83125b12014-05-26 19:58:09 +01004105 * ecm_db_iface_bridge_address_get()
4106 * Obtain the ethernet address for a bridge interface
4107 */
4108void ecm_db_iface_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
4109{
4110 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4111 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_BRIDGE, "%p: Bad type, expected bridge, actual: %d\n", ii, ii->type);
4112 spin_lock_bh(&ecm_db_lock);
4113 memcpy(address, ii->type_info.bridge.address, sizeof(ii->type_info.bridge.address));
4114 spin_unlock_bh(&ecm_db_lock);
4115}
4116EXPORT_SYMBOL(ecm_db_iface_bridge_address_get);
4117
Gareth Williamsf98d4192015-03-11 16:55:41 +00004118/*
Shyam Sunder39e25672015-09-03 14:28:09 +05304119 * _ecm_db_iface_identifier_hash_table_insert_entry()
4120 * Calculate the hash index based on updated interface_identifier, and
4121 * re-insert into interface identifier chain.
4122 *
4123 * Note: Must take ecm_db_lock before calling this.
4124 */
4125static void _ecm_db_iface_identifier_hash_table_insert_entry(struct ecm_db_iface_instance *ii, int32_t interface_identifier)
4126{
4127 ecm_db_iface_id_hash_t iface_id_hash_index;
4128
4129 /*
4130 * Compute hash chain for insertion
4131 */
4132 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
4133 ii->iface_id_hash_index = iface_id_hash_index;
4134
4135 /*
4136 * Insert into interface identifier chain
4137 */
4138 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
4139 if (ecm_db_iface_id_table[iface_id_hash_index]) {
4140 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
4141 }
4142
4143 ecm_db_iface_id_table[iface_id_hash_index] = ii;
4144 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
4145 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]);
4146}
4147
4148/*
4149 * _ecm_db_iface_identifier_hash_table_remove_entry()
4150 * Remove an entry of a given interface instance from interface identifier chain.
4151 *
4152 * Note: Must take ecm_db_lock before calling this.
4153 */
4154static void _ecm_db_iface_identifier_hash_table_remove_entry(struct ecm_db_iface_instance *ii)
4155{
4156 /*
4157 * Remove from database if inserted
4158 */
4159 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
4160 return;
4161 }
4162
4163 /*
4164 * Link out of interface identifier hash table
4165 */
4166 if (!ii->iface_id_hash_prev) {
4167 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);
4168 ecm_db_iface_id_table[ii->iface_id_hash_index] = ii->iface_id_hash_next;
4169 } else {
4170 ii->iface_id_hash_prev->iface_id_hash_next = ii->iface_id_hash_next;
4171 }
4172
4173 if (ii->iface_id_hash_next) {
4174 ii->iface_id_hash_next->iface_id_hash_prev = ii->iface_id_hash_prev;
4175 }
4176
4177 ii->iface_id_hash_next = NULL;
4178 ii->iface_id_hash_prev = NULL;
4179 ecm_db_iface_id_table_lengths[ii->iface_id_hash_index]--;
4180 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]);
4181}
4182
4183/*
4184 * ecm_db_iface_identifier_hash_table_entry_check_and_update()
4185 * Update the hash table entry of interface identifier hash table.
4186 * First remove the 'ii' from curent hash index position, re-calculate new hash and re-insert
4187 * the 'ii' at new hash index position into interface identifier hash table.
4188 */
4189void ecm_db_iface_identifier_hash_table_entry_check_and_update(struct ecm_db_iface_instance *ii, int32_t new_interface_identifier)
4190{
4191 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4192 spin_lock_bh(&ecm_db_lock);
4193 if (ii->interface_identifier == new_interface_identifier) {
4194 spin_unlock_bh(&ecm_db_lock);
4195 return;
4196 }
4197
4198 DEBUG_TRACE("%p: interface ifindex has changed Old %d, New %d \n", ii, ii->interface_identifier, new_interface_identifier);
4199 _ecm_db_iface_identifier_hash_table_remove_entry(ii);
4200 ii->interface_identifier = new_interface_identifier;
4201 _ecm_db_iface_identifier_hash_table_insert_entry(ii, new_interface_identifier);
4202 spin_unlock_bh(&ecm_db_lock);
4203}
4204EXPORT_SYMBOL(ecm_db_iface_identifier_hash_table_entry_check_and_update);
4205
4206/*
Murat Sezgin91c5d712015-06-12 15:16:22 -07004207 * ecm_db_iface_find_and_ref_by_interface_identifier()
4208 * Return an interface based on a hlos interface identifier
4209 */
4210struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_by_interface_identifier(int32_t interface_id)
4211{
4212 ecm_db_iface_id_hash_t hash_index;
4213 struct ecm_db_iface_instance *ii;
4214
4215 DEBUG_TRACE("Lookup database iface with interface_id %d\n", interface_id);
4216
4217 /*
4218 * Compute the hash chain index and prepare to walk the chain
4219 */
4220 hash_index = ecm_db_iface_id_generate_hash_index(interface_id);
4221
4222 /*
4223 * Iterate the chain looking for a host with matching details
4224 */
4225 spin_lock_bh(&ecm_db_lock);
4226 ii = ecm_db_iface_id_table[hash_index];
Murat Sezgin91c5d712015-06-12 15:16:22 -07004227 while (ii) {
Murat Sezgin91c5d712015-06-12 15:16:22 -07004228 if (ii->interface_identifier == interface_id) {
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004229 _ecm_db_iface_ref(ii);
4230 spin_unlock_bh(&ecm_db_lock);
Murat Sezgin91c5d712015-06-12 15:16:22 -07004231 DEBUG_TRACE("iface found %p\n", ii);
4232 return ii;
4233 }
4234
4235 /*
4236 * Try next
4237 */
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004238 ii = ii->iface_id_hash_next;
Murat Sezgin91c5d712015-06-12 15:16:22 -07004239 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004240 spin_unlock_bh(&ecm_db_lock);
Murat Sezgin91c5d712015-06-12 15:16:22 -07004241 DEBUG_TRACE("Iface not found\n");
4242 return NULL;
4243}
4244EXPORT_SYMBOL(ecm_db_iface_find_and_ref_by_interface_identifier);
4245
4246/*
Gareth Williamsf98d4192015-03-11 16:55:41 +00004247 * ecm_db_iface_ifidx_find_and_ref_ethernet()
4248 * Return an interface based on a MAC address and interface hlos interface identifier
4249 */
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304250struct 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 +00004251{
4252 ecm_db_iface_hash_t hash_index;
4253 struct ecm_db_iface_instance *ii;
4254
4255 DEBUG_TRACE("Lookup ethernet iface with addr %pM\n", address);
4256
4257 /*
4258 * Compute the hash chain index and prepare to walk the chain
4259 */
4260 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4261
4262 /*
4263 * Iterate the chain looking for a host with matching details
4264 */
4265 spin_lock_bh(&ecm_db_lock);
4266 ii = ecm_db_iface_table[hash_index];
4267 while (ii) {
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304268 if ((ii->type != ECM_DB_IFACE_TYPE_ETHERNET)
4269 || memcmp(ii->type_info.ethernet.address, address, ETH_ALEN)
4270 || ii->interface_identifier != ifidx) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004271 ii = ii->hash_next;
4272 continue;
4273 }
4274
4275 _ecm_db_iface_ref(ii);
4276 spin_unlock_bh(&ecm_db_lock);
4277 DEBUG_TRACE("iface found %p\n", ii);
4278 return ii;
4279 }
4280 spin_unlock_bh(&ecm_db_lock);
4281 DEBUG_TRACE("Iface not found\n");
4282 return NULL;
4283}
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05304284EXPORT_SYMBOL(ecm_db_iface_ifidx_find_and_ref_ethernet);
4285
Murat Sezgin37fb3952015-03-10 16:45:13 -07004286#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004287/*
4288 * ecm_db_iface_vlan_info_get()
4289 * Get vlan interface specific information
4290 */
4291void ecm_db_iface_vlan_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_vlan *vlan_info)
4292{
4293 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4294 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_VLAN, "%p: Bad type, expected vlan, actual: %d\n", ii, ii->type);
4295 spin_lock_bh(&ecm_db_lock);
4296 memcpy(vlan_info->address, ii->type_info.vlan.address, sizeof(ii->type_info.vlan.address));
4297 vlan_info->vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304298 vlan_info->vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00004299 spin_unlock_bh(&ecm_db_lock);
4300}
4301EXPORT_SYMBOL(ecm_db_iface_vlan_info_get);
4302
4303/*
4304 * ecm_db_iface_find_and_ref_vlan()
4305 * Lookup and return a iface reference if any
4306 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304307struct 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 +00004308{
4309 ecm_db_iface_hash_t hash_index;
4310 struct ecm_db_iface_instance *ii;
4311
Sol Kavyd7583592014-06-05 18:51:46 -07004312 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 +00004313
4314 /*
4315 * Compute the hash chain index and prepare to walk the chain
4316 */
4317 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4318
4319 /*
4320 * Iterate the chain looking for a host with matching details
4321 */
4322 spin_lock_bh(&ecm_db_lock);
4323 ii = ecm_db_iface_table[hash_index];
4324 while (ii) {
4325 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 +05304326 || (ii->type_info.vlan.vlan_tpid != vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00004327 || memcmp(ii->type_info.vlan.address, address, ETH_ALEN)) {
4328 ii = ii->hash_next;
4329 continue;
4330 }
4331
4332 _ecm_db_iface_ref(ii);
4333 spin_unlock_bh(&ecm_db_lock);
4334 DEBUG_TRACE("iface found %p\n", ii);
4335 return ii;
4336 }
4337 spin_unlock_bh(&ecm_db_lock);
4338 DEBUG_TRACE("Iface not found\n");
4339 return NULL;
4340}
4341EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
Murat Sezgin37fb3952015-03-10 16:45:13 -07004342#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004343
4344/*
4345 * ecm_db_iface_find_and_ref_bridge()
4346 * Lookup and return a iface reference if any
4347 */
4348struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_bridge(uint8_t *address)
4349{
4350 ecm_db_iface_hash_t hash_index;
4351 struct ecm_db_iface_instance *ii;
4352
4353 DEBUG_TRACE("Lookup bridge iface with addr %pM\n", address);
4354
4355 /*
4356 * Compute the hash chain index and prepare to walk the chain
4357 */
4358 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4359
4360 /*
4361 * Iterate the chain looking for a host with matching details
4362 */
4363 spin_lock_bh(&ecm_db_lock);
4364 ii = ecm_db_iface_table[hash_index];
4365 while (ii) {
4366 if ((ii->type != ECM_DB_IFACE_TYPE_BRIDGE) || memcmp(ii->type_info.bridge.address, address, ETH_ALEN)) {
4367 ii = ii->hash_next;
4368 continue;
4369 }
4370
4371 _ecm_db_iface_ref(ii);
4372 spin_unlock_bh(&ecm_db_lock);
4373 DEBUG_TRACE("iface found %p\n", ii);
4374 return ii;
4375 }
4376 spin_unlock_bh(&ecm_db_lock);
4377 DEBUG_TRACE("Iface not found\n");
4378 return NULL;
4379}
4380EXPORT_SYMBOL(ecm_db_iface_find_and_ref_bridge);
4381
Murat Sezgin910c9662015-03-11 16:15:06 -07004382#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004383/*
4384 * ecm_db_iface_find_and_ref_lag()
4385 * Lookup and return a iface reference if any
4386 */
4387struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_lag(uint8_t *address)
4388{
4389 ecm_db_iface_hash_t hash_index;
4390 struct ecm_db_iface_instance *ii;
4391
4392 DEBUG_TRACE("Lookup lag iface with addr %pM\n", address);
4393
4394 /*
4395 * Compute the hash chain index and prepare to walk the chain
4396 */
4397 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
4398
4399 /*
4400 * Iterate the chain looking for a host with matching details
4401 */
4402 spin_lock_bh(&ecm_db_lock);
4403 ii = ecm_db_iface_table[hash_index];
4404 while (ii) {
4405 if ((ii->type != ECM_DB_IFACE_TYPE_LAG) || memcmp(ii->type_info.lag.address, address, ETH_ALEN)) {
4406 ii = ii->hash_next;
4407 continue;
4408 }
4409
4410 _ecm_db_iface_ref(ii);
4411 spin_unlock_bh(&ecm_db_lock);
4412 DEBUG_TRACE("iface found %p\n", ii);
4413 return ii;
4414 }
4415 spin_unlock_bh(&ecm_db_lock);
4416 DEBUG_TRACE("Iface not found\n");
4417 return NULL;
4418}
4419EXPORT_SYMBOL(ecm_db_iface_find_and_ref_lag);
Murat Sezgin910c9662015-03-11 16:15:06 -07004420#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004421
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304422#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004423/*
4424 * ecm_db_iface_pppoe_session_info_get()
Murat Sezgin37fb3952015-03-10 16:45:13 -07004425 * Get pppoe interface specific information
Ben Menchaca84f36632014-02-28 20:57:38 +00004426 */
4427void ecm_db_iface_pppoe_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppoe *pppoe_info)
4428{
4429 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4430 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOE, "%p: Bad type, expected pppoe, actual: %d\n", ii, ii->type);
4431 spin_lock_bh(&ecm_db_lock);
4432 memcpy(pppoe_info->remote_mac, ii->type_info.pppoe.remote_mac, sizeof(ii->type_info.pppoe.remote_mac));
4433 pppoe_info->pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
4434 spin_unlock_bh(&ecm_db_lock);
4435}
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304436
Ben Menchaca84f36632014-02-28 20:57:38 +00004437EXPORT_SYMBOL(ecm_db_iface_pppoe_session_info_get);
4438
4439/*
4440 * ecm_db_iface_find_and_ref_pppoe()
4441 * Lookup and return a iface reference if any
4442 */
4443struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppoe(uint16_t pppoe_session_id, uint8_t *remote_mac)
4444{
4445 ecm_db_iface_hash_t hash_index;
4446 struct ecm_db_iface_instance *ii;
4447
4448 DEBUG_TRACE("Lookup pppoe iface with addr %x\n", pppoe_session_id);
4449
4450 /*
4451 * Compute the hash chain index and prepare to walk the chain
4452 */
4453 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
4454
4455 /*
4456 * Iterate the chain looking for a host with matching details
4457 */
4458 spin_lock_bh(&ecm_db_lock);
4459 ii = ecm_db_iface_table[hash_index];
4460 while (ii) {
4461 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOE)
4462 || (ii->type_info.pppoe.pppoe_session_id != pppoe_session_id)
4463 || memcmp(ii->type_info.pppoe.remote_mac, remote_mac, ETH_ALEN)) {
4464 ii = ii->hash_next;
4465 continue;
4466 }
4467
4468 _ecm_db_iface_ref(ii);
4469 spin_unlock_bh(&ecm_db_lock);
4470 DEBUG_TRACE("iface found %p\n", ii);
4471 return ii;
4472 }
4473 spin_unlock_bh(&ecm_db_lock);
4474 DEBUG_TRACE("Iface not found\n");
4475 return NULL;
4476}
4477EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppoe);
Murat Sezginaad635c2015-03-06 16:11:41 -08004478#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004479
ratheesh kannothed721852015-09-28 12:39:52 +05304480/*
4481 * ecm_db_iface_update_ae_interface_identifier()
4482 * update ae_interface_identifier in iface instance.
4483 */
4484void ecm_db_iface_update_ae_interface_identifier(struct ecm_db_iface_instance *ii, int32_t ae_interface_identifier)
4485{
4486 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304487
ratheesh kannothed721852015-09-28 12:39:52 +05304488 spin_lock_bh(&ecm_db_lock);
4489 if (ii->ae_interface_identifier == ae_interface_identifier) {
4490 spin_unlock_bh(&ecm_db_lock);
4491 return;
4492 }
4493 ii->ae_interface_identifier = ae_interface_identifier;
4494 spin_unlock_bh(&ecm_db_lock);
4495}
4496EXPORT_SYMBOL(ecm_db_iface_update_ae_interface_identifier);
4497
4498#ifdef ECM_INTERFACE_L2TPV2_ENABLE
ratheesh kannotha32fdd12015-09-09 08:02:58 +05304499/*
4500 * ecm_db_iface_pppol2tpv2_session_info_get
4501 * get l2tpv2 specific info
4502 */
4503void ecm_db_iface_pppol2tpv2_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info)
4504{
4505 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4506 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOL2TPV2, "%p: Bad type, expected pppol2tpv2, actual: %d\n", ii, ii->type);
4507 spin_lock_bh(&ecm_db_lock);
4508 memcpy(pppol2tpv2_info, &ii->type_info.pppol2tpv2, sizeof(struct ecm_db_interface_info_pppol2tpv2));
4509 spin_unlock_bh(&ecm_db_lock);
4510}
4511EXPORT_SYMBOL(ecm_db_iface_pppol2tpv2_session_info_get);
4512
4513/*
4514 * ecm_db_iface_find_and_ref_pppol2tpv2()
4515 * Lookup and return a iface reference if any
4516 */
4517struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppol2tpv2(uint32_t pppol2tpv2_tunnel_id, uint32_t pppol2tpv2_session_id)
4518{
4519 ecm_db_iface_hash_t hash_index;
4520 struct ecm_db_iface_instance *ii;
4521
4522 /*
4523 * Compute the hash chain index and prepare to walk the chain
4524 */
4525 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(pppol2tpv2_tunnel_id, pppol2tpv2_session_id);
4526
4527 DEBUG_TRACE("Lookup pppol2tpv2 iface with local_tunnel_id = %d, local_session_id = %d, hash = 0x%x\n", pppol2tpv2_tunnel_id,
4528 pppol2tpv2_session_id, hash_index);
4529
4530 /*
4531 * Iterate the chain looking for a host with matching details
4532 */
4533 spin_lock_bh(&ecm_db_lock);
4534 ii = ecm_db_iface_table[hash_index];
4535
4536 while (ii) {
4537 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOL2TPV2)
4538 || (ii->type_info.pppol2tpv2.l2tp.session.session_id != pppol2tpv2_session_id)
4539 || (ii->type_info.pppol2tpv2.l2tp.tunnel.tunnel_id != pppol2tpv2_tunnel_id)) {
4540 ii = ii->hash_next;
4541 continue;
4542 }
4543
4544 _ecm_db_iface_ref(ii);
4545 spin_unlock_bh(&ecm_db_lock);
4546 DEBUG_TRACE("iface found %p\n", ii);
4547 return ii;
4548 }
4549 spin_unlock_bh(&ecm_db_lock);
4550
4551 DEBUG_TRACE("Iface not found\n");
4552 return NULL;
4553}
4554EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppol2tpv2);
4555
4556#endif
4557
Shyam Sunder23f2e542015-09-28 14:56:49 +05304558#ifdef ECM_INTERFACE_PPTP_ENABLE
4559/*
4560 * ecm_db_iface_pptp_session_info_get
4561 * get pptp specific info
4562 */
4563void ecm_db_iface_pptp_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info)
4564{
4565 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4566 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPTP, "%p: Bad type, expected pptp, actual: %d\n", ii, ii->type);
4567 spin_lock_bh(&ecm_db_lock);
4568 memcpy(pptp_info, &ii->type_info.pptp, sizeof(struct ecm_db_interface_info_pptp));
4569 spin_unlock_bh(&ecm_db_lock);
4570}
4571EXPORT_SYMBOL(ecm_db_iface_pptp_session_info_get);
4572
4573/*
4574 * ecm_db_iface_find_and_ref_pptp()
4575 * Lookup and return a iface reference if any
4576 */
4577struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pptp(uint32_t pptp_src_call_id, uint32_t pptp_dst_call_id)
4578{
4579 ecm_db_iface_hash_t hash_index;
4580 struct ecm_db_iface_instance *ii;
4581
4582 /*
4583 * Compute the hash chain index and prepare to walk the chain
4584 */
4585 hash_index = ecm_db_iface_generate_hash_index_pptp(pptp_src_call_id, pptp_dst_call_id);
4586
4587 DEBUG_TRACE("Lookup pptp iface with local_call_id = %d, remote_call_id = %d, hash = 0x%x\n", pptp_src_call_id,
4588 pptp_dst_call_id, hash_index);
4589
4590 /*
4591 * Iterate the chain looking for a host with matching details
4592 */
4593 spin_lock_bh(&ecm_db_lock);
4594 ii = ecm_db_iface_table[hash_index];
4595
4596 while (ii) {
4597 if ((ii->type != ECM_DB_IFACE_TYPE_PPTP)
4598 || (ii->type_info.pptp.src_call_id != pptp_src_call_id)
4599 || (ii->type_info.pptp.dst_call_id != pptp_dst_call_id)) {
4600 ii = ii->hash_next;
4601 continue;
4602 }
4603
4604 _ecm_db_iface_ref(ii);
4605 spin_unlock_bh(&ecm_db_lock);
4606 DEBUG_TRACE("iface found %p\n", ii);
4607 return ii;
4608 }
4609 spin_unlock_bh(&ecm_db_lock);
4610
4611 DEBUG_TRACE("Iface not found\n");
4612 return NULL;
4613}
4614EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pptp);
4615#endif
4616
Ben Menchaca84f36632014-02-28 20:57:38 +00004617/*
4618 * ecm_db_iface_find_and_ref_unknown()
4619 * Lookup and return a iface reference if any
4620 */
4621struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_unknown(uint32_t os_specific_ident)
4622{
4623 ecm_db_iface_hash_t hash_index;
4624 struct ecm_db_iface_instance *ii;
4625
4626 DEBUG_TRACE("Lookup unknown iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4627
4628 /*
4629 * Compute the hash chain index and prepare to walk the chain
4630 */
4631 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
4632
4633 /*
4634 * Iterate the chain looking for a host with matching details
4635 */
4636 spin_lock_bh(&ecm_db_lock);
4637 ii = ecm_db_iface_table[hash_index];
4638 while (ii) {
4639 if ((ii->type != ECM_DB_IFACE_TYPE_UNKNOWN) || (ii->type_info.unknown.os_specific_ident != os_specific_ident)) {
4640 ii = ii->hash_next;
4641 continue;
4642 }
4643
4644 _ecm_db_iface_ref(ii);
4645 spin_unlock_bh(&ecm_db_lock);
4646 DEBUG_TRACE("iface found %p\n", ii);
4647 return ii;
4648 }
4649 spin_unlock_bh(&ecm_db_lock);
4650 DEBUG_TRACE("Iface not found\n");
4651 return NULL;
4652}
4653EXPORT_SYMBOL(ecm_db_iface_find_and_ref_unknown);
4654
4655/*
4656 * ecm_db_iface_find_and_ref_loopback()
4657 * Lookup and return a iface reference if any
4658 */
4659struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident)
4660{
4661 ecm_db_iface_hash_t hash_index;
4662 struct ecm_db_iface_instance *ii;
4663
4664 DEBUG_TRACE("Lookup loopback iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4665
4666 /*
4667 * Compute the hash chain index and prepare to walk the chain
4668 */
4669 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
4670
4671 /*
4672 * Iterate the chain looking for a host with matching details
4673 */
4674 spin_lock_bh(&ecm_db_lock);
4675 ii = ecm_db_iface_table[hash_index];
4676 while (ii) {
4677 if ((ii->type != ECM_DB_IFACE_TYPE_LOOPBACK) || (ii->type_info.loopback.os_specific_ident != os_specific_ident)) {
4678 ii = ii->hash_next;
4679 continue;
4680 }
4681
4682 _ecm_db_iface_ref(ii);
4683 spin_unlock_bh(&ecm_db_lock);
4684 DEBUG_TRACE("iface found %p\n", ii);
4685 return ii;
4686 }
4687 spin_unlock_bh(&ecm_db_lock);
4688 DEBUG_TRACE("Iface not found\n");
4689 return NULL;
4690}
4691EXPORT_SYMBOL(ecm_db_iface_find_and_ref_loopback);
4692
Murat Sezgin69a27532015-03-12 14:09:40 -07004693#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004694/*
4695 * ecm_db_iface_find_and_ref_ipsec_tunnel()
4696 * Lookup and return a iface reference if any.
4697 * GGG TODO Flesh this out using tunnel endpoint keys
4698 */
4699struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident)
4700{
4701 ecm_db_iface_hash_t hash_index;
4702 struct ecm_db_iface_instance *ii;
4703
4704 DEBUG_TRACE("Lookup ipsec_tunnel iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
4705
4706 /*
4707 * Compute the hash chain index and prepare to walk the chain
4708 */
4709 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
4710
4711 /*
4712 * Iterate the chain looking for a host with matching details
4713 */
4714 spin_lock_bh(&ecm_db_lock);
4715 ii = ecm_db_iface_table[hash_index];
4716 while (ii) {
4717 if ((ii->type != ECM_DB_IFACE_TYPE_IPSEC_TUNNEL) || (ii->type_info.ipsec_tunnel.os_specific_ident != os_specific_ident)) {
4718 ii = ii->hash_next;
4719 continue;
4720 }
4721
4722 _ecm_db_iface_ref(ii);
4723 spin_unlock_bh(&ecm_db_lock);
4724 DEBUG_TRACE("iface found %p\n", ii);
4725 return ii;
4726 }
4727 spin_unlock_bh(&ecm_db_lock);
4728 DEBUG_TRACE("Iface not found\n");
4729 return NULL;
4730}
4731EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -07004732#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004733
Murat Sezginbde55f92015-03-11 16:44:11 -07004734#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004735/*
4736 * ecm_db_iface_find_and_ref_sit()
4737 * Lookup and return a iface reference if any
4738 */
4739struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_sit(ip_addr_t saddr, ip_addr_t daddr)
4740{
4741 ecm_db_iface_hash_t hash_index;
4742 struct ecm_db_iface_instance *ii;
4743
4744 DEBUG_TRACE("Lookup sit (6-in-4) iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
4745 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
4746
4747 /*
4748 * Compute the hash chain index and prepare to walk the chain
4749 */
4750 hash_index = ecm_db_iface_generate_hash_index_sit(saddr, daddr);
4751
4752 /*
4753 * Iterate the chain looking for a host with matching details
4754 */
4755 spin_lock_bh(&ecm_db_lock);
4756 ii = ecm_db_iface_table[hash_index];
4757 while (ii) {
4758 if ((ii->type != ECM_DB_IFACE_TYPE_SIT)
4759 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.saddr, saddr)
4760 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.daddr, daddr)) {
4761 ii = ii->hash_next;
4762 continue;
4763 }
4764
4765 _ecm_db_iface_ref(ii);
4766 spin_unlock_bh(&ecm_db_lock);
4767 DEBUG_TRACE("iface found %p\n", ii);
4768 return ii;
4769 }
4770 spin_unlock_bh(&ecm_db_lock);
4771 DEBUG_TRACE("Iface not found\n");
4772 return NULL;
4773}
4774EXPORT_SYMBOL(ecm_db_iface_find_and_ref_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -07004775#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004776
Murat Sezginc1402562015-03-12 12:32:20 -07004777#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00004778#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00004779/*
4780 * ecm_db_iface_find_and_ref_tunipip6()
4781 * Lookup and return a iface reference if any
4782 */
4783struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
4784{
4785 ecm_db_iface_hash_t hash_index;
4786 struct ecm_db_iface_instance *ii;
4787
4788 DEBUG_TRACE("Lookup TUNIPIP6 iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
4789 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
4790
4791 /*
4792 * Compute the hash chain index and prepare to walk the chain
4793 */
4794 hash_index = ecm_db_iface_generate_hash_index_tunipip6(saddr, daddr);
4795
4796 /*
4797 * Iterate the chain looking for a host with matching details
4798 */
4799 spin_lock_bh(&ecm_db_lock);
4800 ii = ecm_db_iface_table[hash_index];
4801 while (ii) {
4802 if ((ii->type != ECM_DB_IFACE_TYPE_TUNIPIP6)
4803 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.saddr, saddr)
4804 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.daddr, daddr)) {
4805 ii = ii->hash_next;
4806 continue;
4807 }
4808
4809 _ecm_db_iface_ref(ii);
4810 spin_unlock_bh(&ecm_db_lock);
4811 DEBUG_TRACE("iface found %p\n", ii);
4812 return ii;
4813 }
4814 spin_unlock_bh(&ecm_db_lock);
4815 DEBUG_TRACE("Iface not found\n");
4816 return NULL;
4817}
4818EXPORT_SYMBOL(ecm_db_iface_find_and_ref_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -07004819#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00004820#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00004821
4822/*
4823 * ecm_db_mapping_find_and_ref()
4824 * Lookup and return a mapping reference if any.
4825 *
4826 * NOTE: For non-port based protocols the ports are expected to be -(protocol)
4827 */
4828struct ecm_db_mapping_instance *ecm_db_mapping_find_and_ref(ip_addr_t address, int port)
4829{
4830 ecm_db_mapping_hash_t hash_index;
4831 struct ecm_db_mapping_instance *mi;
4832
4833 DEBUG_TRACE("Lookup mapping with addr " ECM_IP_ADDR_OCTAL_FMT " and port %d\n", ECM_IP_ADDR_TO_OCTAL(address), port);
4834
4835 /*
4836 * Compute the hash chain index and prepare to walk the chain
4837 */
4838 hash_index = ecm_db_mapping_generate_hash_index(address, port);
4839
4840 /*
4841 * Iterate the chain looking for a mapping with matching details
4842 */
4843 spin_lock_bh(&ecm_db_lock);
4844 mi = ecm_db_mapping_table[hash_index];
4845 while (mi) {
4846 if (mi->port != port) {
4847 mi = mi->hash_next;
4848 continue;
4849 }
4850
4851 if (!ECM_IP_ADDR_MATCH(mi->host->address, address)) {
4852 mi = mi->hash_next;
4853 continue;
4854 }
4855
4856 _ecm_db_mapping_ref(mi);
4857 spin_unlock_bh(&ecm_db_lock);
4858 DEBUG_TRACE("Mapping found %p\n", mi);
4859 return mi;
4860 }
4861 spin_unlock_bh(&ecm_db_lock);
4862 DEBUG_TRACE("Mapping not found\n");
4863 return NULL;
4864}
4865EXPORT_SYMBOL(ecm_db_mapping_find_and_ref);
4866
4867/*
Gareth Williams54d15d92015-04-24 19:28:27 +01004868 * ecm_db_connection_find_and_ref_chain()
4869 * Given a hash chain index locate the connection
Ben Menchaca84f36632014-02-28 20:57:38 +00004870 */
Gareth Williams54d15d92015-04-24 19:28:27 +01004871static struct ecm_db_connection_instance *ecm_db_connection_find_and_ref_chain(ecm_db_connection_hash_t hash_index,
4872 ip_addr_t host1_addr, ip_addr_t host2_addr,
4873 int protocol, int host1_port, int host2_port)
Ben Menchaca84f36632014-02-28 20:57:38 +00004874{
Ben Menchaca84f36632014-02-28 20:57:38 +00004875 struct ecm_db_connection_instance *ci;
4876
Ben Menchaca84f36632014-02-28 20:57:38 +00004877 /*
4878 * Iterate the chain looking for a connection with matching details
4879 */
4880 spin_lock_bh(&ecm_db_lock);
4881 ci = ecm_db_connection_table[hash_index];
Ben Menchaca84f36632014-02-28 20:57:38 +00004882 while (ci) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004883 /*
4884 * The use of unlikely() is liberally used because under fast-hit scenarios the connection would always be at the start of a chain
4885 */
4886 if (unlikely(ci->protocol != protocol)) {
4887 goto try_next;
4888 }
4889
4890 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_from->host->address))) {
4891 goto try_reverse;
4892 }
4893
4894 if (unlikely(host1_port != ci->mapping_from->port)) {
4895 goto try_reverse;
4896 }
4897
4898 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_to->host->address))) {
4899 goto try_reverse;
4900 }
4901
4902 if (unlikely(host2_port != ci->mapping_to->port)) {
4903 goto try_reverse;
4904 }
4905
4906 goto connection_found;
4907
4908try_reverse:
4909 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_to->host->address))) {
4910 goto try_next;
4911 }
4912
4913 if (unlikely(host1_port != ci->mapping_to->port)) {
4914 goto try_next;
4915 }
4916
4917 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_from->host->address))) {
4918 goto try_next;
4919 }
4920
4921 if (unlikely(host2_port != ci->mapping_from->port)) {
4922 goto try_next;
4923 }
4924
4925 goto connection_found;
4926
4927try_next:
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004928 ci = ci->hash_next;
Ben Menchaca84f36632014-02-28 20:57:38 +00004929 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004930 spin_unlock_bh(&ecm_db_lock);
Gareth Williams54d15d92015-04-24 19:28:27 +01004931 DEBUG_TRACE("Connection not found in hash chain\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00004932 return NULL;
4933
4934connection_found:
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004935 _ecm_db_connection_ref(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00004936 spin_unlock_bh(&ecm_db_lock);
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004937 DEBUG_TRACE("Connection found %p\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00004938 return ci;
4939}
Gareth Williams54d15d92015-04-24 19:28:27 +01004940
4941/*
4942 * ecm_db_connection_find_and_ref()
4943 * Locate a connection instance based on addressing, protocol and optional port information.
4944 *
4945 * NOTE: For non-port based protocols then ports are expected to be -(protocol).
4946 */
4947struct 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)
4948{
4949 ecm_db_connection_hash_t hash_index;
4950
4951 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);
4952
4953 /*
4954 * Compute the hash chain index and prepare to walk the chain
4955 */
4956 hash_index = ecm_db_connection_generate_hash_index(host1_addr, host1_port, host2_addr, host2_port, protocol);
4957 return ecm_db_connection_find_and_ref_chain(hash_index, host1_addr, host2_addr, protocol, host1_port, host2_port);
4958}
Ben Menchaca84f36632014-02-28 20:57:38 +00004959EXPORT_SYMBOL(ecm_db_connection_find_and_ref);
4960
4961/*
4962 * ecm_db_connection_serial_find_and_ref()
4963 * Locate a connection instance based on serial if it still exists
4964 */
4965struct ecm_db_connection_instance *ecm_db_connection_serial_find_and_ref(uint32_t serial)
4966{
4967 ecm_db_connection_serial_hash_t serial_hash_index;
4968 struct ecm_db_connection_instance *ci;
4969
4970 DEBUG_TRACE("Lookup connection serial: %u\n", serial);
4971
4972 /*
4973 * Compute the hash chain index and prepare to walk the chain
4974 */
4975 serial_hash_index = ecm_db_connection_generate_serial_hash_index(serial);
4976
4977 /*
4978 * Iterate the chain looking for a connection with matching serial
4979 */
4980 spin_lock_bh(&ecm_db_lock);
4981 ci = ecm_db_connection_serial_table[serial_hash_index];
Ben Menchaca84f36632014-02-28 20:57:38 +00004982 while (ci) {
Ben Menchaca84f36632014-02-28 20:57:38 +00004983 /*
4984 * The use of likely() is used because under fast-hit scenarios the connection would always be at the start of a chain
4985 */
4986 if (likely(ci->serial == serial)) {
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004987 _ecm_db_connection_ref(ci);
4988 spin_unlock_bh(&ecm_db_lock);
4989 DEBUG_TRACE("Connection found %p\n", ci);
4990 return ci;
Ben Menchaca84f36632014-02-28 20:57:38 +00004991 }
4992
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004993 ci = ci->serial_hash_next;
Ben Menchaca84f36632014-02-28 20:57:38 +00004994 }
Gareth Williamse5cb08b2015-10-28 17:02:53 +00004995 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00004996 DEBUG_TRACE("Connection not found\n");
4997 return NULL;
Ben Menchaca84f36632014-02-28 20:57:38 +00004998}
4999EXPORT_SYMBOL(ecm_db_connection_serial_find_and_ref);
5000
5001/*
Gareth Williamsb5903892015-03-20 15:13:07 +00005002 * ecm_db_connection_node_to_get_and_ref()
5003 * Return node reference
5004 */
5005struct ecm_db_node_instance *ecm_db_connection_node_to_get_and_ref(struct ecm_db_connection_instance *ci)
5006{
5007 struct ecm_db_node_instance *ni;
5008
5009 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5010
5011 spin_lock_bh(&ecm_db_lock);
5012 ni = ci->to_node;
5013 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5014 _ecm_db_node_ref(ni);
5015 spin_unlock_bh(&ecm_db_lock);
5016 return ni;
5017}
5018EXPORT_SYMBOL(ecm_db_connection_node_to_get_and_ref);
5019
5020/*
5021 * ecm_db_connection_node_from_get_and_ref()
5022 * Return node reference
5023 */
5024struct ecm_db_node_instance *ecm_db_connection_node_from_get_and_ref(struct ecm_db_connection_instance *ci)
5025{
5026 struct ecm_db_node_instance *ni;
5027
5028 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5029
5030 spin_lock_bh(&ecm_db_lock);
5031 ni = ci->from_node;
5032 _ecm_db_node_ref(ni);
5033 spin_unlock_bh(&ecm_db_lock);
5034 return ni;
5035}
5036EXPORT_SYMBOL(ecm_db_connection_node_from_get_and_ref);
5037
5038#ifdef ECM_DB_XREF_ENABLE
5039/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005040 * ecm_db_mapping_connections_from_get_and_ref_first()
5041 * Return a reference to the first connection made from this mapping
5042 */
5043struct ecm_db_connection_instance *ecm_db_mapping_connections_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5044{
5045 struct ecm_db_connection_instance *ci;
5046
5047 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5048
5049 spin_lock_bh(&ecm_db_lock);
5050 ci = mi->from_connections;
5051 if (ci) {
5052 _ecm_db_connection_ref(ci);
5053 }
5054 spin_unlock_bh(&ecm_db_lock);
5055
5056 return ci;
5057}
5058EXPORT_SYMBOL(ecm_db_mapping_connections_from_get_and_ref_first);
5059
5060/*
5061 * ecm_db_mapping_connections_to_get_and_ref_first()
5062 * Return a reference to the first connection made to this mapping
5063 */
5064struct ecm_db_connection_instance *ecm_db_mapping_connections_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5065{
5066 struct ecm_db_connection_instance *ci;
5067
5068 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5069
5070 spin_lock_bh(&ecm_db_lock);
5071 ci = mi->to_connections;
5072 if (ci) {
5073 _ecm_db_connection_ref(ci);
5074 }
5075 spin_unlock_bh(&ecm_db_lock);
5076
5077 return ci;
5078}
5079EXPORT_SYMBOL(ecm_db_mapping_connections_to_get_and_ref_first);
5080
5081/*
5082 * ecm_db_mapping_connections_nat_from_get_and_ref_first()
5083 * Return a reference to the first NAT connection made from this mapping
5084 */
5085struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5086{
5087 struct ecm_db_connection_instance *ci;
5088
5089 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5090
5091 spin_lock_bh(&ecm_db_lock);
5092 ci = mi->from_nat_connections;
5093 if (ci) {
5094 _ecm_db_connection_ref(ci);
5095 }
5096 spin_unlock_bh(&ecm_db_lock);
5097
5098 return ci;
5099}
5100EXPORT_SYMBOL(ecm_db_mapping_connections_nat_from_get_and_ref_first);
5101
5102/*
5103 * ecm_db_mapping_connections_nat_to_get_and_ref_first()
5104 * Return a reference to the first NAT connection made to this mapping
5105 */
5106struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
5107{
5108 struct ecm_db_connection_instance *ci;
5109
5110 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
5111
5112 spin_lock_bh(&ecm_db_lock);
5113 ci = mi->to_nat_connections;
5114 if (ci) {
5115 _ecm_db_connection_ref(ci);
5116 }
5117 spin_unlock_bh(&ecm_db_lock);
5118
5119 return ci;
5120}
5121EXPORT_SYMBOL(ecm_db_mapping_connections_nat_to_get_and_ref_first);
5122
5123/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005124 * ecm_db_connection_mapping_from_get_and_ref_next()
5125 * Return reference to next connection in from mapping chain
5126 */
5127struct ecm_db_connection_instance *ecm_db_connection_mapping_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5128{
5129 struct ecm_db_connection_instance *nci;
5130
5131 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5132
5133 spin_lock_bh(&ecm_db_lock);
5134 nci = ci->from_next;
5135 if (nci) {
5136 _ecm_db_connection_ref(nci);
5137 }
5138 spin_unlock_bh(&ecm_db_lock);
5139
5140 return nci;
5141}
5142EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref_next);
5143
5144/*
5145 * ecm_db_connection_mapping_to_get_and_ref_next()
5146 * Return reference to next connection in to mapping chain
5147 */
5148struct ecm_db_connection_instance *ecm_db_connection_mapping_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5149{
5150 struct ecm_db_connection_instance *nci;
5151
5152 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5153
5154 spin_lock_bh(&ecm_db_lock);
5155 nci = ci->to_next;
5156 if (nci) {
5157 _ecm_db_connection_ref(nci);
5158 }
5159 spin_unlock_bh(&ecm_db_lock);
5160
5161 return nci;
5162}
5163EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref_next);
5164
5165/*
5166 * ecm_db_connection_mapping_nat_from_get_and_ref_next()
5167 * Return reference to next connection in from NAT mapping chain
5168 */
5169struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5170{
5171 struct ecm_db_connection_instance *nci;
5172
5173 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5174
5175 spin_lock_bh(&ecm_db_lock);
5176 nci = ci->from_nat_next;
5177 if (nci) {
5178 _ecm_db_connection_ref(nci);
5179 }
5180 spin_unlock_bh(&ecm_db_lock);
5181
5182 return nci;
5183}
5184EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref_next);
5185
5186/*
5187 * ecm_db_connection_mapping_nat_to_get_and_ref_next()
5188 * Return reference to next connection in to NAT mapping chain
5189 */
5190struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5191{
5192 struct ecm_db_connection_instance *nci;
5193
5194 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5195
5196 spin_lock_bh(&ecm_db_lock);
5197 nci = ci->to_nat_next;
5198 if (nci) {
5199 _ecm_db_connection_ref(nci);
5200 }
5201 spin_unlock_bh(&ecm_db_lock);
5202
5203 return nci;
5204}
5205EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref_next);
5206
5207/*
5208 * ecm_db_iface_connections_from_get_and_ref_first()
5209 * Return a reference to the first connection made from this iface
5210 */
5211struct ecm_db_connection_instance *ecm_db_iface_connections_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5212{
5213 struct ecm_db_connection_instance *ci;
5214
5215 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5216
5217 spin_lock_bh(&ecm_db_lock);
5218 ci = ii->from_connections;
5219 if (ci) {
5220 _ecm_db_connection_ref(ci);
5221 }
5222 spin_unlock_bh(&ecm_db_lock);
5223
5224 return ci;
5225}
5226EXPORT_SYMBOL(ecm_db_iface_connections_from_get_and_ref_first);
5227
5228/*
5229 * ecm_db_iface_connections_to_get_and_ref_first()
5230 * Return a reference to the first connection made to this iface
5231 */
5232struct ecm_db_connection_instance *ecm_db_iface_connections_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5233{
5234 struct ecm_db_connection_instance *ci;
5235
5236 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5237
5238 spin_lock_bh(&ecm_db_lock);
5239 ci = ii->to_connections;
5240 if (ci) {
5241 _ecm_db_connection_ref(ci);
5242 }
5243 spin_unlock_bh(&ecm_db_lock);
5244
5245 return ci;
5246}
5247EXPORT_SYMBOL(ecm_db_iface_connections_to_get_and_ref_first);
5248
5249/*
5250 * ecm_db_iface_connections_nat_from_get_and_ref_first()
5251 * Return a reference to the first NAT connection made from this iface
5252 */
5253struct ecm_db_connection_instance *ecm_db_iface_connections_nat_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
5254{
5255 struct ecm_db_connection_instance *ci;
5256
5257 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5258
5259 spin_lock_bh(&ecm_db_lock);
5260 ci = ii->from_nat_connections;
5261 if (ci) {
5262 _ecm_db_connection_ref(ci);
5263 }
5264 spin_unlock_bh(&ecm_db_lock);
5265
5266 return ci;
5267}
5268EXPORT_SYMBOL(ecm_db_iface_connections_nat_from_get_and_ref_first);
5269
5270/*
5271 * ecm_db_iface_connections_nat_to_get_and_ref_first()
5272 * Return a reference to the first NAT connection made to this iface
5273 */
5274struct ecm_db_connection_instance *ecm_db_iface_connections_nat_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
5275{
5276 struct ecm_db_connection_instance *ci;
5277
5278 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5279
5280 spin_lock_bh(&ecm_db_lock);
5281 ci = ii->to_nat_connections;
5282 if (ci) {
5283 _ecm_db_connection_ref(ci);
5284 }
5285 spin_unlock_bh(&ecm_db_lock);
5286
5287 return ci;
5288}
5289EXPORT_SYMBOL(ecm_db_iface_connections_nat_to_get_and_ref_first);
5290
5291/*
5292 * ecm_db_connection_iface_from_get_and_ref_next()
5293 * Return reference to next connection in from iface chain
5294 */
5295struct ecm_db_connection_instance *ecm_db_connection_iface_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5296{
5297 struct ecm_db_connection_instance *nci;
5298
5299 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5300
5301 spin_lock_bh(&ecm_db_lock);
5302 nci = ci->iface_from_next;
5303 if (nci) {
5304 _ecm_db_connection_ref(nci);
5305 }
5306 spin_unlock_bh(&ecm_db_lock);
5307
5308 return nci;
5309}
5310EXPORT_SYMBOL(ecm_db_connection_iface_from_get_and_ref_next);
5311
5312/*
5313 * ecm_db_connection_iface_to_get_and_ref_next()
5314 * Return reference to next connection in to iface chain
5315 */
5316struct ecm_db_connection_instance *ecm_db_connection_iface_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5317{
5318 struct ecm_db_connection_instance *nci;
5319
5320 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5321
5322 spin_lock_bh(&ecm_db_lock);
5323 nci = ci->iface_to_next;
5324 if (nci) {
5325 _ecm_db_connection_ref(nci);
5326 }
5327 spin_unlock_bh(&ecm_db_lock);
5328
5329 return nci;
5330}
5331EXPORT_SYMBOL(ecm_db_connection_iface_to_get_and_ref_next);
5332
5333/*
5334 * ecm_db_connection_iface_nat_from_get_and_ref_next()
5335 * Return reference to next connection in from NAT iface chain
5336 */
5337struct ecm_db_connection_instance *ecm_db_connection_iface_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
5338{
5339 struct ecm_db_connection_instance *nci;
5340
5341 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5342
5343 spin_lock_bh(&ecm_db_lock);
5344 nci = ci->iface_from_nat_next;
5345 if (nci) {
5346 _ecm_db_connection_ref(nci);
5347 }
5348 spin_unlock_bh(&ecm_db_lock);
5349
5350 return nci;
5351}
5352EXPORT_SYMBOL(ecm_db_connection_iface_nat_from_get_and_ref_next);
5353
5354/*
5355 * ecm_db_connection_iface_nat_to_get_and_ref_next()
5356 * Return reference to next connection in to NAT iface chain
5357 */
5358struct ecm_db_connection_instance *ecm_db_connection_iface_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
5359{
5360 struct ecm_db_connection_instance *nci;
5361
5362 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5363
5364 spin_lock_bh(&ecm_db_lock);
5365 nci = ci->iface_to_nat_next;
5366 if (nci) {
5367 _ecm_db_connection_ref(nci);
5368 }
5369 spin_unlock_bh(&ecm_db_lock);
5370
5371 return nci;
5372}
5373EXPORT_SYMBOL(ecm_db_connection_iface_nat_to_get_and_ref_next);
5374
5375/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005376 * ecm_db_iface_nodes_get_and_ref_first()
5377 * Return a reference to the first node made from this iface
5378 */
5379struct ecm_db_node_instance *ecm_db_iface_nodes_get_and_ref_first(struct ecm_db_iface_instance *ii)
5380{
5381 struct ecm_db_node_instance *ni;
5382
5383 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
5384
5385 spin_lock_bh(&ecm_db_lock);
5386 ni = ii->nodes;
5387 if (ni) {
5388 _ecm_db_node_ref(ni);
5389 }
5390 spin_unlock_bh(&ecm_db_lock);
5391
5392 return ni;
5393}
5394EXPORT_SYMBOL(ecm_db_iface_nodes_get_and_ref_first);
5395
5396/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005397 * ecm_db_iface_node_count_get()
5398 * Return the number of nodes to this iface
5399 */
5400int ecm_db_iface_node_count_get(struct ecm_db_iface_instance *ii)
5401{
5402 int count;
5403
5404 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305405
Ben Menchaca84f36632014-02-28 20:57:38 +00005406 spin_lock_bh(&ecm_db_lock);
5407 count = ii->node_count;
5408 spin_unlock_bh(&ecm_db_lock);
5409 return count;
5410}
5411EXPORT_SYMBOL(ecm_db_iface_node_count_get);
5412
5413/*
5414 * ecm_db_host_mapping_count_get()
5415 * Return the number of mappings to this host
5416 */
5417int ecm_db_host_mapping_count_get(struct ecm_db_host_instance *hi)
5418{
5419 int count;
5420
5421 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305422
Ben Menchaca84f36632014-02-28 20:57:38 +00005423 spin_lock_bh(&ecm_db_lock);
5424 count = hi->mapping_count;
5425 spin_unlock_bh(&ecm_db_lock);
5426 return count;
5427}
5428EXPORT_SYMBOL(ecm_db_host_mapping_count_get);
Gareth Williamsb5903892015-03-20 15:13:07 +00005429#endif
5430
5431/*
5432 * ecm_db_mapping_host_get_and_ref()
5433 */
5434struct ecm_db_host_instance *ecm_db_mapping_host_get_and_ref(struct ecm_db_mapping_instance *mi)
5435{
5436 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
5437
5438 spin_lock_bh(&ecm_db_lock);
5439 _ecm_db_host_ref(mi->host);
5440 spin_unlock_bh(&ecm_db_lock);
5441 return mi->host;
5442}
5443EXPORT_SYMBOL(ecm_db_mapping_host_get_and_ref);
5444
5445/*
5446 * ecm_db_node_iface_get_and_ref()
5447 */
5448struct ecm_db_iface_instance *ecm_db_node_iface_get_and_ref(struct ecm_db_node_instance *ni)
5449{
5450 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
5451
5452 spin_lock_bh(&ecm_db_lock);
5453 _ecm_db_iface_ref(ni->iface);
5454 spin_unlock_bh(&ecm_db_lock);
5455 return ni->iface;
5456}
5457EXPORT_SYMBOL(ecm_db_node_iface_get_and_ref);
Ben Menchaca84f36632014-02-28 20:57:38 +00005458
5459/*
5460 * ecm_db_mapping_connections_total_count_get()
5461 * Return the total number of connections (NAT and non-NAT) this mapping has
5462 */
5463int ecm_db_mapping_connections_total_count_get(struct ecm_db_mapping_instance *mi)
5464{
5465 int count;
5466
5467 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305468
Ben Menchaca84f36632014-02-28 20:57:38 +00005469 spin_lock_bh(&ecm_db_lock);
5470 count = mi->from + mi->to + mi->nat_from + mi->nat_to;
5471 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);
5472 spin_unlock_bh(&ecm_db_lock);
5473 return count;
5474}
5475EXPORT_SYMBOL(ecm_db_mapping_connections_total_count_get);
5476
5477/*
5478 * ecm_db_connection_mapping_from_get_and_ref()
5479 * Return a reference to the from mapping of the connection
5480 */
5481struct ecm_db_mapping_instance *ecm_db_connection_mapping_from_get_and_ref(struct ecm_db_connection_instance *ci)
5482{
5483 struct ecm_db_mapping_instance *mi;
5484
5485 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305486
Ben Menchaca84f36632014-02-28 20:57:38 +00005487 spin_lock_bh(&ecm_db_lock);
5488 mi = ci->mapping_from;
5489 _ecm_db_mapping_ref(mi);
5490 spin_unlock_bh(&ecm_db_lock);
5491 return mi;
5492}
5493EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref);
5494
5495/*
5496 * ecm_db_connection_mapping_nat_from_get_and_ref()
5497 * Return a reference to the from NAT mapping of the connection
5498 */
5499struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_from_get_and_ref(struct ecm_db_connection_instance *ci)
5500{
5501 struct ecm_db_mapping_instance *mi;
5502
5503 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305504
Ben Menchaca84f36632014-02-28 20:57:38 +00005505 spin_lock_bh(&ecm_db_lock);
5506 mi = ci->mapping_nat_from;
5507 _ecm_db_mapping_ref(mi);
5508 spin_unlock_bh(&ecm_db_lock);
5509 return mi;
5510}
5511EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref);
5512
5513/*
5514 * ecm_db_connection_mapping_to_get_and_ref()
5515 * Return a reference to the from mapping of the connection
5516 */
5517struct ecm_db_mapping_instance *ecm_db_connection_mapping_to_get_and_ref(struct ecm_db_connection_instance *ci)
5518{
5519 struct ecm_db_mapping_instance *mi;
5520
5521 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305522
Ben Menchaca84f36632014-02-28 20:57:38 +00005523 spin_lock_bh(&ecm_db_lock);
5524 mi = ci->mapping_to;
5525 _ecm_db_mapping_ref(mi);
5526 spin_unlock_bh(&ecm_db_lock);
5527 return mi;
5528}
5529EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref);
5530
5531/*
5532 * ecm_db_connection_mapping_to_nat_get_and_ref()
5533 * Return a reference to the from NAT mapping of the connection
5534 */
5535struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_to_get_and_ref(struct ecm_db_connection_instance *ci)
5536{
5537 struct ecm_db_mapping_instance *mi;
5538
5539 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305540
Ben Menchaca84f36632014-02-28 20:57:38 +00005541 spin_lock_bh(&ecm_db_lock);
5542 mi = ci->mapping_nat_to;
5543 _ecm_db_mapping_ref(mi);
5544 spin_unlock_bh(&ecm_db_lock);
5545 return mi;
5546}
5547EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref);
5548
5549/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005550 * ecm_db_timer_groups_check()
5551 * Check for expired group entries, returns the number that have expired
5552 */
5553static uint32_t ecm_db_timer_groups_check(uint32_t time_now)
5554{
5555 ecm_db_timer_group_t i;
5556 uint32_t expired = 0;
5557
5558 DEBUG_TRACE("Timer groups check start %u\n", time_now);
5559
5560 /*
5561 * Examine all timer groups for expired entries.
5562 */
5563 for (i = 0; i < ECM_DB_TIMER_GROUPS_MAX; ++i) {
5564 struct ecm_db_timer_group *timer_group;
5565
5566 /*
5567 * The group tail tracks the oldest entry so that is what we examine.
5568 */
5569 timer_group = &ecm_db_timer_groups[i];
5570 spin_lock_bh(&ecm_db_lock);
5571 while (timer_group->tail) {
5572 struct ecm_db_timer_group_entry *tge;
5573
5574 tge = timer_group->tail;
5575 if (tge->timeout > time_now) {
5576 /*
5577 * Not expired - and no further will be as they are in order
5578 */
5579 break;
5580 }
5581
5582 /*
5583 * Has expired - remove the entry from the list and invoke the callback
5584 * NOTE: We know the entry is at the tail of the group
5585 */
5586 if (tge->prev) {
5587 tge->prev->next = NULL;
5588 } else {
5589 /*
5590 * First in the group
5591 */
5592 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p got %p\n", timer_group, tge, timer_group->head);
5593 timer_group->head = NULL;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05305594 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005595 timer_group->tail = tge->prev;
5596 tge->group = ECM_DB_TIMER_GROUPS_MAX;
5597 spin_unlock_bh(&ecm_db_lock);
5598 expired++;
5599 DEBUG_TRACE("%p: Expired\n", tge);
5600 tge->fn(tge->arg);
5601 spin_lock_bh(&ecm_db_lock);
5602 }
5603 spin_unlock_bh(&ecm_db_lock);
5604 }
5605
5606 spin_lock_bh(&ecm_db_lock);
5607 time_now = ecm_db_time;
5608 spin_unlock_bh(&ecm_db_lock);
5609 DEBUG_TRACE("Timer groups check end %u, expired count %u\n", time_now, expired);
5610 return expired;
5611}
5612
5613/*
5614 * ecm_db_connection_classifier_assign()
5615 * Assign a classifier to the connection assigned classifier list.
5616 *
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005617 * This adds the classifier in the ci->assignments list in ascending priority order according to the classifier type.
5618 * 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 +00005619 * 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.
5620 * This allows fast lookup based on type too.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005621 * 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 +00005622 */
5623void ecm_db_connection_classifier_assign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *new_ca)
5624{
5625 struct ecm_classifier_instance *ca;
5626 struct ecm_classifier_instance *ca_prev;
5627 ecm_classifier_type_t new_ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005628#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005629 struct ecm_db_connection_classifier_type_assignment *ta;
5630 struct ecm_db_connection_classifier_type_assignment_list *tal;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005631#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005632
Ben Menchaca84f36632014-02-28 20:57:38 +00005633 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5634
5635 /*
5636 * Get the type (which is also used as the priority)
5637 */
5638 new_ca_type = new_ca->type_get(new_ca);
5639
5640 /*
5641 * Connection holds ref to the classifier
5642 */
5643 new_ca->ref(new_ca);
5644
5645 /*
5646 * Find place to insert the classifier
5647 */
5648 spin_lock_bh(&ecm_db_lock);
5649 ca = ci->assignments;
5650 ca_prev = NULL;
5651 while (ca) {
5652 ecm_classifier_type_t ca_type;
5653 ca_type = ca->type_get(ca);
5654
5655 /*
5656 * If new ca is less important that the current assigned classifier insert here
5657 */
5658 if (new_ca_type < ca_type) {
5659 break;
5660 }
5661 ca_prev = ca;
5662 ca = ca->ca_next;
5663 }
5664
5665 /*
5666 * Insert new_ca before ca and after ca_prev.
5667 */
5668 new_ca->ca_prev = ca_prev;
5669 if (ca_prev) {
5670 ca_prev->ca_next = new_ca;
5671 } else {
5672 DEBUG_ASSERT(ci->assignments == ca, "%p: Bad assigmnment list, expecting: %p, got: %p\n", ci, ca, ci->assignments);
5673 ci->assignments = new_ca;
5674 }
5675
5676 new_ca->ca_next = ca;
5677 if (ca) {
5678 ca->ca_prev = new_ca;
5679 }
5680
5681 /*
5682 * Insert based on type too
5683 */
5684 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",
5685 ci, new_ca_type, new_ca, ci->assignments_by_type[new_ca_type]);
5686 ci->assignments_by_type[new_ca_type] = new_ca;
5687
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005688#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005689 /*
5690 * Add the connection into the type assignment list too.
5691 */
5692 ta = &ci->type_assignment[new_ca_type];
5693 if (ta->pending_unassign) {
5694 /*
5695 * The connection is pending unassignment / removal from list, but since it has been
5696 * re-assigned to the same type of classifier we can just clear the flag and avoid the removal.
5697 * NOTE: pending_unassign is only ever true if the iteration count is non-zero i.e. iteration is in progress.
5698 */
5699 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5700 DEBUG_ASSERT(ta->iteration_count != 0, "%p: Bad pending_unassign: type: %d, Iteration count zero\n", ci, new_ca_type);
5701 ta->pending_unassign = false;
5702 spin_unlock_bh(&ecm_db_lock);
5703 return;
5704 }
5705
5706 /*
5707 * iteration_count should be zero as there should not be a duplicate assignment of the same type.
5708 * This is because if iteration_count was non-zero then pending_unassign should have been true.
5709 */
5710 DEBUG_ASSERT(ta->iteration_count == 0, "%p: Type: %d, Iteration count not zero: %d\n", ci, new_ca_type, ta->iteration_count);
5711
5712 /*
5713 * Insert the connection into the classifier type assignment list, at the head
5714 */
5715 tal = &ecm_db_connection_classifier_type_assignments[new_ca_type];
5716 ta->next = tal->type_assignments_list;
5717 ta->prev = NULL;
5718
5719 /*
5720 * If there is an existing head, it is no longer the head
5721 */
5722 if (tal->type_assignments_list) {
5723 struct ecm_db_connection_classifier_type_assignment *talh;
5724 talh = &tal->type_assignments_list->type_assignment[new_ca_type];
5725 talh->prev = ci;
5726 }
5727
5728 /*
5729 * Set new head
5730 */
5731 tal->type_assignments_list = ci;
5732
5733 /*
5734 * Set magic
5735 */
5736 DEBUG_SET_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC);
5737
5738 /*
5739 * Increment assignment count
5740 */
5741 tal->type_assignment_count++;
5742 DEBUG_ASSERT(tal->type_assignment_count > 0, "Bad iteration count: %d\n", tal->type_assignment_count);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005743#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005744 spin_unlock_bh(&ecm_db_lock);
5745}
5746EXPORT_SYMBOL(ecm_db_connection_classifier_assign);
5747
5748/*
5749 * ecm_db_connection_classifier_assignments_get_and_ref()
5750 * Populate the given array with references to the currently assigned classifiers.
5751 *
5752 * This function returns the number of assignments starting from [0].
5753 * [0] is the lowest priority classifier, [return_val - 1] is the highest priority.
5754 * Release each classifier when you are done, for convenience use ecm_db_connection_assignments_release().
5755 *
5756 * NOTE: The array also contains the default classifier too which of course will always be at [0]
5757 *
5758 * WARNING: The array MUST be of size ECM_CLASSIFIER_TYPES.
5759 */
5760int ecm_db_connection_classifier_assignments_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *assignments[])
5761{
5762 int aci_count;
5763 struct ecm_classifier_instance *aci;
5764 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5765
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005766 aci_count = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00005767 spin_lock_bh(&ecm_db_lock);
5768 aci = ci->assignments;
5769 while (aci) {
5770 aci->ref(aci);
5771 assignments[aci_count++] = aci;
5772 aci = aci->ca_next;
5773 }
5774 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005775 DEBUG_ASSERT(aci_count >= 1, "%p: Must have at least default classifier!\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005776 return aci_count;
5777}
5778EXPORT_SYMBOL(ecm_db_connection_classifier_assignments_get_and_ref);
5779
5780/*
5781 * ecm_db_connection_assignments_release()
5782 * Release references to classifiers in the assignments array
5783 */
5784void ecm_db_connection_assignments_release(int assignment_count, struct ecm_classifier_instance *assignments[])
5785{
5786 int i;
5787 for (i = 0; i < assignment_count; ++i) {
5788 struct ecm_classifier_instance *aci = assignments[i];
5789 if (aci) {
5790 aci->deref(aci);
5791 }
5792 }
5793}
5794EXPORT_SYMBOL(ecm_db_connection_assignments_release);
5795
5796/*
5797 * ecm_db_connection_assigned_classifier_find_and_ref()
5798 * Return a ref to classifier of the requested type, if found
5799 */
5800struct ecm_classifier_instance *ecm_db_connection_assigned_classifier_find_and_ref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t type)
5801{
5802 struct ecm_classifier_instance *ca;
5803 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5804 spin_lock_bh(&ecm_db_lock);
5805 ca = ci->assignments_by_type[type];
5806 if (ca) {
5807 ca->ref(ca);
5808 }
5809 spin_unlock_bh(&ecm_db_lock);
5810 return ca;
5811}
5812EXPORT_SYMBOL(ecm_db_connection_assigned_classifier_find_and_ref);
5813
5814/*
5815 * ecm_db_connection_classifier_unassign()
5816 * Unassign a classifier
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005817 *
5818 * The default classifier cannot be unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005819 */
5820void ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci)
5821{
5822 ecm_classifier_type_t ca_type;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005823#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005824 struct ecm_db_connection_classifier_type_assignment *ta;
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005825#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005826 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5827
5828 DEBUG_ASSERT(cci->type_get(cci) != ECM_CLASSIFIER_TYPE_DEFAULT, "%p: Cannot unassign default", ci);
5829
Ben Menchaca84f36632014-02-28 20:57:38 +00005830 /*
5831 * Get the type
5832 */
5833 ca_type = cci->type_get(cci);
5834
5835 DEBUG_TRACE("%p: Unassign type: %d, classifier: %p\n", ci, ca_type, cci);
5836
5837 spin_lock_bh(&ecm_db_lock);
5838
5839 /*
5840 * Remove from assignments_by_type
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005841 * NOTE: It is possible that in SMP this classifier has already been unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005842 */
Gareth Williamsee0a38a2014-06-05 15:41:20 +01005843 if (ci->assignments_by_type[ca_type] == NULL) {
5844 spin_unlock_bh(&ecm_db_lock);
5845 DEBUG_TRACE("%p: Classifier type: %d already unassigned\n", ci, ca_type);
5846 return;
5847 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005848 ci->assignments_by_type[ca_type] = NULL;
5849
5850 /*
5851 * Link out of assignments list
5852 */
5853 if (cci->ca_prev) {
5854 cci->ca_prev->ca_next = cci->ca_next;
5855 } else {
5856 DEBUG_ASSERT(ci->assignments == cci, "%p: Bad assigmnment list, expecting: %p, got: %p", ci, cci, ci->assignments);
5857 ci->assignments = cci->ca_next;
5858 }
5859 if (cci->ca_next) {
5860 cci->ca_next->ca_prev = cci->ca_prev;
5861 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005862
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005863#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005864 /*
5865 * Remove from the classifier type assignment list
5866 */
5867 ta = &ci->type_assignment[ca_type];
5868 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5869 if (ta->iteration_count > 0) {
5870 /*
5871 * The list entry is being iterated outside of db lock being held.
5872 * We cannot remove this entry since it would mess up iteration.
5873 * Set the pending flag to be actioned another time
5874 */
5875 ta->pending_unassign = true;
5876 spin_unlock_bh(&ecm_db_lock);
5877 cci->deref(cci);
5878 return;
5879 }
5880
5881 /*
5882 * Remove the list entry
5883 */
5884 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
5885 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005886#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00005887 spin_unlock_bh(&ecm_db_lock);
5888 cci->deref(cci);
5889}
5890EXPORT_SYMBOL(ecm_db_connection_classifier_unassign);
5891
5892/*
5893 * ecm_db_connection_classifier_default_get_and_ref()
5894 * Get a reference to default classifier associated with this connection
5895 */
5896struct ecm_classifier_default_instance *ecm_db_connection_classifier_default_get_and_ref(struct ecm_db_connection_instance *ci)
5897{
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005898 struct ecm_classifier_default_instance *dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005899 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5900
5901 /*
5902 * No need to lock this object - it cannot change
5903 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005904 dci = (struct ecm_classifier_default_instance *)ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT];
5905 DEBUG_ASSERT(dci, "%p: No default classifier!\n", ci);
5906 dci->base.ref((struct ecm_classifier_instance *)dci);
5907 return dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005908}
5909EXPORT_SYMBOL(ecm_db_connection_classifier_default_get_and_ref);
5910
Gareth Williamsb39e7c22015-03-25 10:15:33 +00005911#ifdef ECM_DB_CTA_TRACK_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00005912/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005913 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_first()
5914 * Return a reference to the first connection for which a classifier of the given type is associated with
5915 *
5916 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5917 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5918 */
5919struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ecm_classifier_type_t ca_type)
5920{
5921 struct ecm_db_connection_classifier_type_assignment_list *tal;
5922 struct ecm_db_connection_instance *ci;
5923
5924 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5925
5926 DEBUG_TRACE("Get and ref first connection assigned with classifier type: %d\n", ca_type);
5927
5928 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
5929 spin_lock_bh(&ecm_db_lock);
5930 ci = tal->type_assignments_list;
5931 while (ci) {
5932 struct ecm_db_connection_classifier_type_assignment *ta;
5933 ta = &ci->type_assignment[ca_type];
5934 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5935
5936 if (ta->pending_unassign) {
5937 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", ci, ca_type);
5938 ci = ta->next;
5939 continue;
5940 }
5941
5942 /*
5943 * Take reference to this connection.
5944 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
5945 * and the type assignment list entry maintains integrity.
5946 */
5947 _ecm_db_connection_ref(ci);
5948 ta->iteration_count++;
5949 DEBUG_ASSERT(ta->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
5950 spin_unlock_bh(&ecm_db_lock);
5951 return ci;
5952 }
5953 spin_unlock_bh(&ecm_db_lock);
5954 return NULL;
5955}
5956EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_first);
5957
5958/*
5959 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_next()
5960 * Return a reference to the next connection for which a classifier of the given type is associated with.
5961 *
5962 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5963 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5964 */
5965struct 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)
5966{
5967 struct ecm_db_connection_classifier_type_assignment *ta;
5968 struct ecm_db_connection_instance *cin;
5969
5970 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5971 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5972
5973 DEBUG_TRACE("Get and ref next connection assigned with classifier type: %d and ci: %p\n", ca_type, ci);
5974
5975 spin_lock_bh(&ecm_db_lock);
5976 ta = &ci->type_assignment[ca_type];
5977 cin = ta->next;
5978 while (cin) {
5979 struct ecm_db_connection_classifier_type_assignment *tan;
5980
5981 tan = &cin->type_assignment[ca_type];
5982 DEBUG_CHECK_MAGIC(tan, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", tan, cin);
5983
5984 if (tan->pending_unassign) {
5985 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", cin, ca_type);
5986 cin = tan->next;
5987 continue;
5988 }
5989
5990 /*
5991 * Take reference to this connection.
5992 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
5993 * and the type assignment list entry maintains integrity.
5994 */
5995 _ecm_db_connection_ref(cin);
5996 tan->iteration_count++;
5997 DEBUG_ASSERT(tan->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", tan->iteration_count, ca_type, cin);
5998 spin_unlock_bh(&ecm_db_lock);
5999 return cin;
6000 }
6001 spin_unlock_bh(&ecm_db_lock);
6002 return NULL;
6003}
6004EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_next);
6005
6006/*
6007 * ecm_db_connection_by_classifier_type_assignment_deref()
6008 * Release a reference to a connection while iterating a classifier type assignment list
6009 */
6010void ecm_db_connection_by_classifier_type_assignment_deref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
6011{
6012 struct ecm_db_connection_classifier_type_assignment_list *tal;
6013 struct ecm_db_connection_classifier_type_assignment *ta;
6014
6015 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
6016 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6017
6018 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
6019
6020 /*
6021 * Drop the iteration count
6022 */
6023 spin_lock_bh(&ecm_db_lock);
6024 ta = &ci->type_assignment[ca_type];
6025 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
6026 ta->iteration_count--;
6027 DEBUG_ASSERT(ta->iteration_count >= 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
6028
6029 /*
6030 * If there are no more iterations on-going and this is pending unassign then we can remove it from the assignments list
6031 */
6032 if (ta->pending_unassign && (ta->iteration_count == 0)) {
6033 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
6034 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
6035 }
6036 spin_unlock_bh(&ecm_db_lock);
6037 ecm_db_connection_deref(ci);
6038}
6039EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_deref);
6040
6041/*
6042 * ecm_db_connection_make_defunct_by_assignment_type()
6043 * Make defunct all connections that are currently assigned to a classifier of the given type
6044 */
6045void ecm_db_connection_make_defunct_by_assignment_type(ecm_classifier_type_t ca_type)
6046{
6047 struct ecm_db_connection_instance *ci;
6048
6049 DEBUG_INFO("Make defunct all assigned to type: %d\n", ca_type);
6050
6051 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6052 while (ci) {
6053 struct ecm_db_connection_instance *cin;
6054
6055 DEBUG_TRACE("%p: Make defunct: %d\n", ci, ca_type);
6056 ecm_db_connection_make_defunct(ci);
6057
6058 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6059 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6060 ci = cin;
6061 }
6062}
6063EXPORT_SYMBOL(ecm_db_connection_make_defunct_by_assignment_type);
6064
6065/*
6066 * ecm_db_connection_regenerate_by_assignment_type()
6067 * Cause regeneration all connections that are currently assigned to a classifier of the given type
6068 */
6069void ecm_db_connection_regenerate_by_assignment_type(ecm_classifier_type_t ca_type)
6070{
6071 struct ecm_db_connection_instance *ci;
6072
6073 DEBUG_INFO("Regenerate all assigned to type: %d\n", ca_type);
6074
6075 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
6076 while (ci) {
6077 struct ecm_db_connection_instance *cin;
6078
6079 DEBUG_TRACE("%p: Re-generate: %d\n", ci, ca_type);
Xiaoping Faned6d37e2015-09-17 14:13:47 -07006080 ecm_db_connection_regenerate(ci);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006081
6082 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
6083 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
6084 ci = cin;
6085 }
6086}
6087EXPORT_SYMBOL(ecm_db_connection_regenerate_by_assignment_type);
Gareth Williamsb39e7c22015-03-25 10:15:33 +00006088#endif
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006089
6090/*
Ben Menchaca84f36632014-02-28 20:57:38 +00006091 * ecm_db_connection_from_interfaces_get_and_ref()
6092 * Return the interface heirarchy from which this connection is established.
6093 *
6094 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6095 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6096 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6097 *
6098 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6099 */
6100int32_t ecm_db_connection_from_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6101{
6102 int32_t n;
6103 int32_t i;
6104 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6105
6106 spin_lock_bh(&ecm_db_lock);
6107 n = ci->from_interface_first;
6108 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6109 interfaces[i] = ci->from_interfaces[i];
6110 _ecm_db_iface_ref(interfaces[i]);
6111 }
6112 spin_unlock_bh(&ecm_db_lock);
6113 return n;
6114}
6115EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_and_ref);
6116
6117/*
6118 * ecm_db_connection_to_interfaces_get_and_ref()
6119 * Return the interface heirarchy to which this connection is established.
6120 *
6121 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6122 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6123 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6124 *
6125 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6126 */
6127int32_t ecm_db_connection_to_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6128{
6129 int32_t n;
6130 int32_t i;
6131 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6132
6133 spin_lock_bh(&ecm_db_lock);
6134 n = ci->to_interface_first;
6135 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6136 interfaces[i] = ci->to_interfaces[i];
6137 _ecm_db_iface_ref(interfaces[i]);
6138 }
6139 spin_unlock_bh(&ecm_db_lock);
6140 return n;
6141}
6142EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_and_ref);
6143
6144/*
6145 * ecm_db_connection_from_nat_interfaces_get_and_ref()
6146 * Return the interface heirarchy from (nat) which this connection is established.
6147 *
6148 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6149 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6150 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6151 *
6152 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6153 */
6154int32_t ecm_db_connection_from_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6155{
6156 int32_t n;
6157 int32_t i;
6158 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6159
6160 spin_lock_bh(&ecm_db_lock);
6161 n = ci->from_nat_interface_first;
6162 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6163 interfaces[i] = ci->from_nat_interfaces[i];
6164 _ecm_db_iface_ref(interfaces[i]);
6165 }
6166 spin_unlock_bh(&ecm_db_lock);
6167 return n;
6168}
6169EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_and_ref);
6170
6171/*
6172 * ecm_db_connection_to_nat_interfaces_get_and_ref()
6173 * Return the interface heirarchy to (nat) which this connection is established.
6174 *
6175 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
6176 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
6177 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
6178 *
6179 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
6180 */
6181int32_t ecm_db_connection_to_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
6182{
6183 int32_t n;
6184 int32_t i;
6185 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6186
6187 spin_lock_bh(&ecm_db_lock);
6188 n = ci->to_nat_interface_first;
6189 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6190 interfaces[i] = ci->to_nat_interfaces[i];
6191 _ecm_db_iface_ref(interfaces[i]);
6192 }
6193 spin_unlock_bh(&ecm_db_lock);
6194 return n;
6195}
6196EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_and_ref);
6197
6198/*
6199 * ecm_db_connection_interfaces_deref()
6200 * Release all interfaces in the given interfaces heirarchy array.
6201 *
6202 * 'first' is the number returned by one of the ecm_db_connection_xx_interfaces_get_and_ref().
6203 * You should NOT have released any references to any of the interfaces in the array youself, this releases them all.
6204 */
6205void ecm_db_connection_interfaces_deref(struct ecm_db_iface_instance *interfaces[], int32_t first)
6206{
6207 int32_t i;
6208 DEBUG_ASSERT((first >= 0) && (first <= ECM_DB_IFACE_HEIRARCHY_MAX), "Bad first: %d\n", first);
6209
6210 for (i = first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6211 ecm_db_iface_deref(interfaces[i]);
6212 }
6213}
6214EXPORT_SYMBOL(ecm_db_connection_interfaces_deref);
6215
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306216#ifdef ECM_MULTICAST_ENABLE
6217/*
6218 * ecm_db_multicast_connection_to_interfaces_reset()
6219 * Reset the 'to' interfaces heirarchy with a new set of destination interfaces for
6220 * the multicast connection
6221 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306222int 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 +05306223{
6224 struct ecm_db_iface_instance *ii_temp;
6225 struct ecm_db_iface_instance *ii_single;
6226 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306227 struct ecm_db_iface_instance *ii_db;
6228 struct ecm_db_iface_instance *ii_db_single;
6229 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306230 int32_t *nf_p;
6231 int32_t heirarchy_index;
6232 int32_t i;
6233 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6234
6235 /*
6236 * First remove all old interface hierarchies if any hierarchy
6237 * uphold in the ci->to_mcast_interfaces.
6238 */
6239 ecm_db_multicast_connection_to_interfaces_clear(ci);
6240
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306241 ci->to_mcast_interfaces = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
6242 if (!ci->to_mcast_interfaces) {
6243 DEBUG_WARN("%p: Memory is not available for to_mcast_interfaces\n", ci);
6244 return -1;
6245 }
6246
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306247 /*
6248 * Iterate the to interface list and add the new interface hierarchies
6249 */
6250 spin_lock_bh(&ecm_db_lock);
6251
6252 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6253 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
6254 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6255
6256 if (*nf_p == ECM_DB_IFACE_HEIRARCHY_MAX) {
6257 continue;
6258 }
6259
6260 for (i = *nf_p; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6261
6262 /*
6263 * Store valid dest interface list into DB connection
6264 */
6265 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6266 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306267
6268 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
6269 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, i);
6270 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
6271
6272 *ifaces_db = *ifaces;
6273 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306274 }
6275 }
6276
6277 /*
6278 * Update the first indices
6279 */
6280 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6281 nf_p = ecm_db_multicast_if_first_get_at_index(new_first, heirarchy_index);
6282 ci->to_mcast_interface_first[heirarchy_index] = *nf_p;
6283 }
6284
6285 ci->to_mcast_interfaces_set = true;
6286 spin_unlock_bh(&ecm_db_lock);
6287
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306288 return 0;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306289}
6290EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_reset);
6291
6292/*
6293 * ecm_db_multicast_connection_to_interfaces_update()
6294 * Merge the latest valid multicast destination interfaces into DB Connection
6295 * instance. The new list holds the updated list of interfaces for the multicast
6296 * connection, due to JOIN updates.
6297 */
6298void ecm_db_multicast_connection_to_interfaces_update(struct ecm_db_connection_instance *ci,
6299 struct ecm_db_iface_instance *interfaces, int32_t *mc_join_first, int32_t *mc_join_valid_idx)
6300{
6301 struct ecm_db_iface_instance *ii_temp;
6302 struct ecm_db_iface_instance *ii_single;
6303 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306304 struct ecm_db_iface_instance *ii_db;
6305 struct ecm_db_iface_instance *ii_db_single;
6306 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306307 int32_t *join_first;
6308 int32_t *join_idx;
6309 int heirarchy_index;
6310 int32_t if_index;
6311 int32_t i;
6312
6313 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6314
6315 /*
6316 * Iterate the to interface list, adding in the new
6317 */
6318 spin_lock_bh(&ecm_db_lock);
6319 for (heirarchy_index = 0, if_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
6320 ii_temp = ecm_db_multicast_if_heirarchy_get(interfaces, if_index);
6321 join_first = ecm_db_multicast_if_first_get_at_index(mc_join_first, if_index);
6322 join_idx = ecm_db_multicast_if_num_get_at_index(mc_join_valid_idx, heirarchy_index);
6323
6324 if (*join_idx == 0) {
6325
6326 /*
6327 * No update for the interface at this index
6328 */
6329 continue;
6330 }
6331
6332 /*
6333 * This interface has joined the group. Add it to the list.
6334 */
6335 if (*join_first == ECM_DB_IFACE_HEIRARCHY_MAX) {
6336 if_index++;
6337 continue;
6338 }
6339
6340 ci->to_mcast_interface_first[heirarchy_index] = *join_first;
6341 for (i = *join_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6342
6343 /*
6344 * Store valid dest interface list into DB connection
6345 */
6346 ii_single = ecm_db_multicast_if_instance_get_at_index(ii_temp, i);
6347 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +05306348 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
6349 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, i);
6350 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
6351 *ifaces_db = *ifaces;
6352 _ecm_db_iface_ref(*ifaces_db);
Shyam Sunder3b049ff2015-05-18 20:44:30 +05306353 }
6354 if_index++;
6355 }
6356 spin_unlock_bh(&ecm_db_lock);
6357 return;
6358}
6359EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_update);
6360#endif
6361
Ben Menchaca84f36632014-02-28 20:57:38 +00006362/*
6363 * ecm_db_connection_from_interfaces_reset()
6364 * Reset the from interfaces heirarchy with a new set of interfaces
6365 *
6366 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6367 * This is deliberate - it's stating that there is no list :-)
6368 */
6369void ecm_db_connection_from_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6370{
6371 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6372 int32_t old_first;
6373 int32_t i;
6374 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6375
6376 /*
6377 * Iterate the from interface list, removing the old and adding in the new
6378 */
6379 spin_lock_bh(&ecm_db_lock);
6380 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6381 /*
6382 * Put any previous interface into the old list
6383 */
6384 old[i] = ci->from_interfaces[i];
6385 ci->from_interfaces[i] = NULL;
6386 if (i < new_first) {
6387 continue;
6388 }
6389 ci->from_interfaces[i] = interfaces[i];
6390 _ecm_db_iface_ref(ci->from_interfaces[i]);
6391 }
6392
6393 /*
6394 * Get old first and update to new first
6395 */
6396 old_first = ci->from_interface_first;
6397 ci->from_interface_first = new_first;
6398 ci->from_interface_set = true;
6399 spin_unlock_bh(&ecm_db_lock);
6400
6401 /*
6402 * Release old
6403 */
6404 ecm_db_connection_interfaces_deref(old, old_first);
6405}
6406EXPORT_SYMBOL(ecm_db_connection_from_interfaces_reset);
6407
6408/*
6409 * ecm_db_connection_to_interfaces_reset()
6410 * Reset the to interfaces heirarchy with a new set of interfaces
6411 *
6412 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6413 * This is deliberate - it's stating that there is no list :-)
6414 */
6415void ecm_db_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6416{
6417 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6418 int32_t old_first;
6419 int32_t i;
6420 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6421
6422 /*
6423 * Iterate the to interface list, removing the old and adding in the new
6424 */
6425 spin_lock_bh(&ecm_db_lock);
6426 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6427 /*
6428 * Put any previous interface into the old list
6429 */
6430 old[i] = ci->to_interfaces[i];
6431 ci->to_interfaces[i] = NULL;
6432 if (i < new_first) {
6433 continue;
6434 }
6435 ci->to_interfaces[i] = interfaces[i];
6436 _ecm_db_iface_ref(ci->to_interfaces[i]);
6437 }
6438
6439 /*
6440 * Get old first and update to new first
6441 */
6442 old_first = ci->to_interface_first;
6443 ci->to_interface_first = new_first;
6444 ci->to_interface_set = true;
6445 spin_unlock_bh(&ecm_db_lock);
6446
6447 /*
6448 * Release old
6449 */
6450 ecm_db_connection_interfaces_deref(old, old_first);
6451}
6452EXPORT_SYMBOL(ecm_db_connection_to_interfaces_reset);
6453
6454/*
6455 * ecm_db_connection_from_nat_interfaces_reset()
6456 * Reset the from NAT interfaces heirarchy with a new set of interfaces
6457 *
6458 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6459 * This is deliberate - it's stating that there is no list :-)
6460 */
6461void ecm_db_connection_from_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6462{
6463 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6464 int32_t old_first;
6465 int32_t i;
6466 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6467
6468 /*
6469 * Iterate the from nat interface list, removing the old and adding in the new
6470 */
6471 spin_lock_bh(&ecm_db_lock);
6472 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6473 /*
6474 * Put any previous interface into the old list
6475 */
6476 old[i] = ci->from_nat_interfaces[i];
6477 ci->from_nat_interfaces[i] = NULL;
6478 if (i < new_first) {
6479 continue;
6480 }
6481 ci->from_nat_interfaces[i] = interfaces[i];
6482 _ecm_db_iface_ref(ci->from_nat_interfaces[i]);
6483 }
6484
6485 /*
6486 * Get old first and update to new first
6487 */
6488 old_first = ci->from_nat_interface_first;
6489 ci->from_nat_interface_first = new_first;
6490 ci->from_nat_interface_set = true;
6491 spin_unlock_bh(&ecm_db_lock);
6492
6493 /*
6494 * Release old
6495 */
6496 ecm_db_connection_interfaces_deref(old, old_first);
6497}
6498EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_reset);
6499
6500/*
6501 * ecm_db_connection_to_nat_interfaces_reset()
6502 * Reset the to NAT interfaces heirarchy with a new set of interfaces.
6503 *
6504 * NOTE: This will mark the list as set even if you specify no list as a replacement.
6505 * This is deliberate - it's stating that there is no list :-)
6506 */
6507void ecm_db_connection_to_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
6508{
6509 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
6510 int32_t old_first;
6511 int32_t i;
6512 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6513
6514 /*
6515 * Iterate the to nat interface list, removing the old and adding in the new
6516 */
6517 spin_lock_bh(&ecm_db_lock);
6518 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6519 /*
6520 * Put any previous interface into the old list
6521 */
6522 old[i] = ci->to_nat_interfaces[i];
6523 ci->to_nat_interfaces[i] = NULL;
6524 if (i < new_first) {
6525 continue;
6526 }
6527 ci->to_nat_interfaces[i] = interfaces[i];
6528 _ecm_db_iface_ref(ci->to_nat_interfaces[i]);
6529 }
6530
6531 /*
6532 * Get old first and update to new first
6533 */
6534 old_first = ci->to_nat_interface_first;
6535 ci->to_nat_interface_first = new_first;
6536 ci->to_nat_interface_set = true;
6537 spin_unlock_bh(&ecm_db_lock);
6538
6539 /*
6540 * Release old
6541 */
6542 ecm_db_connection_interfaces_deref(old, old_first);
6543}
6544EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_reset);
6545
6546/*
6547 * ecm_db_connection_to_nat_interfaces_get_count()
6548 * Return the number of interfaces in the list
6549 */
6550int32_t ecm_db_connection_to_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6551{
6552 int32_t first;
6553 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6554 spin_lock_bh(&ecm_db_lock);
6555 first = ci->to_nat_interface_first;
6556 spin_unlock_bh(&ecm_db_lock);
6557 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6558}
6559EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_count);
6560
6561/*
6562 * ecm_db_connection_from_nat_interfaces_get_count()
6563 * Return the number of interfaces in the list
6564 */
6565int32_t ecm_db_connection_from_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
6566{
6567 int32_t first;
6568 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6569 spin_lock_bh(&ecm_db_lock);
6570 first = ci->from_nat_interface_first;
6571 spin_unlock_bh(&ecm_db_lock);
6572 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6573}
6574EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_count);
6575
6576/*
6577 * ecm_db_connection_to_interfaces_get_count()
6578 * Return the number of interfaces in the list
6579 */
6580int32_t ecm_db_connection_to_interfaces_get_count(struct ecm_db_connection_instance *ci)
6581{
6582 int32_t first;
6583 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6584 spin_lock_bh(&ecm_db_lock);
6585 first = ci->to_interface_first;
6586 spin_unlock_bh(&ecm_db_lock);
6587 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6588}
6589EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_count);
6590
6591/*
6592 * ecm_db_connection_from_interfaces_get_count()
6593 * Return the number of interfaces in the list
6594 */
6595int32_t ecm_db_connection_from_interfaces_get_count(struct ecm_db_connection_instance *ci)
6596{
6597 int32_t first;
6598 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6599 spin_lock_bh(&ecm_db_lock);
6600 first = ci->from_interface_first;
6601 spin_unlock_bh(&ecm_db_lock);
6602 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
6603}
6604EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_count);
6605
6606/*
6607 * ecm_db_connection_to_interfaces_set_check()
6608 * Returns true if the interface list has been set - even if set to an empty list!
6609 */
6610bool ecm_db_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
6611{
6612 bool set;
6613
6614 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6615 spin_lock_bh(&ecm_db_lock);
6616 set = ci->to_interface_set;
6617 spin_unlock_bh(&ecm_db_lock);
6618 return set;
6619}
6620EXPORT_SYMBOL(ecm_db_connection_to_interfaces_set_check);
6621
6622/*
6623 * ecm_db_connection_from_interfaces_set_check()
6624 * Returns true if the interface list has been set - even if set to an empty list!
6625 */
6626bool ecm_db_connection_from_interfaces_set_check(struct ecm_db_connection_instance *ci)
6627{
6628 bool set;
6629
6630 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6631 spin_lock_bh(&ecm_db_lock);
6632 set = ci->from_interface_set;
6633 spin_unlock_bh(&ecm_db_lock);
6634 return set;
6635}
6636EXPORT_SYMBOL(ecm_db_connection_from_interfaces_set_check);
6637
6638/*
6639 * ecm_db_connection_to_nat_interfaces_set_check()
6640 * Returns true if the interface list has been set - even if set to an empty list!
6641 */
6642bool ecm_db_connection_to_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6643{
6644 bool set;
6645
6646 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6647 spin_lock_bh(&ecm_db_lock);
6648 set = ci->to_nat_interface_set;
6649 spin_unlock_bh(&ecm_db_lock);
6650 return set;
6651}
6652EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_set_check);
6653
6654/*
6655 * ecm_db_connection_from_nat_interfaces_set_check()
6656 * Returns true if the interface list has been set - even if set to an empty list!
6657 */
6658bool ecm_db_connection_from_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
6659{
6660 bool set;
6661
6662 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6663 spin_lock_bh(&ecm_db_lock);
6664 set = ci->from_nat_interface_set;
6665 spin_unlock_bh(&ecm_db_lock);
6666 return set;
6667}
6668EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_set_check);
6669
6670/*
6671 * ecm_db_connection_from_interfaces_clear()
6672 * Clear down the interfaces list, marking the list as not set
6673 */
6674void ecm_db_connection_from_interfaces_clear(struct ecm_db_connection_instance *ci)
6675{
6676 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6677 int32_t discard_first;
6678 int32_t i;
6679
6680 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6681
6682 spin_lock_bh(&ecm_db_lock);
6683 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6684 discard[i] = ci->from_interfaces[i];
6685 }
6686
6687 discard_first = ci->from_interface_first;
6688 ci->from_interface_set = false;
6689 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6690 spin_unlock_bh(&ecm_db_lock);
6691
6692 /*
6693 * Release previous
6694 */
6695 ecm_db_connection_interfaces_deref(discard, discard_first);
6696}
6697EXPORT_SYMBOL(ecm_db_connection_from_interfaces_clear);
6698
6699/*
6700 * ecm_db_connection_from_nat_interfaces_clear()
6701 * Clear down the interfaces list, marking the list as not set
6702 */
6703void ecm_db_connection_from_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
6704{
6705 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6706 int32_t discard_first;
6707 int32_t i;
6708
6709 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6710
6711 spin_lock_bh(&ecm_db_lock);
6712 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6713 discard[i] = ci->from_nat_interfaces[i];
6714 }
6715
6716 discard_first = ci->from_nat_interface_first;
6717 ci->from_nat_interface_set = false;
6718 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6719 spin_unlock_bh(&ecm_db_lock);
6720
6721 /*
6722 * Release previous
6723 */
6724 ecm_db_connection_interfaces_deref(discard, discard_first);
6725}
6726EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_clear);
6727
6728/*
6729 * ecm_db_connection_to_interfaces_clear()
6730 * Clear down the interfaces list, marking the list as not set
6731 */
6732void ecm_db_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
6733{
6734 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6735 int32_t discard_first;
6736 int32_t i;
6737
6738 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6739
6740 spin_lock_bh(&ecm_db_lock);
6741 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6742 discard[i] = ci->to_interfaces[i];
6743 }
6744
6745 discard_first = ci->to_interface_first;
6746 ci->to_interface_set = false;
6747 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6748 spin_unlock_bh(&ecm_db_lock);
6749
6750 /*
6751 * Release previous
6752 */
6753 ecm_db_connection_interfaces_deref(discard, discard_first);
6754}
6755EXPORT_SYMBOL(ecm_db_connection_to_interfaces_clear);
6756
6757/*
6758 * ecm_db_connection_to_nat_interfaces_clear()
6759 * Clear down the interfaces list, marking the list as not set
6760 */
6761void ecm_db_connection_to_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
6762{
6763 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
6764 int32_t discard_first;
6765 int32_t i;
6766
6767 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6768
6769 spin_lock_bh(&ecm_db_lock);
6770 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
6771 discard[i] = ci->to_nat_interfaces[i];
6772 }
6773
6774 discard_first = ci->to_nat_interface_first;
6775 ci->to_nat_interface_set = false;
6776 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
6777 spin_unlock_bh(&ecm_db_lock);
6778
6779 /*
6780 * Release previous
6781 */
6782 ecm_db_connection_interfaces_deref(discard, discard_first);
6783}
6784EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_clear);
6785
6786/*
6787 * ecm_db_connection_add()
6788 * Add the connection into the database.
6789 *
6790 * NOTE: The parameters are DIRECTIONAL in terms of which mapping established the connection.
6791 * 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.
6792 */
6793void ecm_db_connection_add(struct ecm_db_connection_instance *ci,
6794 struct ecm_front_end_connection_instance *feci,
Ben Menchaca84f36632014-02-28 20:57:38 +00006795 struct ecm_db_mapping_instance *mapping_from, struct ecm_db_mapping_instance *mapping_to,
6796 struct ecm_db_mapping_instance *mapping_nat_from, struct ecm_db_mapping_instance *mapping_nat_to,
Gareth Williams90f2a282014-08-27 15:56:25 +01006797 struct ecm_db_node_instance *from_node, struct ecm_db_node_instance *to_node,
6798 struct ecm_db_node_instance *from_nat_node, struct ecm_db_node_instance *to_nat_node,
Gareth Williams3e5b37f2015-05-13 10:04:12 +01006799 int ip_version,
Ben Menchaca84f36632014-02-28 20:57:38 +00006800 int protocol, ecm_db_direction_t dir,
6801 ecm_db_connection_final_callback_t final,
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07006802 ecm_db_connection_defunct_callback_t defunct,
Ben Menchaca84f36632014-02-28 20:57:38 +00006803 ecm_db_timer_group_t tg, bool is_routed,
6804 void *arg)
6805{
6806 ecm_db_connection_hash_t hash_index;
6807 ecm_db_connection_serial_hash_t serial_hash_index;
6808 struct ecm_db_listener_instance *li;
Gareth Williamsb5903892015-03-20 15:13:07 +00006809#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00006810 struct ecm_db_iface_instance *iface_from;
6811 struct ecm_db_iface_instance *iface_to;
6812 struct ecm_db_iface_instance *iface_nat_from;
6813 struct ecm_db_iface_instance *iface_nat_to;
Gareth Williamsb5903892015-03-20 15:13:07 +00006814#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00006815
6816 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
6817 DEBUG_CHECK_MAGIC(mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_from);
6818 DEBUG_CHECK_MAGIC(mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_to);
6819 DEBUG_CHECK_MAGIC(mapping_nat_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_from);
6820 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 +01006821 DEBUG_CHECK_MAGIC(from_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_node);
6822 DEBUG_CHECK_MAGIC(to_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_node);
6823 DEBUG_CHECK_MAGIC(from_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_nat_node);
6824 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 +00006825 DEBUG_ASSERT((protocol >= 0) && (protocol <= 255), "%p: invalid protocol number %d\n", ci, protocol);
6826
6827 spin_lock_bh(&ecm_db_lock);
6828 DEBUG_ASSERT(!(ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED), "%p: inserted\n", ci);
6829 spin_unlock_bh(&ecm_db_lock);
6830
6831 /*
6832 * Record owner arg and callbacks
6833 */
6834 ci->final = final;
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07006835 ci->defunct = defunct;
Ben Menchaca84f36632014-02-28 20:57:38 +00006836 ci->arg = arg;
6837
6838 /*
6839 * Take reference to the front end
6840 */
6841 feci->ref(feci);
6842 ci->feci = feci;
6843
6844 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006845 * Ensure default classifier has been assigned this is a must to ensure minimum level of classification
Ben Menchaca84f36632014-02-28 20:57:38 +00006846 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01006847 DEBUG_ASSERT(ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT], "%p: No default classifier assigned\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00006848
6849 /*
6850 * Connection takes references to the mappings
6851 */
6852 ecm_db_mapping_ref(mapping_from);
6853 ecm_db_mapping_ref(mapping_to);
6854 ci->mapping_from = mapping_from;
6855 ci->mapping_to = mapping_to;
6856
6857 ecm_db_mapping_ref(mapping_nat_from);
6858 ecm_db_mapping_ref(mapping_nat_to);
6859 ci->mapping_nat_from = mapping_nat_from;
6860 ci->mapping_nat_to = mapping_nat_to;
6861
6862 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01006863 * Take references to the nodes
6864 */
6865 ci->from_node = from_node;
6866 ecm_db_node_ref(from_node);
6867 ci->to_node = to_node;
6868 ecm_db_node_ref(to_node);
6869
6870 ci->from_nat_node = from_nat_node;
6871 ecm_db_node_ref(from_nat_node);
6872 ci->to_nat_node = to_nat_node;
6873 ecm_db_node_ref(to_nat_node);
6874
6875 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00006876 * Set the protocol and routed flag
6877 */
Gareth Williams3e5b37f2015-05-13 10:04:12 +01006878 ci->ip_version = ip_version;
Ben Menchaca84f36632014-02-28 20:57:38 +00006879 ci->protocol = protocol;
6880 ci->is_routed = is_routed;
6881
6882 /*
6883 * Set direction of connection
6884 */
6885 ci->direction = dir;
6886
6887 /*
6888 * Identify which hash chain this connection will go into
6889 */
6890 hash_index = ecm_db_connection_generate_hash_index(mapping_from->host->address, mapping_from->port, mapping_to->host->address, mapping_to->port, protocol);
6891 ci->hash_index = hash_index;
6892
6893 /*
6894 * Identify which serial hash chain this connection will go into
6895 */
6896 serial_hash_index = ecm_db_connection_generate_serial_hash_index(ci->serial);
6897 ci->serial_hash_index = serial_hash_index;
6898
6899 /*
6900 * Now we need to lock
6901 */
6902 spin_lock_bh(&ecm_db_lock);
6903
6904 /*
6905 * Increment protocol counter stats
6906 */
6907 ecm_db_connection_count_by_protocol[protocol]++;
6908 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[protocol] > 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[protocol]);
6909
Ben Menchaca84f36632014-02-28 20:57:38 +00006910 /*
6911 * Set time
6912 */
6913 ci->time_added = ecm_db_time;
6914
6915 /*
6916 * Add connection into the global list
6917 */
6918 ci->prev = NULL;
6919 ci->next = ecm_db_connections;
6920 if (ecm_db_connections) {
6921 ecm_db_connections->prev = ci;
6922 }
6923 ecm_db_connections = ci;
6924
6925 /*
6926 * Add this connection into the connections hash table
6927 */
6928 ci->flags |= ECM_DB_CONNECTION_FLAGS_INSERTED;
6929
6930 /*
Gareth Williamsb5903892015-03-20 15:13:07 +00006931 * Insert connection into the connections hash table
Ben Menchaca84f36632014-02-28 20:57:38 +00006932 */
6933 ci->hash_next = ecm_db_connection_table[hash_index];
6934 if (ecm_db_connection_table[hash_index]) {
6935 ecm_db_connection_table[hash_index]->hash_prev = ci;
6936 }
6937 ecm_db_connection_table[hash_index] = ci;
6938 ecm_db_connection_table_lengths[hash_index]++;
6939 DEBUG_ASSERT(ecm_db_connection_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[hash_index]);
6940
6941 /*
6942 * Insert connection into the connections serial hash table
6943 */
6944 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
6945 if (ecm_db_connection_serial_table[serial_hash_index]) {
6946 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
6947 }
6948 ecm_db_connection_serial_table[serial_hash_index] = ci;
6949 ecm_db_connection_serial_table_lengths[serial_hash_index]++;
6950 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]);
6951
Gareth Williamsb5903892015-03-20 15:13:07 +00006952#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00006953 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01006954 * Add this connection into the FROM node
6955 */
6956 ci->node_from_prev = NULL;
6957 ci->node_from_next = from_node->from_connections;
6958 if (from_node->from_connections) {
6959 from_node->from_connections->node_from_prev = ci;
6960 }
6961 from_node->from_connections = ci;
6962 from_node->from_connections_count++;
6963 DEBUG_ASSERT(from_node->from_connections_count > 0, "%p: invalid count\n", ci);
6964
6965 /*
6966 * Add this connection into the TO node
6967 */
6968 ci->node_to_prev = NULL;
6969 ci->node_to_next = to_node->to_connections;
6970 if (to_node->to_connections) {
6971 to_node->to_connections->node_to_prev = ci;
6972 }
6973 to_node->to_connections = ci;
6974 to_node->to_connections_count++;
6975 DEBUG_ASSERT(to_node->to_connections_count > 0, "%p: invalid count\n", ci);
6976
6977 /*
6978 * Add this connection into the FROM NAT node
6979 */
6980 ci->node_from_nat_prev = NULL;
6981 ci->node_from_nat_next = from_nat_node->from_nat_connections;
6982 if (from_nat_node->from_nat_connections) {
6983 from_nat_node->from_nat_connections->node_from_nat_prev = ci;
6984 }
6985 from_nat_node->from_nat_connections = ci;
6986 from_nat_node->from_nat_connections_count++;
6987 DEBUG_ASSERT(from_nat_node->from_nat_connections_count > 0, "%p: invalid count\n", ci);
6988
6989 /*
6990 * Add this connection into the TO NAT node
6991 */
6992 ci->node_to_nat_prev = NULL;
6993 ci->node_to_nat_next = to_nat_node->to_nat_connections;
6994 if (to_nat_node->to_nat_connections) {
6995 to_nat_node->to_nat_connections->node_to_nat_prev = ci;
6996 }
6997 to_nat_node->to_nat_connections = ci;
6998 to_nat_node->to_nat_connections_count++;
6999 DEBUG_ASSERT(to_nat_node->to_nat_connections_count > 0, "%p: invalid count\n", ci);
7000
7001 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007002 * Add this connection into the FROM mapping
7003 */
7004 ci->from_prev = NULL;
7005 ci->from_next = mapping_from->from_connections;
7006 if (mapping_from->from_connections) {
7007 mapping_from->from_connections->from_prev = ci;
7008 }
7009 mapping_from->from_connections = ci;
7010
7011 /*
7012 * Add this connection into the TO mapping
7013 */
7014 ci->to_prev = NULL;
7015 ci->to_next = mapping_to->to_connections;
7016 if (mapping_to->to_connections) {
7017 mapping_to->to_connections->to_prev = ci;
7018 }
7019 mapping_to->to_connections = ci;
7020
7021 /*
7022 * Add this connection into the FROM NAT mapping
7023 */
7024 ci->from_nat_prev = NULL;
7025 ci->from_nat_next = mapping_nat_from->from_nat_connections;
7026 if (mapping_nat_from->from_nat_connections) {
7027 mapping_nat_from->from_nat_connections->from_nat_prev = ci;
7028 }
7029 mapping_nat_from->from_nat_connections = ci;
7030
7031 /*
7032 * Add this connection into the TO NAT mapping
7033 */
7034 ci->to_nat_prev = NULL;
7035 ci->to_nat_next = mapping_nat_to->to_nat_connections;
7036 if (mapping_nat_to->to_nat_connections) {
7037 mapping_nat_to->to_nat_connections->to_nat_prev = ci;
7038 }
7039 mapping_nat_to->to_nat_connections = ci;
7040
7041 /*
7042 * Add this connection into the FROM iface list of connections
7043 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7044 * due to the heirarchy of dependencies being kept by the database.
7045 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007046 iface_from = from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007047 ci->iface_from_prev = NULL;
7048 ci->iface_from_next = iface_from->from_connections;
7049 if (iface_from->from_connections) {
7050 iface_from->from_connections->iface_from_prev = ci;
7051 }
7052 iface_from->from_connections = ci;
7053
7054 /*
7055 * Add this connection into the TO iface list of connections
7056 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
7057 * due to the heirarchy of dependencies being kept by the database.
7058 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007059 iface_to = to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007060 ci->iface_to_prev = NULL;
7061 ci->iface_to_next = iface_to->to_connections;
7062 if (iface_to->to_connections) {
7063 iface_to->to_connections->iface_to_prev = ci;
7064 }
7065 iface_to->to_connections = ci;
7066
7067 /*
7068 * Add this connection into the FROM NAT 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_nat_from = from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007073 ci->iface_from_nat_prev = NULL;
7074 ci->iface_from_nat_next = iface_nat_from->from_nat_connections;
7075 if (iface_nat_from->from_nat_connections) {
7076 iface_nat_from->from_nat_connections->iface_from_nat_prev = ci;
7077 }
7078 iface_nat_from->from_nat_connections = ci;
7079
7080 /*
7081 * Add this connection into the TO NAT 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_nat_to = to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00007086 ci->iface_to_nat_prev = NULL;
7087 ci->iface_to_nat_next = iface_nat_to->to_nat_connections;
7088 if (iface_nat_to->to_nat_connections) {
7089 iface_nat_to->to_nat_connections->iface_to_nat_prev = ci;
7090 }
7091 iface_nat_to->to_nat_connections = ci;
Gareth Williamsb5903892015-03-20 15:13:07 +00007092#endif
Gareth Williams90f2a282014-08-27 15:56:25 +01007093
Ben Menchaca84f36632014-02-28 20:57:38 +00007094 /*
7095 * NOTE: The interface heirarchy lists are deliberately left empty - these are completed
7096 * by the front end if it is appropriate to do so.
7097 */
7098
7099 /*
7100 * Update the counters in the mapping
7101 */
7102 if (protocol == IPPROTO_UDP) {
7103 mapping_from->udp_from++;
7104 mapping_to->udp_to++;
7105 mapping_nat_from->udp_nat_from++;
7106 mapping_nat_to->udp_nat_to++;
7107 } else if (protocol == IPPROTO_TCP) {
7108 mapping_from->tcp_from++;
7109 mapping_to->tcp_to++;
7110 mapping_nat_from->tcp_nat_from++;
7111 mapping_nat_to->tcp_nat_to++;
7112 }
7113
7114 mapping_from->from++;
7115 mapping_to->to++;
7116 mapping_nat_from->nat_from++;
7117 mapping_nat_to->nat_to++;
7118
7119 /*
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307120 * Set the generation number to match global
Ben Menchaca84f36632014-02-28 20:57:38 +00007121 */
Tushar Mathurd38cacd2015-07-28 12:19:10 +05307122 ci->generation = ecm_db_connection_generation;
Ben Menchaca84f36632014-02-28 20:57:38 +00007123
7124 spin_unlock_bh(&ecm_db_lock);
7125
7126 /*
7127 * Throw add event to the listeners
7128 */
7129 DEBUG_TRACE("%p: Throw connection added event\n", ci);
7130 li = ecm_db_listeners_get_and_ref_first();
7131 while (li) {
7132 struct ecm_db_listener_instance *lin;
7133 if (li->connection_added) {
7134 li->connection_added(li->arg, ci);
7135 }
7136
7137 /*
7138 * Get next listener
7139 */
7140 lin = ecm_db_listener_get_and_ref_next(li);
7141 ecm_db_listener_deref(li);
7142 li = lin;
7143 }
7144
7145 /*
7146 * Set timer group. 'ref' the connection to ensure it persists for the timer.
7147 */
7148 ecm_db_connection_ref(ci);
7149 ecm_db_timer_group_entry_set(&ci->defunct_timer, tg);
7150}
7151EXPORT_SYMBOL(ecm_db_connection_add);
7152
7153/*
7154 * ecm_db_mapping_add()
7155 * Add a mapping instance into the database
7156 *
7157 * NOTE: The mapping will take a reference to the host instance.
7158 */
7159void ecm_db_mapping_add(struct ecm_db_mapping_instance *mi, struct ecm_db_host_instance *hi, int port,
7160 ecm_db_mapping_final_callback_t final, void *arg)
7161{
7162 ecm_db_mapping_hash_t hash_index;
7163 struct ecm_db_listener_instance *li;
7164
7165 spin_lock_bh(&ecm_db_lock);
7166 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
7167 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007168 DEBUG_ASSERT(!(mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED), "%p: inserted\n", mi);
7169 DEBUG_ASSERT((hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: not inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007170 DEBUG_ASSERT(!mi->tcp_from && !mi->tcp_to && !mi->udp_from && !mi->udp_to, "%p: protocol count errors\n", mi);
7171#ifdef ECM_DB_XREF_ENABLE
7172 DEBUG_ASSERT(mi->from_connections == NULL, "%p: connections not null\n", mi);
7173 DEBUG_ASSERT(mi->to_connections == NULL, "%p: connections not null\n", mi);
7174 DEBUG_ASSERT(!mi->from && !mi->to && !mi->nat_from && !mi->nat_to, "%p: connection count errors\n", mi);
7175#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007176 spin_unlock_bh(&ecm_db_lock);
7177
7178 mi->arg = arg;
7179 mi->final = final;
7180
7181 /*
7182 * Compute hash table position for insertion
7183 */
7184 hash_index = ecm_db_mapping_generate_hash_index(hi->address, port);
7185 mi->hash_index = hash_index;
7186
7187 /*
7188 * Record port
7189 */
7190 mi->port = port;
7191
7192 /*
7193 * Mapping takes a ref to the host
7194 */
7195 ecm_db_host_ref(hi);
7196 mi->host = hi;
7197
7198 /*
7199 * Set time
7200 */
7201 spin_lock_bh(&ecm_db_lock);
7202 mi->time_added = ecm_db_time;
7203
7204 /*
7205 * Record the mapping is inserted
7206 */
7207 mi->flags |= ECM_DB_MAPPING_FLAGS_INSERTED;
7208
7209 /*
7210 * Add into the global list
7211 */
7212 mi->prev = NULL;
7213 mi->next = ecm_db_mappings;
7214 if (ecm_db_mappings) {
7215 ecm_db_mappings->prev = mi;
7216 }
7217 ecm_db_mappings = mi;
7218
7219 /*
7220 * Insert mapping into the mappings hash table
7221 */
7222 mi->hash_next = ecm_db_mapping_table[hash_index];
7223 if (ecm_db_mapping_table[hash_index]) {
7224 ecm_db_mapping_table[hash_index]->hash_prev = mi;
7225 }
7226 ecm_db_mapping_table[hash_index] = mi;
7227 ecm_db_mapping_table_lengths[hash_index]++;
7228 DEBUG_ASSERT(ecm_db_mapping_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_mapping_table_lengths[hash_index]);
7229
Gareth Williamsb5903892015-03-20 15:13:07 +00007230#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007231 /*
7232 * Insert mapping into the host mapping list
7233 */
7234 mi->mapping_prev = NULL;
7235 mi->mapping_next = hi->mappings;
7236 if (hi->mappings) {
7237 hi->mappings->mapping_prev = mi;
7238 }
7239 hi->mappings = mi;
7240 hi->mapping_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007241#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007242 spin_unlock_bh(&ecm_db_lock);
7243
7244 /*
7245 * Throw add event to the listeners
7246 */
7247 DEBUG_TRACE("%p: Throw mapping added event\n", mi);
7248 li = ecm_db_listeners_get_and_ref_first();
7249 while (li) {
7250 struct ecm_db_listener_instance *lin;
7251 if (li->mapping_added) {
7252 li->mapping_added(li->arg, mi);
7253 }
7254
7255 /*
7256 * Get next listener
7257 */
7258 lin = ecm_db_listener_get_and_ref_next(li);
7259 ecm_db_listener_deref(li);
7260 li = lin;
7261 }
7262}
7263EXPORT_SYMBOL(ecm_db_mapping_add);
7264
7265/*
7266 * ecm_db_host_add()
7267 * Add a host instance into the database
7268 */
Gareth Williams90f2a282014-08-27 15:56:25 +01007269void 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 +00007270{
7271 ecm_db_host_hash_t hash_index;
7272 struct ecm_db_listener_instance *li;
7273
7274 spin_lock_bh(&ecm_db_lock);
7275 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007276 DEBUG_ASSERT(!(hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: inserted\n", hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00007277#ifdef ECM_DB_XREF_ENABLE
7278 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
7279#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007280 spin_unlock_bh(&ecm_db_lock);
7281
7282 hi->arg = arg;
7283 hi->final = final;
7284 ECM_IP_ADDR_COPY(hi->address, address);
7285 hi->on_link = on_link;
7286
7287 /*
7288 * Compute hash index into which host will be added
7289 */
7290 hash_index = ecm_db_host_generate_hash_index(address);
7291 hi->hash_index = hash_index;
7292
7293 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007294 * Add into the global list
7295 */
7296 spin_lock_bh(&ecm_db_lock);
7297 hi->flags |= ECM_DB_HOST_FLAGS_INSERTED;
7298 hi->prev = NULL;
7299 hi->next = ecm_db_hosts;
7300 if (ecm_db_hosts) {
7301 ecm_db_hosts->prev = hi;
7302 }
7303 ecm_db_hosts = hi;
7304
7305 /*
7306 * Add host into the hash table
7307 */
7308 hi->hash_next = ecm_db_host_table[hash_index];
7309 if (ecm_db_host_table[hash_index]) {
7310 ecm_db_host_table[hash_index]->hash_prev = hi;
7311 }
7312 ecm_db_host_table[hash_index] = hi;
7313 ecm_db_host_table_lengths[hash_index]++;
7314 DEBUG_ASSERT(ecm_db_host_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hash_index]);
7315
7316 /*
7317 * Set time of add
7318 */
7319 hi->time_added = ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00007320 spin_unlock_bh(&ecm_db_lock);
7321
7322 /*
7323 * Throw add event to the listeners
7324 */
7325 DEBUG_TRACE("%p: Throw host added event\n", hi);
7326 li = ecm_db_listeners_get_and_ref_first();
7327 while (li) {
7328 struct ecm_db_listener_instance *lin;
7329 if (li->host_added) {
7330 li->host_added(li->arg, hi);
7331 }
7332
7333 /*
7334 * Get next listener
7335 */
7336 lin = ecm_db_listener_get_and_ref_next(li);
7337 ecm_db_listener_deref(li);
7338 li = lin;
7339 }
7340}
7341EXPORT_SYMBOL(ecm_db_host_add);
7342
7343/*
7344 * ecm_db_node_add()
7345 * Add a node instance into the database
7346 */
7347void ecm_db_node_add(struct ecm_db_node_instance *ni, struct ecm_db_iface_instance *ii, uint8_t *address,
7348 ecm_db_node_final_callback_t final, void *arg)
7349{
7350 ecm_db_node_hash_t hash_index;
7351 struct ecm_db_listener_instance *li;
7352
7353 spin_lock_bh(&ecm_db_lock);
7354 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
7355 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7356 DEBUG_ASSERT(address, "%p: address null\n", ni);
Gareth Williamsb5903892015-03-20 15:13:07 +00007357 DEBUG_ASSERT((ni->iface == NULL), "%p: iface not null\n", ni);
7358 DEBUG_ASSERT(!(ni->flags & ECM_DB_NODE_FLAGS_INSERTED), "%p: inserted\n", ni);
7359#ifdef ECM_DB_XREF_ENABLE
Gareth Williams90f2a282014-08-27 15:56:25 +01007360 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
7361 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
7362 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
7363 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 +00007364#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007365 spin_unlock_bh(&ecm_db_lock);
7366
7367 memcpy(ni->address, address, ETH_ALEN);
7368 ni->arg = arg;
7369 ni->final = final;
7370
7371 /*
7372 * Compute hash chain for insertion
7373 */
7374 hash_index = ecm_db_node_generate_hash_index(address);
7375 ni->hash_index = hash_index;
7376
7377 /*
7378 * Node takes a ref to the iface
7379 */
7380 ecm_db_iface_ref(ii);
7381 ni->iface = ii;
7382
7383 /*
7384 * Add into the global list
7385 */
7386 spin_lock_bh(&ecm_db_lock);
7387 ni->flags |= ECM_DB_NODE_FLAGS_INSERTED;
7388 ni->prev = NULL;
7389 ni->next = ecm_db_nodes;
7390 if (ecm_db_nodes) {
7391 ecm_db_nodes->prev = ni;
7392 }
7393 ecm_db_nodes = ni;
7394
7395 /*
7396 * Insert into the hash chain
7397 */
7398 ni->hash_next = ecm_db_node_table[hash_index];
7399 if (ecm_db_node_table[hash_index]) {
7400 ecm_db_node_table[hash_index]->hash_prev = ni;
7401 }
7402 ecm_db_node_table[hash_index] = ni;
7403 ecm_db_node_table_lengths[hash_index]++;
7404 DEBUG_ASSERT(ecm_db_node_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[hash_index]);
7405
7406 /*
7407 * Set time of add
7408 */
7409 ni->time_added = ecm_db_time;
7410
Gareth Williamsb5903892015-03-20 15:13:07 +00007411#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007412 /*
7413 * Insert node into the iface nodes list
7414 */
7415 ni->node_prev = NULL;
7416 ni->node_next = ii->nodes;
7417 if (ii->nodes) {
7418 ii->nodes->node_prev = ni;
7419 }
7420 ii->nodes = ni;
7421 ii->node_count++;
Gareth Williamsb5903892015-03-20 15:13:07 +00007422#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007423 spin_unlock_bh(&ecm_db_lock);
7424
7425 /*
7426 * Throw add event to the listeners
7427 */
7428 DEBUG_TRACE("%p: Throw node added event\n", ni);
7429 li = ecm_db_listeners_get_and_ref_first();
7430 while (li) {
7431 struct ecm_db_listener_instance *lin;
7432 if (li->node_added) {
7433 li->node_added(li->arg, ni);
7434 }
7435
7436 /*
7437 * Get next listener
7438 */
7439 lin = ecm_db_listener_get_and_ref_next(li);
7440 ecm_db_listener_deref(li);
7441 li = lin;
7442 }
7443}
7444EXPORT_SYMBOL(ecm_db_node_add);
7445
Gareth Williamsd5618a82015-05-20 11:13:32 +01007446/*
7447 * ecm_db_adv_stats_state_write()
7448 * Write out advanced stats state
7449 */
7450static int ecm_db_adv_stats_state_write(struct ecm_state_file_instance *sfi,uint64_t from_data_total, uint64_t to_data_total,
7451 uint64_t from_packet_total, uint64_t to_packet_total, uint64_t from_data_total_dropped,
7452 uint64_t to_data_total_dropped, uint64_t from_packet_total_dropped, uint64_t to_packet_total_dropped)
7453{
7454 int result;
7455
7456 if ((result = ecm_state_prefix_add(sfi, "adv_stats"))) {
7457 return result;
7458 }
7459
7460 if ((result = ecm_state_write(sfi, "from_data_total", "%llu", from_data_total))) {
7461 return result;
7462 }
7463 if ((result = ecm_state_write(sfi, "to_data_total", "%llu", to_data_total))) {
7464 return result;
7465 }
7466 if ((result = ecm_state_write(sfi, "from_packet_total", "%llu", from_packet_total))) {
7467 return result;
7468 }
7469 if ((result = ecm_state_write(sfi, "to_packet_total", "%llu", to_packet_total))) {
7470 return result;
7471 }
7472 if ((result = ecm_state_write(sfi, "from_data_total_dropped", "%llu", from_data_total_dropped))) {
7473 return result;
7474 }
7475 if ((result = ecm_state_write(sfi, "to_data_total_dropped", "%llu", to_data_total_dropped))) {
7476 return result;
7477 }
7478 if ((result = ecm_state_write(sfi, "from_packet_total_dropped", "%llu", from_packet_total_dropped))) {
7479 return result;
7480 }
7481 if ((result = ecm_state_write(sfi, "to_packet_total_dropped", "%llu", to_packet_total_dropped))) {
7482 return result;
7483 }
7484
7485 return ecm_state_prefix_remove(sfi);
7486}
7487
Gareth Williamsf98d4192015-03-11 16:55:41 +00007488#ifdef ECM_STATE_OUTPUT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007489/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007490 * ecm_db_iface_state_get_base()
7491 * Get the basic state for an interface object
Ben Menchaca84f36632014-02-28 20:57:38 +00007492 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007493static 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 +00007494{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007495 int result;
Gareth Williamsb5903892015-03-20 15:13:07 +00007496#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007497 int node_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00007498#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007499 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00007500 int32_t interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007501 int32_t ae_interface_identifier;
Gareth Williams85331c92015-03-11 20:39:18 +00007502 char name[IFNAMSIZ];
7503 int32_t mtu;
7504 ecm_db_iface_type_t type;
7505#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007506 uint64_t from_data_total;
7507 uint64_t to_data_total;
7508 uint64_t from_packet_total;
7509 uint64_t to_packet_total;
7510 uint64_t from_data_total_dropped;
7511 uint64_t to_data_total_dropped;
7512 uint64_t from_packet_total_dropped;
7513 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00007514#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007515
7516 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7517 DEBUG_TRACE("%p: Open iface msg\n", ii);
7518
Gareth Williamsd5618a82015-05-20 11:13:32 +01007519 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
7520 return result;
7521 }
7522
Gareth Williamsb5903892015-03-20 15:13:07 +00007523#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007524 node_count = ecm_db_iface_node_count_get(ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00007525#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007526 time_added = ii->time_added;
Ben Menchaca84f36632014-02-28 20:57:38 +00007527 type = ii->type;
Gareth Williamsd5618a82015-05-20 11:13:32 +01007528 interface_identifier = ii->interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07007529 ae_interface_identifier = ii->ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00007530 spin_lock_bh(&ecm_db_lock);
7531 strcpy(name, ii->name);
7532 mtu = ii->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00007533 spin_unlock_bh(&ecm_db_lock);
7534
Gareth Williams85331c92015-03-11 20:39:18 +00007535#ifdef ECM_DB_ADVANCED_STATS_ENABLE
7536 ecm_db_iface_data_stats_get(ii, &from_data_total, &to_data_total,
7537 &from_packet_total, &to_packet_total,
7538 &from_data_total_dropped, &to_data_total_dropped,
7539 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williamsd5618a82015-05-20 11:13:32 +01007540
7541 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
7542 from_packet_total, to_packet_total, from_data_total_dropped,
7543 to_data_total_dropped, from_packet_total_dropped,
7544 to_packet_total_dropped))) {
7545 return result;
7546 }
Gareth Williams85331c92015-03-11 20:39:18 +00007547#endif
7548
Gareth Williamsd5618a82015-05-20 11:13:32 +01007549 if ((result = ecm_state_write(sfi, "type", "%d", type))) {
7550 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007551 }
7552
Gareth Williamsd5618a82015-05-20 11:13:32 +01007553 if ((result = ecm_state_write(sfi, "name", "%s", name))) {
7554 return result;
7555 }
7556
7557 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
7558 return result;
7559 }
7560
7561 if ((result = ecm_state_write(sfi, "mtu", "%d", mtu))) {
7562 return result;
7563 }
7564
7565 if ((result = ecm_state_write(sfi, "interface_identifier", "%d", interface_identifier))) {
7566 return result;
7567 }
7568
Murat Sezgin91c5d712015-06-12 15:16:22 -07007569 if ((result = ecm_state_write(sfi, "ae_interface_identifier", "%d", ae_interface_identifier))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01007570 return result;
7571 }
7572
7573#ifdef ECM_DB_XREF_ENABLE
7574 if ((result = ecm_state_write(sfi, "nodes", "%d", node_count))) {
7575 return result;
7576 }
7577#endif
7578
7579 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007580}
7581
7582/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007583 * ecm_db_iface_ethernet_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007584 * Return interface type specific state
7585 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007586static 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 +00007587{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007588 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007589 uint8_t address[ETH_ALEN];
7590
7591 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7592 spin_lock_bh(&ecm_db_lock);
7593 memcpy(address, ii->type_info.ethernet.address, ETH_ALEN);
7594 spin_unlock_bh(&ecm_db_lock);
7595
Gareth Williamsd5618a82015-05-20 11:13:32 +01007596 if ((result = ecm_state_prefix_add(sfi, "ethernet"))) {
7597 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007598 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007599
Gareth Williamsd5618a82015-05-20 11:13:32 +01007600 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7601 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007602 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007603
Gareth Williamsd5618a82015-05-20 11:13:32 +01007604 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7605 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007606 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007607
7608 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007609}
7610
Murat Sezgin910c9662015-03-11 16:15:06 -07007611#ifdef ECM_INTERFACE_BOND_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007612/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007613 * ecm_db_iface_lag_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007614 * Return interface type specific state
7615 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007616static 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 +00007617{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007618 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007619 uint8_t address[ETH_ALEN];
7620
7621 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7622 spin_lock_bh(&ecm_db_lock);
7623 memcpy(address, ii->type_info.lag.address, ETH_ALEN);
7624 spin_unlock_bh(&ecm_db_lock);
7625
Gareth Williamsd5618a82015-05-20 11:13:32 +01007626 if ((result = ecm_state_prefix_add(sfi, "lag"))) {
7627 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007628 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007629 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7630 return result;
7631 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007632
Gareth Williamsd5618a82015-05-20 11:13:32 +01007633 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7634 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007635 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007636
Gareth Williamsd5618a82015-05-20 11:13:32 +01007637 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007638}
Murat Sezgin910c9662015-03-11 16:15:06 -07007639#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007640
7641/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007642 * ecm_db_iface_bridge_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007643 * Return interface type specific state
7644 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007645static 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 +00007646{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007647 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007648 uint8_t address[ETH_ALEN];
7649
7650 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7651 spin_lock_bh(&ecm_db_lock);
7652 memcpy(address, ii->type_info.bridge.address, ETH_ALEN);
7653 spin_unlock_bh(&ecm_db_lock);
7654
Gareth Williamsd5618a82015-05-20 11:13:32 +01007655 if ((result = ecm_state_prefix_add(sfi, "bridge"))) {
7656 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007657 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007658 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7659 return result;
7660 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007661
Gareth Williamsd5618a82015-05-20 11:13:32 +01007662 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7663 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007664 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007665
Gareth Williamsd5618a82015-05-20 11:13:32 +01007666 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007667}
7668
Murat Sezgin37fb3952015-03-10 16:45:13 -07007669#ifdef ECM_INTERFACE_VLAN_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007670/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007671 * ecm_db_iface_vlan_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007672 * Return interface type specific state
7673 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007674static 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 +00007675{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007676 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007677 uint8_t address[ETH_ALEN];
7678 uint16_t vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307679 uint16_t vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007680
7681 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7682 spin_lock_bh(&ecm_db_lock);
7683 memcpy(address, ii->type_info.vlan.address, ETH_ALEN);
7684 vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307685 vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007686 spin_unlock_bh(&ecm_db_lock);
7687
Gareth Williamsd5618a82015-05-20 11:13:32 +01007688 if ((result = ecm_state_prefix_add(sfi, "vlan"))) {
7689 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007690 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007691 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7692 return result;
7693 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007694
Gareth Williamsd5618a82015-05-20 11:13:32 +01007695 if ((result = ecm_state_write(sfi, "address", "%pM", address))) {
7696 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007697 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007698 if ((result = ecm_state_write(sfi, "tag", "%x", vlan_tag))) {
7699 return result;
7700 }
7701 if ((result = ecm_state_write(sfi, "tpid", "%x", vlan_tpid))) {
7702 return result;
7703 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007704
Gareth Williamsd5618a82015-05-20 11:13:32 +01007705 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007706}
Murat Sezgin37fb3952015-03-10 16:45:13 -07007707#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007708
ratheesh kannotha32fdd12015-09-09 08:02:58 +05307709#ifdef ECM_INTERFACE_PPPOE_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007710/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007711 * ecm_db_iface_pppoe_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007712 * Return interface type specific state
7713 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007714static 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 +00007715{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007716 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007717 uint16_t pppoe_session_id;
7718 uint8_t remote_mac[ETH_ALEN];
7719
7720 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7721 spin_lock_bh(&ecm_db_lock);
7722 pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
7723 memcpy(remote_mac, ii->type_info.pppoe.remote_mac, ETH_ALEN);
7724 spin_unlock_bh(&ecm_db_lock);
7725
Gareth Williamsd5618a82015-05-20 11:13:32 +01007726 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
7727 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007728 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007729 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7730 return result;
7731 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007732
Gareth Williamsd5618a82015-05-20 11:13:32 +01007733 if ((result = ecm_state_write(sfi, "remote_max", "%pM", remote_mac))) {
7734 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007735 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007736 if ((result = ecm_state_write(sfi, "session_id", "%u", pppoe_session_id))) {
7737 return result;
7738 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007739
Gareth Williamsd5618a82015-05-20 11:13:32 +01007740 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007741}
Murat Sezginaad635c2015-03-06 16:11:41 -08007742#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007743
ratheesh kannotha32fdd12015-09-09 08:02:58 +05307744#ifdef ECM_INTERFACE_L2TPV2_ENABLE
7745
7746/*
7747 * ecm_db_iface_pppol2tpv2_state_get()
7748 * Return interface type specific state
7749 */
7750static int ecm_db_iface_pppol2tpv2_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
7751{
7752 int result;
7753 struct ecm_db_interface_info_pppol2tpv2 type_info;
7754
7755 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7756 spin_lock_bh(&ecm_db_lock);
7757 memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
7758 spin_unlock_bh(&ecm_db_lock);
7759
7760 if ((result = ecm_state_prefix_add(sfi, "pppol2tpv2"))) {
7761 return result;
7762 }
7763
7764 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7765 return result;
7766 }
7767
7768 if ((result = ecm_state_write(sfi, "local_tunnel_id", "%u", type_info.l2tp.tunnel.tunnel_id))) {
7769 return result;
7770 }
7771
7772 if ((result = ecm_state_write(sfi, "local_session_id", "%u", type_info.l2tp.session.session_id))) {
7773 return result;
7774 }
7775
7776 if ((result = ecm_state_write(sfi, "peer_tunnnel_id", "%u", type_info.l2tp.tunnel.peer_tunnel_id))) {
7777 return result;
7778 }
7779
7780 if ((result = ecm_state_write(sfi, "peer_session_id", "%u", type_info.l2tp.session.peer_session_id))) {
7781 return result;
7782 }
7783
7784 return ecm_state_prefix_remove(sfi);
7785}
7786
7787#endif
7788
Shyam Sunder23f2e542015-09-28 14:56:49 +05307789#ifdef ECM_INTERFACE_PPTP_ENABLE
7790/*
7791 * ecm_db_iface_pptp_state_get()
7792 * Return interface type specific state
7793 */
7794static int ecm_db_iface_pptp_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
7795{
7796 int result;
7797 struct ecm_db_interface_info_pptp type_info;
7798
7799 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7800 spin_lock_bh(&ecm_db_lock);
7801 memcpy(&type_info, &ii->type_info, sizeof(struct ecm_db_interface_info_pptp));
7802 spin_unlock_bh(&ecm_db_lock);
7803
7804 result = ecm_state_prefix_add(sfi, "pptp");
7805 if (result) {
7806 return result;
7807 }
7808
7809 result = ecm_db_iface_state_get_base(ii, sfi);
7810 if (result) {
7811 return result;
7812 }
7813
7814 result = ecm_state_write(sfi, "local_call_id", "%u", type_info.src_call_id);
7815 if (result) {
7816 return result;
7817 }
7818
7819 result = ecm_state_write(sfi, "peer_call_id", "%u", type_info.dst_call_id);
7820 if (result) {
7821 return result;
7822 }
7823
7824 return ecm_state_prefix_remove(sfi);
7825}
7826#endif
7827
Ben Menchaca84f36632014-02-28 20:57:38 +00007828/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007829 * ecm_db_iface_unknown_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007830 * Return interface type specific state
7831 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007832static 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 +00007833{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007834 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007835 uint32_t os_specific_ident;
7836
7837 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7838 spin_lock_bh(&ecm_db_lock);
7839 os_specific_ident = ii->type_info.unknown.os_specific_ident;
7840 spin_unlock_bh(&ecm_db_lock);
7841
Gareth Williamsd5618a82015-05-20 11:13:32 +01007842 if ((result = ecm_state_prefix_add(sfi, "pppoe"))) {
7843 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007844 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007845 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7846 return result;
7847 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007848
Gareth Williamsd5618a82015-05-20 11:13:32 +01007849 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7850 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007851 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007852
Gareth Williamsd5618a82015-05-20 11:13:32 +01007853 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007854}
7855
7856/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007857 * ecm_db_iface_loopback_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007858 * Return interface type specific state
7859 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007860static 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 +00007861{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007862 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007863 uint32_t os_specific_ident;
7864
7865 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7866 spin_lock_bh(&ecm_db_lock);
7867 os_specific_ident = ii->type_info.loopback.os_specific_ident;
7868 spin_unlock_bh(&ecm_db_lock);
7869
Gareth Williamsd5618a82015-05-20 11:13:32 +01007870 if ((result = ecm_state_prefix_add(sfi, "loopback"))) {
7871 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007872 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007873 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7874 return result;
7875 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007876
Gareth Williamsd5618a82015-05-20 11:13:32 +01007877 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7878 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007879 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007880
Gareth Williamsd5618a82015-05-20 11:13:32 +01007881 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007882}
7883
Murat Sezgin69a27532015-03-12 14:09:40 -07007884#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00007885/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007886 * ecm_db_iface_ipsec_tunnel_state_get()
Ben Menchaca84f36632014-02-28 20:57:38 +00007887 * Return interface type specific state
7888 *
7889 * GGG TODO Output state on ipsec tunnel specific data
7890 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007891static 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 +00007892{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007893 int result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007894 uint32_t os_specific_ident;
7895
7896 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7897 spin_lock_bh(&ecm_db_lock);
7898 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7899 spin_unlock_bh(&ecm_db_lock);
7900
Gareth Williamsd5618a82015-05-20 11:13:32 +01007901 if ((result = ecm_state_prefix_add(sfi, "ipsec"))) {
7902 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007903 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007904 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7905 return result;
7906 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007907
Gareth Williamsd5618a82015-05-20 11:13:32 +01007908 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7909 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00007910 }
Ben Menchaca84f36632014-02-28 20:57:38 +00007911
Gareth Williamsd5618a82015-05-20 11:13:32 +01007912 return ecm_state_prefix_remove(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00007913}
Murat Sezgin69a27532015-03-12 14:09:40 -07007914#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00007915
Gareth Williamsf98d4192015-03-11 16:55:41 +00007916#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +00007917#ifdef ECM_IPV6_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00007918/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007919 * ecm_db_iface_tunipip6_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00007920 * Return interface type specific state
7921 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007922static 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 +00007923{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007924 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007925 uint32_t os_specific_ident;
7926
7927 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7928 spin_lock_bh(&ecm_db_lock);
7929 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7930 spin_unlock_bh(&ecm_db_lock);
7931
Gareth Williamsd5618a82015-05-20 11:13:32 +01007932 if ((result = ecm_state_prefix_add(sfi, "tunipip6"))) {
7933 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007934 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007935 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7936 return result;
7937 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007938
Gareth Williamsd5618a82015-05-20 11:13:32 +01007939 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7940 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007941 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007942
Gareth Williamsd5618a82015-05-20 11:13:32 +01007943 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00007944}
7945#endif
Gareth Williams8ac34292015-03-17 14:06:58 +00007946#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00007947
7948#ifdef ECM_INTERFACE_SIT_ENABLE
7949/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007950 * ecm_db_iface_sit_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00007951 * Return interface type specific state
7952 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007953static 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 +00007954{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007955 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007956 uint32_t os_specific_ident;
7957
7958 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7959 spin_lock_bh(&ecm_db_lock);
7960 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7961 spin_unlock_bh(&ecm_db_lock);
7962
Gareth Williamsd5618a82015-05-20 11:13:32 +01007963 if ((result = ecm_state_prefix_add(sfi, "sit"))) {
7964 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007965 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01007966 if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
7967 return result;
7968 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007969
Gareth Williamsd5618a82015-05-20 11:13:32 +01007970 if ((result = ecm_state_write(sfi, "os_specific_ident", "%u", os_specific_ident))) {
7971 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00007972 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00007973
Gareth Williamsd5618a82015-05-20 11:13:32 +01007974 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00007975}
7976#endif
7977
7978/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01007979 * ecm_db_iface_state_get()
7980 * Obtain state for the interface.
Gareth Williamsf98d4192015-03-11 16:55:41 +00007981 *
7982 * State specific to the interface type will be returned.
7983 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01007984int ecm_db_iface_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_iface_instance *ii)
Gareth Williamsf98d4192015-03-11 16:55:41 +00007985{
Gareth Williamsd5618a82015-05-20 11:13:32 +01007986 int result;
7987
Gareth Williamsf98d4192015-03-11 16:55:41 +00007988 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsd5618a82015-05-20 11:13:32 +01007989
7990 if ((result = ecm_state_prefix_add(sfi, "iface"))) {
7991 return result;
7992 }
7993
7994 if ((result = ii->state_get(ii, sfi))) {
7995 return result;
7996 }
7997
7998 return ecm_state_prefix_remove(sfi);
7999
Gareth Williamsf98d4192015-03-11 16:55:41 +00008000}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008001EXPORT_SYMBOL(ecm_db_iface_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008002
8003/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008004 * ecm_db_connection_heirarchy_state_get()
8005 * Output state for an interface heirarchy list.
Gareth Williamsf98d4192015-03-11 16:55:41 +00008006 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008007static 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 +00008008{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008009 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008010 int count;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008011 int i;
Gareth Williamsd5618a82015-05-20 11:13:32 +01008012 int j;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008013
Gareth Williamsd5618a82015-05-20 11:13:32 +01008014 count = ECM_DB_IFACE_HEIRARCHY_MAX - first_interface;
8015 if ((result = ecm_state_write(sfi, "interface_count", "%d", count))) {
8016 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008017 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008018
8019 /*
8020 * Iterate the interface heirarchy list and output the information
8021 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008022 for (i = first_interface, j = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i, ++j) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008023 struct ecm_db_iface_instance *ii = interfaces[i];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008024 DEBUG_TRACE("Output interface @ %d: %p\n", i, ii);
8025
8026 if ((result = ecm_state_prefix_index_add(sfi, j))) {
8027 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008028 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008029 result = ii->state_get(ii, sfi);
8030 if (result) {
8031 return result;
8032 }
8033 if ((result = ecm_state_prefix_remove(sfi))) {
8034 return result;
8035 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008036 }
8037
Gareth Williamsd5618a82015-05-20 11:13:32 +01008038 return 0;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008039}
8040
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308041#ifdef ECM_MULTICAST_ENABLE
8042/*
8043 * ecm_db_multicast_to_interfaces_xml_state_get()
8044 * Obtain XML state for the multicast destination interfaces list
8045 */
8046static int ecm_db_multicast_to_interfaces_xml_state_get(struct ecm_db_connection_instance *ci, struct ecm_state_file_instance *sfi)
8047{
8048 struct ecm_db_iface_instance *mc_ifaces;
8049 struct ecm_db_iface_instance *mc_ifaces_single[ECM_DB_IFACE_HEIRARCHY_MAX];
8050 struct ecm_db_iface_instance *ii_temp;
8051 int32_t *mc_ifaces_first;
8052 int32_t *ifaces_first;
8053 int32_t heirarchy_index;
8054 int ret;
8055
8056 ret = ecm_db_multicast_connection_to_interfaces_get_and_ref_all(ci, &mc_ifaces, &mc_ifaces_first);
8057 if (ret == 0) {
Shyam Sunder3af86a52015-08-28 18:04:10 +05308058 return ret;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308059 }
8060
8061 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
8062
8063 ii_temp = ecm_db_multicast_if_heirarchy_get(mc_ifaces, heirarchy_index);
8064 ecm_db_multicast_copy_if_heirarchy(mc_ifaces_single, ii_temp);
8065 ifaces_first = ecm_db_multicast_if_first_get_at_index(mc_ifaces_first, heirarchy_index);
8066
8067 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
8068 ret = ecm_db_connection_heirarchy_state_get(sfi, mc_ifaces_single, *ifaces_first);
8069 if (ret) {
8070 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8071 return ret;
8072 }
8073
8074 }
8075 }
8076 ecm_db_multicast_connection_to_interfaces_deref_all(mc_ifaces, mc_ifaces_first);
8077
8078 return ret;
8079}
8080#endif
8081
Gareth Williamsf98d4192015-03-11 16:55:41 +00008082/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008083 * ecm_db_connection_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008084 * Prepare a connection message
8085 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008086int ecm_db_connection_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_connection_instance *ci)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008087{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008088 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008089 long int expires_in;
8090 int sport;
8091 int sport_nat;
8092 char snode_address[25];
8093 char snode_address_nat[25];
8094 char sip_address[50];
8095 char sip_address_nat[50];
8096 char dnode_address[25];
8097 char dnode_address_nat[25];
8098 int dport;
8099 int dport_nat;
8100 char dip_address[50];
8101 char dip_address_nat[50];
8102 ecm_db_direction_t direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008103 int ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008104 int protocol;
8105 bool is_routed;
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308106 uint32_t regen_success;
8107 uint32_t regen_fail;
8108 uint16_t regen_required;
8109 uint16_t regen_occurances;
8110 bool regen_in_progress;
8111 uint16_t generation;
8112 uint16_t global_generation;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008113 uint32_t time_added;
8114 uint32_t serial;
8115 uint64_t from_data_total;
8116 uint64_t to_data_total;
8117 uint64_t from_packet_total;
8118 uint64_t to_packet_total;
8119 uint64_t from_data_total_dropped;
8120 uint64_t to_data_total_dropped;
8121 uint64_t from_packet_total_dropped;
8122 uint64_t to_packet_total_dropped;
8123 struct ecm_db_host_instance *hi;
8124 struct ecm_db_node_instance *ni;
8125 int aci_index;
8126 int aci_count;
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308127 ip_addr_t __attribute__((unused)) group_ip;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008128 struct ecm_front_end_connection_instance *feci;
8129 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
8130 int32_t first_interface;
8131 struct ecm_db_iface_instance *interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
8132
8133 DEBUG_TRACE("Prep conn msg for %p\n", ci);
8134
8135 /*
8136 * Identify expiration
8137 */
8138 spin_lock_bh(&ecm_db_lock);
8139 if (ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX) {
8140 expires_in = -1;
8141 } else {
8142 expires_in = (long int)(ci->defunct_timer.timeout - ecm_db_time);
8143 if (expires_in <= 0) {
8144 expires_in = 0;
8145 }
8146 }
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308147
8148 regen_success = ci->regen_success;
8149 regen_fail = ci->regen_fail;
8150 regen_required = ci->regen_required;
8151 regen_occurances = ci->regen_occurances;
8152 regen_in_progress = ci->regen_in_progress;
8153 generation = ci->generation;
8154 global_generation = ecm_db_connection_generation;
8155
Gareth Williamsf98d4192015-03-11 16:55:41 +00008156 spin_unlock_bh(&ecm_db_lock);
8157
8158 /*
8159 * Extract information from the connection for inclusion into the message
8160 */
8161 sport = ci->mapping_from->port;
8162 sport_nat = ci->mapping_nat_from->port;
8163 dport = ci->mapping_to->port;
8164 dport_nat = ci->mapping_nat_to->port;
8165
8166 hi = ci->mapping_to->host;
8167 ecm_ip_addr_to_string(dip_address, hi->address);
8168 ni = ci->to_node;
8169 sprintf(dnode_address, "%pM", ni->address);
8170 hi = ci->mapping_nat_to->host;
8171 ecm_ip_addr_to_string(dip_address_nat, hi->address);
8172
8173 hi = ci->mapping_from->host;
8174 ecm_ip_addr_to_string(sip_address, hi->address);
8175 ni = ci->from_node;
8176 sprintf(snode_address, "%pM", ni->address);
8177 hi = ci->mapping_nat_from->host;
8178 ecm_ip_addr_to_string(sip_address_nat, hi->address);
8179
8180 ni = ci->to_nat_node;
8181 sprintf(dnode_address_nat, "%pM", ni->address);
8182
8183 ni = ci->from_nat_node;
8184 sprintf(snode_address_nat, "%pM", ni->address);
8185
8186 direction = ci->direction;
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008187 ip_version = ci->ip_version;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008188 protocol = ci->protocol;
8189 is_routed = ci->is_routed;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008190 time_added = ci->time_added;
8191 serial = ci->serial;
8192 ecm_db_connection_data_stats_get(ci, &from_data_total, &to_data_total,
8193 &from_packet_total, &to_packet_total,
8194 &from_data_total_dropped, &to_data_total_dropped,
8195 &from_packet_total_dropped, &to_packet_total_dropped);
8196
Gareth Williamsd5618a82015-05-20 11:13:32 +01008197 if ((result = ecm_state_prefix_add(sfi, "conn"))) {
8198 return result;
8199 }
8200 if ((result = ecm_state_prefix_index_add(sfi, serial))) {
8201 return result;
8202 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008203
Gareth Williamsd5618a82015-05-20 11:13:32 +01008204 if ((result = ecm_state_write(sfi, "serial", "%u", serial))) {
8205 return result;
8206 }
8207
8208 if ((result = ecm_state_write(sfi, "sip_address", "%s", sip_address))) {
8209 return result;
8210 }
8211
8212 if ((result = ecm_state_write(sfi, "sip_address_nat", "%s", sip_address_nat))) {
8213 return result;
8214 }
8215
8216 if ((result = ecm_state_write(sfi, "sport", "%d", sport))) {
8217 return result;
8218 }
8219
8220 if ((result = ecm_state_write(sfi, "sport_nat", "%d", sport_nat))) {
8221 return result;
8222 }
8223
8224 if ((result = ecm_state_write(sfi, "snode_address", "%s", snode_address))) {
8225 return result;
8226 }
8227
8228 if ((result = ecm_state_write(sfi, "snode_address_nat", "%s", snode_address_nat))) {
8229 return result;
8230 }
8231
8232 if ((result = ecm_state_write(sfi, "dip_address", "%s", dip_address))) {
8233 return result;
8234 }
8235
8236 if ((result = ecm_state_write(sfi, "dip_address_nat", "%s", dip_address_nat))) {
8237 return result;
8238 }
8239
8240 if ((result = ecm_state_write(sfi, "dport", "%d", dport))) {
8241 return result;
8242 }
8243
8244 if ((result = ecm_state_write(sfi, "dport_nat", "%d", dport_nat))) {
8245 return result;
8246 }
8247
8248 if ((result = ecm_state_write(sfi, "dnode_address", "%s", dnode_address))) {
8249 return result;
8250 }
8251
8252 if ((result = ecm_state_write(sfi, "dnode_address_nat", "%s", dnode_address_nat))) {
8253 return result;
8254 }
8255
Gareth Williams3e5b37f2015-05-13 10:04:12 +01008256 if ((result = ecm_state_write(sfi, "ip_version", "%d", ip_version))) {
8257 return result;
8258 }
8259
Gareth Williamsd5618a82015-05-20 11:13:32 +01008260 if ((result = ecm_state_write(sfi, "protocol", "%d", protocol))) {
8261 return result;
8262 }
8263
8264 if ((result = ecm_state_write(sfi, "is_routed", "%d", is_routed))) {
8265 return result;
8266 }
8267
8268 if ((result = ecm_state_write(sfi, "expires", "%ld", expires_in))) {
8269 return result;
8270 }
8271
8272 if ((result = ecm_state_write(sfi, "direction", "%d", direction))) {
8273 return result;
8274 }
8275
8276 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8277 return result;
8278 }
8279
Tushar Mathurd38cacd2015-07-28 12:19:10 +05308280 if ((result = ecm_state_write(sfi, "regen_success", "%u", regen_success))) {
8281 return result;
8282 }
8283 if ((result = ecm_state_write(sfi, "regen_fail", "%u", regen_fail))) {
8284 return result;
8285 }
8286 if ((result = ecm_state_write(sfi, "regen_required", "%u", regen_required))) {
8287 return result;
8288 }
8289 if ((result = ecm_state_write(sfi, "regen_occurances", "%u", regen_occurances))) {
8290 return result;
8291 }
8292 if ((result = ecm_state_write(sfi, "regen_in_progress", "%u", regen_in_progress))) {
8293 return result;
8294 }
8295 if ((result = ecm_state_write(sfi, "generation", "%u/%u", generation, global_generation))) {
Gareth Williamsd5618a82015-05-20 11:13:32 +01008296 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008297 }
8298
8299 /*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008300 * NOTE: These advanced stats are not conditional compiled.
8301 * Connections always contain these stats
Gareth Williamsf98d4192015-03-11 16:55:41 +00008302 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008303 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8304 from_packet_total, to_packet_total, from_data_total_dropped,
8305 to_data_total_dropped, from_packet_total_dropped,
8306 to_packet_total_dropped))) {
8307 return result;
8308 }
8309
8310 if ((result = ecm_state_prefix_add(sfi, "from_interfaces"))) {
8311 return result;
8312 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008313 first_interface = ecm_db_connection_from_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008314 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008315 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008316 if (result) {
8317 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008318 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008319 if ((result = ecm_state_prefix_remove(sfi))) {
8320 return result;
8321 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008322
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308323#ifdef ECM_MULTICAST_ENABLE
8324 ecm_db_connection_to_address_get(ci, group_ip);
8325 if (ecm_ip_addr_is_multicast(group_ip)) {
8326 if ((result = ecm_state_prefix_add(sfi, "to_mc_interfaces"))) {
8327 return result;
8328 }
8329
8330 if ((result = ecm_db_multicast_to_interfaces_xml_state_get(ci, sfi))) {
8331 return result;
8332 }
8333
8334 if ((result = ecm_state_prefix_remove(sfi))) {
8335 return result;
8336 }
8337 }
8338 else {
8339 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8340 return result;
8341 }
8342
8343 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
8344 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8345 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8346 if (result) {
8347 return result;
8348 }
8349
8350 if ((result = ecm_state_prefix_remove(sfi))) {
8351 return result;
8352 }
8353 }
8354#else
Gareth Williamsd5618a82015-05-20 11:13:32 +01008355 if ((result = ecm_state_prefix_add(sfi, "to_interfaces"))) {
8356 return result;
8357 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008358 first_interface = ecm_db_connection_to_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008359 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008360 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008361 if (result) {
8362 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008363 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008364 if ((result = ecm_state_prefix_remove(sfi))) {
8365 return result;
8366 }
Shyam Sunder3b049ff2015-05-18 20:44:30 +05308367#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008368
Gareth Williamsd5618a82015-05-20 11:13:32 +01008369 if ((result = ecm_state_prefix_add(sfi, "from_nat_interfaces"))) {
8370 return result;
8371 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008372 first_interface = ecm_db_connection_from_nat_interfaces_get_and_ref(ci, interfaces);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008373 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008374 ecm_db_connection_interfaces_deref(interfaces, first_interface);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008375 if (result) {
8376 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008377 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008378 if ((result = ecm_state_prefix_remove(sfi))) {
8379 return result;
8380 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008381
Gareth Williamsd5618a82015-05-20 11:13:32 +01008382 if ((result = ecm_state_prefix_add(sfi, "to_nat_interfaces"))) {
8383 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008384 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008385 first_interface = ecm_db_connection_to_nat_interfaces_get_and_ref(ci, interfaces);
8386 result = ecm_db_connection_heirarchy_state_get(sfi, interfaces, first_interface);
8387 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8388 if (result) {
8389 return result;
8390 }
8391 if ((result = ecm_state_prefix_remove(sfi))) {
8392 return result;
8393 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008394
8395 /*
8396 * Output front end state
8397 */
8398 feci = ecm_db_connection_front_end_get_and_ref(ci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008399 result = feci->state_get(feci, sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008400 feci->deref(feci);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008401 if (result) {
8402 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008403 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008404
8405 if ((result = ecm_state_prefix_add(sfi, "classifiers"))) {
8406 return result;
8407 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008408
8409 /*
8410 * Grab references to the assigned classifiers so we can produce state for them
8411 */
8412 aci_count = ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
8413
8414 /*
8415 * Iterate the assigned classifiers and provide a state record for each
8416 */
8417 for (aci_index = 0; aci_index < aci_count; ++aci_index) {
8418 struct ecm_classifier_instance *aci;
8419
8420 aci = assignments[aci_index];
Gareth Williamsd5618a82015-05-20 11:13:32 +01008421 result = aci->state_get(aci, sfi);
8422 if (result) {
Gareth Williamsf98d4192015-03-11 16:55:41 +00008423 ecm_db_connection_assignments_release(aci_count, assignments);
Gareth Williamsd5618a82015-05-20 11:13:32 +01008424 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008425 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008426 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008427
Gareth Williamsf98d4192015-03-11 16:55:41 +00008428 ecm_db_connection_assignments_release(aci_count, assignments);
8429
Gareth Williamsd5618a82015-05-20 11:13:32 +01008430 if ((result = ecm_state_prefix_remove(sfi))) {
8431 return result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008432 }
Gareth Williamsd5618a82015-05-20 11:13:32 +01008433
8434 if ((result = ecm_state_prefix_remove(sfi))) {
8435 return result;
8436 }
8437
8438 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008439}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008440EXPORT_SYMBOL(ecm_db_connection_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008441
8442/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008443 * ecm_db_mapping_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008444 * Prepare a mapping message
8445 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008446int ecm_db_mapping_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_mapping_instance *mi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008447{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008448 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008449 int port;
8450 char address[25];
8451 int tcp_from;
8452 int tcp_to;
8453 int udp_from;
8454 int udp_to;
8455 int from;
8456 int to;
8457 int tcp_nat_from;
8458 int tcp_nat_to;
8459 int udp_nat_from;
8460 int udp_nat_to;
8461 int nat_from;
8462 int nat_to;
8463 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008464 struct ecm_db_host_instance *hi;
8465#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008466 uint64_t from_data_total;
8467 uint64_t to_data_total;
8468 uint64_t from_packet_total;
8469 uint64_t to_packet_total;
8470 uint64_t from_data_total_dropped;
8471 uint64_t to_data_total_dropped;
8472 uint64_t from_packet_total_dropped;
8473 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008474#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008475
8476 DEBUG_TRACE("Prep mapping msg for %p\n", mi);
8477
8478 /*
8479 * Create a small xml stats element for our mapping.
8480 * Extract information from the mapping for inclusion into the message
8481 */
8482 ecm_db_mapping_port_count_get(mi, &tcp_from, &tcp_to, &udp_from, &udp_to, &from, &to,
8483 &tcp_nat_from, &tcp_nat_to, &udp_nat_from, &udp_nat_to, &nat_from, &nat_to);
8484 port = mi->port;
8485 time_added = mi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008486 hi = mi->host;
8487 ecm_ip_addr_to_string(address, hi->address);
8488
8489#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008490 ecm_db_mapping_data_stats_get(mi, &from_data_total, &to_data_total,
8491 &from_packet_total, &to_packet_total,
8492 &from_data_total_dropped, &to_data_total_dropped,
8493 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008494#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008495
Gareth Williamsd5618a82015-05-20 11:13:32 +01008496 if ((result = ecm_state_prefix_add(sfi, "mapping"))) {
8497 return result;
8498 }
Gareth Williamsf98d4192015-03-11 16:55:41 +00008499
Gareth Williamsd5618a82015-05-20 11:13:32 +01008500 if ((result = ecm_state_write(sfi, "port", "%d", port))) {
8501 return result;
8502 }
8503
8504 if ((result = ecm_state_write(sfi, "from", "%d", from))) {
8505 return result;
8506 }
8507
8508 if ((result = ecm_state_write(sfi, "to", "%d", to))) {
8509 return result;
8510 }
8511
8512 if ((result = ecm_state_write(sfi, "tcp_from", "%d", tcp_from))) {
8513 return result;
8514 }
8515
8516 if ((result = ecm_state_write(sfi, "tcp_to", "%d", tcp_to))) {
8517 return result;
8518 }
8519
8520 if ((result = ecm_state_write(sfi, "udp_from", "%d", udp_from))) {
8521 return result;
8522 }
8523
8524 if ((result = ecm_state_write(sfi, "udp_to", "%d", udp_to))) {
8525 return result;
8526 }
8527
8528 if ((result = ecm_state_write(sfi, "nat_from", "%d", nat_from))) {
8529 return result;
8530 }
8531
8532 if ((result = ecm_state_write(sfi, "nat_to", "%d", nat_to))) {
8533 return result;
8534 }
8535
8536 if ((result = ecm_state_write(sfi, "tcp_nat_from", "%d", tcp_nat_from))) {
8537 return result;
8538 }
8539
8540 if ((result = ecm_state_write(sfi, "tcp_nat_to", "%d", tcp_nat_to))) {
8541 return result;
8542 }
8543
8544 if ((result = ecm_state_write(sfi, "udp_nat_from", "%d", udp_nat_from))) {
8545 return result;
8546 }
8547
8548 if ((result = ecm_state_write(sfi, "udp_nat_to", "%d", udp_nat_to))) {
8549 return result;
8550 }
8551
8552 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8553 return result;
8554 }
8555
8556 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8557 return result;
8558 }
8559
8560#ifdef ECM_DB_ADVANCED_STATS_ENABLE
8561 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8562 from_packet_total, to_packet_total, from_data_total_dropped,
8563 to_data_total_dropped, from_packet_total_dropped,
8564 to_packet_total_dropped))) {
8565 return result;
8566 }
8567#endif
8568
8569 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008570}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008571EXPORT_SYMBOL(ecm_db_mapping_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008572
8573/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008574 * ecm_db_host_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008575 * Prepare a host message
8576 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008577int ecm_db_host_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_host_instance *hi)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008578{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008579 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008580 char address[50];
Gareth Williamsb5903892015-03-20 15:13:07 +00008581#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008582 int mapping_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00008583#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008584 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008585 bool on_link;
8586#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008587 uint64_t from_data_total;
8588 uint64_t to_data_total;
8589 uint64_t from_packet_total;
8590 uint64_t to_packet_total;
8591 uint64_t from_data_total_dropped;
8592 uint64_t to_data_total_dropped;
8593 uint64_t from_packet_total_dropped;
8594 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008595#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008596
8597 DEBUG_TRACE("Prep host msg for %p\n", hi);
8598
8599 /*
8600 * Create a small xml stats element for our host.
8601 * Extract information from the host for inclusion into the message
8602 */
Gareth Williamsb5903892015-03-20 15:13:07 +00008603#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008604 mapping_count = ecm_db_host_mapping_count_get(hi);
Gareth Williamsb5903892015-03-20 15:13:07 +00008605#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008606 ecm_ip_addr_to_string(address, hi->address);
8607 time_added = hi->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008608 on_link = hi->on_link;
8609
8610#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008611 ecm_db_host_data_stats_get(hi, &from_data_total, &to_data_total,
8612 &from_packet_total, &to_packet_total,
8613 &from_data_total_dropped, &to_data_total_dropped,
8614 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008615#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008616
Gareth Williamsd5618a82015-05-20 11:13:32 +01008617 if ((result = ecm_state_prefix_add(sfi, "host"))) {
8618 return result;
8619 }
8620
8621 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8622 return result;
8623 }
8624 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8625 return result;
8626 }
8627 if ((result = ecm_state_write(sfi, "on_link", "%d", on_link))) {
8628 return result;
8629 }
8630
Gareth Williamsb5903892015-03-20 15:13:07 +00008631#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008632 if ((result = ecm_state_write(sfi, "mappings", "%d", mapping_count))) {
8633 return result;
8634 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008635#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008636
Gareth Williams85331c92015-03-11 20:39:18 +00008637#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008638 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8639 from_packet_total, to_packet_total, from_data_total_dropped,
8640 to_data_total_dropped, from_packet_total_dropped,
8641 to_packet_total_dropped))) {
8642 return result;
8643 }
Gareth Williams85331c92015-03-11 20:39:18 +00008644#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008645
8646 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008647}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008648EXPORT_SYMBOL(ecm_db_host_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008649
8650/*
Gareth Williamsd5618a82015-05-20 11:13:32 +01008651 * ecm_db_node_state_get()
Gareth Williamsf98d4192015-03-11 16:55:41 +00008652 * Prepare a node message
8653 */
Gareth Williamsd5618a82015-05-20 11:13:32 +01008654int ecm_db_node_state_get(struct ecm_state_file_instance *sfi, struct ecm_db_node_instance *ni)
Gareth Williamsf98d4192015-03-11 16:55:41 +00008655{
Gareth Williamsd5618a82015-05-20 11:13:32 +01008656 int result;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008657 char address[25];
Gareth Williamsb5903892015-03-20 15:13:07 +00008658#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008659 int from_connections_count;
8660 int to_connections_count;
8661 int from_nat_connections_count;
8662 int to_nat_connections_count;
Gareth Williamsb5903892015-03-20 15:13:07 +00008663#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008664 uint32_t time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008665#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008666 uint64_t from_data_total;
8667 uint64_t to_data_total;
8668 uint64_t from_packet_total;
8669 uint64_t to_packet_total;
8670 uint64_t from_data_total_dropped;
8671 uint64_t to_data_total_dropped;
8672 uint64_t from_packet_total_dropped;
8673 uint64_t to_packet_total_dropped;
Gareth Williams85331c92015-03-11 20:39:18 +00008674#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008675
8676 DEBUG_TRACE("Prep node msg for %p\n", ni);
8677
8678 /*
8679 * Create a small xml stats block for our managed node, like:
8680 * <node address="" hosts="" time_added="" from_data_total="" to_data_total="" />
8681 *
8682 * Extract information from the node for inclusion into the message
8683 */
Gareth Williamsb5903892015-03-20 15:13:07 +00008684#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008685 spin_lock_bh(&ecm_db_lock);
8686 from_connections_count = ni->from_connections_count;
8687 to_connections_count = ni->to_connections_count;
8688 from_nat_connections_count = ni->from_nat_connections_count;
8689 to_nat_connections_count = ni->to_nat_connections_count;
8690 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsb5903892015-03-20 15:13:07 +00008691#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008692 time_added = ni->time_added;
Gareth Williams85331c92015-03-11 20:39:18 +00008693 sprintf(address, "%pM", ni->address);
8694
8695#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008696 ecm_db_node_data_stats_get(ni, &from_data_total, &to_data_total,
8697 &from_packet_total, &to_packet_total,
8698 &from_data_total_dropped, &to_data_total_dropped,
8699 &from_packet_total_dropped, &to_packet_total_dropped);
Gareth Williams85331c92015-03-11 20:39:18 +00008700
8701#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008702
Gareth Williamsd5618a82015-05-20 11:13:32 +01008703 if ((result = ecm_state_prefix_add(sfi, "node"))) {
8704 return result;
8705 }
8706 if ((result = ecm_state_write(sfi, "address", "%s", address))) {
8707 return result;
8708 }
8709 if ((result = ecm_state_write(sfi, "time_added", "%u", time_added))) {
8710 return result;
8711 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008712#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008713 if ((result = ecm_state_write(sfi, "from_connections_count", "%d", from_connections_count))) {
8714 return result;
8715 }
8716 if ((result = ecm_state_write(sfi, "to_connections_count", "%d", to_connections_count))) {
8717 return result;
8718 }
8719 if ((result = ecm_state_write(sfi, "from_nat_connections_count", "%d", from_nat_connections_count))) {
8720 return result;
8721 }
8722 if ((result = ecm_state_write(sfi, "to_nat_connections_count", "%d", to_nat_connections_count))) {
8723 return result;
8724 }
Gareth Williamsb5903892015-03-20 15:13:07 +00008725#endif
Gareth Williams85331c92015-03-11 20:39:18 +00008726#ifdef ECM_DB_ADVANCED_STATS_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008727 if ((result = ecm_db_adv_stats_state_write(sfi, from_data_total, to_data_total,
8728 from_packet_total, to_packet_total, from_data_total_dropped,
8729 to_data_total_dropped, from_packet_total_dropped,
8730 to_packet_total_dropped))) {
8731 return result;
8732 }
Gareth Williams85331c92015-03-11 20:39:18 +00008733#endif
Gareth Williamsd5618a82015-05-20 11:13:32 +01008734 return ecm_state_prefix_remove(sfi);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008735}
Gareth Williamsd5618a82015-05-20 11:13:32 +01008736EXPORT_SYMBOL(ecm_db_node_state_get);
Gareth Williamsf98d4192015-03-11 16:55:41 +00008737
8738/*
8739 * ecm_db_connection_hash_table_lengths_get()
8740 * Return hash table length
8741 */
8742int ecm_db_connection_hash_table_lengths_get(int index)
8743{
8744 int length;
8745
8746 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
8747 spin_lock_bh(&ecm_db_lock);
8748 length = ecm_db_connection_table_lengths[index];
8749 spin_unlock_bh(&ecm_db_lock);
8750 return length;
8751}
8752EXPORT_SYMBOL(ecm_db_connection_hash_table_lengths_get);
8753
8754/*
8755 * ecm_db_connection_hash_index_get_next()
8756 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8757 */
8758int ecm_db_connection_hash_index_get_next(int index)
8759{
8760 index++;
8761 if (index >= ECM_DB_CONNECTION_SERIAL_HASH_SLOTS) {
8762 return -1;
8763 }
8764 return index;
8765}
8766EXPORT_SYMBOL(ecm_db_connection_hash_index_get_next);
8767
8768/*
8769 * ecm_db_connection_hash_index_get_first()
8770 * Return first hash index
8771 */
8772int ecm_db_connection_hash_index_get_first(void)
8773{
8774 return 0;
8775}
8776EXPORT_SYMBOL(ecm_db_connection_hash_index_get_first);
8777
8778/*
8779 * ecm_db_mapping_hash_table_lengths_get()
8780 * Return hash table length
8781 */
8782int ecm_db_mapping_hash_table_lengths_get(int index)
8783{
8784 int length;
8785
8786 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_MAPPING_HASH_SLOTS), "Bad protocol: %d\n", index);
8787 spin_lock_bh(&ecm_db_lock);
8788 length = ecm_db_mapping_table_lengths[index];
8789 spin_unlock_bh(&ecm_db_lock);
8790 return length;
8791}
8792EXPORT_SYMBOL(ecm_db_mapping_hash_table_lengths_get);
8793
8794/*
8795 * ecm_db_mapping_hash_index_get_next()
8796 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8797 */
8798int ecm_db_mapping_hash_index_get_next(int index)
8799{
8800 index++;
8801 if (index >= ECM_DB_MAPPING_HASH_SLOTS) {
8802 return -1;
8803 }
8804 return index;
8805}
8806EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_next);
8807
8808/*
8809 * ecm_db_mapping_hash_index_get_first()
8810 * Return first hash index
8811 */
8812int ecm_db_mapping_hash_index_get_first(void)
8813{
8814 return 0;
8815}
8816EXPORT_SYMBOL(ecm_db_mapping_hash_index_get_first);
8817
8818/*
8819 * ecm_db_host_hash_table_lengths_get()
8820 * Return hash table length
8821 */
8822int ecm_db_host_hash_table_lengths_get(int index)
8823{
8824 int length;
8825
8826 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_HOST_HASH_SLOTS), "Bad protocol: %d\n", index);
8827 spin_lock_bh(&ecm_db_lock);
8828 length = ecm_db_host_table_lengths[index];
8829 spin_unlock_bh(&ecm_db_lock);
8830 return length;
8831}
8832EXPORT_SYMBOL(ecm_db_host_hash_table_lengths_get);
8833
8834/*
8835 * ecm_db_host_hash_index_get_next()
8836 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8837 */
8838int ecm_db_host_hash_index_get_next(int index)
8839{
8840 index++;
8841 if (index >= ECM_DB_HOST_HASH_SLOTS) {
8842 return -1;
8843 }
8844 return index;
8845}
8846EXPORT_SYMBOL(ecm_db_host_hash_index_get_next);
8847
8848/*
8849 * ecm_db_host_hash_index_get_first()
8850 * Return first hash index
8851 */
8852int ecm_db_host_hash_index_get_first(void)
8853{
8854 return 0;
8855}
8856EXPORT_SYMBOL(ecm_db_host_hash_index_get_first);
8857
8858/*
8859 * ecm_db_node_hash_table_lengths_get()
8860 * Return hash table length
8861 */
8862int ecm_db_node_hash_table_lengths_get(int index)
8863{
8864 int length;
8865
8866 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_NODE_HASH_SLOTS), "Bad protocol: %d\n", index);
8867 spin_lock_bh(&ecm_db_lock);
8868 length = ecm_db_node_table_lengths[index];
8869 spin_unlock_bh(&ecm_db_lock);
8870 return length;
8871}
8872EXPORT_SYMBOL(ecm_db_node_hash_table_lengths_get);
8873
8874/*
8875 * ecm_db_node_hash_index_get_next()
8876 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8877 */
8878int ecm_db_node_hash_index_get_next(int index)
8879{
8880 index++;
8881 if (index >= ECM_DB_NODE_HASH_SLOTS) {
8882 return -1;
8883 }
8884 return index;
8885}
8886EXPORT_SYMBOL(ecm_db_node_hash_index_get_next);
8887
8888/*
8889 * ecm_db_node_hash_index_get_first()
8890 * Return first hash index
8891 */
8892int ecm_db_node_hash_index_get_first(void)
8893{
8894 return 0;
8895}
8896EXPORT_SYMBOL(ecm_db_node_hash_index_get_first);
8897
8898/*
8899 * ecm_db_iface_hash_table_lengths_get()
8900 * Return hash table length
8901 */
8902int ecm_db_iface_hash_table_lengths_get(int index)
8903{
8904 int length;
8905
8906 DEBUG_ASSERT((index >= 0) && (index < ECM_DB_IFACE_HASH_SLOTS), "Bad protocol: %d\n", index);
8907 spin_lock_bh(&ecm_db_lock);
8908 length = ecm_db_iface_table_lengths[index];
8909 spin_unlock_bh(&ecm_db_lock);
8910 return length;
8911}
8912EXPORT_SYMBOL(ecm_db_iface_hash_table_lengths_get);
8913
8914/*
8915 * ecm_db_iface_hash_index_get_next()
8916 * Given a hash index, return the next one OR return -1 for no more hash indicies to return.
8917 */
8918int ecm_db_iface_hash_index_get_next(int index)
8919{
8920 index++;
8921 if (index >= ECM_DB_IFACE_HASH_SLOTS) {
8922 return -1;
8923 }
8924 return index;
8925}
8926EXPORT_SYMBOL(ecm_db_iface_hash_index_get_next);
8927
8928/*
8929 * ecm_db_iface_hash_index_get_first()
8930 * Return first hash index
8931 */
8932int ecm_db_iface_hash_index_get_first(void)
8933{
8934 return 0;
8935}
8936EXPORT_SYMBOL(ecm_db_iface_hash_index_get_first);
8937
8938/*
8939 * ecm_db_protocol_get_next()
8940 * Given a number, return the next one OR return -1 for no more protocol numbers to return.
8941 */
8942int ecm_db_protocol_get_next(int protocol)
8943{
8944 protocol++;
8945 if (protocol >= ECM_DB_PROTOCOL_COUNT) {
8946 return -1;
8947 }
8948 return protocol;
8949}
8950EXPORT_SYMBOL(ecm_db_protocol_get_next);
8951
8952/*
8953 * ecm_db_protocol_get_first()
8954 * Return first protocol number
8955 */
8956int ecm_db_protocol_get_first(void)
8957{
8958 return 0;
8959}
8960EXPORT_SYMBOL(ecm_db_protocol_get_first);
8961#endif
8962
8963/*
8964 * ecm_db_iface_add_ethernet()
8965 * Add a iface instance into the database
8966 */
8967void 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 -07008968 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00008969 ecm_db_iface_final_callback_t final, void *arg)
8970{
8971 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07008972 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008973 struct ecm_db_listener_instance *li;
8974 struct ecm_db_interface_info_ethernet *type_info;
8975
8976 spin_lock_bh(&ecm_db_lock);
8977 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
8978 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00008979#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00008980 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00008981#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00008982 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
8983 DEBUG_ASSERT(name, "%p: no name given\n", ii);
8984 spin_unlock_bh(&ecm_db_lock);
8985
8986 /*
8987 * Record general info
8988 */
8989 ii->type = ECM_DB_IFACE_TYPE_ETHERNET;
8990#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01008991 ii->state_get = ecm_db_iface_ethernet_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008992#endif
8993 ii->arg = arg;
8994 ii->final = final;
8995 strcpy(ii->name, name);
8996 ii->mtu = mtu;
8997 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07008998 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00008999
9000 /*
9001 * Type specific info
9002 */
9003 type_info = &ii->type_info.ethernet;
9004 memcpy(type_info->address, address, ETH_ALEN);
9005
9006 /*
9007 * Compute hash chain for insertion
9008 */
9009 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9010 ii->hash_index = hash_index;
9011
Murat Sezgin91c5d712015-06-12 15:16:22 -07009012 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9013 ii->iface_id_hash_index = iface_id_hash_index;
9014
Gareth Williamsf98d4192015-03-11 16:55:41 +00009015 /*
9016 * Add into the global list
9017 */
9018 spin_lock_bh(&ecm_db_lock);
9019 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9020 ii->prev = NULL;
9021 ii->next = ecm_db_interfaces;
9022 if (ecm_db_interfaces) {
9023 ecm_db_interfaces->prev = ii;
9024 }
9025 ecm_db_interfaces = ii;
9026
9027 /*
9028 * Insert into chain
9029 */
9030 ii->hash_next = ecm_db_iface_table[hash_index];
9031 if (ecm_db_iface_table[hash_index]) {
9032 ecm_db_iface_table[hash_index]->hash_prev = ii;
9033 }
9034 ecm_db_iface_table[hash_index] = ii;
9035 ecm_db_iface_table_lengths[hash_index]++;
9036 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9037
9038 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);
9039
9040 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009041 * Insert into interface identifier chain
9042 */
9043 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9044 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9045 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9046 }
9047 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9048 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9049 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]);
9050
9051 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009052 * Set time of addition
9053 */
9054 ii->time_added = ecm_db_time;
9055 spin_unlock_bh(&ecm_db_lock);
9056
9057 /*
9058 * Throw add event to the listeners
9059 */
9060 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9061 li = ecm_db_listeners_get_and_ref_first();
9062 while (li) {
9063 struct ecm_db_listener_instance *lin;
9064 if (li->iface_added) {
9065 li->iface_added(li->arg, ii);
9066 }
9067
9068 /*
9069 * Get next listener
9070 */
9071 lin = ecm_db_listener_get_and_ref_next(li);
9072 ecm_db_listener_deref(li);
9073 li = lin;
9074 }
9075}
9076EXPORT_SYMBOL(ecm_db_iface_add_ethernet);
9077
9078#ifdef ECM_INTERFACE_BOND_ENABLE
9079/*
9080 * ecm_db_iface_add_lag()
9081 * Add a iface instance into the database
9082 */
9083void 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 -07009084 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009085 ecm_db_iface_final_callback_t final, void *arg)
9086{
9087 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009088 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009089 struct ecm_db_listener_instance *li;
9090 struct ecm_db_interface_info_lag *type_info;
9091
9092 spin_lock_bh(&ecm_db_lock);
9093 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9094 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009095#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009096 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009097#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009098 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9099 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9100 spin_unlock_bh(&ecm_db_lock);
9101
9102 /*
9103 * Record general info
9104 */
9105 ii->type = ECM_DB_IFACE_TYPE_LAG;
9106#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009107 ii->state_get = ecm_db_iface_lag_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009108#endif
9109 ii->arg = arg;
9110 ii->final = final;
9111 strcpy(ii->name, name);
9112 ii->mtu = mtu;
9113 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009114 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009115
9116 /*
9117 * Type specific info
9118 */
9119 type_info = &ii->type_info.lag;
9120 memcpy(type_info->address, address, ETH_ALEN);
9121
9122 /*
9123 * Compute hash chain for insertion
9124 */
9125 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9126 ii->hash_index = hash_index;
9127
Murat Sezgin91c5d712015-06-12 15:16:22 -07009128 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9129 ii->iface_id_hash_index = iface_id_hash_index;
9130
Gareth Williamsf98d4192015-03-11 16:55:41 +00009131 /*
9132 * Add into the global list
9133 */
9134 spin_lock_bh(&ecm_db_lock);
9135 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9136 ii->prev = NULL;
9137 ii->next = ecm_db_interfaces;
9138 if (ecm_db_interfaces) {
9139 ecm_db_interfaces->prev = ii;
9140 }
9141 ecm_db_interfaces = ii;
9142
9143 /*
9144 * Insert into chain
9145 */
9146 ii->hash_next = ecm_db_iface_table[hash_index];
9147 if (ecm_db_iface_table[hash_index]) {
9148 ecm_db_iface_table[hash_index]->hash_prev = ii;
9149 }
9150 ecm_db_iface_table[hash_index] = ii;
9151 ecm_db_iface_table_lengths[hash_index]++;
9152 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9153
9154 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);
9155
9156 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009157 * Insert into interface identifier chain
9158 */
9159 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9160 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9161 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9162 }
9163 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9164 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9165 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]);
9166
9167 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009168 * Set time of addition
9169 */
9170 ii->time_added = ecm_db_time;
9171 spin_unlock_bh(&ecm_db_lock);
9172
9173 /*
9174 * Throw add event to the listeners
9175 */
9176 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9177 li = ecm_db_listeners_get_and_ref_first();
9178 while (li) {
9179 struct ecm_db_listener_instance *lin;
9180 if (li->iface_added) {
9181 li->iface_added(li->arg, ii);
9182 }
9183
9184 /*
9185 * Get next listener
9186 */
9187 lin = ecm_db_listener_get_and_ref_next(li);
9188 ecm_db_listener_deref(li);
9189 li = lin;
9190 }
9191}
9192EXPORT_SYMBOL(ecm_db_iface_add_lag);
9193#endif
9194
9195/*
9196 * ecm_db_iface_add_bridge()
9197 * Add a iface instance into the database
9198 */
9199void 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 -07009200 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009201 ecm_db_iface_final_callback_t final, void *arg)
9202{
9203 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009204 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009205 struct ecm_db_listener_instance *li;
9206 struct ecm_db_interface_info_bridge *type_info;
9207
9208 spin_lock_bh(&ecm_db_lock);
9209 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9210 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009211#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009212 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009213#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009214 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9215 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9216 spin_unlock_bh(&ecm_db_lock);
9217
9218 /*
9219 * Record general info
9220 */
9221 ii->type = ECM_DB_IFACE_TYPE_BRIDGE;
9222#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009223 ii->state_get = ecm_db_iface_bridge_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009224#endif
9225 ii->arg = arg;
9226 ii->final = final;
9227 strcpy(ii->name, name);
9228 ii->mtu = mtu;
9229 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009230 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009231
9232 /*
9233 * Type specific info
9234 */
9235 type_info = &ii->type_info.bridge;
9236 memcpy(type_info->address, address, ETH_ALEN);
9237
9238 /*
9239 * Compute hash chain for insertion
9240 */
9241 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9242 ii->hash_index = hash_index;
9243
Murat Sezgin91c5d712015-06-12 15:16:22 -07009244 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9245 ii->iface_id_hash_index = iface_id_hash_index;
9246
Gareth Williamsf98d4192015-03-11 16:55:41 +00009247 /*
9248 * Add into the global list
9249 */
9250 spin_lock_bh(&ecm_db_lock);
9251 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9252 ii->prev = NULL;
9253 ii->next = ecm_db_interfaces;
9254 if (ecm_db_interfaces) {
9255 ecm_db_interfaces->prev = ii;
9256 }
9257 ecm_db_interfaces = ii;
9258
9259 /*
9260 * Insert into chain
9261 */
9262 ii->hash_next = ecm_db_iface_table[hash_index];
9263 if (ecm_db_iface_table[hash_index]) {
9264 ecm_db_iface_table[hash_index]->hash_prev = ii;
9265 }
9266 ecm_db_iface_table[hash_index] = ii;
9267 ecm_db_iface_table_lengths[hash_index]++;
9268 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9269
9270 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);
9271
9272 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009273 * Insert into interface identifier chain
9274 */
9275 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9276 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9277 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9278 }
9279 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9280 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9281 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]);
9282
9283 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009284 * Set time of addition
9285 */
9286 ii->time_added = ecm_db_time;
9287 spin_unlock_bh(&ecm_db_lock);
9288
9289 /*
9290 * Throw add event to the listeners
9291 */
9292 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9293 li = ecm_db_listeners_get_and_ref_first();
9294 while (li) {
9295 struct ecm_db_listener_instance *lin;
9296 if (li->iface_added) {
9297 li->iface_added(li->arg, ii);
9298 }
9299
9300 /*
9301 * Get next listener
9302 */
9303 lin = ecm_db_listener_get_and_ref_next(li);
9304 ecm_db_listener_deref(li);
9305 li = lin;
9306 }
9307}
9308EXPORT_SYMBOL(ecm_db_iface_add_bridge);
9309
9310#ifdef ECM_INTERFACE_VLAN_ENABLE
9311/*
9312 * ecm_db_iface_add_vlan()
9313 * Add a iface instance into the database
9314 */
9315void 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 -07009316 int32_t interface_identifier, int32_t ae_interface_identifier,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009317 ecm_db_iface_final_callback_t final, void *arg)
9318{
9319 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009320 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009321 struct ecm_db_listener_instance *li;
9322 struct ecm_db_interface_info_vlan *type_info;
9323
9324 spin_lock_bh(&ecm_db_lock);
9325 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9326 DEBUG_ASSERT(address, "%p: address null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009327#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009328 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009329#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009330 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9331 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9332 spin_unlock_bh(&ecm_db_lock);
9333
9334 /*
9335 * Record general info
9336 */
9337 ii->type = ECM_DB_IFACE_TYPE_VLAN;
9338#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009339 ii->state_get = ecm_db_iface_vlan_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009340#endif
9341 ii->arg = arg;
9342 ii->final = final;
9343 strcpy(ii->name, name);
9344 ii->mtu = mtu;
9345 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009346 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009347
9348 /*
9349 * Type specific info
9350 */
9351 type_info = &ii->type_info.vlan;
9352 type_info->vlan_tag = vlan_tag;
9353 type_info->vlan_tpid = vlan_tpid;
9354 memcpy(type_info->address, address, ETH_ALEN);
9355
9356 /*
9357 * Compute hash chain for insertion
9358 */
9359 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
9360 ii->hash_index = hash_index;
9361
Murat Sezgin91c5d712015-06-12 15:16:22 -07009362 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9363 ii->iface_id_hash_index = iface_id_hash_index;
9364
Gareth Williamsf98d4192015-03-11 16:55:41 +00009365 /*
9366 * Add into the global list
9367 */
9368 spin_lock_bh(&ecm_db_lock);
9369 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9370 ii->prev = NULL;
9371 ii->next = ecm_db_interfaces;
9372 if (ecm_db_interfaces) {
9373 ecm_db_interfaces->prev = ii;
9374 }
9375 ecm_db_interfaces = ii;
9376
9377 /*
9378 * Insert into chain
9379 */
9380 ii->hash_next = ecm_db_iface_table[hash_index];
9381 if (ecm_db_iface_table[hash_index]) {
9382 ecm_db_iface_table[hash_index]->hash_prev = ii;
9383 }
9384 ecm_db_iface_table[hash_index] = ii;
9385 ecm_db_iface_table_lengths[hash_index]++;
9386 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9387
9388 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);
9389
9390 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009391 * Insert into interface identifier chain
9392 */
9393 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9394 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9395 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9396 }
9397 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9398 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9399 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]);
9400
9401 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009402 * Set time of addition
9403 */
9404 ii->time_added = ecm_db_time;
9405 spin_unlock_bh(&ecm_db_lock);
9406
9407 /*
9408 * Throw add event to the listeners
9409 */
9410 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9411 li = ecm_db_listeners_get_and_ref_first();
9412 while (li) {
9413 struct ecm_db_listener_instance *lin;
9414 if (li->iface_added) {
9415 li->iface_added(li->arg, ii);
9416 }
9417
9418 /*
9419 * Get next listener
9420 */
9421 lin = ecm_db_listener_get_and_ref_next(li);
9422 ecm_db_listener_deref(li);
9423 li = lin;
9424 }
9425}
9426EXPORT_SYMBOL(ecm_db_iface_add_vlan);
9427#endif
9428
ratheesh kannotha32fdd12015-09-09 08:02:58 +05309429#ifdef ECM_INTERFACE_PPPOE_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009430/*
9431 * ecm_db_iface_add_pppoe()
9432 * Add a iface instance into the database
9433 */
9434void ecm_db_iface_add_pppoe(struct ecm_db_iface_instance *ii, uint16_t pppoe_session_id, uint8_t *remote_mac,
9435 char *name, int32_t mtu, int32_t interface_identifier,
Murat Sezgin91c5d712015-06-12 15:16:22 -07009436 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
Gareth Williamsf98d4192015-03-11 16:55:41 +00009437 void *arg)
9438{
9439 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009440 ecm_db_iface_id_hash_t iface_id_hash_index;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009441 struct ecm_db_listener_instance *li;
9442 struct ecm_db_interface_info_pppoe *type_info;
9443
9444 spin_lock_bh(&ecm_db_lock);
9445 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009446#ifdef ECM_DB_XREF_ENABLE
Gareth Williamsf98d4192015-03-11 16:55:41 +00009447 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009448#endif
Gareth Williamsf98d4192015-03-11 16:55:41 +00009449 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9450 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9451 spin_unlock_bh(&ecm_db_lock);
9452
9453 /*
9454 * Record general info
9455 */
9456 ii->type = ECM_DB_IFACE_TYPE_PPPOE;
9457#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009458 ii->state_get = ecm_db_iface_pppoe_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009459#endif
9460 ii->arg = arg;
9461 ii->final = final;
9462 strcpy(ii->name, name);
9463 ii->mtu = mtu;
9464 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009465 ii->ae_interface_identifier = ae_interface_identifier;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009466
9467 /*
9468 * Type specific info
9469 */
9470 type_info = &ii->type_info.pppoe;
9471 type_info->pppoe_session_id = pppoe_session_id;
9472 memcpy(type_info->remote_mac, remote_mac, ETH_ALEN);
9473
9474 /*
9475 * Compute hash chain for insertion
9476 */
9477 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
9478 ii->hash_index = hash_index;
9479
Murat Sezgin91c5d712015-06-12 15:16:22 -07009480 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9481 ii->iface_id_hash_index = iface_id_hash_index;
9482
Gareth Williamsf98d4192015-03-11 16:55:41 +00009483 /*
9484 * Add into the global list
9485 */
9486 spin_lock_bh(&ecm_db_lock);
9487 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9488 ii->prev = NULL;
9489 ii->next = ecm_db_interfaces;
9490 if (ecm_db_interfaces) {
9491 ecm_db_interfaces->prev = ii;
9492 }
9493 ecm_db_interfaces = ii;
9494
9495 /*
9496 * Insert into chain
9497 */
9498 ii->hash_next = ecm_db_iface_table[hash_index];
9499 if (ecm_db_iface_table[hash_index]) {
9500 ecm_db_iface_table[hash_index]->hash_prev = ii;
9501 }
9502 ecm_db_iface_table[hash_index] = ii;
9503 ecm_db_iface_table_lengths[hash_index]++;
9504 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9505
9506 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);
9507
9508 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009509 * Insert into interface identifier chain
9510 */
9511 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9512 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9513 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9514 }
9515 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9516 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9517 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]);
9518
9519 /*
Gareth Williamsf98d4192015-03-11 16:55:41 +00009520 * Set time of addition
9521 */
9522 ii->time_added = ecm_db_time;
9523 spin_unlock_bh(&ecm_db_lock);
9524
9525 /*
9526 * Throw add event to the listeners
9527 */
9528 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9529 li = ecm_db_listeners_get_and_ref_first();
9530 while (li) {
9531 struct ecm_db_listener_instance *lin;
9532 if (li->iface_added) {
9533 li->iface_added(li->arg, ii);
9534 }
9535
9536 /*
9537 * Get next listener
9538 */
9539 lin = ecm_db_listener_get_and_ref_next(li);
9540 ecm_db_listener_deref(li);
9541 li = lin;
9542 }
9543}
9544EXPORT_SYMBOL(ecm_db_iface_add_pppoe);
9545#endif
9546
ratheesh kannotha32fdd12015-09-09 08:02:58 +05309547#ifdef ECM_INTERFACE_L2TPV2_ENABLE
9548/*
9549 * ecm_db_iface_add_pppol2tpv2()
9550 * Add a iface instance into the database
9551 */
9552void ecm_db_iface_add_pppol2tpv2(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppol2tpv2 *pppol2tpv2_info,
9553 char *name, int32_t mtu, int32_t interface_identifier,
9554 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
9555 void *arg)
9556{
9557 ecm_db_iface_hash_t hash_index;
9558 ecm_db_iface_id_hash_t iface_id_hash_index;
9559 struct ecm_db_listener_instance *li;
9560 struct ecm_db_interface_info_pppol2tpv2 *type_info;
9561
9562 spin_lock_bh(&ecm_db_lock);
9563 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9564#ifdef ECM_DB_XREF_ENABLE
9565 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
9566#endif
9567 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9568 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9569 spin_unlock_bh(&ecm_db_lock);
9570
9571 /*
9572 * Record general info
9573 */
9574 ii->type = ECM_DB_IFACE_TYPE_PPPOL2TPV2;
9575#ifdef ECM_STATE_OUTPUT_ENABLE
9576 ii->state_get = ecm_db_iface_pppol2tpv2_state_get;
9577#endif
9578 ii->arg = arg;
9579 ii->final = final;
9580 strlcpy(ii->name, name, IFNAMSIZ);
9581 ii->mtu = mtu;
9582 ii->interface_identifier = interface_identifier;
9583 ii->ae_interface_identifier = ae_interface_identifier;
9584
9585 /*
9586 * Type specific info
9587 */
9588 type_info = &ii->type_info.pppol2tpv2;
9589 memcpy(type_info, pppol2tpv2_info, sizeof(struct ecm_db_interface_info_pppol2tpv2));
9590
9591 /*
9592 * Compute hash chain for insertion
9593 */
9594 hash_index = ecm_db_iface_generate_hash_index_pppol2tpv2(type_info->l2tp.tunnel.tunnel_id,
9595 type_info->l2tp.session.session_id);
9596 ii->hash_index = hash_index;
9597
9598 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9599 ii->iface_id_hash_index = iface_id_hash_index;
9600 /*
9601 * Add into the global list
9602 */
9603 spin_lock_bh(&ecm_db_lock);
9604 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9605 ii->prev = NULL;
9606 ii->next = ecm_db_interfaces;
9607 if (ecm_db_interfaces) {
9608 ecm_db_interfaces->prev = ii;
9609 }
9610 ecm_db_interfaces = ii;
9611
9612 /*
9613 * Insert into chain
9614 */
9615 ii->hash_next = ecm_db_iface_table[hash_index];
9616 if (ecm_db_iface_table[hash_index]) {
9617 ecm_db_iface_table[hash_index]->hash_prev = ii;
9618 }
9619 ecm_db_iface_table[hash_index] = ii;
9620 ecm_db_iface_table_lengths[hash_index]++;
9621 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9622
9623 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);
9624
9625 /*
9626 * Insert into interface identifier chain
9627 */
9628 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9629 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9630 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9631 }
9632 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9633 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9634 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]);
9635
9636 /*
9637 * Set time of addition
9638 */
9639 ii->time_added = ecm_db_time;
9640 spin_unlock_bh(&ecm_db_lock);
9641
9642 /*
9643 * Throw add event to the listeners
9644 */
9645 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9646 li = ecm_db_listeners_get_and_ref_first();
9647 while (li) {
9648 struct ecm_db_listener_instance *lin;
9649 if (li->iface_added) {
9650 li->iface_added(li->arg, ii);
9651 }
9652
9653 /*
9654 * Get next listener
9655 */
9656 lin = ecm_db_listener_get_and_ref_next(li);
9657 ecm_db_listener_deref(li);
9658 li = lin;
9659 }
9660}
9661EXPORT_SYMBOL(ecm_db_iface_add_pppol2tpv2);
9662
9663#endif
9664
Shyam Sunder23f2e542015-09-28 14:56:49 +05309665#ifdef ECM_INTERFACE_PPTP_ENABLE
9666/*
9667 * ecm_db_iface_add_pptp()
9668 * Add a iface instance into the database
9669 */
9670void ecm_db_iface_add_pptp(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pptp *pptp_info,
9671 char *name, int32_t mtu, int32_t interface_identifier,
9672 int32_t ae_interface_identifier, ecm_db_iface_final_callback_t final,
9673 void *arg)
9674{
9675 ecm_db_iface_hash_t hash_index;
9676 ecm_db_iface_id_hash_t iface_id_hash_index;
9677 struct ecm_db_listener_instance *li;
9678 struct ecm_db_interface_info_pptp *type_info;
9679
9680 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
9681 spin_lock_bh(&ecm_db_lock);
9682#ifdef ECM_DB_XREF_ENABLE
9683 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
9684#endif
9685 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9686 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9687 spin_unlock_bh(&ecm_db_lock);
9688
9689 /*
9690 * Record general info
9691 */
9692 ii->type = ECM_DB_IFACE_TYPE_PPTP;
9693#ifdef ECM_STATE_OUTPUT_ENABLE
9694 ii->state_get = ecm_db_iface_pptp_state_get;
9695#endif
9696 ii->arg = arg;
9697 ii->final = final;
9698 strlcpy(ii->name, name, IFNAMSIZ);
9699 ii->mtu = mtu;
9700 ii->interface_identifier = interface_identifier;
9701 ii->ae_interface_identifier = ae_interface_identifier;
9702
9703 /*
9704 * Type specific info
9705 */
9706 type_info = &ii->type_info.pptp;
9707 memcpy(type_info, pptp_info, sizeof(struct ecm_db_interface_info_pptp));
9708
9709 /*
9710 * Compute hash chain for insertion
9711 */
9712 hash_index = ecm_db_iface_generate_hash_index_pptp(type_info->src_call_id,
9713 type_info->dst_call_id);
9714 ii->hash_index = hash_index;
9715
9716 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9717 ii->iface_id_hash_index = iface_id_hash_index;
9718 /*
9719 * Add into the global list
9720 */
9721 spin_lock_bh(&ecm_db_lock);
9722 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9723 ii->prev = NULL;
9724 ii->next = ecm_db_interfaces;
9725 if (ecm_db_interfaces) {
9726 ecm_db_interfaces->prev = ii;
9727 }
9728 ecm_db_interfaces = ii;
9729
9730 /*
9731 * Insert into chain
9732 */
9733 ii->hash_next = ecm_db_iface_table[hash_index];
9734 if (ecm_db_iface_table[hash_index]) {
9735 ecm_db_iface_table[hash_index]->hash_prev = ii;
9736 }
9737 ecm_db_iface_table[hash_index] = ii;
9738 ecm_db_iface_table_lengths[hash_index]++;
9739 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9740
9741 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);
9742
9743 /*
9744 * Insert into interface identifier chain
9745 */
9746 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9747 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9748 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9749 }
9750 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9751 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9752 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]);
9753
9754 /*
9755 * Set time of addition
9756 */
9757 ii->time_added = ecm_db_time;
9758 spin_unlock_bh(&ecm_db_lock);
9759
9760 /*
9761 * Throw add event to the listeners
9762 */
9763 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9764 li = ecm_db_listeners_get_and_ref_first();
9765 while (li) {
9766 struct ecm_db_listener_instance *lin;
9767 if (li->iface_added) {
9768 li->iface_added(li->arg, ii);
9769 }
9770
9771 /*
9772 * Get next listener
9773 */
9774 lin = ecm_db_listener_get_and_ref_next(li);
9775 ecm_db_listener_deref(li);
9776 li = lin;
9777 }
9778}
9779EXPORT_SYMBOL(ecm_db_iface_add_pptp);
9780#endif
9781
Ben Menchaca84f36632014-02-28 20:57:38 +00009782/*
9783 * ecm_db_iface_add_unknown()
9784 * Add a iface instance into the database
9785 */
9786void 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 -07009787 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +00009788 ecm_db_iface_final_callback_t final, void *arg)
9789{
9790 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009791 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +00009792 struct ecm_db_listener_instance *li;
9793 struct ecm_db_interface_info_unknown *type_info;
9794
9795 spin_lock_bh(&ecm_db_lock);
9796 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009797#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00009798 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009799#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009800 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9801 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9802 spin_unlock_bh(&ecm_db_lock);
9803
9804 /*
9805 * Record general info
9806 */
9807 ii->type = ECM_DB_IFACE_TYPE_UNKNOWN;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009808#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009809 ii->state_get = ecm_db_iface_unknown_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009810#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009811 ii->arg = arg;
9812 ii->final = final;
9813 strcpy(ii->name, name);
9814 ii->mtu = mtu;
9815 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009816 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00009817
9818 /*
9819 * Type specific info
9820 */
9821 type_info = &ii->type_info.unknown;
9822 type_info->os_specific_ident = os_specific_ident;
9823
9824 /*
9825 * Compute hash chain for insertion
9826 */
9827 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
9828 ii->hash_index = hash_index;
9829
Murat Sezgin91c5d712015-06-12 15:16:22 -07009830 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9831 ii->iface_id_hash_index = iface_id_hash_index;
9832
Ben Menchaca84f36632014-02-28 20:57:38 +00009833 /*
9834 * Add into the global list
9835 */
9836 spin_lock_bh(&ecm_db_lock);
9837 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9838 ii->prev = NULL;
9839 ii->next = ecm_db_interfaces;
9840 if (ecm_db_interfaces) {
9841 ecm_db_interfaces->prev = ii;
9842 }
9843 ecm_db_interfaces = ii;
9844
9845 /*
9846 * Insert into chain
9847 */
9848 ii->hash_next = ecm_db_iface_table[hash_index];
9849 if (ecm_db_iface_table[hash_index]) {
9850 ecm_db_iface_table[hash_index]->hash_prev = ii;
9851 }
9852 ecm_db_iface_table[hash_index] = ii;
9853 ecm_db_iface_table_lengths[hash_index]++;
9854 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9855
9856 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);
9857
9858 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009859 * Insert into interface identifier chain
9860 */
9861 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9862 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9863 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9864 }
9865 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9866 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9867 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]);
9868
9869 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00009870 * Set time of addition
9871 */
9872 ii->time_added = ecm_db_time;
9873 spin_unlock_bh(&ecm_db_lock);
9874
9875 /*
9876 * Throw add event to the listeners
9877 */
9878 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9879 li = ecm_db_listeners_get_and_ref_first();
9880 while (li) {
9881 struct ecm_db_listener_instance *lin;
9882 if (li->iface_added) {
9883 li->iface_added(li->arg, ii);
9884 }
9885
9886 /*
9887 * Get next listener
9888 */
9889 lin = ecm_db_listener_get_and_ref_next(li);
9890 ecm_db_listener_deref(li);
9891 li = lin;
9892 }
9893}
9894EXPORT_SYMBOL(ecm_db_iface_add_unknown);
9895
9896/*
9897 * ecm_db_iface_add_loopback()
9898 * Add a iface instance into the database
9899 */
9900void 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 -07009901 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +00009902 ecm_db_iface_final_callback_t final, void *arg)
9903{
9904 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009905 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +00009906 struct ecm_db_listener_instance *li;
9907 struct ecm_db_interface_info_loopback *type_info;
9908
9909 spin_lock_bh(&ecm_db_lock);
9910 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009911#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +00009912 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +00009913#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009914 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
9915 DEBUG_ASSERT(name, "%p: no name given\n", ii);
9916 spin_unlock_bh(&ecm_db_lock);
9917
9918 /*
9919 * Record general info
9920 */
9921 ii->type = ECM_DB_IFACE_TYPE_LOOPBACK;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009922#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +01009923 ii->state_get = ecm_db_iface_loopback_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +00009924#endif
Ben Menchaca84f36632014-02-28 20:57:38 +00009925 ii->arg = arg;
9926 ii->final = final;
9927 strcpy(ii->name, name);
9928 ii->mtu = mtu;
9929 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -07009930 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +00009931
9932 /*
9933 * Type specific info
9934 */
9935 type_info = &ii->type_info.loopback;
9936 type_info->os_specific_ident = os_specific_ident;
9937
9938 /*
9939 * Compute hash chain for insertion
9940 */
9941 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
9942 ii->hash_index = hash_index;
9943
Murat Sezgin91c5d712015-06-12 15:16:22 -07009944 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
9945 ii->iface_id_hash_index = iface_id_hash_index;
9946
Ben Menchaca84f36632014-02-28 20:57:38 +00009947 /*
9948 * Add into the global list
9949 */
9950 spin_lock_bh(&ecm_db_lock);
9951 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
9952 ii->prev = NULL;
9953 ii->next = ecm_db_interfaces;
9954 if (ecm_db_interfaces) {
9955 ecm_db_interfaces->prev = ii;
9956 }
9957 ecm_db_interfaces = ii;
9958
9959 /*
9960 * Insert into chain
9961 */
9962 ii->hash_next = ecm_db_iface_table[hash_index];
9963 if (ecm_db_iface_table[hash_index]) {
9964 ecm_db_iface_table[hash_index]->hash_prev = ii;
9965 }
9966 ecm_db_iface_table[hash_index] = ii;
9967 ecm_db_iface_table_lengths[hash_index]++;
9968 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
9969
9970 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);
9971
9972 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -07009973 * Insert into interface identifier chain
9974 */
9975 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
9976 if (ecm_db_iface_id_table[iface_id_hash_index]) {
9977 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
9978 }
9979 ecm_db_iface_id_table[iface_id_hash_index] = ii;
9980 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
9981 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]);
9982
9983 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00009984 * Set time of addition
9985 */
9986 ii->time_added = ecm_db_time;
9987 spin_unlock_bh(&ecm_db_lock);
9988
9989 /*
9990 * Throw add event to the listeners
9991 */
9992 DEBUG_TRACE("%p: Throw iface added event\n", ii);
9993 li = ecm_db_listeners_get_and_ref_first();
9994 while (li) {
9995 struct ecm_db_listener_instance *lin;
9996 if (li->iface_added) {
9997 li->iface_added(li->arg, ii);
9998 }
9999
10000 /*
10001 * Get next listener
10002 */
10003 lin = ecm_db_listener_get_and_ref_next(li);
10004 ecm_db_listener_deref(li);
10005 li = lin;
10006 }
10007}
10008EXPORT_SYMBOL(ecm_db_iface_add_loopback);
10009
Murat Sezginbde55f92015-03-11 16:44:11 -070010010#ifdef ECM_INTERFACE_SIT_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010011/*
Zhu Ken56477be2014-08-05 17:50:28 +080010012 * ecm_db_iface_sit_daddr_is_null()
10013 * The sit addr is null or not
10014 */
10015bool ecm_db_iface_sit_daddr_is_null(struct ecm_db_iface_instance *ii)
10016{
10017 return ii->type_info.sit.daddr[0] == 0;
10018}
10019EXPORT_SYMBOL(ecm_db_iface_sit_daddr_is_null);
10020
10021/*
Ben Menchaca84f36632014-02-28 20:57:38 +000010022 * ecm_db_iface_add_sit()
10023 * Add a iface instance into the database
10024 */
10025void 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 -070010026 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010027 ecm_db_iface_final_callback_t final, void *arg)
10028{
10029 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010030 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010031 struct ecm_db_listener_instance *li;
10032
10033 spin_lock_bh(&ecm_db_lock);
10034 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010035#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010036 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010037#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010038 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10039 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10040 spin_unlock_bh(&ecm_db_lock);
10041
10042 /*
10043 * Record general info
10044 */
10045 ii->type = ECM_DB_IFACE_TYPE_SIT;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010046#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010047 ii->state_get = ecm_db_iface_sit_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010048#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010049 ii->arg = arg;
10050 ii->final = final;
10051 strcpy(ii->name, name);
10052 ii->mtu = mtu;
10053 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010054 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010055
10056 /*
10057 * Type specific info to be copied
10058 */
10059 ii->type_info.sit = *type_info;
10060
10061 /*
10062 * Compute hash chain for insertion
10063 */
10064 hash_index = ecm_db_iface_generate_hash_index_sit(type_info->saddr, type_info->daddr);
10065 ii->hash_index = hash_index;
10066
Murat Sezgin91c5d712015-06-12 15:16:22 -070010067 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10068 ii->iface_id_hash_index = iface_id_hash_index;
10069
Ben Menchaca84f36632014-02-28 20:57:38 +000010070 /*
10071 * Add into the global list
10072 */
10073 spin_lock_bh(&ecm_db_lock);
10074 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10075 ii->prev = NULL;
10076 ii->next = ecm_db_interfaces;
10077 if (ecm_db_interfaces) {
10078 ecm_db_interfaces->prev = ii;
10079 }
10080 ecm_db_interfaces = ii;
10081
10082 /*
10083 * Insert into chain
10084 */
10085 ii->hash_next = ecm_db_iface_table[hash_index];
10086 if (ecm_db_iface_table[hash_index]) {
10087 ecm_db_iface_table[hash_index]->hash_prev = ii;
10088 }
10089 ecm_db_iface_table[hash_index] = ii;
10090 ecm_db_iface_table_lengths[hash_index]++;
10091 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10092
10093 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);
10094
10095 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010096 * Insert into interface identifier chain
10097 */
10098 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10099 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10100 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10101 }
10102 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10103 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10104 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]);
10105
10106 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010107 * Set time of addition
10108 */
10109 ii->time_added = ecm_db_time;
10110 spin_unlock_bh(&ecm_db_lock);
10111
10112 /*
10113 * Throw add event to the listeners
10114 */
10115 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10116 li = ecm_db_listeners_get_and_ref_first();
10117 while (li) {
10118 struct ecm_db_listener_instance *lin;
10119 if (li->iface_added) {
10120 li->iface_added(li->arg, ii);
10121 }
10122
10123 /*
10124 * Get next listener
10125 */
10126 lin = ecm_db_listener_get_and_ref_next(li);
10127 ecm_db_listener_deref(li);
10128 li = lin;
10129 }
10130}
10131EXPORT_SYMBOL(ecm_db_iface_add_sit);
Murat Sezginbde55f92015-03-11 16:44:11 -070010132#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010133
Murat Sezginc1402562015-03-12 12:32:20 -070010134#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
Gareth Williams8ac34292015-03-17 14:06:58 +000010135#ifdef ECM_IPV6_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010136/*
10137 * ecm_db_iface_add_tunipip6()
10138 * Add a iface instance into the database
10139 */
10140void 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 -070010141 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010142 ecm_db_iface_final_callback_t final, void *arg)
10143{
10144 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010145 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010146 struct ecm_db_listener_instance *li;
10147
10148 spin_lock_bh(&ecm_db_lock);
10149 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010150#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010151 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010152#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010153 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10154 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10155 spin_unlock_bh(&ecm_db_lock);
10156
10157 /*
10158 * Record general info
10159 */
10160 ii->type = ECM_DB_IFACE_TYPE_TUNIPIP6;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010161#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010162 ii->state_get = ecm_db_iface_tunipip6_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010163#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010164 ii->arg = arg;
10165 ii->final = final;
10166 strcpy(ii->name, name);
10167 ii->mtu = mtu;
10168 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010169 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010170
10171 /*
10172 * Type specific info to be copied
10173 */
10174 ii->type_info.tunipip6 = *type_info;
10175
10176 /*
10177 * Compute hash chain for insertion
10178 */
10179 hash_index = ecm_db_iface_generate_hash_index_tunipip6(type_info->saddr, type_info->daddr);
10180 ii->hash_index = hash_index;
10181
Murat Sezgin91c5d712015-06-12 15:16:22 -070010182 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10183 ii->iface_id_hash_index = iface_id_hash_index;
10184
Ben Menchaca84f36632014-02-28 20:57:38 +000010185 /*
10186 * Add into the global list
10187 */
10188 spin_lock_bh(&ecm_db_lock);
10189 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10190 ii->prev = NULL;
10191 ii->next = ecm_db_interfaces;
10192 if (ecm_db_interfaces) {
10193 ecm_db_interfaces->prev = ii;
10194 }
10195 ecm_db_interfaces = ii;
10196
10197 /*
10198 * Insert into chain
10199 */
10200 ii->hash_next = ecm_db_iface_table[hash_index];
10201 if (ecm_db_iface_table[hash_index]) {
10202 ecm_db_iface_table[hash_index]->hash_prev = ii;
10203 }
10204 ecm_db_iface_table[hash_index] = ii;
10205 ecm_db_iface_table_lengths[hash_index]++;
10206 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10207
10208 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);
10209
10210 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010211 * Insert into interface identifier chain
10212 */
10213 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10214 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10215 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10216 }
10217 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10218 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10219 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]);
10220
10221 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010222 * Set time of addition
10223 */
10224 ii->time_added = ecm_db_time;
10225 spin_unlock_bh(&ecm_db_lock);
10226
10227 /*
10228 * Throw add event to the listeners
10229 */
10230 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10231 li = ecm_db_listeners_get_and_ref_first();
10232 while (li) {
10233 struct ecm_db_listener_instance *lin;
10234 if (li->iface_added) {
10235 li->iface_added(li->arg, ii);
10236 }
10237
10238 /*
10239 * Get next listener
10240 */
10241 lin = ecm_db_listener_get_and_ref_next(li);
10242 ecm_db_listener_deref(li);
10243 li = lin;
10244 }
10245}
10246EXPORT_SYMBOL(ecm_db_iface_add_tunipip6);
Murat Sezginc1402562015-03-12 12:32:20 -070010247#endif
Gareth Williams8ac34292015-03-17 14:06:58 +000010248#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010249
Murat Sezgin69a27532015-03-12 14:09:40 -070010250#ifdef ECM_INTERFACE_IPSEC_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010251/*
10252 * ecm_db_iface_add_ipsec_tunnel()
10253 * Add a iface instance into the database
10254 *
10255 * GGG TODO This needs to take ipsec tunnel endpoint information etc. something very appropriate for ipsec tunnels, anyhow.
10256 */
10257void 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 -070010258 int32_t interface_identifier, int32_t ae_interface_identifier,
Ben Menchaca84f36632014-02-28 20:57:38 +000010259 ecm_db_iface_final_callback_t final, void *arg)
10260{
10261 ecm_db_iface_hash_t hash_index;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010262 ecm_db_iface_id_hash_t iface_id_hash_index;
Ben Menchaca84f36632014-02-28 20:57:38 +000010263 struct ecm_db_listener_instance *li;
10264 struct ecm_db_interface_info_ipsec_tunnel *type_info;
10265
10266 spin_lock_bh(&ecm_db_lock);
10267 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010268#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000010269 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
Gareth Williamsb5903892015-03-20 15:13:07 +000010270#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010271 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
10272 DEBUG_ASSERT(name, "%p: no name given\n", ii);
10273 spin_unlock_bh(&ecm_db_lock);
10274
10275 /*
10276 * Record general info
10277 */
Ankit Dhanuka60683c52014-06-09 17:43:38 +053010278 ii->type = ECM_DB_IFACE_TYPE_IPSEC_TUNNEL;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010279#ifdef ECM_STATE_OUTPUT_ENABLE
Gareth Williamsd5618a82015-05-20 11:13:32 +010010280 ii->state_get = ecm_db_iface_ipsec_tunnel_state_get;
Gareth Williamsf98d4192015-03-11 16:55:41 +000010281#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010282 ii->arg = arg;
10283 ii->final = final;
10284 strcpy(ii->name, name);
10285 ii->mtu = mtu;
10286 ii->interface_identifier = interface_identifier;
Murat Sezgin91c5d712015-06-12 15:16:22 -070010287 ii->ae_interface_identifier = ae_interface_identifier;
Ben Menchaca84f36632014-02-28 20:57:38 +000010288
10289 /*
10290 * Type specific info
10291 */
10292 type_info = &ii->type_info.ipsec_tunnel;
10293 type_info->os_specific_ident = os_specific_ident;
10294
10295 /*
10296 * Compute hash chain for insertion
10297 */
10298 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
10299 ii->hash_index = hash_index;
10300
Murat Sezgin91c5d712015-06-12 15:16:22 -070010301 iface_id_hash_index = ecm_db_iface_id_generate_hash_index(interface_identifier);
10302 ii->iface_id_hash_index = iface_id_hash_index;
10303
Ben Menchaca84f36632014-02-28 20:57:38 +000010304 /*
10305 * Add into the global list
10306 */
10307 spin_lock_bh(&ecm_db_lock);
10308 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
10309 ii->prev = NULL;
10310 ii->next = ecm_db_interfaces;
10311 if (ecm_db_interfaces) {
10312 ecm_db_interfaces->prev = ii;
10313 }
10314 ecm_db_interfaces = ii;
10315
10316 /*
10317 * Insert into chain
10318 */
10319 ii->hash_next = ecm_db_iface_table[hash_index];
10320 if (ecm_db_iface_table[hash_index]) {
10321 ecm_db_iface_table[hash_index]->hash_prev = ii;
10322 }
10323 ecm_db_iface_table[hash_index] = ii;
10324 ecm_db_iface_table_lengths[hash_index]++;
10325 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
10326
10327 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);
10328
10329 /*
Murat Sezgin91c5d712015-06-12 15:16:22 -070010330 * Insert into interface identifier chain
10331 */
10332 ii->iface_id_hash_next = ecm_db_iface_id_table[iface_id_hash_index];
10333 if (ecm_db_iface_id_table[iface_id_hash_index]) {
10334 ecm_db_iface_id_table[iface_id_hash_index]->iface_id_hash_prev = ii;
10335 }
10336 ecm_db_iface_id_table[iface_id_hash_index] = ii;
10337 ecm_db_iface_id_table_lengths[iface_id_hash_index]++;
10338 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]);
10339
10340 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010341 * Set time of addition
10342 */
10343 ii->time_added = ecm_db_time;
10344 spin_unlock_bh(&ecm_db_lock);
10345
10346 /*
10347 * Throw add event to the listeners
10348 */
10349 DEBUG_TRACE("%p: Throw iface added event\n", ii);
10350 li = ecm_db_listeners_get_and_ref_first();
10351 while (li) {
10352 struct ecm_db_listener_instance *lin;
10353 if (li->iface_added) {
10354 li->iface_added(li->arg, ii);
10355 }
10356
10357 /*
10358 * Get next listener
10359 */
10360 lin = ecm_db_listener_get_and_ref_next(li);
10361 ecm_db_listener_deref(li);
10362 li = lin;
10363 }
10364}
10365EXPORT_SYMBOL(ecm_db_iface_add_ipsec_tunnel);
Murat Sezgin69a27532015-03-12 14:09:40 -070010366#endif
Ben Menchaca84f36632014-02-28 20:57:38 +000010367
10368/*
10369 * ecm_db_listener_add()
10370 * Add a listener instance into the database.
10371 */
10372void ecm_db_listener_add(struct ecm_db_listener_instance *li,
10373 ecm_db_iface_listener_added_callback_t iface_added,
10374 ecm_db_iface_listener_removed_callback_t iface_removed,
10375 ecm_db_node_listener_added_callback_t node_added,
10376 ecm_db_node_listener_removed_callback_t node_removed,
10377 ecm_db_host_listener_added_callback_t host_added,
10378 ecm_db_host_listener_removed_callback_t host_removed,
10379 ecm_db_mapping_listener_added_callback_t mapping_added,
10380 ecm_db_mapping_listener_removed_callback_t mapping_removed,
10381 ecm_db_connection_listener_added_callback_t connection_added,
10382 ecm_db_connection_listener_removed_callback_t connection_removed,
10383 ecm_db_listener_final_callback_t final,
10384 void *arg)
10385{
10386 spin_lock_bh(&ecm_db_lock);
10387 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed\n", li);
10388 DEBUG_ASSERT(!(li->flags & ECM_DB_LISTENER_FLAGS_INSERTED), "%p: inserted\n", li);
10389 spin_unlock_bh(&ecm_db_lock);
10390
10391 li->arg = arg;
10392 li->final = final;
10393 li->iface_added = iface_added;
10394 li->iface_removed = iface_removed;
10395 li->node_added = node_added;
10396 li->node_removed = node_removed;
10397 li->host_added = host_added;
10398 li->host_removed = host_removed;
10399 li->mapping_added = mapping_added;
10400 li->mapping_removed = mapping_removed;
10401 li->connection_added = connection_added;
10402 li->connection_removed = connection_removed;
10403
10404 /*
10405 * Add instance into listener list
10406 */
10407 spin_lock_bh(&ecm_db_lock);
10408 li->flags |= ECM_DB_LISTENER_FLAGS_INSERTED;
10409 li->next = ecm_db_listeners;
10410 ecm_db_listeners = li;
10411 spin_unlock_bh(&ecm_db_lock);
10412}
10413EXPORT_SYMBOL(ecm_db_listener_add);
10414
10415/*
10416 * ecm_db_connection_alloc()
10417 * Allocate a connection instance
10418 */
10419struct ecm_db_connection_instance *ecm_db_connection_alloc(void)
10420{
10421 struct ecm_db_connection_instance *ci;
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010422 int __attribute__((unused)) i;
Ben Menchaca84f36632014-02-28 20:57:38 +000010423
10424 /*
10425 * Allocate the connection
10426 */
10427 ci = (struct ecm_db_connection_instance *)kzalloc(sizeof(struct ecm_db_connection_instance), GFP_ATOMIC | __GFP_NOWARN);
10428 if (!ci) {
10429 DEBUG_WARN("Connection alloc failed\n");
10430 return NULL;
10431 }
10432
10433 /*
10434 * Initialise the defunct timer entry
10435 */
10436 ecm_db_timer_group_entry_init(&ci->defunct_timer, ecm_db_connection_defunct_callback, ci);
10437
10438 /*
10439 * Refs is 1 for the creator of the connection
10440 */
10441 ci->refs = 1;
10442 DEBUG_SET_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC);
10443
10444 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010445 * Initialise the interfaces from/to lists.
10446 * Interfaces are added from end of array.
10447 */
10448 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10449 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10450 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10451 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
10452
Shyam Sunder3b049ff2015-05-18 20:44:30 +053010453#ifdef ECM_MULTICAST_ENABLE
10454 for (i = 0; i < ECM_DB_MULTICAST_IF_MAX; ++i) {
10455 ci->to_mcast_interface_first[i] = ECM_DB_IFACE_HEIRARCHY_MAX;
10456 }
10457#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010458 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000010459 * If the master thread is terminating then we cannot create new instances
10460 */
10461 spin_lock_bh(&ecm_db_lock);
10462 if (ecm_db_terminate_pending) {
10463 spin_unlock_bh(&ecm_db_lock);
10464 DEBUG_WARN("Thread terminating\n");
10465 kfree(ci);
10466 return NULL;
10467 }
10468
10469 /*
10470 * Assign runtime unique serial
10471 */
10472 ci->serial = ecm_db_connection_serial++;
10473
Ben Menchaca84f36632014-02-28 20:57:38 +000010474 ecm_db_connection_count++;
10475 DEBUG_ASSERT(ecm_db_connection_count > 0, "%p: connection count wrap\n", ci);
10476 spin_unlock_bh(&ecm_db_lock);
10477
10478 DEBUG_TRACE("Connection created %p\n", ci);
10479 return ci;
10480}
10481EXPORT_SYMBOL(ecm_db_connection_alloc);
10482
10483/*
10484 * ecm_db_mapping_alloc()
10485 * Allocate a mapping instance
10486 */
10487struct ecm_db_mapping_instance *ecm_db_mapping_alloc(void)
10488{
10489 struct ecm_db_mapping_instance *mi;
10490
10491 mi = (struct ecm_db_mapping_instance *)kzalloc(sizeof(struct ecm_db_mapping_instance), GFP_ATOMIC | __GFP_NOWARN);
10492 if (!mi) {
10493 DEBUG_WARN("Alloc failed\n");
10494 return NULL;
10495 }
10496
10497 mi->refs = 1;
10498 DEBUG_SET_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC);
10499
10500 /*
10501 * Alloc operation must be atomic to ensure thread and module can be held
10502 */
10503 spin_lock_bh(&ecm_db_lock);
10504
10505 /*
10506 * If the event processing thread is terminating then we cannot create new instances
10507 */
10508 if (ecm_db_terminate_pending) {
10509 spin_unlock_bh(&ecm_db_lock);
10510 DEBUG_WARN("Thread terminating\n");
10511 kfree(mi);
10512 return NULL;
10513 }
10514
Ben Menchaca84f36632014-02-28 20:57:38 +000010515 ecm_db_mapping_count++;
10516 spin_unlock_bh(&ecm_db_lock);
10517
10518 DEBUG_TRACE("Mapping created %p\n", mi);
10519 return mi;
10520}
10521EXPORT_SYMBOL(ecm_db_mapping_alloc);
10522
Ben Menchaca84f36632014-02-28 20:57:38 +000010523/*
10524 * ecm_db_host_alloc()
10525 * Allocate a host instance
10526 */
10527struct ecm_db_host_instance *ecm_db_host_alloc(void)
10528{
10529 struct ecm_db_host_instance *hi;
10530 hi = (struct ecm_db_host_instance *)kzalloc(sizeof(struct ecm_db_host_instance), GFP_ATOMIC | __GFP_NOWARN);
10531 if (!hi) {
10532 DEBUG_WARN("Alloc failed\n");
10533 return NULL;
10534 }
10535
10536 hi->refs = 1;
10537 DEBUG_SET_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC);
10538
10539 /*
10540 * Alloc operation must be atomic to ensure thread and module can be held
10541 */
10542 spin_lock_bh(&ecm_db_lock);
10543
10544 /*
10545 * If the event processing thread is terminating then we cannot create new instances
10546 */
10547 if (ecm_db_terminate_pending) {
10548 spin_unlock_bh(&ecm_db_lock);
10549 DEBUG_WARN("Thread terminating\n");
10550 kfree(hi);
10551 return NULL;
10552 }
10553
Ben Menchaca84f36632014-02-28 20:57:38 +000010554 ecm_db_host_count++;
10555 spin_unlock_bh(&ecm_db_lock);
10556
10557 DEBUG_TRACE("Host created %p\n", hi);
10558 return hi;
10559}
10560EXPORT_SYMBOL(ecm_db_host_alloc);
10561
10562/*
10563 * ecm_db_node_alloc()
10564 * Allocate a node instance
10565 */
10566struct ecm_db_node_instance *ecm_db_node_alloc(void)
10567{
10568 struct ecm_db_node_instance *ni;
10569
10570 ni = (struct ecm_db_node_instance *)kzalloc(sizeof(struct ecm_db_node_instance), GFP_ATOMIC | __GFP_NOWARN);
10571 if (!ni) {
10572 DEBUG_WARN("Alloc failed\n");
10573 return NULL;
10574 }
10575
10576 ni->refs = 1;
10577 DEBUG_SET_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC);
10578
10579 /*
10580 * Alloc operation must be atomic to ensure thread and module can be held
10581 */
10582 spin_lock_bh(&ecm_db_lock);
10583
10584 /*
10585 * If the event processing thread is terminating then we cannot create new instances
10586 */
10587 if (ecm_db_terminate_pending) {
10588 spin_unlock_bh(&ecm_db_lock);
10589 DEBUG_WARN("Thread terminating\n");
10590 kfree(ni);
10591 return NULL;
10592 }
10593
Ben Menchaca84f36632014-02-28 20:57:38 +000010594 ecm_db_node_count++;
10595 spin_unlock_bh(&ecm_db_lock);
10596
10597 DEBUG_TRACE("Node created %p\n", ni);
10598 return ni;
10599}
10600EXPORT_SYMBOL(ecm_db_node_alloc);
10601
10602/*
10603 * ecm_db_iface_alloc()
10604 * Allocate a iface instance
10605 */
10606struct ecm_db_iface_instance *ecm_db_iface_alloc(void)
10607{
10608 struct ecm_db_iface_instance *ii;
10609
10610 ii = (struct ecm_db_iface_instance *)kzalloc(sizeof(struct ecm_db_iface_instance), GFP_ATOMIC | __GFP_NOWARN);
10611 if (!ii) {
10612 DEBUG_WARN("Alloc failed\n");
10613 return NULL;
10614 }
10615
10616 ii->refs = 1;
10617 DEBUG_SET_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC);
10618
10619 /*
10620 * Alloc operation must be atomic to ensure thread and module can be held
10621 */
10622 spin_lock_bh(&ecm_db_lock);
10623
10624 /*
10625 * If the event processing thread is terminating then we cannot create new instances
10626 */
10627 if (ecm_db_terminate_pending) {
10628 spin_unlock_bh(&ecm_db_lock);
10629 DEBUG_WARN("Thread terminating\n");
10630 kfree(ii);
10631 return NULL;
10632 }
10633
Ben Menchaca84f36632014-02-28 20:57:38 +000010634 ecm_db_iface_count++;
10635 spin_unlock_bh(&ecm_db_lock);
10636
10637 DEBUG_TRACE("iface created %p\n", ii);
10638 return ii;
10639}
10640EXPORT_SYMBOL(ecm_db_iface_alloc);
10641
10642/*
10643 * ecm_db_listener_alloc()
10644 * Allocate a listener instance
10645 */
10646struct ecm_db_listener_instance *ecm_db_listener_alloc(void)
10647{
10648 struct ecm_db_listener_instance *li;
10649
10650 li = (struct ecm_db_listener_instance *)kzalloc(sizeof(struct ecm_db_listener_instance), GFP_ATOMIC | __GFP_NOWARN);
10651 if (!li) {
10652 DEBUG_WARN("Alloc failed\n");
10653 return NULL;
10654 }
10655
10656 li->refs = 1;
10657 DEBUG_SET_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC);
10658
10659 /*
10660 * Alloc operation must be atomic to ensure thread and module can be held
10661 */
10662 spin_lock_bh(&ecm_db_lock);
10663
10664 /*
10665 * If the event processing thread is terminating then we cannot create new instances
10666 */
10667 if (ecm_db_terminate_pending) {
10668 spin_unlock_bh(&ecm_db_lock);
10669 DEBUG_WARN("Thread terminating\n");
10670 kfree(li);
10671 return NULL;
10672 }
10673
Ben Menchaca84f36632014-02-28 20:57:38 +000010674 ecm_db_listeners_count++;
10675 DEBUG_ASSERT(ecm_db_listeners_count > 0, "%p: listener count wrap\n", li);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010676 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +000010677
10678 DEBUG_TRACE("Listener created %p\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +000010679 return li;
10680}
10681EXPORT_SYMBOL(ecm_db_listener_alloc);
10682
Shyam Sunder1f037262015-05-18 20:04:13 +053010683#ifdef ECM_MULTICAST_ENABLE
10684/*
10685 * _ecm_db_multicast_tuple_instance_ref()
10686 * Increment tuple reference count by one
10687 */
10688static void _ecm_db_multicast_tuple_instance_ref(struct ecm_db_multicast_tuple_instance *ti)
10689{
10690 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10691 ti->refs++;
10692 DEBUG_TRACE("%p: ti ref %d\n", ti, ti->refs);
10693 DEBUG_ASSERT(ti->refs > 0, "%p: ref wrap\n", ti)
10694}
10695
10696/*
10697 * ecm_db_multicast_alloc_connection()
10698 * Allocate memory for the connection structure.
10699 */
10700struct 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)
10701{
10702 struct ecm_db_multicast_tuple_instance *ti;
10703 ti = (struct ecm_db_multicast_tuple_instance *)kzalloc(sizeof(struct ecm_db_multicast_tuple_instance), GFP_ATOMIC | __GFP_NOWARN);
10704 if (!ti) {
10705 DEBUG_WARN("ti: Alloc failed\n");
10706 return NULL;
10707 }
10708 ti->src_port = src_port;
10709 ti->dst_port = dst_port;
10710 ECM_IP_ADDR_COPY(ti->src_ip, origin);
10711 ECM_IP_ADDR_COPY(ti->grp_ip, group);
10712 ti->proto = IPPROTO_UDP;
10713 ti->hash_index = ecm_db_multicast_generate_hash_index(group);
10714 ti->flags = 0;
10715 ti->refs = 1;
10716 ti->next = NULL;
10717 ti->prev = NULL;
10718 DEBUG_SET_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC);
10719
10720 return ti;
10721}
10722EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_alloc);
10723
10724/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010725 * ecm_db_multicast_connection_find_and_ref()
Shyam Sunder1f037262015-05-18 20:04:13 +053010726 * Called by MFC event update to fetch connection from the table
Shyam Sunder3af86a52015-08-28 18:04:10 +053010727 * This function takes a ref count for both tuple_instance and 'ci'
10728 * Call ecm_db_multicast_connection_deref function for deref both
10729 * 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053010730 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053010731struct 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 +053010732{
10733 ecm_db_multicast_tuple_instance_hash_t hash_index;
10734 struct ecm_db_multicast_tuple_instance *ti;
10735
10736 /*
10737 * Compute the hash chain index
10738 */
10739 hash_index = ecm_db_multicast_generate_hash_index(group);
10740
10741 spin_lock_bh(&ecm_db_lock);
10742 ti = ecm_db_multicast_tuple_instance_table[hash_index];
10743
10744 /*
10745 * Traverse through the list and find the ti
10746 */
10747 while (ti) {
10748 if (!(ECM_IP_ADDR_MATCH(ti->src_ip, origin) && ECM_IP_ADDR_MATCH(ti->grp_ip, group))) {
10749 ti = ti->next;
10750 continue;
10751 }
10752
10753 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053010754 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053010755 spin_unlock_bh(&ecm_db_lock);
10756 DEBUG_TRACE("multicast tuple instance found %p\n", ti);
10757 return ti;
10758 }
10759
10760 spin_unlock_bh(&ecm_db_lock);
10761 DEBUG_TRACE("multicast tuple instance not found\n");
10762 return NULL;
10763}
Shyam Sunder3af86a52015-08-28 18:04:10 +053010764EXPORT_SYMBOL(ecm_db_multicast_connection_find_and_ref);
Shyam Sunder1f037262015-05-18 20:04:13 +053010765
10766/*
10767 * ecm_db_multicast_tuple_instance_deref()
10768 * Deref the reference count or
Shyam Sunder3af86a52015-08-28 18:04:10 +053010769 * Free the tuple_instance struct, when the multicast connection dies
Shyam Sunder1f037262015-05-18 20:04:13 +053010770 */
10771int ecm_db_multicast_tuple_instance_deref(struct ecm_db_multicast_tuple_instance *ti)
10772{
10773 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10774 spin_lock_bh(&ecm_db_lock);
10775 ti->refs--;
10776 DEBUG_TRACE("%p: ti deref %d\n", ti, ti->refs);
10777 DEBUG_ASSERT(ti->refs >= 0, "%p: ref wrap\n", ti);
10778
10779 if (ti->refs > 0) {
10780 int refs = ti->refs;
10781 spin_unlock_bh(&ecm_db_lock);
10782 return refs;
10783 }
10784
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010785 if (ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED) {
10786
10787 if (!ti->prev) {
10788 DEBUG_ASSERT(ecm_db_multicast_tuple_instance_table[ti->hash_index] == ti, "%p: hash table bad\n", ti);
10789 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti->next;
10790 } else {
10791 ti->prev->next = ti->next;
10792 }
10793
10794 if (ti->next) {
10795 ti->next->prev = ti->prev;
10796 }
Shyam Sunder1f037262015-05-18 20:04:13 +053010797 }
10798
Shyam Sunder1f037262015-05-18 20:04:13 +053010799 spin_unlock_bh(&ecm_db_lock);
Shyam Sunder1f037262015-05-18 20:04:13 +053010800 DEBUG_CLEAR_MAGIC(ti);
10801 kfree(ti);
10802
10803 return 0;
10804}
10805EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_deref);
10806
10807/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010808 * ecm_db_multicast_connection_deref()
10809 * Deref both 'ti' and 'ci'
10810 * call this function after ecm_db_multicast_connection_find_and_ref()
10811 */
10812void ecm_db_multicast_connection_deref(struct ecm_db_multicast_tuple_instance *ti)
10813{
10814 struct ecm_db_connection_instance *ci;
10815 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10816
10817 ci = ti->ci;
10818 ecm_db_multicast_tuple_instance_deref(ti);
10819 ecm_db_connection_deref(ci);
10820
10821}
10822EXPORT_SYMBOL(ecm_db_multicast_connection_deref);
10823
10824/*
Shyam Sunder1f037262015-05-18 20:04:13 +053010825 * ecm_db_multicast_tuple_instance_add()
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010826 * Add the tuple instance into the hash table. Also, attach the tuple instance
10827 * with connection instance.
10828 *
Shyam Sunder1f037262015-05-18 20:04:13 +053010829 * Note: This function takes a reference count and caller has to also call
10830 * ecm_db_multicast_tuple_instance_deref() after this function.
10831 */
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010832void 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 +053010833{
10834 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10835
10836 spin_lock_bh(&ecm_db_lock);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010837 DEBUG_ASSERT(!(ti->flags & ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED), "%p: inserted\n", ti);
10838
10839 /*
10840 * Attach the multicast tuple instance with the connection instance
10841 */
10842 ci->ti = ti;
Shyam Sunder3af86a52015-08-28 18:04:10 +053010843 ti->ci = ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053010844
10845 /*
10846 * Take a local reference to ti
10847 */
10848 _ecm_db_multicast_tuple_instance_ref(ti);
10849 ti->next = ecm_db_multicast_tuple_instance_table[ti->hash_index];
10850 if (ecm_db_multicast_tuple_instance_table[ti->hash_index]) {
10851 ecm_db_multicast_tuple_instance_table[ti->hash_index]->prev = ti;
10852 }
10853
10854 ecm_db_multicast_tuple_instance_table[ti->hash_index] = ti;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010855
10856 ti->flags |= ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED;
Shyam Sunder1f037262015-05-18 20:04:13 +053010857 spin_unlock_bh(&ecm_db_lock);
10858
10859}
10860EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_add);
10861
10862/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010863 * ecm_db_multicast_connection_get_and_ref_first()
Shyam Sunder1f037262015-05-18 20:04:13 +053010864 * Return the first tuple instance from the table when given a group
Shyam Sunder3af86a52015-08-28 18:04:10 +053010865 * Also take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
10866 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053010867 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053010868struct ecm_db_multicast_tuple_instance *ecm_db_multicast_connection_get_and_ref_first(ip_addr_t group)
Shyam Sunder1f037262015-05-18 20:04:13 +053010869{
10870 ecm_db_multicast_tuple_instance_hash_t hash_index;
10871 struct ecm_db_multicast_tuple_instance *ti;
10872
10873 hash_index = ecm_db_multicast_generate_hash_index(group);
10874
10875 spin_lock_bh(&ecm_db_lock);
10876 ti = ecm_db_multicast_tuple_instance_table[hash_index];
10877 if (ti) {
10878 _ecm_db_multicast_tuple_instance_ref(ti);
Shyam Sunder3af86a52015-08-28 18:04:10 +053010879 _ecm_db_connection_ref(ti->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053010880 }
10881 spin_unlock_bh(&ecm_db_lock);
10882
10883 return ti;
10884}
Shyam Sunder3af86a52015-08-28 18:04:10 +053010885EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_first);
Shyam Sunder1f037262015-05-18 20:04:13 +053010886
10887/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053010888 * ecm_db_multicast_connection_get_and_ref_next()
10889 * Return the next tuple instance node and
10890 * take a ref count for 'ci', once done call ecm_db_multicast_connection_deref()
10891 * to deref both 'ti' and 'ci'
Shyam Sunder1f037262015-05-18 20:04:13 +053010892 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053010893struct 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 +053010894{
10895 struct ecm_db_multicast_tuple_instance *tin;
10896 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10897 spin_lock_bh(&ecm_db_lock);
10898 tin = ti->next;
10899 if (tin) {
10900 _ecm_db_multicast_tuple_instance_ref(tin);
Shyam Sunder3af86a52015-08-28 18:04:10 +053010901 _ecm_db_connection_ref(tin->ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053010902 }
10903 spin_unlock_bh(&ecm_db_lock);
10904 return tin;
10905}
Shyam Sunder3af86a52015-08-28 18:04:10 +053010906EXPORT_SYMBOL(ecm_db_multicast_connection_get_and_ref_next);
Shyam Sunder1f037262015-05-18 20:04:13 +053010907
10908/*
10909 * ecm_db_multicast_tuple_instance_source_ip_get()
10910 * This function return the source IP for a connection object
10911 */
10912void ecm_db_multicast_tuple_instance_source_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t origin)
10913{
10914 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10915 ECM_IP_ADDR_COPY(origin, ti->src_ip);
10916}
10917EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_source_ip_get);
10918
10919/*
Shyam Sunderf34c25b2015-06-11 21:14:50 +053010920 * ecm_db_multicast_tuple_instance_group_ip_get()
10921 * This function return the group IP for a connection object
10922 */
10923void ecm_db_multicast_tuple_instance_group_ip_get(struct ecm_db_multicast_tuple_instance *ti, ip_addr_t group)
10924{
10925 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
10926 ECM_IP_ADDR_COPY(group, ti->grp_ip);
10927}
10928EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_group_ip_get);
10929
10930/*
Shyam Sunder1f037262015-05-18 20:04:13 +053010931 * ecm_db_multicast_tuple_instance_flags_get()
10932 * Return flags related to Multicast connection
10933 */
10934uint32_t ecm_db_multicast_tuple_instance_flags_get(struct ecm_db_multicast_tuple_instance *ti)
10935{
10936 uint32_t flags;
10937
10938 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
10939 spin_lock_bh(&ecm_db_lock);
10940 flags = ti->flags;
10941 spin_unlock_bh(&ecm_db_lock);
10942 return flags;
10943}
10944EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_get);
10945
10946/*
10947 * ecm_db_multicast_tuple_instance_flags_set()
10948 * Set the multicast connection flags
10949 */
10950void ecm_db_multicast_tuple_instance_flags_set(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
10951{
10952 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
10953
10954 spin_lock_bh(&ecm_db_lock);
10955 ti->flags |= flags;
10956 spin_unlock_bh(&ecm_db_lock);
10957}
10958EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_set);
10959
10960/*
10961 * ecm_db_multicast_tuple_instance_flags_clear()
10962 * Clear the multicast connection flags
10963 */
10964void ecm_db_multicast_tuple_instance_flags_clear(struct ecm_db_multicast_tuple_instance *ti, uint32_t flags)
10965{
10966 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed\n", ti);
10967
10968 spin_lock_bh(&ecm_db_lock);
10969 ti->flags &= ~flags;
10970 spin_unlock_bh(&ecm_db_lock);
10971}
10972EXPORT_SYMBOL(ecm_db_multicast_tuple_instance_flags_clear);
10973
10974/*
10975 * ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
10976 * Return the list of multicast destination interface heirarchies to which this connection is established.
10977 * The function returns the heirarchies using the 'interface' pointer passed to it. It also returns the first
10978 * index in the interface heirarchy for each of the heirarchies using the 'ifaces_first' pointer.
10979 *
10980 * NOTE: This function allocates the memory for the destination interface heirachy. This memory is expected to be
10981 * freed only by making a call to ecm_db_multicast_connection_interfaces_deref_all().
10982 *
10983 * The size of the buffer allocated for the heirarchies and pointed to by 'interfaces' is as large as
10984 * sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX.
10985 * Returns the number of interface heirarchies in the list as a return value.
10986 *
10987 * Each interface is referenced on return, be sure to release them using ecm_db_multicast_connection_interfaces_deref_all().
10988 */
10989int32_t ecm_db_multicast_connection_to_interfaces_get_and_ref_all(struct ecm_db_connection_instance *ci,
10990 struct ecm_db_iface_instance **interfaces, int32_t **ifaces_first)
10991{
10992 struct ecm_db_iface_instance *heirarchy_base;
10993 struct ecm_db_iface_instance *heirarchy_temp;
10994 struct ecm_db_iface_instance *ii_single;
10995 struct ecm_db_iface_instance **ifaces;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053010996 struct ecm_db_iface_instance *ii_db;
10997 struct ecm_db_iface_instance *ii_db_single;
10998 struct ecm_db_iface_instance **ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053010999 int32_t *ii_first_base;
11000 int32_t *ii_first;
11001 int32_t heirarchy_index;
11002 int32_t ii_index;
11003 int32_t if_count = 0;
11004
11005 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11006
11007 heirarchy_base = (struct ecm_db_iface_instance *)kzalloc(ECM_DB_TO_MCAST_INTERFACES_SIZE, GFP_ATOMIC | __GFP_NOWARN);
11008 if (!heirarchy_base) {
11009 DEBUG_WARN("%p: No memory for interface hierarchies \n", ci);
11010 return if_count;
11011 }
11012
11013 ii_first_base = (int32_t *)kzalloc(sizeof(int32_t *) * ECM_DB_MULTICAST_IF_MAX, GFP_ATOMIC | __GFP_NOWARN);
11014 if (!ii_first_base) {
11015 DEBUG_WARN("%p: No memory for first interface \n", ci);
11016 kfree(heirarchy_base);
11017 return if_count;
11018 }
11019
11020 spin_lock_bh(&ecm_db_lock);
11021 if (!ci->to_mcast_interfaces_set) {
11022 spin_unlock_bh(&ecm_db_lock);
11023 kfree(ii_first_base);
11024 kfree(heirarchy_base);
11025 return if_count;
11026 }
11027
11028 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11029
11030 heirarchy_temp = ecm_db_multicast_if_heirarchy_get(heirarchy_base, heirarchy_index);
11031
11032 if (ci->to_mcast_interface_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
11033 if_count++;
11034 }
11035
11036 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 +053011037 ii_db = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, heirarchy_index);
11038 ii_db_single = ecm_db_multicast_if_instance_get_at_index(ii_db, ii_index);
11039 ifaces_db = (struct ecm_db_iface_instance **)ii_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053011040
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011041 /*
11042 * Take a reference count
11043 */
11044 _ecm_db_iface_ref(*ifaces_db);
11045
Shyam Sunder1f037262015-05-18 20:04:13 +053011046 ii_single = ecm_db_multicast_if_instance_get_at_index(heirarchy_temp, ii_index);
11047 ifaces = (struct ecm_db_iface_instance **)ii_single;
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011048 *ifaces = *ifaces_db;
Shyam Sunder1f037262015-05-18 20:04:13 +053011049 }
11050
11051 ii_first = ecm_db_multicast_if_first_get_at_index(ii_first_base, heirarchy_index);
11052 *ii_first = ci->to_mcast_interface_first[heirarchy_index];
11053 }
11054
11055 *interfaces = heirarchy_base;
11056 *ifaces_first = ii_first_base;
11057
11058 spin_unlock_bh(&ecm_db_lock);
11059 return if_count;
11060}
11061EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_get_and_ref_all);
11062
11063/*
11064 * ecm_db_multicast_connection_to_interfaces_set_check()
11065 * Returns true if the multicast destination interfaces list has been set.
11066 */
11067bool ecm_db_multicast_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
11068{
11069 bool set;
11070
11071 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11072 spin_lock_bh(&ecm_db_lock);
11073 set = ci->to_mcast_interfaces_set;
11074 spin_unlock_bh(&ecm_db_lock);
11075 return set;
11076}
11077EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_set_check);
11078
11079/*
11080 * ecm_db_multicast_connection_to_interfaces_set_clear()
11081 * Clear the to_mcast_interfaces_set flag if the multicast destination interfaces list has been freed.
11082 */
11083static void _ecm_db_multicast_connection_to_interfaces_set_clear(struct ecm_db_connection_instance *ci)
11084{
11085 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Shyam Sunder1f037262015-05-18 20:04:13 +053011086 ci->to_mcast_interfaces_set = false;
Shyam Sunder1f037262015-05-18 20:04:13 +053011087}
11088
11089/*
Shyam Sunder3af86a52015-08-28 18:04:10 +053011090 * ecm_db_multicast_connection_get_from_tuple()
Shyam Sunder1f037262015-05-18 20:04:13 +053011091 * Return the connection instance
11092 */
Shyam Sunder3af86a52015-08-28 18:04:10 +053011093struct 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 +053011094{
Shyam Sunder3af86a52015-08-28 18:04:10 +053011095 DEBUG_CHECK_MAGIC(ti, ECM_DB_MULTICAST_INSTANCE_MAGIC, "%p: magic failed", ti);
11096 DEBUG_ASSERT(ti->ci, "%p: Bad multicast connection instance \n", ti);
11097
11098 return ti->ci;
Shyam Sunder1f037262015-05-18 20:04:13 +053011099}
Shyam Sunder3af86a52015-08-28 18:04:10 +053011100EXPORT_SYMBOL(ecm_db_multicast_connection_get_from_tuple);
Shyam Sunder1f037262015-05-18 20:04:13 +053011101
11102/*
11103 * ecm_db_multicast_connection_to_interfaces_deref_all()
11104 * Deref all destination multicast interface heirarchies at once
11105 */
11106void ecm_db_multicast_connection_to_interfaces_deref_all(struct ecm_db_iface_instance *interfaces, int32_t *ifaces_first)
11107{
11108 struct ecm_db_iface_instance *ifaces_single;
11109 struct ecm_db_iface_instance *ii_temp[ECM_DB_IFACE_HEIRARCHY_MAX];
11110 int32_t *to_first;
11111 int heirarchy_index;
Shyam Sunder1f037262015-05-18 20:04:13 +053011112 DEBUG_ASSERT(interfaces, "Bad memory, multicast interfaces list has been already freed\n");
11113 DEBUG_ASSERT(ifaces_first, "Bad memory, multicast interfaces first has been already freed\n");
11114
11115 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11116 to_first = ecm_db_multicast_if_first_get_at_index(ifaces_first, heirarchy_index);
11117 if (*to_first < ECM_DB_IFACE_HEIRARCHY_MAX) {
11118 ifaces_single = ecm_db_multicast_if_heirarchy_get(interfaces, heirarchy_index);
11119 ecm_db_multicast_copy_if_heirarchy(ii_temp, ifaces_single);
11120 ecm_db_connection_interfaces_deref(ii_temp, *to_first);
11121 }
11122 }
11123
11124 /*
11125 * Free the temporary memory allocated by ecm_db_multicast_connection_to_interfaces_get_and_ref_all()
11126 */
11127 kfree(interfaces);
11128 kfree(ifaces_first);
11129
11130}
11131EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_deref_all);
11132
11133/*
11134 * _ecm_db_multicast_connection_to_interface_first_is_valid()
11135 * Check if destnation interfaces first list uphold a valid interface
11136 * first or all entries have discarded.
11137 */
11138static bool _ecm_db_multicast_connection_to_interface_first_is_valid(int32_t ifaces_first[])
11139{
11140 int heirarchy_index;
11141
11142 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11143 if (ifaces_first[heirarchy_index] < ECM_DB_IFACE_HEIRARCHY_MAX) {
11144 return true;
11145 }
11146 }
11147
11148 return false;
11149}
11150
11151/*
11152 * ecm_db_multicast_connection_to_interfaces_clear_at_index()
11153 * Dereference and clear a interface heirarchy at 'index' position
11154 */
11155void ecm_db_multicast_connection_to_interfaces_clear_at_index(struct ecm_db_connection_instance *ci, uint32_t index)
11156{
11157 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011158 struct ecm_db_iface_instance *ifaces_db_single;
Shyam Sunder1f037262015-05-18 20:04:13 +053011159 int32_t discard_first;
Shyam Sunder1f037262015-05-18 20:04:13 +053011160
11161 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11162
11163 /*
11164 * Invalid Index Value
11165 */
11166 DEBUG_ASSERT((index < ECM_DB_MULTICAST_IF_MAX), "%p: Invalid index for multicast interface heirarchies list %u\n", ci, index);
11167
11168 spin_lock_bh(&ecm_db_lock);
11169 if (ci->to_mcast_interface_first[index] == ECM_DB_IFACE_HEIRARCHY_MAX) {
11170 spin_unlock_bh(&ecm_db_lock);
11171 return;
11172 }
11173
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011174 ifaces_db_single = ecm_db_multicast_if_heirarchy_get(ci->to_mcast_interfaces, index);
11175 ecm_db_multicast_copy_if_heirarchy(discard, ifaces_db_single);
Shyam Sunder1f037262015-05-18 20:04:13 +053011176
11177 discard_first = ci->to_mcast_interface_first[index];
11178 ci->to_mcast_interface_first[index] = ECM_DB_IFACE_HEIRARCHY_MAX;
11179
11180 /*
11181 * If this is the only valid interface hierarchy left in the list of destination
11182 * interface hierarchies then clear the ci->to_mcast_interfaces_set flag here before
11183 * deleting this.
11184 */
11185 if (!_ecm_db_multicast_connection_to_interface_first_is_valid(ci->to_mcast_interface_first)) {
11186 ci->to_mcast_interfaces_set = false;
11187 }
11188
11189 spin_unlock_bh(&ecm_db_lock);
11190
11191 ecm_db_connection_interfaces_deref(discard, discard_first);
11192}
11193EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear_at_index);
11194
11195/*
11196 * ecm_db_multicast_connection_to_interfaces_clear()
11197 * Deref and clear all destination multicast interface heirarchies
11198 */
11199void ecm_db_multicast_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
11200{
11201 int heirarchy_index;
11202 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
11203
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011204 spin_lock_bh(&ecm_db_lock);
11205 if (!ci->to_mcast_interfaces) {
11206 spin_unlock_bh(&ecm_db_lock);
11207 return;
11208 }
11209
Shyam Sunder1f037262015-05-18 20:04:13 +053011210 _ecm_db_multicast_connection_to_interfaces_set_clear(ci);
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011211 spin_unlock_bh(&ecm_db_lock);
11212
Shyam Sunder1f037262015-05-18 20:04:13 +053011213 for (heirarchy_index = 0; heirarchy_index < ECM_DB_MULTICAST_IF_MAX; heirarchy_index++) {
11214 ecm_db_multicast_connection_to_interfaces_clear_at_index(ci, heirarchy_index);
11215 }
Shyam Sunderbf40d0e2015-06-23 15:56:37 +053011216
11217 kfree(ci->to_mcast_interfaces);
11218 ci->to_mcast_interfaces = NULL;
Shyam Sunder1f037262015-05-18 20:04:13 +053011219}
11220EXPORT_SYMBOL(ecm_db_multicast_connection_to_interfaces_clear);
11221#endif
11222
Ben Menchaca84f36632014-02-28 20:57:38 +000011223/*
11224 * ecm_db_time_get()
11225 * Return database time, in seconds since the database started.
11226 */
11227uint32_t ecm_db_time_get(void)
11228{
11229 uint32_t time_now;
11230 spin_lock_bh(&ecm_db_lock);
11231 time_now = ecm_db_time;
11232 spin_unlock_bh(&ecm_db_lock);
11233 return time_now;
11234}
11235EXPORT_SYMBOL(ecm_db_time_get);
11236
11237/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011238 * ecm_db_get_defunct_all()
11239 * Reading this file returns the accumulated total of all objects
11240 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011241static ssize_t ecm_db_get_defunct_all(struct file *file,
11242 char __user *user_buf,
11243 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011244{
Murat Sezgin908ecb32015-05-10 20:54:36 -070011245 int ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011246 int num;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011247 char *buf;
11248
11249 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11250 if (!buf) {
11251 return -ENOMEM;
11252 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011253
11254 /*
11255 * Operate under our locks
11256 */
11257 spin_lock_bh(&ecm_db_lock);
11258 num = ecm_db_connection_count + ecm_db_mapping_count + ecm_db_host_count
11259 + ecm_db_node_count + ecm_db_iface_count;
11260 spin_unlock_bh(&ecm_db_lock);
11261
Murat Sezgin908ecb32015-05-10 20:54:36 -070011262 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
11263 if (ret < 0) {
11264 kfree(buf);
11265 return ret;
11266 }
11267
11268 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11269 kfree(buf);
11270 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011271}
11272
11273/*
11274 * ecm_db_set_defunct_all()
11275 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011276static ssize_t ecm_db_set_defunct_all(struct file *file,
11277 const char __user *user_buf,
11278 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011279{
11280 ecm_db_connection_defunct_all();
Murat Sezgin908ecb32015-05-10 20:54:36 -070011281 return sz;
Ben Menchaca84f36632014-02-28 20:57:38 +000011282}
11283
11284/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011285 * File operations for defunct_all.
11286 */
11287static struct file_operations ecm_db_defunct_all_fops = {
11288 .read = ecm_db_get_defunct_all,
11289 .write = ecm_db_set_defunct_all,
11290};
11291
11292/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011293 * ecm_db_get_connection_counts_simple()
11294 * Return total of connections for each simple protocol (tcp, udp, other). Primarily for use by the luci-bwc service.
11295 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011296static ssize_t ecm_db_get_connection_counts_simple(struct file *file,
11297 char __user *user_buf,
11298 size_t sz, loff_t *ppos)
Ben Menchaca84f36632014-02-28 20:57:38 +000011299{
11300 int tcp_count;
11301 int udp_count;
11302 int other_count;
11303 int total_count;
Murat Sezgin908ecb32015-05-10 20:54:36 -070011304 int ret;
11305 char *buf;
11306
11307 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
11308 if (!buf) {
11309 return -ENOMEM;
11310 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011311
11312 /*
11313 * Get snapshot of the protocol counts
11314 */
11315 spin_lock_bh(&ecm_db_lock);
11316 tcp_count = ecm_db_connection_count_by_protocol[IPPROTO_TCP];
11317 udp_count = ecm_db_connection_count_by_protocol[IPPROTO_UDP];
11318 total_count = ecm_db_connection_count;
11319 other_count = total_count - (tcp_count + udp_count);
11320 spin_unlock_bh(&ecm_db_lock);
11321
Murat Sezgin908ecb32015-05-10 20:54:36 -070011322 ret = snprintf(buf, (ssize_t)PAGE_SIZE, "tcp %d udp %d other %d total %d\n", tcp_count, udp_count, other_count, total_count);
11323 if (ret < 0) {
11324 kfree(buf);
11325 return -EFAULT;
11326 }
11327
11328 ret = simple_read_from_buffer(user_buf, sz, ppos, buf, ret);
11329 kfree(buf);
11330 return ret;
Ben Menchaca84f36632014-02-28 20:57:38 +000011331}
11332
Ben Menchaca84f36632014-02-28 20:57:38 +000011333/*
Murat Sezgin908ecb32015-05-10 20:54:36 -070011334 * File operations for simple connection counts.
Ben Menchaca84f36632014-02-28 20:57:38 +000011335 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011336static struct file_operations ecm_db_connection_count_simple_fops = {
11337 .read = ecm_db_get_connection_counts_simple,
Ben Menchaca84f36632014-02-28 20:57:38 +000011338};
11339
11340/*
Ben Menchaca84f36632014-02-28 20:57:38 +000011341 * ecm_db_timer_callback()
11342 * Manage expiration of connections
11343 * NOTE: This is softirq context
11344 */
11345static void ecm_db_timer_callback(unsigned long data)
11346{
11347 uint32_t timer;
11348
11349 /*
11350 * Increment timer.
11351 */
11352 spin_lock_bh(&ecm_db_lock);
11353 timer = ++ecm_db_time;
11354 spin_unlock_bh(&ecm_db_lock);
11355 DEBUG_TRACE("Garbage timer tick %d\n", timer);
11356
11357 /*
11358 * Check timer groups
11359 */
11360 ecm_db_timer_groups_check(timer);
11361
11362 /*
11363 * Set the timer for the next second
11364 */
11365 ecm_db_timer.expires += HZ;
11366 if (ecm_db_timer.expires <= jiffies) {
11367 DEBUG_WARN("losing time %lu, jiffies = %lu\n", ecm_db_timer.expires, jiffies);
11368 ecm_db_timer.expires = jiffies + HZ;
11369 }
11370 add_timer(&ecm_db_timer);
11371}
Gareth Williamsd5618a82015-05-20 11:13:32 +010011372#ifdef ECM_DB_XREF_ENABLE
Ben Menchaca84f36632014-02-28 20:57:38 +000011373/*
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011374 * ecm_db_node_from_connections_get_and_ref_first()
11375 * Obtain a ref to the first connection instance of "from list" of node, if any
11376 */
11377static inline struct ecm_db_connection_instance *ecm_db_node_from_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11378{
11379 struct ecm_db_connection_instance *ci;
11380 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11381 spin_lock_bh(&ecm_db_lock);
11382 ci = node->from_connections;
11383 if (ci) {
11384 _ecm_db_connection_ref(ci);
11385 }
11386 spin_unlock_bh(&ecm_db_lock);
11387 return ci;
11388}
11389
11390/*
11391 * ecm_db_node_from_connection_get_and_ref_next()
11392 * Return the next connection in the "from list" of given a connection
11393 */
11394static inline struct ecm_db_connection_instance *ecm_db_node_from_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11395{
11396 struct ecm_db_connection_instance *cin;
11397 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11398 spin_lock_bh(&ecm_db_lock);
11399 cin = ci->node_from_next;
11400 if (cin) {
11401 _ecm_db_connection_ref(cin);
11402 }
11403 spin_unlock_bh(&ecm_db_lock);
11404 return cin;
11405}
11406
11407/*
11408 * ecm_db_node_to_connections_get_and_ref_first()
11409 * Obtain a ref to the first connection instance of a "to list" of node, if any
11410 */
11411static inline struct ecm_db_connection_instance *ecm_db_node_to_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11412{
11413 struct ecm_db_connection_instance *ci;
11414 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11415 spin_lock_bh(&ecm_db_lock);
11416 ci = node->to_connections;
11417 if (ci) {
11418 _ecm_db_connection_ref(ci);
11419 }
11420 spin_unlock_bh(&ecm_db_lock);
11421 return ci;
11422}
11423
11424/*
11425 * ecm_db_node_to_connection_get_and_ref_next()
11426 * Return the next connection in the "to list" of given a connection
11427 */
11428static inline struct ecm_db_connection_instance *ecm_db_node_to_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11429{
11430 struct ecm_db_connection_instance *cin;
11431 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11432 spin_lock_bh(&ecm_db_lock);
11433 cin = ci->node_to_next;
11434 if (cin) {
11435 _ecm_db_connection_ref(cin);
11436 }
11437 spin_unlock_bh(&ecm_db_lock);
11438 return cin;
11439}
11440
11441/*
11442 * ecm_db_node_from_nat_connections_get_and_ref_first()
11443 * Obtain a ref to the first connection instance of a "from_nat list" of node, if any
11444 */
11445static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11446{
11447 struct ecm_db_connection_instance *ci;
11448 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11449 spin_lock_bh(&ecm_db_lock);
11450 ci = node->from_nat_connections;
11451 if (ci) {
11452 _ecm_db_connection_ref(ci);
11453 }
11454 spin_unlock_bh(&ecm_db_lock);
11455 return ci;
11456}
11457
11458/*
11459 * ecm_db_node_from_nat_connection_get_and_ref_next()
11460 * Return the next connection in the "from nat list" of given a connection
11461 */
11462static inline struct ecm_db_connection_instance *ecm_db_node_from_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11463{
11464 struct ecm_db_connection_instance *cin;
11465 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11466 spin_lock_bh(&ecm_db_lock);
11467 cin = ci->node_from_nat_next;
11468 if (cin) {
11469 _ecm_db_connection_ref(cin);
11470 }
11471 spin_unlock_bh(&ecm_db_lock);
11472 return cin;
11473}
11474
11475/*
11476 * ecm_db_node_to_nat_connections_get_and_ref_first()
11477 * Obtain a ref to the first connection instance of a "to_nat list" of node, if any
11478 */
11479static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connections_get_and_ref_first(struct ecm_db_node_instance *node)
11480{
11481 struct ecm_db_connection_instance *ci;
11482 DEBUG_CHECK_MAGIC(node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", node);
11483 spin_lock_bh(&ecm_db_lock);
11484 ci = node->to_nat_connections;
11485 if (ci) {
11486 _ecm_db_connection_ref(ci);
11487 }
11488 spin_unlock_bh(&ecm_db_lock);
11489 return ci;
11490}
11491
11492/*
11493 * ecm_db_node_to_nat_connection_get_and_ref_next()
11494 * Return the next connection in the "to nat list" of given a connection
11495 */
11496static inline struct ecm_db_connection_instance *ecm_db_node_to_nat_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
11497{
11498 struct ecm_db_connection_instance *cin;
11499 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11500 spin_lock_bh(&ecm_db_lock);
11501 cin = ci->node_to_nat_next;
11502 if (cin) {
11503 _ecm_db_connection_ref(cin);
11504 }
11505 spin_unlock_bh(&ecm_db_lock);
11506 return cin;
11507}
11508
11509/*
11510 * ecm_db_connection_decelerate_and_defunct()
11511 * decelerate and defunct a connection
11512 */
11513static inline void ecm_db_connection_decelerate_and_defunct(struct ecm_db_connection_instance *ci)
11514{
11515 struct ecm_front_end_connection_instance *feci = NULL;
11516
11517 if(unlikely(!ci)) {
11518 DEBUG_WARN("%p: ecm db connection instance pointer is null\n", ci);
11519 return;
11520 }
11521
11522 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
11523
11524 feci = ecm_db_connection_front_end_get_and_ref(ci);
11525
11526 feci->decelerate(feci);
11527 feci->deref(feci);
11528 ecm_db_connection_make_defunct(ci);
11529}
11530
11531/*
Murat Sezgine34b0172015-11-05 21:58:14 -080011532 * ecm_db_should_keep_connection()
11533 * check if any classifier believes this connection should
11534 * be kept
11535 */
11536static bool ecm_db_should_keep_connection(
11537 struct ecm_db_connection_instance *ci, uint8_t *mac)
11538{
11539 bool should_keep_connection = false;
11540 int assignment_count;
11541 int aci_index;
11542 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
11543
11544 assignment_count =
11545 ecm_db_connection_classifier_assignments_get_and_ref(ci, assignments);
11546 for (aci_index = 0; aci_index < assignment_count; ++aci_index) {
11547 struct ecm_classifier_instance *aci;
11548 aci = assignments[aci_index];
11549 if (aci->should_keep_connection &&
11550 aci->should_keep_connection(aci, mac)) {
11551 should_keep_connection = true;
11552 break;
11553 }
11554 }
11555 ecm_db_connection_assignments_release(assignment_count, assignments);
11556
11557 return should_keep_connection;
11558}
11559
11560/*
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011561 * ecm_db_traverse_node_from_connection_list_and_decelerate()
11562 * traverse from_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11563 * for each entry
11564 */
Murat Sezgine34b0172015-11-05 21:58:14 -080011565void ecm_db_traverse_node_from_connection_list_and_decelerate(
11566 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011567{
11568 struct ecm_db_connection_instance *ci = NULL;
11569
11570 /*
11571 * Iterate all from connections
11572 */
11573 ci = ecm_db_node_from_connections_get_and_ref_first(node);
11574 while (ci) {
11575 struct ecm_db_connection_instance *cin;
11576
Murat Sezgine34b0172015-11-05 21:58:14 -080011577 if (!ecm_db_should_keep_connection(ci, node->address)) {
11578 DEBUG_TRACE("%p: defunct\n", ci);
11579 ecm_db_connection_decelerate_and_defunct(ci);
11580 } else {
11581 DEBUG_TRACE("%p: keeping connection\n", ci);
11582 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011583
11584 cin = ecm_db_node_from_connection_get_and_ref_next(ci);
11585 ecm_db_connection_deref(ci);
11586 ci = cin;
11587 }
11588 DEBUG_INFO("%p: Defuncting node's from connection list complete\n", node);
11589}
11590
11591/*
11592 * ecm_db_traverse_node_to_connection_list_and_decelerate()
11593 * traverse to_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11594 * for each entry
11595 */
Murat Sezgine34b0172015-11-05 21:58:14 -080011596void ecm_db_traverse_node_to_connection_list_and_decelerate(
11597 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011598{
11599 struct ecm_db_connection_instance *ci = NULL;
11600
11601 /*
11602 * Iterate all to connections
11603 */
11604 ci = ecm_db_node_to_connections_get_and_ref_first(node);
11605 while (ci) {
11606 struct ecm_db_connection_instance *cin;
11607
Murat Sezgine34b0172015-11-05 21:58:14 -080011608 if (!ecm_db_should_keep_connection(ci, node->address)) {
11609 DEBUG_TRACE("%p: defunct\n", ci);
11610 ecm_db_connection_decelerate_and_defunct(ci);
11611 } else {
11612 DEBUG_TRACE("%p: keeping connection\n", ci);
11613 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011614
11615 cin = ecm_db_node_to_connection_get_and_ref_next(ci);
11616 ecm_db_connection_deref(ci);
11617 ci = cin;
11618 }
11619 DEBUG_INFO("%p: Defuncting node's to connection list complete\n", node);
11620}
11621
11622/*
11623 * ecm_db_traverse_node_from_nat_connection_list_and_decelerate()
11624 * traverse from_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11625 * for each entry
11626 */
Murat Sezgine34b0172015-11-05 21:58:14 -080011627void ecm_db_traverse_node_from_nat_connection_list_and_decelerate(
11628 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011629{
11630 struct ecm_db_connection_instance *ci = NULL;
11631
11632 /*
11633 * Iterate all from nat connections
11634 */
11635 ci = ecm_db_node_from_nat_connections_get_and_ref_first(node);
11636 while (ci) {
11637 struct ecm_db_connection_instance *cin;
11638
Murat Sezgine34b0172015-11-05 21:58:14 -080011639 if (!ecm_db_should_keep_connection(ci, node->address)) {
11640 DEBUG_TRACE("%p: defunct\n", ci);
11641 ecm_db_connection_decelerate_and_defunct(ci);
11642 } else {
11643 DEBUG_TRACE("%p: keeping connection\n", ci);
11644 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011645
11646 cin = ecm_db_node_from_nat_connection_get_and_ref_next(ci);
11647 ecm_db_connection_deref(ci);
11648 ci = cin;
11649 }
11650 DEBUG_INFO("%p: Defuncting node's from nat connection list complete\n", node);
11651}
11652
11653/*
11654 * ecm_db_traverse_node_to_nat_connection_list_and_decelerate()
11655 * traverse to_nat_list of a node and calls ecm_db_connection_decelerate_and_defunct()
11656 * for each entry
11657 */
Murat Sezgine34b0172015-11-05 21:58:14 -080011658void ecm_db_traverse_node_to_nat_connection_list_and_decelerate(
11659 struct ecm_db_node_instance *node)
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011660{
11661 struct ecm_db_connection_instance *ci = NULL;
11662
11663 /*
11664 * Iterate all to nat connections
11665 */
11666 ci = ecm_db_node_to_nat_connections_get_and_ref_first(node);
11667 while (ci) {
11668 struct ecm_db_connection_instance *cin;
11669
Murat Sezgine34b0172015-11-05 21:58:14 -080011670 if (!ecm_db_should_keep_connection(ci, node->address)) {
11671 DEBUG_TRACE("%p: defunct\n", ci);
11672 ecm_db_connection_decelerate_and_defunct(ci);
11673 } else {
11674 DEBUG_TRACE("%p: keeping connection\n", ci);
11675 }
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011676
11677 cin = ecm_db_node_to_nat_connection_get_and_ref_next(ci);
11678 ecm_db_connection_deref(ci);
11679 ci = cin;
11680 }
11681 DEBUG_INFO("%p: Defuncting to node's nat connection list complete\n", node);
11682}
Murat Sezgin8c345822015-05-27 15:35:38 -070011683#endif
Murat Sezgin1134fb82015-10-06 14:03:49 -070011684
11685/*
11686 * ecm_db_connection_ipv6_from_ct_get_and_ref()
11687 * Return, if any, a connection given a ct
11688 */
11689struct ecm_db_connection_instance *ecm_db_connection_ipv6_from_ct_get_and_ref(struct nf_conn *ct)
11690{
11691 struct nf_conntrack_tuple orig_tuple;
11692 struct nf_conntrack_tuple reply_tuple;
11693 ip_addr_t host1_addr;
11694 ip_addr_t host2_addr;
11695 int host1_port;
11696 int host2_port;
11697 int protocol;
11698
11699 /*
11700 * Look up the associated connection for this conntrack connection
11701 */
11702 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
11703 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
11704 ECM_NIN6_ADDR_TO_IP_ADDR(host1_addr, orig_tuple.src.u3.in6);
11705 ECM_NIN6_ADDR_TO_IP_ADDR(host2_addr, reply_tuple.src.u3.in6);
11706 protocol = orig_tuple.dst.protonum;
11707 if (protocol == IPPROTO_TCP) {
11708 host1_port = ntohs(orig_tuple.src.u.tcp.port);
11709 host2_port = ntohs(reply_tuple.src.u.tcp.port);
11710 } else if (protocol == IPPROTO_UDP) {
11711 host1_port = ntohs(orig_tuple.src.u.udp.port);
11712 host2_port = ntohs(reply_tuple.src.u.udp.port);
11713 } else if ((protocol == IPPROTO_IPIP)) {
11714 host1_port = 0;
11715 host2_port = 0;
11716 } else {
11717 host1_port = -protocol;
11718 host2_port = -protocol;
11719 }
11720
11721 DEBUG_TRACE("%p: lookup src: " ECM_IP_ADDR_OCTAL_FMT ":%d, "
11722 "dest: " ECM_IP_ADDR_OCTAL_FMT ":%d, "
11723 "protocol %d\n",
11724 ct,
11725 ECM_IP_ADDR_TO_OCTAL(host1_addr),
11726 host1_port,
11727 ECM_IP_ADDR_TO_OCTAL(host2_addr),
11728 host2_port,
11729 protocol);
11730
11731 return ecm_db_connection_find_and_ref(host1_addr,
11732 host2_addr,
11733 protocol,
11734 host1_port,
11735 host2_port);
11736}
11737
11738/*
11739 * ecm_db_connection_ipv4_from_ct_get_and_ref()
11740 * Return, if any, a connection given a ct
11741 */
11742struct ecm_db_connection_instance *ecm_db_connection_ipv4_from_ct_get_and_ref(struct nf_conn *ct)
11743{
11744 struct nf_conntrack_tuple orig_tuple;
11745 struct nf_conntrack_tuple reply_tuple;
11746 ip_addr_t host1_addr;
11747 ip_addr_t host2_addr;
11748 int host1_port;
11749 int host2_port;
11750 int protocol;
11751
11752 /*
11753 * Look up the associated connection for this conntrack connection
11754 */
11755 orig_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
11756 reply_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
11757 ECM_NIN4_ADDR_TO_IP_ADDR(host1_addr, orig_tuple.src.u3.ip);
11758 ECM_NIN4_ADDR_TO_IP_ADDR(host2_addr, reply_tuple.src.u3.ip);
11759 protocol = orig_tuple.dst.protonum;
11760 if (protocol == IPPROTO_TCP) {
11761 host1_port = ntohs(orig_tuple.src.u.tcp.port);
11762 host2_port = ntohs(reply_tuple.src.u.tcp.port);
11763 } else if (protocol == IPPROTO_UDP) {
11764 host1_port = ntohs(orig_tuple.src.u.udp.port);
11765 host2_port = ntohs(reply_tuple.src.u.udp.port);
11766 } else if ((protocol == IPPROTO_IPV6) || (protocol == IPPROTO_ESP)) {
11767 host1_port = 0;
11768 host2_port = 0;
11769 } else {
11770 host1_port = -protocol;
11771 host2_port = -protocol;
11772 }
11773
11774 DEBUG_TRACE("%p: lookup src: " ECM_IP_ADDR_DOT_FMT ":%d, "
11775 "dest: " ECM_IP_ADDR_DOT_FMT ":%d, "
11776 "protocol %d\n",
11777 ct,
11778 ECM_IP_ADDR_TO_DOT(host1_addr),
11779 host1_port,
11780 ECM_IP_ADDR_TO_DOT(host2_addr),
11781 host2_port,
11782 protocol);
11783
11784 return ecm_db_connection_find_and_ref(host1_addr,
11785 host2_addr,
11786 protocol,
11787 host1_port,
11788 host2_port);
11789}
11790 /*
11791 * ecm_db_iproute_connection_cmp()
11792 * This is the "iterate" function passed to the nf_ct_iterate_cleanup()
11793 * function.
11794 */
11795static int ecm_db_iproute_connection_cmp(struct nf_conn *i, void *data)
11796{
11797 struct ecm_db_connection_instance *ci;
11798
11799 /*
11800 * Go through the conntarck entries and if they are found in ECM db,
11801 * decelerate and defunct the connection.
11802 */
11803 ci = ecm_db_connection_ipv4_from_ct_get_and_ref(i);
11804 if (ci) {
11805 ecm_db_connection_decelerate_and_defunct(ci);
11806 ecm_db_connection_deref(ci);
11807 }
11808
11809 return 0;
11810}
11811
11812/*
11813 * ecm_db_iproute_table_update_event()
11814 * This is a call back for "routing table update event for IPv4"
11815 */
11816static int ecm_db_iproute_table_update_event(struct notifier_block *nb,
11817 unsigned long event,
11818 void *ptr)
11819{
11820 DEBUG_TRACE("iproute table update event\n");
11821
11822#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 0))
11823 nf_ct_iterate_cleanup(&init_net, ecm_db_iproute_connection_cmp, 0);
11824#else
11825 nf_ct_iterate_cleanup(&init_net, ecm_db_iproute_connection_cmp, 0, 0, 0);
11826#endif
11827 return NOTIFY_DONE;
11828}
11829
11830static struct notifier_block ecm_db_iproute_table_update_nb = {
11831 .notifier_call = ecm_db_iproute_table_update_event,
11832};
11833
11834 /*
11835 * ecm_db_ip6route_connection_cmp()
11836 * This is the "iterate" function passed to the nf_ct_iterate_cleanup()
11837 * function.
11838 */
11839static int ecm_db_ip6route_connection_cmp(struct nf_conn *i, void *data)
11840{
11841 struct ecm_db_connection_instance *ci;
11842
11843 /*
11844 * Go through the conntarck entries and if they are found in ECM db,
11845 * decelerate and defunct the connection.
11846 */
11847 ci = ecm_db_connection_ipv6_from_ct_get_and_ref(i);
11848 if (ci) {
11849 ecm_db_connection_decelerate_and_defunct(ci);
11850 ecm_db_connection_deref(ci);
11851 }
11852
11853 return 0;
11854}
11855
11856/*
11857 * ecm_db_ip6route_table_update_event()
11858 * This is a call back for "routing table update event for IPv6"
11859 */
11860static int ecm_db_ip6route_table_update_event(struct notifier_block *nb,
11861 unsigned long event,
11862 void *ptr)
11863{
11864 DEBUG_TRACE("ip6route table update event\n");
11865
11866#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 0))
11867 nf_ct_iterate_cleanup(&init_net, ecm_db_ip6route_connection_cmp, 0);
11868#else
11869 nf_ct_iterate_cleanup(&init_net, ecm_db_ip6route_connection_cmp, 0, 0, 0);
11870#endif
11871 return NOTIFY_DONE;
11872}
11873
11874static struct notifier_block ecm_db_ip6route_table_update_nb = {
11875 .notifier_call = ecm_db_ip6route_table_update_event,
11876};
11877
ratheesh kannoth37e35b02015-03-26 11:25:02 +053011878/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011879 * ecm_db_init()
Ben Menchaca84f36632014-02-28 20:57:38 +000011880 */
Murat Sezgin908ecb32015-05-10 20:54:36 -070011881int ecm_db_init(struct dentry *dentry)
Ben Menchaca84f36632014-02-28 20:57:38 +000011882{
Nicolas Costaf46c33b2014-05-15 10:02:00 -050011883 DEBUG_INFO("ECM Module init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +000011884
Murat Sezgin908ecb32015-05-10 20:54:36 -070011885 ecm_db_dentry = debugfs_create_dir("ecm_db", dentry);
11886 if (!ecm_db_dentry) {
11887 DEBUG_ERROR("Failed to create ecm db directory in debugfs\n");
11888 return -1;
11889 }
Ben Menchaca84f36632014-02-28 20:57:38 +000011890
11891 /*
Gareth Williams54d15d92015-04-24 19:28:27 +010011892 * Get a random seed for jhash()
11893 */
11894 get_random_bytes(&ecm_db_jhash_rnd, sizeof(ecm_db_jhash_rnd));
11895 DEBUG_INFO("jhash random seed: %u\n", ecm_db_jhash_rnd);
11896
Murat Sezgin908ecb32015-05-10 20:54:36 -070011897 if (!debugfs_create_u32("connection_count", S_IRUGO, ecm_db_dentry,
11898 (u32 *)&ecm_db_connection_count)) {
11899 DEBUG_ERROR("Failed to create ecm db connection count file in debugfs\n");
11900 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000011901 }
11902
Murat Sezgin908ecb32015-05-10 20:54:36 -070011903 if (!debugfs_create_u32("host_count", S_IRUGO, ecm_db_dentry,
11904 (u32 *)&ecm_db_host_count)) {
11905 DEBUG_ERROR("Failed to create ecm db host count file in debugfs\n");
11906 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000011907 }
11908
Murat Sezgin908ecb32015-05-10 20:54:36 -070011909 if (!debugfs_create_u32("mapping_count", S_IRUGO, ecm_db_dentry,
11910 (u32 *)&ecm_db_mapping_count)) {
11911 DEBUG_ERROR("Failed to create ecm db mapping count file in debugfs\n");
11912 goto init_cleanup;
11913 }
11914
11915 if (!debugfs_create_u32("node_count", S_IRUGO, ecm_db_dentry,
11916 (u32 *)&ecm_db_node_count)) {
11917 DEBUG_ERROR("Failed to create ecm db node count file in debugfs\n");
11918 goto init_cleanup;
11919 }
11920
11921 if (!debugfs_create_u32("iface_count", S_IRUGO, ecm_db_dentry,
11922 (u32 *)&ecm_db_iface_count)) {
11923 DEBUG_ERROR("Failed to create ecm db iface count file in debugfs\n");
11924 goto init_cleanup;
11925 }
11926
11927 if (!debugfs_create_file("defunct_all", S_IRUGO | S_IWUSR, ecm_db_dentry,
11928 NULL, &ecm_db_defunct_all_fops)) {
11929 DEBUG_ERROR("Failed to create ecm db defunct_all file in debugfs\n");
11930 goto init_cleanup;
11931 }
11932
11933 if (!debugfs_create_file("connection_count_simple", S_IRUGO, ecm_db_dentry,
11934 NULL, &ecm_db_connection_count_simple_fops)) {
11935 DEBUG_ERROR("Failed to create ecm db connection count simple file in debugfs\n");
11936 goto init_cleanup;
Ben Menchaca84f36632014-02-28 20:57:38 +000011937 }
11938
11939 /*
Ben Menchaca84f36632014-02-28 20:57:38 +000011940 * Set a timer to manage cleanup of expired connections
11941 */
11942 init_timer(&ecm_db_timer);
11943 ecm_db_timer.function = ecm_db_timer_callback;
11944 ecm_db_timer.data = 0;
11945 ecm_db_timer.expires = jiffies + HZ;
11946 add_timer(&ecm_db_timer);
11947
11948 /*
11949 * Initialise timer groups with time values
11950 */
11951 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].time = ECM_DB_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
11952 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
11953 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_GENERIC_TIMEOUT;
11954 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT;
11955 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].time = ECM_DB_CONNECTION_IGMP_TIMEOUT;
11956 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT;
11957 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
11958 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT;
11959 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
11960 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT;
11961 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].time = ECM_DB_CONNECTION_ICMP_TIMEOUT;
11962 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT;
11963 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].time = ECM_DB_CONNECTION_TCP_SHORT_TIMEOUT;
11964 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT;
11965 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].time = ECM_DB_CONNECTION_TCP_RST_TIMEOUT;
11966 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT;
11967 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
11968 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT;
11969 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].time = ECM_DB_CONNECTION_PPTP_DATA_TIMEOUT;
11970 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT;
11971 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].time = ECM_DB_CONNECTION_RTCP_TIMEOUT;
11972 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT;
11973 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
11974 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT;
11975 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_FAST_TIMEOUT;
11976 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT;
11977 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_SLOW_TIMEOUT;
11978 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT;
11979 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].time = ECM_DB_CONNECTION_DNS_TIMEOUT;
11980 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT;
11981 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].time = ECM_DB_CONNECTION_FTP_TIMEOUT;
11982 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT;
11983 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].time = ECM_DB_CONNECTION_BITTORRENT_TIMEOUT;
11984 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT;
11985
11986 /*
11987 * H323 timeout value is 8 hours (8h * 60m * 60s == 28800 seconds).
11988 */
11989 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].time = ECM_DB_CONNECTION_H323_TIMEOUT;
11990 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT;
11991
11992 /*
11993 * IKE Timeout (seconds) = 15 hours
11994 */
11995 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].time = ECM_DB_CONNECTION_IKE_TIMEOUT;
11996 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT;
11997
11998 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].time = ECM_DB_CONNECTION_ESP_TIMEOUT;
11999 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT;
12000 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].time = ECM_DB_CONNECTION_ESP_PENDING_TIMEOUT;
12001 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT;
12002
12003 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].time = ECM_DB_CONNECTION_SDP_TIMEOUT;
12004 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT;
12005 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].time = ECM_DB_CONNECTION_SIP_TIMEOUT;
12006 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT;
12007
12008 /*
12009 * Reset connection by protocol counters
12010 */
12011 memset(ecm_db_connection_count_by_protocol, 0, sizeof(ecm_db_connection_count_by_protocol));
12012
Gareth Williamsb39e7c22015-03-25 10:15:33 +000012013#ifdef ECM_DB_CTA_TRACK_ENABLE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010012014 /*
12015 * Reset classifier type assignment lists
12016 */
12017 memset(ecm_db_connection_classifier_type_assignments, 0, sizeof(ecm_db_connection_classifier_type_assignments));
Gareth Williamsb39e7c22015-03-25 10:15:33 +000012018#endif
Murat Sezgin1134fb82015-10-06 14:03:49 -070012019 /*
12020 * register for route table modification events
12021 */
12022 ip_rt_register_notifier(&ecm_db_iproute_table_update_nb);
12023 rt6_register_notifier(&ecm_db_ip6route_table_update_nb);
12024
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012025 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +000012026
Murat Sezgin908ecb32015-05-10 20:54:36 -070012027init_cleanup:
Ben Menchaca84f36632014-02-28 20:57:38 +000012028
Murat Sezgin908ecb32015-05-10 20:54:36 -070012029 debugfs_remove_recursive(ecm_db_dentry);
12030 return -1;
Ben Menchaca84f36632014-02-28 20:57:38 +000012031}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012032EXPORT_SYMBOL(ecm_db_init);
Ben Menchaca84f36632014-02-28 20:57:38 +000012033
12034/*
12035 * ecm_db_exit()
12036 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012037void ecm_db_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +000012038{
12039 DEBUG_INFO("ECM DB Module exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012040
12041 spin_lock_bh(&ecm_db_lock);
12042 ecm_db_terminate_pending = true;
12043 spin_unlock_bh(&ecm_db_lock);
12044
12045 ecm_db_connection_defunct_all();
12046
12047 /*
12048 * Destroy garbage timer
12049 * Timer must be cancelled outside of holding db lock - if the
12050 * timer callback runs on another CPU we would deadlock
12051 * as we would wait for the callback to finish and it would wait
12052 * indefinately for the lock to be released!
12053 */
12054 del_timer_sync(&ecm_db_timer);
Murat Sezgin1f381852014-11-20 09:51:07 -080012055
Murat Sezgin908ecb32015-05-10 20:54:36 -070012056 /*
12057 * Remove the debugfs files recursively.
12058 */
12059 if (ecm_db_dentry) {
12060 debugfs_remove_recursive(ecm_db_dentry);
Murat Sezgin1f381852014-11-20 09:51:07 -080012061 }
Murat Sezgin1134fb82015-10-06 14:03:49 -070012062
12063 /*
12064 * unregister for route table update events
12065 */
12066 ip_rt_unregister_notifier(&ecm_db_iproute_table_update_nb);
12067 rt6_unregister_notifier(&ecm_db_ip6route_table_update_nb);
Ben Menchaca84f36632014-02-28 20:57:38 +000012068}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050012069EXPORT_SYMBOL(ecm_db_exit);