blob: 2636522c21d825376915c54b57d5de03f47153f6 [file] [log] [blame]
Ben Menchaca84f36632014-02-28 20:57:38 +00001/*
2 **************************************************************************
3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
4 * 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>
24#include <linux/sysctl.h>
25#include <linux/kthread.h>
Murat Sezgin1f381852014-11-20 09:51:07 -080026#include <linux/device.h>
Ben Menchaca84f36632014-02-28 20:57:38 +000027#include <linux/fs.h>
28#include <linux/pkt_sched.h>
29#include <linux/string.h>
30#include <net/route.h>
31#include <net/ip.h>
32#include <net/tcp.h>
33#include <asm/unaligned.h>
34#include <asm/uaccess.h> /* for put_user */
35#include <net/ipv6.h>
36#include <linux/inet.h>
37#include <linux/in.h>
38#include <linux/udp.h>
39#include <linux/tcp.h>
40
41#include <linux/netfilter_ipv4.h>
42#include <linux/netfilter_bridge.h>
43#include <net/netfilter/nf_conntrack.h>
44#include <net/netfilter/nf_conntrack_helper.h>
45#include <net/netfilter/nf_conntrack_l4proto.h>
46#include <net/netfilter/nf_conntrack_l3proto.h>
47#include <net/netfilter/nf_conntrack_core.h>
48#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
49#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
50
51/*
52 * Debug output levels
53 * 0 = OFF
54 * 1 = ASSERTS / ERRORS
55 * 2 = 1 + WARN
56 * 3 = 2 + INFO
57 * 4 = 3 + TRACE
58 */
59#define DEBUG_LEVEL ECM_DB_DEBUG_LEVEL
60
61#include <nss_api_if.h>
62
63#include "ecm_types.h"
64#include "ecm_db_types.h"
65#include "ecm_tracker.h"
66#include "ecm_classifier.h"
67#include "ecm_front_end_types.h"
68#include "ecm_classifier_default.h"
69#include "ecm_db.h"
70
71/*
72 * Magic numbers
73 */
74#define ECM_DB_CONNECTION_INSTANCE_MAGIC 0xff23
75#define ECM_DB_HOST_INSTANCE_MAGIC 0x2873
76#define ECM_DB_MAPPING_INSTANCE_MAGIC 0x8765
77#define ECM_DB_LISTENER_INSTANCE_MAGIC 0x9876
78#define ECM_DB_NODE_INSTANCE_MAGIC 0x3312
79#define ECM_DB_IFACE_INSTANCE_MAGIC 0xAEF1
80#define ECM_DB_STATE_FILE_INSTANCE_MAGIC 0xB3FE
Gareth Williamsdd6dfce2014-10-14 15:51:31 +010081#define ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC 0xAEF4
Ben Menchaca84f36632014-02-28 20:57:38 +000082
83/*
84 * Global lists.
85 * All instances are inserted into global list - this allows easy iteration of all instances of a particular type.
86 * The list is doubly linked for fast removal. The list is in no particular order.
87 */
88struct ecm_db_connection_instance *ecm_db_connections = NULL;
89struct ecm_db_mapping_instance *ecm_db_mappings = NULL;
90struct ecm_db_host_instance *ecm_db_hosts = NULL;
91struct ecm_db_node_instance *ecm_db_nodes = NULL;
92struct ecm_db_iface_instance *ecm_db_interfaces = NULL;
93
94/*
95 * Connection hash table
96 */
97#define ECM_DB_CONNECTION_HASH_SLOTS 32768
98static struct ecm_db_connection_instance *ecm_db_connection_table[ECM_DB_CONNECTION_HASH_SLOTS];
99 /* Slots of the connection hash table */
100static int ecm_db_connection_table_lengths[ECM_DB_CONNECTION_HASH_SLOTS];
101 /* Tracks how long each chain is */
102static int ecm_db_connection_count = 0; /* Number of connections allocated */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100103static int ecm_db_connection_serial = 0; /* Serial number - ensures each connection has a unique serial number.
Ben Menchaca84f36632014-02-28 20:57:38 +0000104 * Serial numbers are used mainly by classifiers that keep their own state
105 * and can 'link' their state to the right connection using a serial number.
106 * In the XML state files a key can be set up on serial for fast association between
107 * state data.
108 * 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
166/*
167 * Listeners
168 */
169static int ecm_db_listeners_count = 0; /* Number of listeners allocated */
170static struct ecm_db_listener_instance *ecm_db_listeners = NULL;
171 /* Event listeners */
172
173/*
174 * ecm_db_iface_xml_state_get_method_t
175 * Used to obtain interface XML state
176 */
177typedef int (*ecm_db_iface_xml_state_get_method_t)(struct ecm_db_iface_instance *ii, char *buf, int buf_sz);
178
179/*
180 * struct ecm_db_iface_instance
181 */
182struct ecm_db_iface_instance {
183 struct ecm_db_iface_instance *next; /* Next instance in global list */
184 struct ecm_db_iface_instance *prev; /* Previous instance in global list */
185 struct ecm_db_iface_instance *hash_next; /* Next Interface in the chain of Interfaces */
186 struct ecm_db_iface_instance *hash_prev; /* previous Interface in the chain of Interfaces */
187 ecm_db_iface_type_t type; /* RO: Type of interface */
188 struct ecm_db_node_instance *nodes; /* Nodes associated with this Interface */
189 int node_count; /* Number of Nodes in the nodes list */
190 uint32_t time_added; /* RO: DB time stamp when the Interface was added into the database */
191
192 int32_t interface_identifier; /* RO: The operating system dependent identifier of this interface */
193 int32_t nss_interface_identifier; /* RO: The NSS identifier of this interface */
194 char name[IFNAMSIZ]; /* Name of interface */
195 int32_t mtu; /* Interface MTU */
196
197 uint64_t from_data_total; /* Total of data sent by this Interface */
198 uint64_t to_data_total; /* Total of data sent to this Interface */
199 uint64_t from_packet_total; /* Total of packets sent by this Interface */
200 uint64_t to_packet_total; /* Total of packets sent to this Interface */
201 uint64_t from_data_total_dropped;
202 uint64_t to_data_total_dropped;
203 uint64_t from_packet_total_dropped;
204 uint64_t to_packet_total_dropped;
205
206 /*
207 * For convenience interfaces keep lists of connections that have been established
208 * from them and to them.
209 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
210 * Interfaces keep this information for rapid iteration of connections e.g. when an interface 'goes down' we
211 * can defunct all associated connections or destroy any NSS rules.
212 */
213 struct ecm_db_connection_instance *from_connections; /* list of connections made from this interface */
214 struct ecm_db_connection_instance *to_connections; /* list of connections made to this interface */
215
216 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this interface */
217 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this interface */
218
219 /*
220 * Interface specific information.
221 * type identifies which information is applicable.
222 */
223 union {
224 struct ecm_db_interface_info_ethernet ethernet; /* type == ECM_DB_IFACE_TYPE_ETHERNET */
225 struct ecm_db_interface_info_vlan vlan; /* type == ECM_DB_IFACE_TYPE_VLAN */
226 struct ecm_db_interface_info_lag lag; /* type == ECM_DB_IFACE_TYPE_LAG */
227 struct ecm_db_interface_info_bridge bridge; /* type == ECM_DB_IFACE_TYPE_BRIDGE */
228 struct ecm_db_interface_info_pppoe pppoe; /* type == ECM_DB_IFACE_TYPE_PPPOE */
229 struct ecm_db_interface_info_unknown unknown; /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
230 struct ecm_db_interface_info_loopback loopback; /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
231 struct ecm_db_interface_info_ipsec_tunnel ipsec_tunnel; /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
232 struct ecm_db_interface_info_sit sit; /* type == ECM_DB_IFACE_TYPE_SIT (6-in-4) */
233 struct ecm_db_interface_info_tunipip6 tunipip6; /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 (IPIP v6 Tunnel i.e. TUNNEL6) */
234 } type_info;
235
236 ecm_db_iface_xml_state_get_method_t xml_state_get; /* Type specific state method to return XML state for it */
237
238 ecm_db_iface_final_callback_t final; /* Callback to owner when object is destroyed */
239 void *arg; /* Argument returned to owner in callbacks */
240 uint32_t flags;
241 int refs; /* Integer to trap we never go negative */
242 ecm_db_iface_hash_t hash_index;
243#if (DEBUG_LEVEL > 0)
244 uint16_t magic;
245#endif
246};
247
248/*
249 * Interface flags
250 */
251#define ECM_DB_IFACE_FLAGS_INSERTED 1 /* Interface is inserted into connection database tables */
252
253/*
254 * struct ecm_db_node_instance
255 */
256struct ecm_db_node_instance {
257 struct ecm_db_node_instance *next; /* Next instance in global list */
258 struct ecm_db_node_instance *prev; /* Previous instance in global list */
Gareth Williams90f2a282014-08-27 15:56:25 +0100259 struct ecm_db_node_instance *hash_next; /* Next node in the chain of nodes */
260 struct ecm_db_node_instance *hash_prev; /* previous node in the chain of nodes */
Ben Menchaca84f36632014-02-28 20:57:38 +0000261 uint8_t address[ETH_ALEN]; /* RO: MAC Address of this node */
Gareth Williams90f2a282014-08-27 15:56:25 +0100262
263 /*
264 * For convenience nodes keep lists of connections that have been established from them and to them.
265 * In fact the same connection could be listed as from & to on the same interface (think: WLAN<>WLAN AP function)
266 * Nodes keep this information for rapid iteration of connections e.g. when a node 'goes down' we
267 * can defunct all associated connections or destroy any NSS rules.
268 */
269 struct ecm_db_connection_instance *from_connections; /* list of connections made from this node */
270 struct ecm_db_connection_instance *to_connections; /* list of connections made to this node */
271 int from_connections_count; /* Number of connections in the from_connections list */
272 int to_connections_count; /* Number of connections in the to_connections list */
273
274 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this node */
275 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this node */
276 int from_nat_connections_count; /* Number of connections in the from_nat_connections list */
277 int to_nat_connections_count; /* Number of connections in the to_nat_connections list */
278
Ben Menchaca84f36632014-02-28 20:57:38 +0000279 uint32_t time_added; /* RO: DB time stamp when the node was added into the database */
280
281 uint64_t from_data_total; /* Total of data sent by this node */
282 uint64_t to_data_total; /* Total of data sent to this node */
283 uint64_t from_packet_total; /* Total of packets sent by this node */
284 uint64_t to_packet_total; /* Total of packets sent to this node */
285 uint64_t from_data_total_dropped;
286 uint64_t to_data_total_dropped;
287 uint64_t from_packet_total_dropped;
288 uint64_t to_packet_total_dropped;
289
290 struct ecm_db_iface_instance *iface; /* The interface to which this node relates */
291 struct ecm_db_node_instance *node_next; /* The next node within the same iface nodes list */
292 struct ecm_db_node_instance *node_prev; /* The previous node within the same iface nodes list */
293
294 ecm_db_node_final_callback_t final; /* Callback to owner when object is destroyed */
295 void *arg; /* Argument returned to owner in callbacks */
296 uint8_t flags;
297 int refs; /* Integer to trap we never go negative */
298 ecm_db_node_hash_t hash_index;
299#if (DEBUG_LEVEL > 0)
300 uint16_t magic;
301#endif
302};
303
304/*
305 * Node flags
306 */
307#define ECM_DB_NODE_FLAGS_INSERTED 1 /* Node is inserted into connection database tables */
308
309/*
310 * struct ecm_db_host_instance
311 */
312struct ecm_db_host_instance {
313 struct ecm_db_host_instance *next; /* Next instance in global list */
314 struct ecm_db_host_instance *prev; /* Previous instance in global list */
315 struct ecm_db_host_instance *hash_next; /* Next host in the chain of hosts */
316 struct ecm_db_host_instance *hash_prev; /* previous host in the chain of hosts */
317 ip_addr_t address; /* RO: IPv4/v6 Address of this host */
318 bool on_link; /* RO: false when this host is reached via a gateway */
319 struct ecm_db_mapping_instance *mappings; /* Mappings made on this host */
320 int mapping_count; /* Number of mappings in the mapping list */
321 uint32_t time_added; /* RO: DB time stamp when the host was added into the database */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530322
Ben Menchaca84f36632014-02-28 20:57:38 +0000323 uint64_t from_data_total; /* Total of data sent by this host */
324 uint64_t to_data_total; /* Total of data sent to this host */
325 uint64_t from_packet_total; /* Total of packets sent by this host */
326 uint64_t to_packet_total; /* Total of packets sent to this host */
327 uint64_t from_data_total_dropped;
328 uint64_t to_data_total_dropped;
329 uint64_t from_packet_total_dropped;
330 uint64_t to_packet_total_dropped;
331
332 ecm_db_host_final_callback_t final; /* Callback to owner when object is destroyed */
333 void *arg; /* Argument returned to owner in callbacks */
334 uint32_t flags;
335 int refs; /* Integer to trap we never go negative */
336 ecm_db_host_hash_t hash_index;
337#if (DEBUG_LEVEL > 0)
338 uint16_t magic;
339#endif
340};
341
342/*
343 * Host flags
344 */
345#define ECM_DB_HOST_FLAGS_INSERTED 1 /* Host is inserted into connection database tables */
346
347/*
348 * struct ecm_db_mapping_instance
349 */
350struct ecm_db_mapping_instance {
351 struct ecm_db_mapping_instance *next; /* Next instance in global list */
352 struct ecm_db_mapping_instance *prev; /* Previous instance in global list */
353
354 struct ecm_db_mapping_instance *hash_next; /* Next mapping in the chain of mappings */
355 struct ecm_db_mapping_instance *hash_prev; /* previous mapping in the chain of mappings */
356
357 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
358 struct ecm_db_host_instance *host; /* The host to which this mapping relates */
359 int port; /* RO: The port number on the host - only applicable for mapping protocols that are port based */
360 struct ecm_db_mapping_instance *mapping_next; /* Next mapping in the list of mappings for the host */
361 struct ecm_db_mapping_instance *mapping_prev; /* previous mapping in the list of mappings for the host */
362
363 struct ecm_db_connection_instance *from_connections; /* list of connections made from this host mapping */
364 struct ecm_db_connection_instance *to_connections; /* list of connections made to this host mapping */
365
366 struct ecm_db_connection_instance *from_nat_connections; /* list of NAT connections made from this host mapping */
367 struct ecm_db_connection_instance *to_nat_connections; /* list of NAT connections made to this host mapping */
368
369 /*
370 * Connection counts
371 */
372 int tcp_from;
373 int tcp_to;
374 int udp_from;
375 int udp_to;
376 int tcp_nat_from;
377 int tcp_nat_to;
378 int udp_nat_from;
379 int udp_nat_to;
380
381 /*
382 * Total counts
383 */
384 int from;
385 int to;
386 int nat_from;
387 int nat_to;
388
389 /*
390 * Data totals
391 */
392 uint64_t from_data_total; /* Total of data sent by this mapping */
393 uint64_t to_data_total; /* Total of data sent to this mapping */
394 uint64_t from_packet_total; /* Total of packets sent by this mapping */
395 uint64_t to_packet_total; /* Total of packets sent to this mapping */
396 uint64_t from_data_total_dropped;
397 uint64_t to_data_total_dropped;
398 uint64_t from_packet_total_dropped;
399 uint64_t to_packet_total_dropped;
400
401 ecm_db_mapping_final_callback_t final; /* Callback to owner when object is destroyed */
402 void *arg; /* Argument returned to owner in callbacks */
403 uint32_t flags;
404 int refs; /* Integer to trap we never go negative */
405 ecm_db_mapping_hash_t hash_index;
406#if (DEBUG_LEVEL > 0)
407 uint16_t magic;
408#endif
409};
410
411/*
412 * Mapping flags
413 */
414#define ECM_DB_MAPPING_FLAGS_INSERTED 1 /* Mapping is inserted into connection database tables */
415
416/*
417 * struct ecm_db_timer_group
418 * A timer group - all group members within the same group have the same TTL reset value.
419 *
420 * Expiry of entries occurs from tail to head.
421 */
422struct ecm_db_timer_group {
423 struct ecm_db_timer_group_entry *head; /* Most recently used entry in this timer group */
424 struct ecm_db_timer_group_entry *tail; /* Least recently used entry in this timer group. */
425 uint32_t time; /* Time in seconds a group entry will be given to live when 'touched' */
426 ecm_db_timer_group_t tg; /* RO: The group id */
427#if (DEBUG_LEVEL > 0)
428 uint16_t magic;
429#endif
430};
431
432/*
433 * Timers and cleanup
434 */
435static uint32_t ecm_db_time = 0; /* Time in seconds since start */
436static struct ecm_db_timer_group ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_MAX];
437 /* Timer groups */
438static struct timer_list ecm_db_timer; /* Timer to drive timer groups */
439
440/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100441 * Classifier assignments
442 *
443 * Each connection has a list of classifier instances that are assigned to it. Only one instance of each type may be assigned to a connection at any time.
444 * These structures store, in a list, all connections that are assigned to a TYPE of classifier.
445 * This allows iterating of all connections that are currently assigned to a classifier TYPE.
446 */
447struct ecm_db_connection_classifier_type_assignment {
448 struct ecm_db_connection_instance *next; /* Next connection assigned to a classifier of this type */
449 struct ecm_db_connection_instance *prev; /* Previous connection assigned to a classifier of this type */
450 int iteration_count; /* >0 if something is examining this list entry and it may not be unlinked. The connection will persist. */
451 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 */
452#if (DEBUG_LEVEL > 0)
453 uint16_t magic;
454#endif
455};
456struct ecm_db_connection_classifier_type_assignment_list {
457 struct ecm_db_connection_instance *type_assignments_list;
458 /* Lists of connections assigned to this type of classifier */
459 int32_t type_assignment_count; /* Number of connections in the list */
460} ecm_db_connection_classifier_type_assignments[ECM_CLASSIFIER_TYPES];
461 /* Each classifier type has a list of connections that are assigned to classifier instances of that type */
462
463/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000464 * struct ecm_db_connection_instance
465 */
466struct ecm_db_connection_instance {
467 struct ecm_db_connection_instance *next; /* Next instance in global list */
468 struct ecm_db_connection_instance *prev; /* Previous instance in global list */
469
470 struct ecm_db_connection_instance *hash_next; /* Next connection in chain */
471 struct ecm_db_connection_instance *hash_prev; /* Previous connection in chain */
472 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 +0530473
Ben Menchaca84f36632014-02-28 20:57:38 +0000474 struct ecm_db_connection_instance *serial_hash_next; /* Next connection in serial hash chain */
475 struct ecm_db_connection_instance *serial_hash_prev; /* Previous connection in serial hash chain */
476 ecm_db_connection_hash_t serial_hash_index; /* The hash table slot whose chain of connections this is inserted into */
477
478 uint32_t time_added; /* RO: DB time stamp when the connection was added into the database */
479
480 int protocol; /* RO: Protocol of the connection */
481 ecm_db_direction_t direction; /* RO: 'Direction' of connection establishment. */
482 bool is_routed; /* RO: True when connection is routed, false when not */
483
484 /*
485 * Connection endpoint mapping
486 */
487 struct ecm_db_mapping_instance *mapping_from; /* The connection was established from this mapping */
488 struct ecm_db_mapping_instance *mapping_to; /* The connection was established to this mapping */
489 struct ecm_db_connection_instance *from_next; /* Next connection made from the same mapping */
490 struct ecm_db_connection_instance *from_prev; /* Previous connection made from the same mapping */
491 struct ecm_db_connection_instance *to_next; /* Next connection made to the same mapping */
492 struct ecm_db_connection_instance *to_prev; /* Previous connection made to the same mapping */
493
494 /*
495 * Connection endpoint mapping for NAT purposes
496 * NOTE: For non-NAT connections these would be identical to the endpoint mappings.
497 */
498 struct ecm_db_mapping_instance *mapping_nat_from; /* The connection was established from this mapping */
499 struct ecm_db_mapping_instance *mapping_nat_to; /* The connection was established to this mapping */
500 struct ecm_db_connection_instance *from_nat_next; /* Next connection made from the same mapping */
501 struct ecm_db_connection_instance *from_nat_prev; /* Previous connection made from the same mapping */
502 struct ecm_db_connection_instance *to_nat_next; /* Next connection made to the same mapping */
503 struct ecm_db_connection_instance *to_nat_prev; /* Previous connection made to the same mapping */
504
505 /*
506 * Connection endpoint interface
Gareth Williams90f2a282014-08-27 15:56:25 +0100507 * GGG TODO Deprecated - use interface lists instead. To be removed.
Ben Menchaca84f36632014-02-28 20:57:38 +0000508 */
509 struct ecm_db_connection_instance *iface_from_next; /* Next connection made from the same interface */
510 struct ecm_db_connection_instance *iface_from_prev; /* Previous connection made from the same interface */
511 struct ecm_db_connection_instance *iface_to_next; /* Next connection made to the same interface */
512 struct ecm_db_connection_instance *iface_to_prev; /* Previous connection made to the same interface */
513
514 /*
515 * Connection endpoint interface for NAT purposes
516 * NOTE: For non-NAT connections these would be identical to the endpoint interface.
Gareth Williams90f2a282014-08-27 15:56:25 +0100517 * GGG TODO Deprecated - use interface lists instead. To be removed.
Ben Menchaca84f36632014-02-28 20:57:38 +0000518 */
519 struct ecm_db_connection_instance *iface_from_nat_next; /* Next connection made from the same interface */
520 struct ecm_db_connection_instance *iface_from_nat_prev; /* Previous connection made from the same interface */
521 struct ecm_db_connection_instance *iface_to_nat_next; /* Next connection made to the same interface */
522 struct ecm_db_connection_instance *iface_to_nat_prev; /* Previous connection made to the same interface */
523
524 /*
525 * From / To interfaces list
526 */
527 struct ecm_db_iface_instance *from_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
528 /* The outermost to innnermost interface this connection is using in the from path.
529 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
530 */
531 int32_t from_interface_first; /* The index of the first interface in the list */
532 bool from_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
533 struct ecm_db_iface_instance *to_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
534 /* The outermost to innnermost interface this connection is using in the to path */
535 int32_t to_interface_first; /* The index of the first interface in the list */
536 bool to_interface_set; /* True when a list has been set - even if there is NO list, it's still deliberately set that way. */
537
538 /*
539 * From / To NAT interfaces list
Gareth Williams90f2a282014-08-27 15:56:25 +0100540 * GGG TODO Not sure if NAT interface lists are necessary or appropriate or practical.
541 * Needs to be assessed if it gives any clear benefit and possibly remove these if not.
Ben Menchaca84f36632014-02-28 20:57:38 +0000542 */
543 struct ecm_db_iface_instance *from_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
544 /* The outermost to innnermost interface this connection is using in the from path.
545 * Relationships are recorded from [ECM_DB_IFACE_HEIRARCHY_MAX - 1] to [0]
546 */
547 int32_t from_nat_interface_first; /* The index of the first interface in the list */
548 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. */
549 struct ecm_db_iface_instance *to_nat_interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
550 /* The outermost to innnermost interface this connection is using in the to path */
551 int32_t to_nat_interface_first; /* The index of the first interface in the list */
552 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. */
553
554 /*
Gareth Williams90f2a282014-08-27 15:56:25 +0100555 * From / To Node
556 */
557 struct ecm_db_node_instance *from_node; /* Node from which this connection was established */
558 struct ecm_db_node_instance *to_node; /* Node to which this connection was established */
559 struct ecm_db_connection_instance *node_from_next; /* Next connection in the nodes from_connections list */
560 struct ecm_db_connection_instance *node_from_prev; /* Prev connection in the nodes from_connections list */
561 struct ecm_db_connection_instance *node_to_next; /* Next connection in the nodes to_connections list */
562 struct ecm_db_connection_instance *node_to_prev; /* Prev connection in the nodes to_connections list */
563
564 /*
565 * From / To Node (NAT)
566 * GGG TODO Evaluate this, these may not be beneficial. Added in for now for completeness.
567 */
568 struct ecm_db_node_instance *from_nat_node; /* Node from which this connection was established */
569 struct ecm_db_node_instance *to_nat_node; /* Node to which this connection was established */
570 struct ecm_db_connection_instance *node_from_nat_next; /* Next connection in the nodes from_nat_connections list */
571 struct ecm_db_connection_instance *node_from_nat_prev; /* Prev connection in the nodes from_nat_connections list */
572 struct ecm_db_connection_instance *node_to_nat_next; /* Next connection in the nodes to_nat_connections list */
573 struct ecm_db_connection_instance *node_to_nat_prev; /* Prev connection in the nodes to_nat_connections list */
574
575 /*
Ben Menchaca84f36632014-02-28 20:57:38 +0000576 * Time values in seconds
577 */
578 struct ecm_db_timer_group_entry defunct_timer; /* Used to defunct the connection on inactivity */
579
580 /*
581 * Byte and packet counts
582 */
583 uint64_t from_data_total; /* Totals of data as sent by the 'from' side of this connection */
584 uint64_t to_data_total; /* Totals of data as sent by the 'to' side of this connection */
585 uint64_t from_packet_total; /* Totals of packets as sent by the 'from' side of this connection */
586 uint64_t to_packet_total; /* Totals of packets as sent by the 'to' side of this connection */
587 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 */
588 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 */
589 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 */
590 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 */
591
592 /*
593 * Classifiers attached to this connection
594 */
Ben Menchaca84f36632014-02-28 20:57:38 +0000595 struct ecm_classifier_instance *assignments; /* A list of all classifiers that are still assigned to this connection.
596 * When a connection is created, instances of every type of classifier are assigned to the connection.
597 * Classifiers are added in ascending order of priority - so the most important processes a packet last.
598 * Classifiers may drop out of this list (become unassigned) at any time.
599 */
600 struct ecm_classifier_instance *assignments_by_type[ECM_CLASSIFIER_TYPES];
601 /* All assignments are also recorded in this array, since there can be only one of each type, this array allows
602 * rapid retrieval of a classifier type, saving having to iterate the assignments list.
603 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100604 struct ecm_db_connection_classifier_type_assignment type_assignment[ECM_CLASSIFIER_TYPES];
605 /* Each classifier TYPE has a list of connections that have a classifier instance (of that type) assigned to it */
606
Ben Menchaca84f36632014-02-28 20:57:38 +0000607 uint16_t classifier_generation; /* Used to detect when a re-evaluation of this connection is necessary */
Gareth Williamsda721272014-11-13 17:48:12 -0800608 uint32_t generations; /* Tracks how many times re-generation was seen for this connection */
Ben Menchaca84f36632014-02-28 20:57:38 +0000609 struct ecm_front_end_connection_instance *feci; /* Front end instance specific to this connection */
610
Murat Sezgin7f6cdf62014-09-11 13:41:06 -0700611 ecm_db_connection_defunct_callback_t defunct; /* Callback to be called when connection has become defunct */
Ben Menchaca84f36632014-02-28 20:57:38 +0000612 ecm_db_connection_final_callback_t final; /* Callback to owner when object is destroyed */
613 void *arg; /* Argument returned to owner in callbacks */
614
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100615 uint32_t serial; /* RO: Serial number for the connection - unique for run lifetime */
Ben Menchaca84f36632014-02-28 20:57:38 +0000616 uint32_t flags;
617 int refs; /* Integer to trap we never go negative */
618#if (DEBUG_LEVEL > 0)
619 uint16_t magic;
620#endif
621};
622
623/*
624 * Connection flags
625 */
626#define ECM_DB_CONNECTION_FLAGS_INSERTED 1 /* Connection is inserted into connection database tables */
627
628/*
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530629 * struct ecm_db_listener_instance
Ben Menchaca84f36632014-02-28 20:57:38 +0000630 * listener instances
631 */
632struct ecm_db_listener_instance {
633 struct ecm_db_listener_instance *next;
634 struct ecm_db_listener_instance *event_next;
635 uint32_t flags;
636 void *arg;
637 int refs; /* Integer to trap we never go negative */
638 ecm_db_mapping_final_callback_t final; /* Final callback for this instance */
639
640 ecm_db_iface_listener_added_callback_t iface_added;
641 ecm_db_iface_listener_removed_callback_t iface_removed;
642 ecm_db_node_listener_added_callback_t node_added;
643 ecm_db_node_listener_removed_callback_t node_removed;
644 ecm_db_host_listener_added_callback_t host_added;
645 ecm_db_host_listener_removed_callback_t host_removed;
646 ecm_db_mapping_listener_added_callback_t mapping_added;
647 ecm_db_mapping_listener_removed_callback_t mapping_removed;
648 ecm_db_connection_listener_added_callback_t connection_added;
649 ecm_db_connection_listener_removed_callback_t connection_removed;
650#if (DEBUG_LEVEL > 0)
651 uint16_t magic;
652#endif
653};
654
655/*
656 * Listener flags
657 */
658#define ECM_DB_LISTENER_FLAGS_INSERTED 1 /* Is inserted into database */
659
660/*
661 * Simple stats
662 */
663static int ecm_db_connection_count_by_protocol[256]; /* Each IP protocol has its own count */
664
665/*
666 * Locking of the database - concurrency control
667 */
668static spinlock_t ecm_db_lock; /* Protect the table from SMP access. */
669
670/*
671 * Connection validity
672 */
673static uint16_t ecm_db_classifier_generation = 0; /* Generation counter to detect out of date connections that should be reclassified */
674
675/*
Murat Sezgin1f381852014-11-20 09:51:07 -0800676 * System device linkage
Ben Menchaca84f36632014-02-28 20:57:38 +0000677 */
Murat Sezgin1f381852014-11-20 09:51:07 -0800678static struct device ecm_db_dev; /* System device linkage */
Ben Menchaca84f36632014-02-28 20:57:38 +0000679
680/*
681 * Management thread control
682 */
683static bool ecm_db_terminate_pending = false; /* When true the user has requested termination */
Ben Menchaca84f36632014-02-28 20:57:38 +0000684
685/*
686 * Character device stuff - used to communicate status back to user space
687 */
Gareth Williams72b43ed2014-05-14 18:23:43 +0100688#define ECM_DB_STATE_FILE_BUFFER_SIZE 8192
Ben Menchaca84f36632014-02-28 20:57:38 +0000689static int ecm_db_dev_major_id = 0; /* Major ID of registered char dev from which we can dump out state to userspace */
690
691#define ECM_DB_STATE_FILE_OUTPUT_CONNECTIONS 1
692#define ECM_DB_STATE_FILE_OUTPUT_MAPPINGS 2
693#define ECM_DB_STATE_FILE_OUTPUT_HOSTS 4
694#define ECM_DB_STATE_FILE_OUTPUT_NODES 8
695#define ECM_DB_STATE_FILE_OUTPUT_INTERFACES 16
696#define ECM_DB_STATE_FILE_OUTPUT_CONNECTIONS_CHAIN 32
697#define ECM_DB_STATE_FILE_OUTPUT_MAPPINGS_CHAIN 64
698#define ECM_DB_STATE_FILE_OUTPUT_HOSTS_CHAIN 128
699#define ECM_DB_STATE_FILE_OUTPUT_NODES_CHAIN 256
700#define ECM_DB_STATE_FILE_OUTPUT_INTERFACES_CHAIN 512
701#define ECM_DB_STATE_FILE_OUTPUT_PROTOCOL_COUNTS 1024
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100702#define ECM_DB_STATE_FILE_OUTPUT_CLASSIFIER_TYPE_ASSIGNMENTS 2048
703
704/*
705 * Assistive flags for classifier connection type assignments
706 */
707#define ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN 1
708#define ECM_DB_STATE_FILE_CTA_FLAG_CONTENT_UNWRITTEN 2
709#define ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN 4
Ben Menchaca84f36632014-02-28 20:57:38 +0000710
711/*
712 * struct ecm_db_state_file_instance
713 * Structure used as state per open instance of our db state file
714 */
715struct ecm_db_state_file_instance {
Gareth Williamsdd6dfce2014-10-14 15:51:31 +0100716 int output_mask; /* The content types wanted by the user */
717 struct ecm_db_connection_instance *ci; /* All connections list iterator */
718 struct ecm_db_mapping_instance *mi; /* All mappings list iterator */
719 struct ecm_db_host_instance *hi; /* All hosts list iterator */
720 struct ecm_db_node_instance *ni; /* All nodes list iterator */
721 struct ecm_db_iface_instance *ii; /* All interfaces list iterator */
722 struct ecm_db_connection_instance *classifier_type_assignments[ECM_CLASSIFIER_TYPES];
723 /* Classifier type connection assignments iterator, one for each classifier type */
724 int classifier_type_assignments_flags[ECM_CLASSIFIER_TYPES];
725 /* Classifier type connection assignments flags to assist the iteration */
726 int connection_hash_index; /* Connection hash table lengths iterator */
727 int mapping_hash_index; /* Mapping hash table lengths iterator */
728 int host_hash_index; /* Host hash table lengths iterator */
729 int node_hash_index; /* Node hash table lengths iterator */
730 int iface_hash_index; /* Interface hash table lengths iterator */
731 int protocol; /* Protocol connection count iterator */
732 bool doc_start_written; /* Has xml doc opening element been written? */
733 bool doc_end_written; /* Has xml doc closing element been written? */
Ben Menchaca84f36632014-02-28 20:57:38 +0000734 char msg_buffer[ECM_DB_STATE_FILE_BUFFER_SIZE]; /* Used to hold the current state message being output */
735 char *msgp; /* Points into the msg buffer as we output it piece by piece */
736 int msg_len; /* Length of the buffer still to be written out */
737#if (DEBUG_LEVEL > 0)
738 uint16_t magic;
739#endif
740};
741static int ecm_db_state_file_output_mask = ECM_DB_STATE_FILE_OUTPUT_CONNECTIONS;
742 /* Bit mask specifies which data to output in the state file */
743
744/*
745 * ecm_db_interface_type_names[]
746 * Array that maps the interface type to a string
747 */
748static char *ecm_db_interface_type_names[ECM_DB_IFACE_TYPE_COUNT] = {
749 "ETHERNET",
750 "PPPoE",
751 "LINK-AGGREGATION",
752 "VLAN",
753 "BRIDGE",
754 "LOOPBACK",
755 "IPSEC_TUNNEL",
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530756 "UNKNOWN",
Murat Sezginb3cc8792014-06-06 19:16:51 -0700757 "SIT",
758 "TUNIPIP6",
Ben Menchaca84f36632014-02-28 20:57:38 +0000759};
760
761/*
Gareth Williamsf28ba5f2015-02-13 11:07:28 +0000762 * ecm_db_connection_count_get()
763 * Return the connection count
764 */
765int ecm_db_connection_count_get(void)
766{
767 int count;
768
769 spin_lock_bh(&ecm_db_lock);
770 count = ecm_db_connection_count;
771 spin_unlock_bh(&ecm_db_lock);
772 return count;
773}
774EXPORT_SYMBOL(ecm_db_connection_count_get);
775
776/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000777 * ecm_db_interface_type_to_string()
778 * Return a string buffer containing the type name of the interface
779 */
780char *ecm_db_interface_type_to_string(ecm_db_iface_type_t type)
781{
782 DEBUG_ASSERT((type >= 0) && (type < ECM_DB_IFACE_TYPE_COUNT), "Invalid type: %d\n", type);
783 return ecm_db_interface_type_names[(int)type];
784}
785EXPORT_SYMBOL(ecm_db_interface_type_to_string);
786
787/*
788 * ecm_db_iface_nss_interface_identifier_get()
789 * Return the NSS interface number of this ecm interface
790 */
791int32_t ecm_db_iface_nss_interface_identifier_get(struct ecm_db_iface_instance *ii)
792{
793 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
794 return ii->nss_interface_identifier;
795}
796EXPORT_SYMBOL(ecm_db_iface_nss_interface_identifier_get);
797
798/*
Kiran Kumar C. S. K451b62e2014-05-19 20:34:06 +0530799 * ecm_db_iface_interface_identifier_get()
800 * Return the interface number of this ecm interface
801 */
802int32_t ecm_db_iface_interface_identifier_get(struct ecm_db_iface_instance *ii)
803{
804 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
805 return ii->interface_identifier;
806}
807EXPORT_SYMBOL(ecm_db_iface_interface_identifier_get);
808
809/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000810 * ecm_db_iface_mtu_reset()
811 * Reset the mtu
812 */
813int32_t ecm_db_iface_mtu_reset(struct ecm_db_iface_instance *ii, int32_t mtu)
814{
815 int32_t mtu_old;
816 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
817 spin_lock_bh(&ecm_db_lock);
818 mtu_old = ii->mtu;
819 ii->mtu = mtu;
820 spin_unlock_bh(&ecm_db_lock);
821 DEBUG_INFO("%p: Mtu change from %d to %d\n", ii, mtu_old, mtu);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530822
Ben Menchaca84f36632014-02-28 20:57:38 +0000823 return mtu_old;
824}
825EXPORT_SYMBOL(ecm_db_iface_mtu_reset);
826
827/*
828 * ecm_db_connection_front_end_get_and_ref()
829 * Return ref to the front end instance of the connection
830 */
831struct ecm_front_end_connection_instance *ecm_db_connection_front_end_get_and_ref(struct ecm_db_connection_instance *ci)
832{
833 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
834 ci->feci->ref(ci->feci);
835 return ci->feci;
836}
837EXPORT_SYMBOL(ecm_db_connection_front_end_get_and_ref);
838
839/*
840 * ecm_db_connection_defunct_callback()
841 * Invoked by the expiration of the defunct_timer contained in a connection instance
842 */
843static void ecm_db_connection_defunct_callback(void *arg)
844{
845 struct ecm_db_connection_instance *ci = (struct ecm_db_connection_instance *)arg;
846 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
847
848 DEBUG_INFO("%p: defunct timer expired\n", ci);
Gareth Williams2bfb0b82015-01-15 16:31:15 +0000849
850 if (ci->defunct) {
851 ci->defunct(ci->feci);
852 }
853
Ben Menchaca84f36632014-02-28 20:57:38 +0000854 ecm_db_connection_deref(ci);
855}
856
857/*
858 * ecm_db_connection_defunct_timer_reset()
859 * 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.
860 */
861bool ecm_db_connection_defunct_timer_reset(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg)
862{
863 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
864 return ecm_db_timer_group_entry_reset(&ci->defunct_timer, tg);
865}
866EXPORT_SYMBOL(ecm_db_connection_defunct_timer_reset);
867
868/*
869 * ecm_db_connection_defunct_timer_touch()
870 * Update the connections defunct timer to stop it timing out. Returns false if the connection defunct timer has expired.
871 */
872bool ecm_db_connection_defunct_timer_touch(struct ecm_db_connection_instance *ci)
873{
874 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
875 return ecm_db_timer_group_entry_touch(&ci->defunct_timer);
876}
877EXPORT_SYMBOL(ecm_db_connection_defunct_timer_touch);
878
879/*
880 * ecm_db_connection_timer_group_get()
881 * Return the timer group id
882 */
883ecm_db_timer_group_t ecm_db_connection_timer_group_get(struct ecm_db_connection_instance *ci)
884{
885 ecm_db_timer_group_t tg;
886 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
887
888 spin_lock_bh(&ecm_db_lock);
889 tg = ci->defunct_timer.group;
890 spin_unlock_bh(&ecm_db_lock);
891 return tg;
892}
893EXPORT_SYMBOL(ecm_db_connection_timer_group_get);
894
895/*
896 * ecm_db_connection_make_defunct()
897 * Make connection defunct.
898 */
899void ecm_db_connection_make_defunct(struct ecm_db_connection_instance *ci)
900{
901 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Murat Sezgin7f6cdf62014-09-11 13:41:06 -0700902
903 if (ci->defunct) {
904 ci->defunct(ci->feci);
905 }
906
Ben Menchaca84f36632014-02-28 20:57:38 +0000907 if (ecm_db_timer_group_entry_remove(&ci->defunct_timer)) {
908 ecm_db_connection_deref(ci);
909 }
910}
911EXPORT_SYMBOL(ecm_db_connection_make_defunct);
912
913/*
914 * ecm_db_connection_data_totals_update()
915 * Update the total data (and packets) sent/received by the given host
916 */
917void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
918{
919 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
920
921 spin_lock_bh(&ecm_db_lock);
922
923 if (is_from) {
924 /*
925 * Update totals sent by the FROM side of connection
926 */
927 ci->from_data_total += size;
928 ci->mapping_from->from_data_total += size;
929 ci->mapping_from->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100930 ci->from_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000931 ci->from_packet_total += packets;
932 ci->mapping_from->from_packet_total += packets;
933 ci->mapping_from->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100934 ci->from_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000935
936 /*
937 * Data from the host is essentially TO the interface on which the host is reachable
938 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100939 ci->from_node->iface->to_data_total += size;
940 ci->from_node->iface->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000941
942 /*
943 * Update totals sent TO the other side of the connection
944 */
945 ci->mapping_to->to_data_total += size;
946 ci->mapping_to->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100947 ci->to_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000948 ci->mapping_to->to_packet_total += packets;
949 ci->mapping_to->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100950 ci->to_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000951
952 /*
953 * Sending to the other side means FROM the interface we reach that host
954 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100955 ci->to_node->iface->from_data_total += size;
956 ci->to_node->iface->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000957 spin_unlock_bh(&ecm_db_lock);
958 return;
959 }
960
961 /*
962 * Update totals sent by the TO side of this connection
963 */
964 ci->to_data_total += size;
965 ci->mapping_to->from_data_total += size;
966 ci->mapping_to->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100967 ci->to_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000968 ci->to_packet_total += packets;
969 ci->mapping_to->from_packet_total += packets;
970 ci->mapping_to->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100971 ci->to_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000972
973 /*
974 * Data from the host is essentially TO the interface on which the host is reachable
975 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100976 ci->to_node->iface->to_data_total += size;
977 ci->to_node->iface->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000978
979 /*
980 * Update totals sent TO the other side of the connection
981 */
982 ci->mapping_from->to_data_total += size;
983 ci->mapping_from->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100984 ci->from_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000985 ci->mapping_from->to_packet_total += packets;
986 ci->mapping_from->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100987 ci->from_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000988
989 /*
990 * Sending to the other side means FROM the interface we reach that host
991 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100992 ci->from_node->iface->from_data_total += size;
993 ci->from_node->iface->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000994 spin_unlock_bh(&ecm_db_lock);
995}
996EXPORT_SYMBOL(ecm_db_connection_data_totals_update);
997
998/*
999 * ecm_db_connection_data_totals_update_dropped()
1000 * Update the total data (and packets) sent by the given host but which we dropped
1001 */
1002void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
1003{
1004 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
1005
1006 if (is_from) {
1007 /*
1008 * Update dropped totals sent by the FROM side
1009 */
1010 spin_lock_bh(&ecm_db_lock);
1011 ci->from_data_total_dropped += size;
1012 ci->mapping_from->from_data_total_dropped += size;
1013 ci->mapping_from->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001014 ci->from_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001015 ci->from_packet_total_dropped += packets;
1016 ci->mapping_from->from_packet_total_dropped += packets;
1017 ci->mapping_from->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001018 ci->from_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001019
1020 /*
1021 * Data from the host is essentially TO the interface on which the host is reachable
1022 */
Gareth Williams90f2a282014-08-27 15:56:25 +01001023 ci->from_node->iface->to_data_total_dropped += size;
1024 ci->from_node->iface->to_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001025 spin_unlock_bh(&ecm_db_lock);
1026 return;
1027 }
1028
1029 /*
1030 * Update dropped totals sent by the TO side of this connection
1031 */
1032 spin_lock_bh(&ecm_db_lock);
1033 ci->to_data_total_dropped += size;
1034 ci->mapping_to->from_data_total_dropped += size;
1035 ci->mapping_to->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001036 ci->to_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001037 ci->to_packet_total_dropped += packets;
1038 ci->mapping_to->from_packet_total_dropped += packets;
1039 ci->mapping_to->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001040 ci->to_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001041
1042 /*
1043 * Data from the host is essentially TO the interface on which the host is reachable
1044 */
Gareth Williams90f2a282014-08-27 15:56:25 +01001045 ci->to_node->iface->to_data_total_dropped += size;
1046 ci->to_node->iface->to_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001047 spin_unlock_bh(&ecm_db_lock);
1048}
1049EXPORT_SYMBOL(ecm_db_connection_data_totals_update_dropped);
1050
1051/*
1052 * ecm_db_connection_data_stats_get()
1053 * Return data stats for the instance
1054 */
1055void ecm_db_connection_data_stats_get(struct ecm_db_connection_instance *ci, uint64_t *from_data_total, uint64_t *to_data_total,
1056 uint64_t *from_packet_total, uint64_t *to_packet_total,
1057 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1058 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1059{
1060 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1061
1062 spin_lock_bh(&ecm_db_lock);
1063 if (from_data_total) {
1064 *from_data_total = ci->from_data_total;
1065 }
1066 if (to_data_total) {
1067 *to_data_total = ci->to_data_total;
1068 }
1069 if (from_packet_total) {
1070 *from_packet_total = ci->from_packet_total;
1071 }
1072 if (to_packet_total) {
1073 *to_packet_total = ci->to_packet_total;
1074 }
1075 if (from_data_total_dropped) {
1076 *from_data_total_dropped = ci->from_data_total_dropped;
1077 }
1078 if (to_data_total_dropped) {
1079 *to_data_total_dropped = ci->to_data_total_dropped;
1080 }
1081 if (from_packet_total_dropped) {
1082 *from_packet_total_dropped = ci->from_packet_total_dropped;
1083 }
1084 if (to_packet_total_dropped) {
1085 *to_packet_total_dropped = ci->to_packet_total_dropped;
1086 }
1087 spin_unlock_bh(&ecm_db_lock);
1088}
1089EXPORT_SYMBOL(ecm_db_connection_data_stats_get);
1090
1091/*
1092 * ecm_db_mapping_data_stats_get()
1093 * Return data stats for the instance
1094 */
1095void ecm_db_mapping_data_stats_get(struct ecm_db_mapping_instance *mi, uint64_t *from_data_total, uint64_t *to_data_total,
1096 uint64_t *from_packet_total, uint64_t *to_packet_total,
1097 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1098 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1099{
1100 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1101 spin_lock_bh(&ecm_db_lock);
1102 if (from_data_total) {
1103 *from_data_total = mi->from_data_total;
1104 }
1105 if (to_data_total) {
1106 *to_data_total = mi->to_data_total;
1107 }
1108 if (from_packet_total) {
1109 *from_packet_total = mi->from_packet_total;
1110 }
1111 if (to_packet_total) {
1112 *to_packet_total = mi->to_packet_total;
1113 }
1114 if (from_data_total_dropped) {
1115 *from_data_total_dropped = mi->from_data_total_dropped;
1116 }
1117 if (to_data_total_dropped) {
1118 *to_data_total_dropped = mi->to_data_total_dropped;
1119 }
1120 if (from_packet_total_dropped) {
1121 *from_packet_total_dropped = mi->from_packet_total_dropped;
1122 }
1123 if (to_packet_total_dropped) {
1124 *to_packet_total_dropped = mi->to_packet_total_dropped;
1125 }
1126 spin_unlock_bh(&ecm_db_lock);
1127}
1128EXPORT_SYMBOL(ecm_db_mapping_data_stats_get);
1129
1130/*
1131 * ecm_db_host_data_stats_get()
1132 * Return data stats for the instance
1133 */
1134void ecm_db_host_data_stats_get(struct ecm_db_host_instance *hi, uint64_t *from_data_total, uint64_t *to_data_total,
1135 uint64_t *from_packet_total, uint64_t *to_packet_total,
1136 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1137 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1138{
1139 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1140 spin_lock_bh(&ecm_db_lock);
1141 if (from_data_total) {
1142 *from_data_total = hi->from_data_total;
1143 }
1144 if (to_data_total) {
1145 *to_data_total = hi->to_data_total;
1146 }
1147 if (from_packet_total) {
1148 *from_packet_total = hi->from_packet_total;
1149 }
1150 if (to_packet_total) {
1151 *to_packet_total = hi->to_packet_total;
1152 }
1153 if (from_data_total_dropped) {
1154 *from_data_total_dropped = hi->from_data_total_dropped;
1155 }
1156 if (to_data_total_dropped) {
1157 *to_data_total_dropped = hi->to_data_total_dropped;
1158 }
1159 if (from_packet_total_dropped) {
1160 *from_packet_total_dropped = hi->from_packet_total_dropped;
1161 }
1162 if (to_packet_total_dropped) {
1163 *to_packet_total_dropped = hi->to_packet_total_dropped;
1164 }
1165 spin_unlock_bh(&ecm_db_lock);
1166}
1167EXPORT_SYMBOL(ecm_db_host_data_stats_get);
1168
1169/*
1170 * ecm_db_node_data_stats_get()
1171 * Return data stats for the instance
1172 */
1173void ecm_db_node_data_stats_get(struct ecm_db_node_instance *ni, uint64_t *from_data_total, uint64_t *to_data_total,
1174 uint64_t *from_packet_total, uint64_t *to_packet_total,
1175 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1176 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1177{
1178 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1179 spin_lock_bh(&ecm_db_lock);
1180 if (from_data_total) {
1181 *from_data_total = ni->from_data_total;
1182 }
1183 if (to_data_total) {
1184 *to_data_total = ni->to_data_total;
1185 }
1186 if (from_packet_total) {
1187 *from_packet_total = ni->from_packet_total;
1188 }
1189 if (to_packet_total) {
1190 *to_packet_total = ni->to_packet_total;
1191 }
1192 if (from_data_total_dropped) {
1193 *from_data_total_dropped = ni->from_data_total_dropped;
1194 }
1195 if (to_data_total_dropped) {
1196 *to_data_total_dropped = ni->to_data_total_dropped;
1197 }
1198 if (from_packet_total_dropped) {
1199 *from_packet_total_dropped = ni->from_packet_total_dropped;
1200 }
1201 if (to_packet_total_dropped) {
1202 *to_packet_total_dropped = ni->to_packet_total_dropped;
1203 }
1204 spin_unlock_bh(&ecm_db_lock);
1205}
1206EXPORT_SYMBOL(ecm_db_node_data_stats_get);
1207
1208/*
1209 * ecm_db_iface_data_stats_get()
1210 * Return data stats for the instance
1211 */
1212void ecm_db_iface_data_stats_get(struct ecm_db_iface_instance *ii, uint64_t *from_data_total, uint64_t *to_data_total,
1213 uint64_t *from_packet_total, uint64_t *to_packet_total,
1214 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1215 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1216{
1217 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1218 spin_lock_bh(&ecm_db_lock);
1219 if (from_data_total) {
1220 *from_data_total = ii->from_data_total;
1221 }
1222 if (to_data_total) {
1223 *to_data_total = ii->to_data_total;
1224 }
1225 if (from_packet_total) {
1226 *from_packet_total = ii->from_packet_total;
1227 }
1228 if (to_packet_total) {
1229 *to_packet_total = ii->to_packet_total;
1230 }
1231 if (from_data_total_dropped) {
1232 *from_data_total_dropped = ii->from_data_total_dropped;
1233 }
1234 if (to_data_total_dropped) {
1235 *to_data_total_dropped = ii->to_data_total_dropped;
1236 }
1237 if (from_packet_total_dropped) {
1238 *from_packet_total_dropped = ii->from_packet_total_dropped;
1239 }
1240 if (to_packet_total_dropped) {
1241 *to_packet_total_dropped = ii->to_packet_total_dropped;
1242 }
1243 spin_unlock_bh(&ecm_db_lock);
1244}
1245EXPORT_SYMBOL(ecm_db_iface_data_stats_get);
1246
1247/*
1248 * ecm_db_connection_serial_get()
1249 * Return serial
1250 */
1251uint32_t ecm_db_connection_serial_get(struct ecm_db_connection_instance *ci)
1252{
1253 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1254 return ci->serial;
1255}
1256EXPORT_SYMBOL(ecm_db_connection_serial_get);
1257
1258/*
1259 * ecm_db_connection_from_address_get()
1260 * Return ip address address
1261 */
1262void ecm_db_connection_from_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1263{
1264 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1265 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1266 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1267 ECM_IP_ADDR_COPY(addr, ci->mapping_from->host->address);
1268}
1269EXPORT_SYMBOL(ecm_db_connection_from_address_get);
1270
1271/*
1272 * ecm_db_connection_from_address_nat_get()
1273 * Return NAT ip address address
1274 */
1275void ecm_db_connection_from_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1276{
1277 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1278 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1279 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1280 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_from->host->address);
1281}
1282EXPORT_SYMBOL(ecm_db_connection_from_address_nat_get);
1283
1284/*
1285 * ecm_db_connection_to_address_get()
1286 * Return ip address address
1287 */
1288void ecm_db_connection_to_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1289{
1290 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1291 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1292 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1293 ECM_IP_ADDR_COPY(addr, ci->mapping_to->host->address);
1294}
1295EXPORT_SYMBOL(ecm_db_connection_to_address_get);
1296
1297/*
1298 * ecm_db_connection_to_address_nat_get()
1299 * Return NAT ip address address
1300 */
1301void ecm_db_connection_to_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1302{
1303 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1304 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1305 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1306 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_to->host->address);
1307}
1308EXPORT_SYMBOL(ecm_db_connection_to_address_nat_get);
1309
1310/*
1311 * ecm_db_connection_to_port_get()
1312 * Return port
1313 */
1314int ecm_db_connection_to_port_get(struct ecm_db_connection_instance *ci)
1315{
1316 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1317 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1318 return ci->mapping_to->port;
1319}
1320EXPORT_SYMBOL(ecm_db_connection_to_port_get);
1321
1322/*
1323 * ecm_db_connection_to_port_nat_get()
1324 * Return port
1325 */
1326int ecm_db_connection_to_port_nat_get(struct ecm_db_connection_instance *ci)
1327{
1328 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1329 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1330 return ci->mapping_nat_to->port;
1331}
1332EXPORT_SYMBOL(ecm_db_connection_to_port_nat_get);
1333
1334/*
1335 * ecm_db_connection_from_port_get()
1336 * Return port
1337 */
1338int ecm_db_connection_from_port_get(struct ecm_db_connection_instance *ci)
1339{
1340 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1341 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1342 return ci->mapping_from->port;
1343}
1344EXPORT_SYMBOL(ecm_db_connection_from_port_get);
1345
1346/*
1347 * ecm_db_connection_from_port_nat_get()
1348 * Return port
1349 */
1350int ecm_db_connection_from_port_nat_get(struct ecm_db_connection_instance *ci)
1351{
1352 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1353 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1354 return ci->mapping_nat_from->port;
1355}
1356EXPORT_SYMBOL(ecm_db_connection_from_port_nat_get);
1357
1358/*
1359 * ecm_db_connection_to_node_address_get()
1360 * Return address of the node used when sending packets to the 'to' side.
1361 */
1362void ecm_db_connection_to_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1363{
1364 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001365 memcpy(address_buffer, ci->to_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001366}
1367EXPORT_SYMBOL(ecm_db_connection_to_node_address_get);
1368
1369/*
1370 * ecm_db_connection_from_node_address_get()
1371 * Return address of the node used when sending packets to the 'from' side.
1372 */
1373void ecm_db_connection_from_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1374{
1375 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001376 memcpy(address_buffer, ci->from_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001377}
1378EXPORT_SYMBOL(ecm_db_connection_from_node_address_get);
1379
1380/*
1381 * ecm_db_connection_to_nat_node_address_get()
1382 * Return address of the node used when sending packets to the 'to' NAT side.
1383 */
1384void ecm_db_connection_to_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1385{
1386 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001387 memcpy(address_buffer, ci->to_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001388}
1389EXPORT_SYMBOL(ecm_db_connection_to_nat_node_address_get);
1390
1391/*
1392 * ecm_db_connection_from_nat_node_address_get()
1393 * Return address of the node used when sending packets to the 'from' NAT side.
1394 */
1395void ecm_db_connection_from_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1396{
1397 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001398 memcpy(address_buffer, ci->from_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001399}
1400EXPORT_SYMBOL(ecm_db_connection_from_nat_node_address_get);
1401
1402/*
1403 * ecm_db_connection_to_iface_name_get()
1404 * Return name of interface on which the 'to' side may be reached
1405 */
1406void ecm_db_connection_to_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1407{
1408 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001409 strcpy(name_buffer, ci->to_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001410}
1411EXPORT_SYMBOL(ecm_db_connection_to_iface_name_get);
1412
1413/*
1414 * ecm_db_connection_from_iface_name_get()
1415 * Return name of interface on which the 'from' side may be reached
1416 */
1417void ecm_db_connection_from_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1418{
1419 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001420 strcpy(name_buffer, ci->from_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001421}
1422EXPORT_SYMBOL(ecm_db_connection_from_iface_name_get);
1423
1424/*
1425 * ecm_db_connection_to_iface_mtu_get()
1426 * Return MTU of interface on which the 'to' side may be reached
1427 */
1428int ecm_db_connection_to_iface_mtu_get(struct ecm_db_connection_instance *ci)
1429{
1430 int mtu;
1431 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1432 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001433 mtu = ci->to_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001434 spin_unlock_bh(&ecm_db_lock);
1435 return mtu;
1436}
1437EXPORT_SYMBOL(ecm_db_connection_to_iface_mtu_get);
1438
1439/*
1440 * ecm_db_connection_to_iface_type_get()
1441 * Return type of interface on which the 'to' side may be reached
1442 */
1443ecm_db_iface_type_t ecm_db_connection_to_iface_type_get(struct ecm_db_connection_instance *ci)
1444{
1445 ecm_db_iface_type_t type;
1446
1447 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1448 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001449 type = ci->to_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001450 spin_unlock_bh(&ecm_db_lock);
1451 return type;
1452}
1453EXPORT_SYMBOL(ecm_db_connection_to_iface_type_get);
1454
1455/*
1456 * ecm_db_connection_from_iface_mtu_get()
1457 * Return MTU of interface on which the 'from' side may be reached
1458 */
1459int ecm_db_connection_from_iface_mtu_get(struct ecm_db_connection_instance *ci)
1460{
1461 int mtu;
1462 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1463 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001464 mtu = ci->from_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001465 spin_unlock_bh(&ecm_db_lock);
1466 return mtu;
1467}
1468EXPORT_SYMBOL(ecm_db_connection_from_iface_mtu_get);
1469
1470/*
1471 * ecm_db_connection_from_iface_type_get()
1472 * Return type of interface on which the 'from' side may be reached
1473 */
1474ecm_db_iface_type_t ecm_db_connection_from_iface_type_get(struct ecm_db_connection_instance *ci)
1475{
1476 ecm_db_iface_type_t type;
1477
1478 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1479 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001480 type = ci->from_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001481 spin_unlock_bh(&ecm_db_lock);
1482 return type;
1483}
1484EXPORT_SYMBOL(ecm_db_connection_from_iface_type_get);
1485
1486/*
1487 * ecm_db_connection_iface_type_get()
1488 * Return type of interface
1489 */
1490ecm_db_iface_type_t ecm_db_connection_iface_type_get(struct ecm_db_iface_instance *ii)
1491{
1492 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1493 return ii->type;
1494}
1495EXPORT_SYMBOL(ecm_db_connection_iface_type_get);
1496
1497/*
1498 * ecm_db_connection_classifier_generation_changed()
1499 * Returns true if the classifier generation has changed for this connection.
1500 *
1501 * NOTE: The generation index will be reset on return from this call so action any true result immediately.
1502 */
1503bool ecm_db_connection_classifier_generation_changed(struct ecm_db_connection_instance *ci)
1504{
1505 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1506
1507 spin_lock_bh(&ecm_db_lock);
1508 if (ci->classifier_generation == ecm_db_classifier_generation) {
1509 spin_unlock_bh(&ecm_db_lock);
1510 return false;
1511 }
Gareth Williamsda721272014-11-13 17:48:12 -08001512 ci->generations++;
Ben Menchaca84f36632014-02-28 20:57:38 +00001513 ci->classifier_generation = ecm_db_classifier_generation;
1514 spin_unlock_bh(&ecm_db_lock);
1515 return true;
1516}
1517EXPORT_SYMBOL(ecm_db_connection_classifier_generation_changed);
1518
1519/*
1520 * ecm_db_connection_classifier_peek_generation_changed()
1521 * Returns true if the classifier generation has changed for this connection.
1522 *
1523 * NOTE: The generation index will NOT be reset on return from this call.
1524 */
1525bool ecm_db_connection_classifier_peek_generation_changed(struct ecm_db_connection_instance *ci)
1526{
1527 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1528
1529 spin_lock_bh(&ecm_db_lock);
1530 if (ci->classifier_generation == ecm_db_classifier_generation) {
1531 spin_unlock_bh(&ecm_db_lock);
1532 return false;
1533 }
1534 spin_unlock_bh(&ecm_db_lock);
1535 return true;
1536}
1537EXPORT_SYMBOL(ecm_db_connection_classifier_peek_generation_changed);
1538
1539/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01001540 * _ecm_db_connection_classifier_generation_change()
1541 * Cause a specific connection to be re-generated
1542 */
1543static void _ecm_db_connection_classifier_generation_change(struct ecm_db_connection_instance *ci)
1544{
1545 ci->classifier_generation = ecm_db_classifier_generation - 1;
1546}
1547
1548/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001549 * ecm_db_connection_classifier_generation_change()
1550 * Cause a specific connection to be re-generated
1551 */
1552void ecm_db_connection_classifier_generation_change(struct ecm_db_connection_instance *ci)
1553{
1554 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1555
1556 spin_lock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01001557 _ecm_db_connection_classifier_generation_change(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00001558 spin_unlock_bh(&ecm_db_lock);
1559}
1560EXPORT_SYMBOL(ecm_db_connection_classifier_generation_change);
1561
1562/*
1563 * ecm_db_classifier_generation_change()
1564 * Bump the generation index to cause a re-classification of connections
1565 *
1566 * NOTE: Any connections that see activity after a call to this could be put back to undetermined qos state
1567 * and driven back through the classifiers.
1568 */
1569void ecm_db_classifier_generation_change(void)
1570{
1571 spin_lock_bh(&ecm_db_lock);
1572 ecm_db_classifier_generation++;
1573 spin_unlock_bh(&ecm_db_lock);
1574}
1575EXPORT_SYMBOL(ecm_db_classifier_generation_change);
1576
1577/*
1578 * ecm_db_connection_direction_get()
1579 * Return direction of the connection.
1580 *
1581 * NOTE: an EGRESS connection means that packets being sent to mapping_to should have qos applied.
1582 * INGRESS means that packets being sent to mapping_from should have qos applied.
1583 */
1584ecm_db_direction_t ecm_db_connection_direction_get(struct ecm_db_connection_instance *ci)
1585{
1586 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1587 return ci->direction;
1588}
1589EXPORT_SYMBOL(ecm_db_connection_direction_get);
1590
1591/*
1592 * ecm_db_mapping_port_count_get()
1593 * Return port count stats for a mapping.
1594 */
1595void ecm_db_mapping_port_count_get(struct ecm_db_mapping_instance *mi,
1596 int *tcp_from, int *tcp_to, int *udp_from, int *udp_to, int *from, int *to,
1597 int *tcp_nat_from, int *tcp_nat_to, int *udp_nat_from, int *udp_nat_to, int *nat_from, int *nat_to)
1598{
1599 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1600
1601 spin_lock_bh(&ecm_db_lock);
1602
1603 *tcp_from = mi->tcp_from;
1604 *tcp_to = mi->tcp_to;
1605 *udp_from = mi->udp_from;
1606 *udp_to = mi->udp_to;
1607 *from = mi->from;
1608 *to = mi->to;
1609
1610 *tcp_nat_from = mi->tcp_nat_from;
1611 *tcp_nat_to = mi->tcp_nat_to;
1612 *udp_nat_from = mi->udp_nat_from;
1613 *udp_nat_to = mi->udp_nat_to;
1614 *nat_from = mi->nat_from;
1615 *nat_to = mi->nat_to;
1616
1617 spin_unlock_bh(&ecm_db_lock);
1618}
1619EXPORT_SYMBOL(ecm_db_mapping_port_count_get);
1620
1621/*
1622 * ecm_db_connection_is_routed_get()
1623 * Return whether connection is a routed path or not
1624 */
1625bool ecm_db_connection_is_routed_get(struct ecm_db_connection_instance *ci)
1626{
1627 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1628 return ci->is_routed;
1629}
1630EXPORT_SYMBOL(ecm_db_connection_is_routed_get);
1631
1632/*
1633 * ecm_db_connection_protocol_get()
1634 * Return protocol of connection
1635 */
1636int ecm_db_connection_protocol_get(struct ecm_db_connection_instance *ci)
1637{
1638 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1639 return ci->protocol;
1640}
1641EXPORT_SYMBOL(ecm_db_connection_protocol_get);
1642
1643/*
1644 * ecm_db_host_address_get()
1645 * Return address of host
1646 */
1647void ecm_db_host_address_get(struct ecm_db_host_instance *hi, ip_addr_t addr)
1648{
1649 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1650 ECM_IP_ADDR_COPY(addr, hi->address);
1651}
1652EXPORT_SYMBOL(ecm_db_host_address_get);
1653
1654/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001655 * ecm_db_host_on_link_get()
1656 * Return on link status of host
1657 */
1658bool ecm_db_host_on_link_get(struct ecm_db_host_instance *hi)
1659{
1660 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1661 return hi->on_link;
1662}
1663EXPORT_SYMBOL(ecm_db_host_on_link_get);
1664
1665/*
1666 * ecm_db_mapping_adress_get()
1667 * Return address
1668 */
1669void ecm_db_mapping_adress_get(struct ecm_db_mapping_instance *mi, ip_addr_t addr)
1670{
1671 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1672 ECM_IP_ADDR_COPY(addr, mi->host->address);
1673}
1674EXPORT_SYMBOL(ecm_db_mapping_adress_get);
1675
1676/*
1677 * ecm_db_mapping_port_get()
1678 * Return port
1679 */
1680int ecm_db_mapping_port_get(struct ecm_db_mapping_instance *mi)
1681{
1682 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1683 return mi->port;
1684}
1685EXPORT_SYMBOL(ecm_db_mapping_port_get);
1686
1687/*
1688 * ecm_db_node_adress_get()
1689 * Return address
1690 */
1691void ecm_db_node_adress_get(struct ecm_db_node_instance *ni, uint8_t *address_buffer)
1692{
1693 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1694 memcpy(address_buffer, ni->address, ETH_ALEN);
1695}
1696EXPORT_SYMBOL(ecm_db_node_adress_get);
1697
1698/*
1699 * _ecm_db_timer_group_entry_remove()
1700 * Remove the entry from its timer group, returns false if the entry has already expired.
1701 */
1702static bool _ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
1703{
1704 struct ecm_db_timer_group *timer_group;
1705
1706 /*
1707 * If not in a timer group then it is already removed
1708 */
1709 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
1710 return false;
1711 }
1712
1713 /*
1714 * Remove the connection from its current group
1715 */
1716 timer_group = &ecm_db_timer_groups[tge->group];
1717
1718 /*
1719 * Somewhere in the list?
1720 */
1721 if (tge->prev) {
1722 tge->prev->next = tge->next;
1723 } else {
1724 /*
1725 * First in the group
1726 */
1727 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p, got %p\n", timer_group, tge, timer_group->head);
1728 timer_group->head = tge->next;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301729 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001730
1731 if (tge->next) {
1732 tge->next->prev = tge->prev;
1733 } else {
1734 /*
1735 * No next so this must be the last item - we need to adjust the tail pointer
1736 */
1737 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
1738 timer_group->tail = tge->prev;
1739 }
1740
1741 /*
1742 * No longer a part of a timer group
1743 */
1744 tge->group = ECM_DB_TIMER_GROUPS_MAX;
1745 return true;
1746}
1747
1748/*
1749 * ecm_db_timer_group_entry_remove()
1750 * Remove the connection from its timer group, returns false if the entry has already expired.
1751 */
1752bool ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
1753{
1754 bool res;
1755 spin_lock_bh(&ecm_db_lock);
1756 res = _ecm_db_timer_group_entry_remove(tge);
1757 spin_unlock_bh(&ecm_db_lock);
1758 return res;
1759}
1760EXPORT_SYMBOL(ecm_db_timer_group_entry_remove);
1761
1762/*
1763 * _ecm_db_timer_group_entry_set()
1764 * Set the timer group to which this entry will be a member
1765 */
1766void _ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
1767{
1768 struct ecm_db_timer_group *timer_group;
1769
1770 DEBUG_ASSERT(tge->group == ECM_DB_TIMER_GROUPS_MAX, "%p: already set\n", tge);
1771
1772 /*
1773 * Set group
1774 */
1775 tge->group = tg;
1776 timer_group = &ecm_db_timer_groups[tge->group];
1777 tge->timeout = timer_group->time + ecm_db_time;
1778
1779 /*
1780 * Insert into a timer group at the head (as this is now touched)
1781 */
1782 tge->prev = NULL;
1783 tge->next = timer_group->head;
1784 if (!timer_group->head) {
1785 /*
1786 * As there is no head there is also no tail so we need to set that
1787 */
1788 timer_group->tail = tge;
1789 } else {
1790 /*
1791 * As there is a head already there must be a tail. Since we insert before
1792 * the current head we don't adjust the tail.
1793 */
1794 timer_group->head->prev = tge;
1795 }
1796 timer_group->head = tge;
1797}
1798
1799/*
1800 * ecm_db_timer_group_entry_reset()
1801 * Re-set the timer group to which this entry will be a member.
1802 *
1803 * Returns false if the timer cannot be reset because it has expired
1804 */
1805bool ecm_db_timer_group_entry_reset(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
1806{
1807 spin_lock_bh(&ecm_db_lock);
1808
1809 /*
1810 * Remove it from its current group, if any
1811 */
1812 if (!_ecm_db_timer_group_entry_remove(tge)) {
1813 spin_unlock_bh(&ecm_db_lock);
1814 return false;
1815 }
1816
1817 /*
1818 * Set new group
1819 */
1820 _ecm_db_timer_group_entry_set(tge, tg);
1821 spin_unlock_bh(&ecm_db_lock);
1822 return true;
1823}
1824EXPORT_SYMBOL(ecm_db_timer_group_entry_reset);
1825
1826/*
1827 * ecm_db_timer_group_entry_set()
1828 * Set the timer group to which this entry will be a member
1829 */
1830void ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
1831{
1832 spin_lock_bh(&ecm_db_lock);
1833 _ecm_db_timer_group_entry_set(tge, tg);
1834 spin_unlock_bh(&ecm_db_lock);
1835}
1836EXPORT_SYMBOL(ecm_db_timer_group_entry_set);
1837
1838/*
1839 * ecm_db_timer_group_entry_init()
1840 * Initialise a timer entry ready for setting
1841 */
1842void ecm_db_timer_group_entry_init(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_entry_callback_t fn, void *arg)
1843{
1844 memset(tge, 0, sizeof(struct ecm_db_timer_group_entry));
1845 tge->group = ECM_DB_TIMER_GROUPS_MAX;
1846 tge->arg = arg;
1847 tge->fn = fn;
1848}
1849EXPORT_SYMBOL(ecm_db_timer_group_entry_init);
1850
1851/*
1852 * ecm_db_timer_group_entry_touch()
1853 * Update the timeout, if the timer is not running this has no effect.
1854 * It returns false if the timer is not running.
1855 */
1856bool ecm_db_timer_group_entry_touch(struct ecm_db_timer_group_entry *tge)
1857{
1858 struct ecm_db_timer_group *timer_group;
1859
1860 spin_lock_bh(&ecm_db_lock);
1861
1862 /*
1863 * If not in a timer group then do nothing
1864 */
1865 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
1866 spin_unlock_bh(&ecm_db_lock);
1867 return false;
1868 }
1869
1870 /*
1871 * Update time to live
1872 */
1873 timer_group = &ecm_db_timer_groups[tge->group];
1874
1875 /*
1876 * Link out of its current position.
1877 */
1878 if (!tge->prev) {
1879 /*
1880 * Already at the head, just update the time
1881 */
1882 tge->timeout = timer_group->time + ecm_db_time;
1883 spin_unlock_bh(&ecm_db_lock);
1884 return true;
1885 }
1886
1887 /*
1888 * tge->prev is not null, so:
1889 * 1) it is in a timer list
1890 * 2) is not at the head of the list
1891 * 3) there is a head already (so more than one item on the list)
1892 * 4) there is a prev pointer.
1893 * Somewhere in the group list - unlink it.
1894 */
1895 tge->prev->next = tge->next;
1896
1897 if (tge->next) {
1898 tge->next->prev = tge->prev;
1899 } else {
1900 /*
1901 * Since there is no next this must be the tail
1902 */
1903 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
1904 timer_group->tail = tge->prev;
1905 }
1906
1907 /*
1908 * Link in to head.
1909 */
Sol Kavy213e45d2014-06-05 18:04:07 -07001910 tge->timeout = timer_group->time + ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00001911 tge->prev = NULL;
1912 tge->next = timer_group->head;
1913 timer_group->head->prev = tge;
1914 timer_group->head = tge;
1915 spin_unlock_bh(&ecm_db_lock);
1916 return true;
1917}
1918EXPORT_SYMBOL(ecm_db_timer_group_entry_touch);
1919
1920/*
1921 * _ecm_db_connection_ref()
1922 */
1923static void _ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
1924{
1925 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1926 ci->refs++;
1927 DEBUG_TRACE("%p: connection ref %d\n", ci, ci->refs);
1928 DEBUG_ASSERT(ci->refs > 0, "%p: ref wrap\n", ci);
1929}
1930
1931/*
1932 * ecm_db_connection_ref()
1933 */
1934void ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
1935{
1936 spin_lock_bh(&ecm_db_lock);
1937 _ecm_db_connection_ref(ci);
1938 spin_unlock_bh(&ecm_db_lock);
1939}
1940EXPORT_SYMBOL(ecm_db_connection_ref);
1941
1942/*
1943 * _ecm_db_mapping_ref()
1944 */
1945static void _ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
1946{
1947 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
1948 mi->refs++;
1949 DEBUG_TRACE("%p: mapping ref %d\n", mi, mi->refs);
1950 DEBUG_ASSERT(mi->refs > 0, "%p: ref wrap\n", mi);
1951}
1952
1953/*
1954 * ecm_db_mapping_ref()
1955 */
1956void ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
1957{
1958 spin_lock_bh(&ecm_db_lock);
1959 _ecm_db_mapping_ref(mi);
1960 spin_unlock_bh(&ecm_db_lock);
1961}
1962EXPORT_SYMBOL(ecm_db_mapping_ref);
1963
1964/*
1965 * _ecm_db_host_ref()
1966 */
1967static void _ecm_db_host_ref(struct ecm_db_host_instance *hi)
1968{
1969 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
1970 hi->refs++;
1971 DEBUG_TRACE("%p: host ref %d\n", hi, hi->refs);
1972 DEBUG_ASSERT(hi->refs > 0, "%p: ref wrap\n", hi);
1973}
1974
1975/*
1976 * ecm_db_host_ref()
1977 */
1978void ecm_db_host_ref(struct ecm_db_host_instance *hi)
1979{
1980 spin_lock_bh(&ecm_db_lock);
1981 _ecm_db_host_ref(hi);
1982 spin_unlock_bh(&ecm_db_lock);
1983}
1984EXPORT_SYMBOL(ecm_db_host_ref);
1985
1986/*
1987 * _ecm_db_node_ref()
1988 */
1989static void _ecm_db_node_ref(struct ecm_db_node_instance *ni)
1990{
1991 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
1992 ni->refs++;
1993 DEBUG_TRACE("%p: node ref %d\n", ni, ni->refs);
1994 DEBUG_ASSERT(ni->refs > 0, "%p: ref wrap\n", ni);
1995}
1996
1997/*
1998 * ecm_db_node_ref()
1999 */
2000void ecm_db_node_ref(struct ecm_db_node_instance *ni)
2001{
2002 spin_lock_bh(&ecm_db_lock);
2003 _ecm_db_node_ref(ni);
2004 spin_unlock_bh(&ecm_db_lock);
2005}
2006EXPORT_SYMBOL(ecm_db_node_ref);
2007
2008/*
2009 * _ecm_db_iface_ref()
2010 */
2011static void _ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2012{
2013 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
2014 ii->refs++;
2015 DEBUG_TRACE("%p: iface ref %d\n", ii, ii->refs);
2016 DEBUG_ASSERT(ii->refs > 0, "%p: ref wrap\n", ii);
2017}
2018
2019/*
2020 * ecm_db_iface_ref()
2021 */
2022void ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2023{
2024 spin_lock_bh(&ecm_db_lock);
2025 _ecm_db_iface_ref(ii);
2026 spin_unlock_bh(&ecm_db_lock);
2027}
2028EXPORT_SYMBOL(ecm_db_iface_ref);
2029
2030/*
2031 * _ecm_db_listener_ref()
2032 */
2033static void _ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2034{
2035 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2036 li->refs++;
2037 DEBUG_ASSERT(li->refs > 0, "%p: ref wrap\n", li);
2038}
2039
2040/*
2041 * ecm_db_listener_ref()
2042 */
2043void ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2044{
2045 spin_lock_bh(&ecm_db_lock);
2046 _ecm_db_listener_ref(li);
2047 spin_unlock_bh(&ecm_db_lock);
2048}
2049EXPORT_SYMBOL(ecm_db_listener_ref);
2050
2051/*
2052 * ecm_db_connections_get_and_ref_first()
2053 * Obtain a ref to the first connection instance, if any
2054 */
2055static struct ecm_db_connection_instance *ecm_db_connections_get_and_ref_first(void)
2056{
2057 struct ecm_db_connection_instance *ci;
2058 spin_lock_bh(&ecm_db_lock);
2059 ci = ecm_db_connections;
2060 if (ci) {
2061 _ecm_db_connection_ref(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302062 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002063 spin_unlock_bh(&ecm_db_lock);
2064 return ci;
2065}
2066EXPORT_SYMBOL(ecm_db_connections_get_and_ref_first);
2067
2068/*
2069 * ecm_db_connection_get_and_ref_next()
2070 * Return the next connection in the list given a connection
2071 */
2072struct ecm_db_connection_instance *ecm_db_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
2073{
2074 struct ecm_db_connection_instance *cin;
2075 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2076 spin_lock_bh(&ecm_db_lock);
2077 cin = ci->next;
2078 if (cin) {
2079 _ecm_db_connection_ref(cin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302080 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002081 spin_unlock_bh(&ecm_db_lock);
2082 return cin;
2083}
2084EXPORT_SYMBOL(ecm_db_connection_get_and_ref_next);
2085
2086/*
2087 * ecm_db_mappings_get_and_ref_first()
2088 * Obtain a ref to the first mapping instance, if any
2089 */
2090struct ecm_db_mapping_instance *ecm_db_mappings_get_and_ref_first(void)
2091{
2092 struct ecm_db_mapping_instance *mi;
2093 spin_lock_bh(&ecm_db_lock);
2094 mi = ecm_db_mappings;
2095 if (mi) {
2096 _ecm_db_mapping_ref(mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302097 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002098 spin_unlock_bh(&ecm_db_lock);
2099 return mi;
2100}
2101EXPORT_SYMBOL(ecm_db_mappings_get_and_ref_first);
2102
2103/*
2104 * ecm_db_mapping_get_and_ref_next()
2105 * Return the next mapping in the list given a mapping
2106 */
2107struct ecm_db_mapping_instance *ecm_db_mapping_get_and_ref_next(struct ecm_db_mapping_instance *mi)
2108{
2109 struct ecm_db_mapping_instance *min;
2110 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2111 spin_lock_bh(&ecm_db_lock);
2112 min = mi->next;
2113 if (min) {
2114 _ecm_db_mapping_ref(min);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302115 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002116 spin_unlock_bh(&ecm_db_lock);
2117 return min;
2118}
2119EXPORT_SYMBOL(ecm_db_mapping_get_and_ref_next);
2120
2121/*
2122 * ecm_db_hosts_get_and_ref_first()
2123 * Obtain a ref to the first host instance, if any
2124 */
2125struct ecm_db_host_instance *ecm_db_hosts_get_and_ref_first(void)
2126{
2127 struct ecm_db_host_instance *hi;
2128 spin_lock_bh(&ecm_db_lock);
2129 hi = ecm_db_hosts;
2130 if (hi) {
2131 _ecm_db_host_ref(hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302132 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002133 spin_unlock_bh(&ecm_db_lock);
2134 return hi;
2135}
2136EXPORT_SYMBOL(ecm_db_hosts_get_and_ref_first);
2137
2138/*
2139 * ecm_db_host_get_and_ref_next()
2140 * Return the next host in the list given a host
2141 */
2142struct ecm_db_host_instance *ecm_db_host_get_and_ref_next(struct ecm_db_host_instance *hi)
2143{
2144 struct ecm_db_host_instance *hin;
2145 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2146 spin_lock_bh(&ecm_db_lock);
2147 hin = hi->next;
2148 if (hin) {
2149 _ecm_db_host_ref(hin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302150 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002151 spin_unlock_bh(&ecm_db_lock);
2152 return hin;
2153}
2154EXPORT_SYMBOL(ecm_db_host_get_and_ref_next);
2155
2156/*
2157 * ecm_db_listeners_get_and_ref_first()
2158 * Obtain a ref to the first listener instance, if any
2159 */
2160static struct ecm_db_listener_instance *ecm_db_listeners_get_and_ref_first(void)
2161{
2162 struct ecm_db_listener_instance *li;
2163 spin_lock_bh(&ecm_db_lock);
2164 li = ecm_db_listeners;
2165 if (li) {
2166 _ecm_db_listener_ref(li);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302167 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002168 spin_unlock_bh(&ecm_db_lock);
2169 return li;
2170}
2171
2172/*
2173 * ecm_db_listener_get_and_ref_next()
2174 * Return the next listener in the list given a listener
2175 */
2176static struct ecm_db_listener_instance *ecm_db_listener_get_and_ref_next(struct ecm_db_listener_instance *li)
2177{
2178 struct ecm_db_listener_instance *lin;
2179 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2180 spin_lock_bh(&ecm_db_lock);
2181 lin = li->next;
2182 if (lin) {
2183 _ecm_db_listener_ref(lin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302184 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002185 spin_unlock_bh(&ecm_db_lock);
2186 return lin;
2187}
2188
2189/*
2190 * ecm_db_nodes_get_and_ref_first()
2191 * Obtain a ref to the first node instance, if any
2192 */
2193struct ecm_db_node_instance *ecm_db_nodes_get_and_ref_first(void)
2194{
2195 struct ecm_db_node_instance *ni;
2196 spin_lock_bh(&ecm_db_lock);
2197 ni = ecm_db_nodes;
2198 if (ni) {
2199 _ecm_db_node_ref(ni);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302200 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002201 spin_unlock_bh(&ecm_db_lock);
2202 return ni;
2203}
2204EXPORT_SYMBOL(ecm_db_nodes_get_and_ref_first);
2205
2206/*
2207 * ecm_db_node_get_and_ref_next()
2208 * Return the next node in the list given a node
2209 */
2210struct ecm_db_node_instance *ecm_db_node_get_and_ref_next(struct ecm_db_node_instance *ni)
2211{
2212 struct ecm_db_node_instance *nin;
2213 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2214 spin_lock_bh(&ecm_db_lock);
2215 nin = ni->next;
2216 if (nin) {
2217 _ecm_db_node_ref(nin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302218 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002219 spin_unlock_bh(&ecm_db_lock);
2220 return nin;
2221}
2222EXPORT_SYMBOL(ecm_db_node_get_and_ref_next);
2223
2224/*
2225 * ecm_db_interfaces_get_and_ref_first()
2226 * Obtain a ref to the first iface instance, if any
2227 */
2228struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void)
2229{
2230 struct ecm_db_iface_instance *ii;
2231 spin_lock_bh(&ecm_db_lock);
2232 ii = ecm_db_interfaces;
2233 if (ii) {
2234 _ecm_db_iface_ref(ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302235 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002236 spin_unlock_bh(&ecm_db_lock);
2237 return ii;
2238}
2239EXPORT_SYMBOL(ecm_db_interfaces_get_and_ref_first);
2240
2241/*
2242 * ecm_db_interface_get_and_ref_next()
2243 * Return the next iface in the list given a iface
2244 */
2245struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii)
2246{
2247 struct ecm_db_iface_instance *iin;
2248 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
2249 spin_lock_bh(&ecm_db_lock);
2250 iin = ii->next;
2251 if (iin) {
2252 _ecm_db_iface_ref(iin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302253 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002254 spin_unlock_bh(&ecm_db_lock);
2255 return iin;
2256}
2257EXPORT_SYMBOL(ecm_db_interface_get_and_ref_next);
2258
2259/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002260 * _ecm_db_classifier_type_assignment_remove()
2261 * Remove the connection from the classifier type assignment list (of the given type)
2262 */
2263static void _ecm_db_classifier_type_assignment_remove(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
2264{
2265 struct ecm_db_connection_classifier_type_assignment *ta;
2266 struct ecm_db_connection_classifier_type_assignment_list *tal;
2267
2268 DEBUG_TRACE("%p: Classifier type assignment remove: %d\n", ci, ca_type);
2269 ta = &ci->type_assignment[ca_type];
2270 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p\n", ta, ci);
2271 DEBUG_ASSERT(ta->iteration_count == 0, "%p: iteration count: %d, type: %d\n", ci, ta->iteration_count, ca_type);
2272
2273 if (ta->next) {
2274 struct ecm_db_connection_classifier_type_assignment *tan = &ta->next->type_assignment[ca_type];
2275 DEBUG_ASSERT(tan->prev == ci, "Bad list, expecting: %p, got: %p\n", ci, tan->prev);
2276 tan->prev = ta->prev;
2277 }
2278
2279 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
2280 if (ta->prev) {
2281 struct ecm_db_connection_classifier_type_assignment *tap = &ta->prev->type_assignment[ca_type];
2282 DEBUG_ASSERT(tap->next == ci, "Bad list, expecting: %p, got: %p\n", ci, tap->next);
2283 tap->next = ta->next;
2284 } else {
2285 /*
2286 * Set new head of list
2287 */
2288 DEBUG_ASSERT(tal->type_assignments_list == ci, "Bad head, expecting %p, got %p, type: %d\n", ci, tal->type_assignments_list, ca_type);
2289 tal->type_assignments_list = ta->next;
2290 }
2291 ta->next = NULL;
2292 ta->prev = NULL;
2293 ta->pending_unassign = false;
2294
2295 /*
2296 * Decrement assignment count
2297 */
2298 tal->type_assignment_count--;
2299 DEBUG_ASSERT(tal->type_assignment_count >= 0, "Bad type assignment count: %d, type: %d\n", tal->type_assignment_count, ca_type);
2300
2301 DEBUG_CLEAR_MAGIC(ta);
2302}
2303
2304/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002305 * ecm_db_connection_deref()
2306 * Release reference to connection. Connection is removed from database on final deref and destroyed.
2307 */
2308int ecm_db_connection_deref(struct ecm_db_connection_instance *ci)
2309{
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002310 ecm_classifier_type_t ca_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00002311 int32_t i;
2312
2313 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2314
2315 spin_lock_bh(&ecm_db_lock);
2316 ci->refs--;
2317 DEBUG_TRACE("%p: connection deref %d\n", ci, ci->refs);
2318 DEBUG_ASSERT(ci->refs >= 0, "%p: ref wrap\n", ci);
2319
2320 if (ci->refs > 0) {
2321 int refs = ci->refs;
2322 spin_unlock_bh(&ecm_db_lock);
2323 return refs;
2324 }
2325
2326 /*
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002327 * Unlink from the "assignments by classifier type" lists.
2328 *
2329 * This is done whether the connection is inserted into the database or not - this is because
2330 * classifier assignments take place before adding into the db.
2331 *
2332 * NOTE: We know that the ci is not being iterated in any of these lists because otherwise
2333 * ci would be being held as part of iteration and so we would not be here!
2334 * Equally we know that if the assignments_by_type[] element is non-null then it must also be in the relevant list too.
2335 */
2336 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
2337 if (!ci->assignments_by_type[ca_type]) {
2338 /*
2339 * No assignment of this type, so would not be in the classifier type assignments list
2340 */
2341 continue;
2342 }
2343 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
2344 }
2345
2346 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002347 * Remove from database if inserted
2348 */
2349 if (!ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED) {
2350 spin_unlock_bh(&ecm_db_lock);
2351 } else {
2352 struct ecm_db_listener_instance *li;
2353 struct ecm_db_iface_instance *iface_from;
2354 struct ecm_db_iface_instance *iface_to;
2355 struct ecm_db_iface_instance *iface_nat_from;
2356 struct ecm_db_iface_instance *iface_nat_to;
2357
2358 /*
2359 * Remove it from the connection hash table
2360 */
2361 if (!ci->hash_prev) {
2362 DEBUG_ASSERT(ecm_db_connection_table[ci->hash_index] == ci, "%p: hash table bad\n", ci);
2363 ecm_db_connection_table[ci->hash_index] = ci->hash_next;
2364 } else {
2365 ci->hash_prev->hash_next = ci->hash_next;
2366 }
2367 if (ci->hash_next) {
2368 ci->hash_next->hash_prev = ci->hash_prev;
2369 }
2370 ecm_db_connection_table_lengths[ci->hash_index]--;
2371 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]);
2372
2373 /*
2374 * Remove it from the connection serial hash table
2375 */
2376 if (!ci->serial_hash_prev) {
2377 DEBUG_ASSERT(ecm_db_connection_serial_table[ci->serial_hash_index] == ci, "%p: hash table bad\n", ci);
2378 ecm_db_connection_serial_table[ci->serial_hash_index] = ci->serial_hash_next;
2379 } else {
2380 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
2381 }
2382 if (ci->serial_hash_next) {
2383 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
2384 }
2385 ecm_db_connection_serial_table_lengths[ci->serial_hash_index]--;
2386 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]);
2387
2388 /*
2389 * Remove from the global list
2390 */
2391 if (!ci->prev) {
2392 DEBUG_ASSERT(ecm_db_connections == ci, "%p: conn table bad\n", ci);
2393 ecm_db_connections = ci->next;
2394 } else {
2395 ci->prev->next = ci->next;
2396 }
2397 if (ci->next) {
2398 ci->next->prev = ci->prev;
2399 }
2400
2401 /*
2402 * Remove connection from the "from" mapping connection list
2403 */
2404 if (!ci->from_prev) {
2405 DEBUG_ASSERT(ci->mapping_from->from_connections == ci, "%p: from conn table bad\n", ci);
2406 ci->mapping_from->from_connections = ci->from_next;
2407 } else {
2408 ci->from_prev->from_next = ci->from_next;
2409 }
2410 if (ci->from_next) {
2411 ci->from_next->from_prev = ci->from_prev;
2412 }
2413
2414 /*
2415 * Remove connection from the "to" mapping connection list
2416 */
2417 if (!ci->to_prev) {
2418 DEBUG_ASSERT(ci->mapping_to->to_connections == ci, "%p: to conn table bad\n", ci);
2419 ci->mapping_to->to_connections = ci->to_next;
2420 } else {
2421 ci->to_prev->to_next = ci->to_next;
2422 }
2423 if (ci->to_next) {
2424 ci->to_next->to_prev = ci->to_prev;
2425 }
2426
2427 /*
2428 * Remove connection from the "from" NAT mapping connection list
2429 */
2430 if (!ci->from_nat_prev) {
2431 DEBUG_ASSERT(ci->mapping_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2432 ci->mapping_nat_from->from_nat_connections = ci->from_nat_next;
2433 } else {
2434 ci->from_nat_prev->from_nat_next = ci->from_nat_next;
2435 }
2436 if (ci->from_nat_next) {
2437 ci->from_nat_next->from_nat_prev = ci->from_nat_prev;
2438 }
2439
2440 /*
2441 * Remove connection from the "to" NAT mapping connection list
2442 */
2443 if (!ci->to_nat_prev) {
2444 DEBUG_ASSERT(ci->mapping_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2445 ci->mapping_nat_to->to_nat_connections = ci->to_nat_next;
2446 } else {
2447 ci->to_nat_prev->to_nat_next = ci->to_nat_next;
2448 }
2449 if (ci->to_nat_next) {
2450 ci->to_nat_next->to_nat_prev = ci->to_nat_prev;
2451 }
2452
2453 /*
2454 * Remove connection from the "from" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002455 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002456 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002457 iface_from = ci->from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002458 if (!ci->iface_from_prev) {
2459 DEBUG_ASSERT(iface_from->from_connections == ci, "%p: iface from conn table bad\n", ci);
2460 iface_from->from_connections = ci->iface_from_next;
2461 } else {
2462 ci->iface_from_prev->iface_from_next = ci->iface_from_next;
2463 }
2464 if (ci->iface_from_next) {
2465 ci->iface_from_next->iface_from_prev = ci->iface_from_prev;
2466 }
2467
2468 /*
2469 * Remove connection from the "to" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002470 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002471 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002472 iface_to = ci->to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002473 if (!ci->iface_to_prev) {
2474 DEBUG_ASSERT(iface_to->to_connections == ci, "%p: to conn table bad\n", ci);
2475 iface_to->to_connections = ci->iface_to_next;
2476 } else {
2477 ci->iface_to_prev->iface_to_next = ci->iface_to_next;
2478 }
2479 if (ci->iface_to_next) {
2480 ci->iface_to_next->iface_to_prev = ci->iface_to_prev;
2481 }
2482
2483 /*
2484 * Remove connection from the "from" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002485 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002486 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002487 iface_nat_from = ci->from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002488 if (!ci->iface_from_nat_prev) {
2489 DEBUG_ASSERT(iface_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2490 iface_nat_from->from_nat_connections = ci->iface_from_nat_next;
2491 } else {
2492 ci->iface_from_nat_prev->iface_from_nat_next = ci->iface_from_nat_next;
2493 }
2494 if (ci->iface_from_nat_next) {
2495 ci->iface_from_nat_next->iface_from_nat_prev = ci->iface_from_nat_prev;
2496 }
2497
2498 /*
2499 * Remove connection from the "to" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002500 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002501 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002502 iface_nat_to = ci->to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002503 if (!ci->iface_to_nat_prev) {
2504 DEBUG_ASSERT(iface_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2505 iface_nat_to->to_nat_connections = ci->iface_to_nat_next;
2506 } else {
2507 ci->iface_to_nat_prev->iface_to_nat_next = ci->iface_to_nat_next;
2508 }
2509 if (ci->iface_to_nat_next) {
2510 ci->iface_to_nat_next->iface_to_nat_prev = ci->iface_to_nat_prev;
2511 }
2512
2513 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01002514 * Remove connection from its "from node" node connection list
2515 */
2516 if (!ci->node_from_prev) {
2517 DEBUG_ASSERT(ci->from_node->from_connections == ci, "%p: from node conn table bad, got: %p\n", ci, ci->from_node->from_connections);
2518 ci->from_node->from_connections = ci->node_from_next;
2519 } else {
2520 ci->node_from_prev->node_from_next = ci->node_from_next;
2521 }
2522 if (ci->node_from_next) {
2523 ci->node_from_next->node_from_prev = ci->node_from_prev;
2524 }
2525 ci->from_node->from_connections_count--;
2526 DEBUG_ASSERT(ci->from_node->from_connections_count >= 0, "%p: bad count\n", ci);
2527
2528 /*
2529 * Remove connection from its "to node" node connection list
2530 */
2531 if (!ci->node_to_prev) {
2532 DEBUG_ASSERT(ci->to_node->to_connections == ci, "%p: to node conn table bad, got: %p\n", ci, ci->to_node->to_connections);
2533 ci->to_node->to_connections = ci->node_to_next;
2534 } else {
2535 ci->node_to_prev->node_to_next = ci->node_to_next;
2536 }
2537 if (ci->node_to_next) {
2538 ci->node_to_next->node_to_prev = ci->node_to_prev;
2539 }
2540 ci->to_node->to_connections_count--;
2541 DEBUG_ASSERT(ci->to_node->to_connections_count >= 0, "%p: bad count\n", ci);
2542
2543 /*
2544 * Remove connection from its "from nat node" node connection list
2545 */
2546 if (!ci->node_from_nat_prev) {
2547 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);
2548 ci->from_nat_node->from_nat_connections = ci->node_from_nat_next;
2549 } else {
2550 ci->node_from_nat_prev->node_from_nat_next = ci->node_from_nat_next;
2551 }
2552 if (ci->node_from_nat_next) {
2553 ci->node_from_nat_next->node_from_nat_prev = ci->node_from_nat_prev;
2554 }
2555 ci->from_nat_node->from_nat_connections_count--;
2556 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections_count >= 0, "%p: bad count\n", ci);
2557
2558 /*
2559 * Remove connection from its "to nat node" node connection list
2560 */
2561 if (!ci->node_to_nat_prev) {
2562 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);
2563 ci->to_nat_node->to_nat_connections = ci->node_to_nat_next;
2564 } else {
2565 ci->node_to_nat_prev->node_to_nat_next = ci->node_to_nat_next;
2566 }
2567 if (ci->node_to_nat_next) {
2568 ci->node_to_nat_next->node_to_nat_prev = ci->node_to_nat_prev;
2569 }
2570 ci->to_nat_node->to_nat_connections_count--;
2571 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections_count >= 0, "%p: bad count\n", ci);
2572
2573 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002574 * Update the counters in the mappings
2575 */
2576 if (ci->protocol == IPPROTO_UDP) {
2577 ci->mapping_from->udp_from--;
2578 ci->mapping_to->udp_to--;
2579 ci->mapping_nat_from->udp_nat_from--;
2580 ci->mapping_nat_to->udp_nat_to--;
2581 } else if (ci->protocol == IPPROTO_TCP) {
2582 ci->mapping_from->tcp_from--;
2583 ci->mapping_to->tcp_to--;
2584 ci->mapping_nat_from->tcp_nat_from--;
2585 ci->mapping_nat_to->tcp_nat_to--;
2586 }
2587
2588 ci->mapping_from->from--;
2589 ci->mapping_to->to--;
2590 ci->mapping_nat_from->nat_from--;
2591 ci->mapping_nat_to->nat_to--;
2592
2593 /*
2594 * Assert that the defunt timer has been detached
2595 */
2596 DEBUG_ASSERT(ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX, "%p: unexpected timer group %d\n", ci, ci->defunct_timer.group);
2597
2598 /*
2599 * Decrement protocol counter stats
2600 */
2601 ecm_db_connection_count_by_protocol[ci->protocol]--;
2602 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 +01002603
Ben Menchaca84f36632014-02-28 20:57:38 +00002604 spin_unlock_bh(&ecm_db_lock);
2605
2606 /*
2607 * Throw removed event to listeners
2608 */
2609 DEBUG_TRACE("%p: Throw connection removed event\n", ci);
2610 li = ecm_db_listeners_get_and_ref_first();
2611 while (li) {
2612 struct ecm_db_listener_instance *lin;
2613 if (li->connection_removed) {
2614 li->connection_removed(li->arg, ci);
2615 }
2616
2617 /*
2618 * Get next listener
2619 */
2620 lin = ecm_db_listener_get_and_ref_next(li);
2621 ecm_db_listener_deref(li);
2622 li = lin;
2623 }
2624 }
2625
2626 /*
2627 * Throw final event
2628 */
2629 if (ci->final) {
2630 ci->final(ci->arg);
2631 }
2632
2633 /*
2634 * Release instances to the objects referenced by the connection
2635 */
2636 while (ci->assignments) {
2637 struct ecm_classifier_instance *classi = ci->assignments;
2638 ci->assignments = classi->ca_next;
2639 classi->deref(classi);
2640 }
2641
Ben Menchaca84f36632014-02-28 20:57:38 +00002642 if (ci->mapping_from) {
2643 ecm_db_mapping_deref(ci->mapping_from);
2644 }
2645 if (ci->mapping_to) {
2646 ecm_db_mapping_deref(ci->mapping_to);
2647 }
2648 if (ci->mapping_nat_from) {
2649 ecm_db_mapping_deref(ci->mapping_nat_from);
2650 }
2651 if (ci->mapping_nat_to) {
2652 ecm_db_mapping_deref(ci->mapping_nat_to);
2653 }
2654 if (ci->feci) {
2655 ci->feci->deref(ci->feci);
2656 }
Gareth Williams90f2a282014-08-27 15:56:25 +01002657 if (ci->from_node) {
2658 ecm_db_node_deref(ci->from_node);
2659 }
2660 if (ci->to_node) {
2661 ecm_db_node_deref(ci->to_node);
2662 }
2663 if (ci->from_nat_node) {
2664 ecm_db_node_deref(ci->from_nat_node);
2665 }
2666 if (ci->to_nat_node) {
2667 ecm_db_node_deref(ci->to_nat_node);
2668 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002669
2670 /*
2671 * Remove references to the interfaces in our heirarchy lists
2672 */
2673 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2674 DEBUG_TRACE("%p: from interface %d remove: %p\n", ci, i, ci->from_interfaces[i]);
2675 ecm_db_iface_deref(ci->from_interfaces[i]);
2676 }
2677 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2678 DEBUG_TRACE("%p: to interface %d remove: %p\n", ci, i, ci->to_interfaces[i]);
2679 ecm_db_iface_deref(ci->to_interfaces[i]);
2680 }
2681 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2682 DEBUG_TRACE("%p: from nat interface %d remove: %p\n", ci, i, ci->from_nat_interfaces[i]);
2683 ecm_db_iface_deref(ci->from_nat_interfaces[i]);
2684 }
2685 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2686 DEBUG_TRACE("%p: to nat interface %d remove: %p\n", ci, i, ci->to_nat_interfaces[i]);
2687 ecm_db_iface_deref(ci->to_nat_interfaces[i]);
2688 }
2689
2690 /*
2691 * We can now destroy the instance
2692 */
2693 DEBUG_CLEAR_MAGIC(ci);
2694 kfree(ci);
2695
2696 /*
2697 * Decrease global connection count
2698 */
2699 spin_lock_bh(&ecm_db_lock);
2700 ecm_db_connection_count--;
2701 DEBUG_ASSERT(ecm_db_connection_count >= 0, "%p: connection count wrap\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002702 spin_unlock_bh(&ecm_db_lock);
2703
Ben Menchaca84f36632014-02-28 20:57:38 +00002704 return 0;
2705}
2706EXPORT_SYMBOL(ecm_db_connection_deref);
2707
2708/*
2709 * ecm_db_mapping_deref()
2710 * Release ref to mapping, possibly removing it from the database and destroying it.
2711 */
2712int ecm_db_mapping_deref(struct ecm_db_mapping_instance *mi)
2713{
2714 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
2715
2716 spin_lock_bh(&ecm_db_lock);
2717 mi->refs--;
2718 DEBUG_TRACE("%p: mapping deref %d\n", mi, mi->refs);
2719 DEBUG_ASSERT(mi->refs >= 0, "%p: ref wrap\n", mi);
2720
2721 if (mi->refs > 0) {
2722 int refs = mi->refs;
2723 spin_unlock_bh(&ecm_db_lock);
2724 return refs;
2725 }
2726
2727 DEBUG_ASSERT(!mi->from_connections && !mi->tcp_from && !mi->udp_from && !mi->from, "%p: from not null: %p, %d, %d, %d\n",
2728 mi, mi->from_connections, mi->tcp_from, mi->udp_from, mi->from);
2729 DEBUG_ASSERT(!mi->to_connections && !mi->tcp_to && !mi->udp_to && !mi->to, "%p: to not null: %p, %d, %d, %d\n",
2730 mi, mi->to_connections, mi->tcp_to, mi->udp_to, mi->to);
2731 DEBUG_ASSERT(!mi->from_nat_connections && !mi->tcp_nat_from && !mi->udp_nat_from && !mi->nat_from, "%p: nat_from not null: %p, %d, %d, %d\n",
2732 mi, mi->from_nat_connections, mi->tcp_nat_from, mi->udp_nat_from, mi->nat_from);
2733 DEBUG_ASSERT(!mi->to_nat_connections && !mi->tcp_nat_to && !mi->udp_nat_to && !mi->nat_to, "%p: nat_to not null: %p, %d, %d, %d\n",
2734 mi, mi->to_nat_connections, mi->tcp_nat_to, mi->udp_nat_to, mi->nat_to);
2735
2736 /*
2737 * Remove from database if inserted
2738 */
2739 if (!mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED) {
2740 spin_unlock_bh(&ecm_db_lock);
2741 } else {
2742 struct ecm_db_listener_instance *li;
2743
2744 /*
2745 * Remove from the global list
2746 */
2747 if (!mi->prev) {
2748 DEBUG_ASSERT(ecm_db_mappings == mi, "%p: mapping table bad\n", mi);
2749 ecm_db_mappings = mi->next;
2750 } else {
2751 mi->prev->next = mi->next;
2752 }
2753 if (mi->next) {
2754 mi->next->prev = mi->prev;
2755 }
2756
2757 /*
2758 * Unlink it from the mapping hash table
2759 */
2760 if (!mi->hash_prev) {
2761 DEBUG_ASSERT(ecm_db_mapping_table[mi->hash_index] == mi, "%p: hash table bad\n", mi);
2762 ecm_db_mapping_table[mi->hash_index] = mi->hash_next;
2763 } else {
2764 mi->hash_prev->hash_next = mi->hash_next;
2765 }
2766 if (mi->hash_next) {
2767 mi->hash_next->hash_prev = mi->hash_prev;
2768 }
2769 mi->hash_next = NULL;
2770 mi->hash_prev = NULL;
2771 ecm_db_mapping_table_lengths[mi->hash_index]--;
2772 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]);
2773
2774 /*
2775 * Unlink it from the host mapping list
2776 */
2777 if (!mi->mapping_prev) {
2778 DEBUG_ASSERT(mi->host->mappings == mi, "%p: mapping table bad\n", mi);
2779 mi->host->mappings = mi->mapping_next;
2780 } else {
2781 mi->mapping_prev->mapping_next = mi->mapping_next;
2782 }
2783 if (mi->mapping_next) {
2784 mi->mapping_next->mapping_prev = mi->mapping_prev;
2785 }
2786 mi->mapping_next = NULL;
2787 mi->mapping_prev = NULL;
2788
2789 mi->host->mapping_count--;
2790 spin_unlock_bh(&ecm_db_lock);
2791
2792 /*
2793 * Throw removed event to listeners
2794 */
2795 DEBUG_TRACE("%p: Throw mapping removed event\n", mi);
2796 li = ecm_db_listeners_get_and_ref_first();
2797 while (li) {
2798 struct ecm_db_listener_instance *lin;
2799 if (li->mapping_removed) {
2800 li->mapping_removed(li->arg, mi);
2801 }
2802
2803 /*
2804 * Get next listener
2805 */
2806 lin = ecm_db_listener_get_and_ref_next(li);
2807 ecm_db_listener_deref(li);
2808 li = lin;
2809 }
2810 }
2811
2812 /*
2813 * Throw final event
2814 */
2815 if (mi->final) {
2816 mi->final(mi->arg);
2817 }
2818
2819 /*
2820 * Now release the host instance if the mapping had one
2821 */
2822 if (mi->host) {
2823 ecm_db_host_deref(mi->host);
2824 }
2825
2826 /*
2827 * We can now destroy the instance
2828 */
2829 DEBUG_CLEAR_MAGIC(mi);
2830 kfree(mi);
2831
2832 /*
2833 * Decrease global mapping count
2834 */
2835 spin_lock_bh(&ecm_db_lock);
2836 ecm_db_mapping_count--;
2837 DEBUG_ASSERT(ecm_db_mapping_count >= 0, "%p: mapping count wrap\n", mi);
Ben Menchaca84f36632014-02-28 20:57:38 +00002838 spin_unlock_bh(&ecm_db_lock);
2839
Ben Menchaca84f36632014-02-28 20:57:38 +00002840 return 0;
2841}
2842EXPORT_SYMBOL(ecm_db_mapping_deref);
2843
2844/*
2845 * ecm_db_host_deref()
2846 * Release a ref to a host instance, possibly causing removal from the database and destruction of the instance
2847 */
2848int ecm_db_host_deref(struct ecm_db_host_instance *hi)
2849{
2850 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
2851
2852 spin_lock_bh(&ecm_db_lock);
2853 hi->refs--;
2854 DEBUG_TRACE("%p: host deref %d\n", hi, hi->refs);
2855 DEBUG_ASSERT(hi->refs >= 0, "%p: ref wrap\n", hi);
2856
2857 if (hi->refs > 0) {
2858 int refs = hi->refs;
2859 spin_unlock_bh(&ecm_db_lock);
2860 return refs;
2861 }
2862
2863 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
2864
2865 /*
2866 * Remove from database if inserted
2867 */
2868 if (!hi->flags & ECM_DB_HOST_FLAGS_INSERTED) {
2869 spin_unlock_bh(&ecm_db_lock);
2870 } else {
2871 struct ecm_db_listener_instance *li;
2872
2873 /*
2874 * Remove from the global list
2875 */
2876 if (!hi->prev) {
2877 DEBUG_ASSERT(ecm_db_hosts == hi, "%p: host table bad\n", hi);
2878 ecm_db_hosts = hi->next;
2879 } else {
2880 hi->prev->next = hi->next;
2881 }
2882 if (hi->next) {
2883 hi->next->prev = hi->prev;
2884 }
2885
2886 /*
2887 * Unlink it from the host hash table
2888 */
2889 if (!hi->hash_prev) {
2890 DEBUG_ASSERT(ecm_db_host_table[hi->hash_index] == hi, "%p: hash table bad\n", hi);
2891 ecm_db_host_table[hi->hash_index] = hi->hash_next;
2892 } else {
2893 hi->hash_prev->hash_next = hi->hash_next;
2894 }
2895 if (hi->hash_next) {
2896 hi->hash_next->hash_prev = hi->hash_prev;
2897 }
2898 hi->hash_next = NULL;
2899 hi->hash_prev = NULL;
2900 ecm_db_host_table_lengths[hi->hash_index]--;
2901 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]);
2902
Ben Menchaca84f36632014-02-28 20:57:38 +00002903 spin_unlock_bh(&ecm_db_lock);
2904
2905 /*
2906 * Throw removed event to listeners
2907 */
2908 DEBUG_TRACE("%p: Throw host removed event\n", hi);
2909 li = ecm_db_listeners_get_and_ref_first();
2910 while (li) {
2911 struct ecm_db_listener_instance *lin;
2912 if (li->host_removed) {
2913 li->host_removed(li->arg, hi);
2914 }
2915
2916 /*
2917 * Get next listener
2918 */
2919 lin = ecm_db_listener_get_and_ref_next(li);
2920 ecm_db_listener_deref(li);
2921 li = lin;
2922 }
2923 }
2924
2925 /*
2926 * Throw final event
2927 */
2928 if (hi->final) {
2929 hi->final(hi->arg);
2930 }
2931
2932 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002933 * We can now destroy the instance
2934 */
2935 DEBUG_CLEAR_MAGIC(hi);
2936 kfree(hi);
2937
2938 /*
2939 * Decrease global host count
2940 */
2941 spin_lock_bh(&ecm_db_lock);
2942 ecm_db_host_count--;
2943 DEBUG_ASSERT(ecm_db_host_count >= 0, "%p: host count wrap\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00002944 spin_unlock_bh(&ecm_db_lock);
2945
Ben Menchaca84f36632014-02-28 20:57:38 +00002946 return 0;
2947}
2948EXPORT_SYMBOL(ecm_db_host_deref);
2949
2950/*
2951 * ecm_db_node_deref()
2952 * Deref a node. Removing it on the last ref and destroying it.
2953 */
2954int ecm_db_node_deref(struct ecm_db_node_instance *ni)
2955{
2956 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
2957
2958 spin_lock_bh(&ecm_db_lock);
2959 ni->refs--;
2960 DEBUG_TRACE("%p: node deref %d\n", ni, ni->refs);
2961 DEBUG_ASSERT(ni->refs >= 0, "%p: ref wrap\n", ni);
2962
2963 if (ni->refs > 0) {
2964 int refs = ni->refs;
2965 spin_unlock_bh(&ecm_db_lock);
2966 return refs;
2967 }
2968
Gareth Williams90f2a282014-08-27 15:56:25 +01002969 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
2970 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
2971 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
2972 DEBUG_ASSERT((ni->to_nat_connections == NULL) && (ni->to_nat_connections_count == 0), "%p: to_nat_connections not null\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00002973
2974 /*
2975 * Remove from database if inserted
2976 */
2977 if (!ni->flags & ECM_DB_NODE_FLAGS_INSERTED) {
2978 spin_unlock_bh(&ecm_db_lock);
2979 } else {
2980 struct ecm_db_listener_instance *li;
2981
2982 /*
2983 * Remove from the global list
2984 */
2985 if (!ni->prev) {
2986 DEBUG_ASSERT(ecm_db_nodes == ni, "%p: node table bad\n", ni);
2987 ecm_db_nodes = ni->next;
2988 } else {
2989 ni->prev->next = ni->next;
2990 }
2991 if (ni->next) {
2992 ni->next->prev = ni->prev;
2993 }
2994
2995 /*
2996 * Link out of hash table
2997 */
2998 if (!ni->hash_prev) {
2999 DEBUG_ASSERT(ecm_db_node_table[ni->hash_index] == ni, "%p: hash table bad\n", ni);
3000 ecm_db_node_table[ni->hash_index] = ni->hash_next;
3001 } else {
3002 ni->hash_prev->hash_next = ni->hash_next;
3003 }
3004 if (ni->hash_next) {
3005 ni->hash_next->hash_prev = ni->hash_prev;
3006 }
3007 ni->hash_next = NULL;
3008 ni->hash_prev = NULL;
3009 ecm_db_node_table_lengths[ni->hash_index]--;
3010 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]);
3011
3012 /*
3013 * Unlink it from the iface node list
3014 */
3015 if (!ni->node_prev) {
3016 DEBUG_ASSERT(ni->iface->nodes == ni, "%p: nodes table bad\n", ni);
3017 ni->iface->nodes = ni->node_next;
3018 } else {
3019 ni->node_prev->node_next = ni->node_next;
3020 }
3021 if (ni->node_next) {
3022 ni->node_next->node_prev = ni->node_prev;
3023 }
3024 ni->node_next = NULL;
3025 ni->node_prev = NULL;
3026 ni->iface->node_count--;
3027 spin_unlock_bh(&ecm_db_lock);
3028
3029 /*
3030 * Throw removed event to listeners
3031 */
3032 DEBUG_TRACE("%p: Throw node removed event\n", ni);
3033 li = ecm_db_listeners_get_and_ref_first();
3034 while (li) {
3035 struct ecm_db_listener_instance *lin;
3036 if (li->node_removed) {
3037 li->node_removed(li->arg, ni);
3038 }
3039
3040 /*
3041 * Get next listener
3042 */
3043 lin = ecm_db_listener_get_and_ref_next(li);
3044 ecm_db_listener_deref(li);
3045 li = lin;
3046 }
3047 }
3048
3049 /*
3050 * Throw final event
3051 */
3052 if (ni->final) {
3053 ni->final(ni->arg);
3054 }
3055
3056 /*
3057 * Now release the iface instance if the node had one
3058 */
3059 if (ni->iface) {
3060 ecm_db_iface_deref(ni->iface);
3061 }
3062
3063 /*
3064 * We can now destroy the instance
3065 */
3066 DEBUG_CLEAR_MAGIC(ni);
3067 kfree(ni);
3068
3069 /*
3070 * Decrease global node count
3071 */
3072 spin_lock_bh(&ecm_db_lock);
3073 ecm_db_node_count--;
3074 DEBUG_ASSERT(ecm_db_node_count >= 0, "%p: node count wrap\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00003075 spin_unlock_bh(&ecm_db_lock);
3076
Ben Menchaca84f36632014-02-28 20:57:38 +00003077 return 0;
3078}
3079EXPORT_SYMBOL(ecm_db_node_deref);
3080
3081/*
3082 * ecm_db_iface_deref()
3083 * Deref a interface instance, removing it from the database on the last ref release
3084 */
3085int ecm_db_iface_deref(struct ecm_db_iface_instance *ii)
3086{
3087 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
3088
3089 /*
3090 * Decrement reference count
3091 */
3092 spin_lock_bh(&ecm_db_lock);
3093 ii->refs--;
3094 DEBUG_TRACE("%p: iface deref %d\n", ii, ii->refs);
3095 DEBUG_ASSERT(ii->refs >= 0, "%p: ref wrap\n", ii);
3096
3097 if (ii->refs > 0) {
3098 int refs = ii->refs;
3099 spin_unlock_bh(&ecm_db_lock);
3100 return refs;
3101 }
3102
3103 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
3104
3105 /*
3106 * Remove from database if inserted
3107 */
3108 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
3109 spin_unlock_bh(&ecm_db_lock);
3110 } else {
3111 struct ecm_db_listener_instance *li;
3112
3113 /*
3114 * Remove from the global list
3115 */
3116 if (!ii->prev) {
3117 DEBUG_ASSERT(ecm_db_interfaces == ii, "%p: interface table bad\n", ii);
3118 ecm_db_interfaces = ii->next;
3119 } else {
3120 ii->prev->next = ii->next;
3121 }
3122 if (ii->next) {
3123 ii->next->prev = ii->prev;
3124 }
3125
3126 /*
3127 * Link out of hash table
3128 */
3129 if (!ii->hash_prev) {
3130 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);
3131 ecm_db_iface_table[ii->hash_index] = ii->hash_next;
3132 } else {
3133 ii->hash_prev->hash_next = ii->hash_next;
3134 }
3135 if (ii->hash_next) {
3136 ii->hash_next->hash_prev = ii->hash_prev;
3137 }
3138 ii->hash_next = NULL;
3139 ii->hash_prev = NULL;
3140 ecm_db_iface_table_lengths[ii->hash_index]--;
3141 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]);
3142 spin_unlock_bh(&ecm_db_lock);
3143
3144 /*
3145 * Throw removed event to listeners
3146 */
3147 DEBUG_TRACE("%p: Throw iface removed event\n", ii);
3148 li = ecm_db_listeners_get_and_ref_first();
3149 while (li) {
3150 struct ecm_db_listener_instance *lin;
3151 if (li->iface_removed) {
3152 li->iface_removed(li->arg, ii);
3153 }
3154
3155 /*
3156 * Get next listener
3157 */
3158 lin = ecm_db_listener_get_and_ref_next(li);
3159 ecm_db_listener_deref(li);
3160 li = lin;
3161 }
3162 }
3163
3164 /*
3165 * Throw final event
3166 */
3167 if (ii->final) {
3168 ii->final(ii->arg);
3169 }
3170
3171 /*
3172 * We can now destroy the instance
3173 */
3174 DEBUG_CLEAR_MAGIC(ii);
3175 kfree(ii);
3176
3177 /*
3178 * Decrease global interface count
3179 */
3180 spin_lock_bh(&ecm_db_lock);
3181 ecm_db_iface_count--;
3182 DEBUG_ASSERT(ecm_db_iface_count >= 0, "%p: iface count wrap\n", ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00003183 spin_unlock_bh(&ecm_db_lock);
3184
Ben Menchaca84f36632014-02-28 20:57:38 +00003185 return 0;
3186}
3187EXPORT_SYMBOL(ecm_db_iface_deref);
3188
3189/*
3190 * ecm_db_listener_deref()
3191 * Release reference to listener.
3192 *
3193 * On final reference release listener shall be removed from the database.
3194 */
3195int ecm_db_listener_deref(struct ecm_db_listener_instance *li)
3196{
3197 struct ecm_db_listener_instance *cli;
3198 struct ecm_db_listener_instance **cli_prev;
3199
3200 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
3201
3202 spin_lock_bh(&ecm_db_lock);
3203 li->refs--;
3204 DEBUG_ASSERT(li->refs >= 0, "%p: ref wrap\n", li);
3205 if (li->refs > 0) {
3206 int refs;
3207 refs = li->refs;
3208 spin_unlock_bh(&ecm_db_lock);
3209 return refs;
3210 }
3211
3212 /*
3213 * Instance is to be removed and destroyed.
3214 * Link the listener out of the listener list.
3215 */
3216 cli = ecm_db_listeners;
3217 cli_prev = &ecm_db_listeners;
3218 while (cli) {
3219 if (cli == li) {
3220 *cli_prev = cli->next;
3221 break;
3222 }
3223 cli_prev = &cli->next;
3224 cli = cli->next;
3225 }
3226 DEBUG_ASSERT(cli, "%p: not found\n", li);
3227 spin_unlock_bh(&ecm_db_lock);
3228
3229 /*
3230 * Invoke final callback
3231 */
3232 if (li->final) {
3233 li->final(li->arg);
3234 }
3235 DEBUG_CLEAR_MAGIC(li);
3236 kfree(li);
3237
3238 /*
3239 * Decrease global listener count
3240 */
3241 spin_lock_bh(&ecm_db_lock);
3242 ecm_db_listeners_count--;
3243 DEBUG_ASSERT(ecm_db_listeners_count >= 0, "%p: listener count wrap\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00003244 spin_unlock_bh(&ecm_db_lock);
3245
Ben Menchaca84f36632014-02-28 20:57:38 +00003246 return 0;
3247}
3248EXPORT_SYMBOL(ecm_db_listener_deref);
3249
3250/*
3251 * ecm_db_connection_defunct_all()
3252 * Make defunct ALL connections.
3253 *
3254 * This API is typically used in shutdown situations commanded by the user.
3255 * NOTE: Ensure all front ends are stopped to avoid further connections being created while this is running.
3256 */
3257void ecm_db_connection_defunct_all(void)
3258{
3259 struct ecm_db_connection_instance *ci;
3260
3261 DEBUG_INFO("Defuncting all\n");
3262
3263 /*
3264 * Iterate all connections
3265 */
3266 ci = ecm_db_connections_get_and_ref_first();
3267 while (ci) {
3268 struct ecm_db_connection_instance *cin;
3269
3270 DEBUG_TRACE("%p: defunct\n", ci);
3271 ecm_db_connection_make_defunct(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303272
Ben Menchaca84f36632014-02-28 20:57:38 +00003273 cin = ecm_db_connection_get_and_ref_next(ci);
3274 ecm_db_connection_deref(ci);
3275 ci = cin;
3276 }
3277 DEBUG_INFO("Defuncting complete\n");
3278}
3279EXPORT_SYMBOL(ecm_db_connection_defunct_all);
3280
3281/*
3282 * ecm_db_connection_generate_hash_index()
3283 * Calculate the hash index.
3284 *
3285 * Note: The hash we produce is symmetric - i.e. we can swap the "from" and "to"
3286 * details without generating a different hash index!
3287 */
3288static 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)
3289{
3290 uint32_t temp;
3291 uint32_t hash_val;
3292
3293 /*
3294 * The hash function only uses both host 1 address/port, host 2 address/port
3295 * and protocol fields.
3296 */
3297 temp = (u32)host1_addr[0] + host1_port + (u32)host2_addr[0] + host2_port + (uint32_t)protocol;
3298 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3299
3300 return (ecm_db_connection_hash_t)(hash_val & (ECM_DB_CONNECTION_HASH_SLOTS - 1));
3301}
3302
3303/*
3304 * ecm_db_connection_generate_serial_hash_index()
3305 * Calculate the serial hash index.
3306 */
3307static inline ecm_db_connection_serial_hash_t ecm_db_connection_generate_serial_hash_index(uint32_t serial)
3308{
3309 return (ecm_db_connection_serial_hash_t)(serial & (ECM_DB_CONNECTION_SERIAL_HASH_SLOTS - 1));
3310}
3311
3312/*
3313 * ecm_db_mapping_generate_hash_index()
3314 * Calculate the hash index.
3315 */
3316static inline ecm_db_mapping_hash_t ecm_db_mapping_generate_hash_index(ip_addr_t address, uint32_t port)
3317{
3318 uint32_t temp;
3319 uint32_t hash_val;
3320
3321 temp = (u32)address[0] + port;
3322 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3323
3324 return (ecm_db_mapping_hash_t)(hash_val & (ECM_DB_MAPPING_HASH_SLOTS - 1));
3325}
3326
3327/*
3328 * ecm_db_host_generate_hash_index()
3329 * Calculate the hash index.
3330 */
3331static inline ecm_db_host_hash_t ecm_db_host_generate_hash_index(ip_addr_t address)
3332{
3333 uint32_t temp;
3334 uint32_t hash_val;
3335
3336 temp = (uint32_t)address[0];
3337 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3338
3339 return (ecm_db_host_hash_t)(hash_val & (ECM_DB_HOST_HASH_SLOTS - 1));
3340}
3341
3342/*
3343 * ecm_db_node_generate_hash_index()
3344 * Calculate the hash index.
3345 */
3346static inline ecm_db_node_hash_t ecm_db_node_generate_hash_index(uint8_t *address)
3347{
3348 uint32_t hash_val;
3349
3350 hash_val = (((uint32_t)(address[2] ^ address[4])) << 8) | (address[3] ^ address[5]);
3351 hash_val &= (ECM_DB_NODE_HASH_SLOTS - 1);
3352
3353 return (ecm_db_node_hash_t)hash_val;
3354}
3355
3356/*
3357 * ecm_db_iface_generate_hash_index_sit()
3358 * Calculate the hash index.
3359 */
3360static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_sit(ip_addr_t saddr, ip_addr_t daddr)
3361{
3362 uint32_t temp;
3363 uint32_t hash_val;
3364
3365 temp = (uint32_t )(saddr[0] ^ daddr[0]);
3366 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3367 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3368}
3369
3370/*
3371 * ecm_db_iface_generate_hash_index_tunipip6()
3372 * Calculate the hash index.
3373 */
3374static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
3375{
3376 uint32_t temp;
3377 uint32_t hash_val;
3378
3379 temp = (uint32_t )(saddr[0] ^ daddr[0]);
3380 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3381 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3382}
3383
3384/*
3385 * ecm_db_iface_generate_hash_index_ethernet()
3386 * Calculate the hash index.
3387 */
3388static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ethernet(uint8_t *address)
3389{
3390 return (ecm_db_iface_hash_t)(address[5] & (ECM_DB_IFACE_HASH_SLOTS - 1));
3391}
3392
3393/*
3394 * ecm_db_iface_generate_hash_index_pppoe()
3395 * Calculate the hash index.
3396 */
3397static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppoe(uint16_t pppoe_session_id)
3398{
3399 return (ecm_db_iface_hash_t)(pppoe_session_id & (ECM_DB_IFACE_HASH_SLOTS - 1));
3400}
3401
3402/*
3403 * ecm_db_iface_generate_hash_index_unknown()
3404 * Calculate the hash index.
3405 */
3406static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_unknown(uint32_t os_specific_ident)
3407{
3408 return (ecm_db_iface_hash_t)(os_specific_ident & (ECM_DB_IFACE_HASH_SLOTS - 1));
3409}
3410
3411/*
3412 * ecm_db_iface_generate_hash_index_loopback()
3413 * Calculate the hash index.
3414 */
3415static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_loopback(uint32_t os_specific_ident)
3416{
3417 return (ecm_db_iface_hash_t)(os_specific_ident & (ECM_DB_IFACE_HASH_SLOTS - 1));
3418}
3419
3420/*
3421 * ecm_db_iface_generate_hash_index_ipsec_tunnel()
3422 * Calculate the hash index.
3423 * GGG TODO Flesh this out using actual tunnel endpoint keys
3424 */
3425static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ipsec_tunnel(uint32_t os_specific_ident)
3426{
3427 return (ecm_db_iface_hash_t)(os_specific_ident & (ECM_DB_IFACE_HASH_SLOTS - 1));
3428}
3429
3430/*
3431 * ecm_db_host_find_and_ref()
3432 * Lookup and return a host reference if any
3433 */
3434struct ecm_db_host_instance *ecm_db_host_find_and_ref(ip_addr_t address)
3435{
3436 ecm_db_host_hash_t hash_index;
3437 struct ecm_db_host_instance *hi;
3438
3439 DEBUG_TRACE("Lookup host with addr " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(address));
3440
3441 /*
3442 * Compute the hash chain index and prepare to walk the chain
3443 */
3444 hash_index = ecm_db_host_generate_hash_index(address);
3445
3446 /*
3447 * Iterate the chain looking for a host with matching details
3448 */
3449 spin_lock_bh(&ecm_db_lock);
3450 hi = ecm_db_host_table[hash_index];
3451 while (hi) {
3452 if (!ECM_IP_ADDR_MATCH(hi->address, address)) {
3453 hi = hi->hash_next;
3454 continue;
3455 }
3456
3457 _ecm_db_host_ref(hi);
3458 spin_unlock_bh(&ecm_db_lock);
3459 DEBUG_TRACE("host found %p\n", hi);
3460 return hi;
3461 }
3462 spin_unlock_bh(&ecm_db_lock);
3463 DEBUG_TRACE("Host not found\n");
3464 return NULL;
3465}
3466EXPORT_SYMBOL(ecm_db_host_find_and_ref);
3467
3468/*
3469 * ecm_db_node_find_and_ref()
3470 * Lookup and return a node reference if any
3471 */
3472struct ecm_db_node_instance *ecm_db_node_find_and_ref(uint8_t *address)
3473{
3474 ecm_db_node_hash_t hash_index;
3475 struct ecm_db_node_instance *ni;
3476
3477 DEBUG_TRACE("Lookup node with addr %pM\n", address);
3478
3479 /*
3480 * Compute the hash chain index and prepare to walk the chain
3481 */
3482 hash_index = ecm_db_node_generate_hash_index(address);
3483
3484 /*
3485 * Iterate the chain looking for a host with matching details
3486 */
3487 spin_lock_bh(&ecm_db_lock);
3488 ni = ecm_db_node_table[hash_index];
3489 while (ni) {
3490 if (memcmp(ni->address, address, ETH_ALEN)) {
3491 ni = ni->hash_next;
3492 continue;
3493 }
3494
3495 _ecm_db_node_ref(ni);
3496 spin_unlock_bh(&ecm_db_lock);
3497 DEBUG_TRACE("node found %p\n", ni);
3498 return ni;
3499 }
3500 spin_unlock_bh(&ecm_db_lock);
3501 DEBUG_TRACE("Node not found\n");
3502 return NULL;
3503}
3504EXPORT_SYMBOL(ecm_db_node_find_and_ref);
3505
3506/*
3507 * ecm_db_iface_ethernet_address_get()
3508 * Obtain the ethernet address for an ethernet interface
3509 */
3510void ecm_db_iface_ethernet_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
3511{
3512 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3513 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_ETHERNET, "%p: Bad type, expected ethernet, actual: %d\n", ii, ii->type);
3514 spin_lock_bh(&ecm_db_lock);
3515 memcpy(address, ii->type_info.ethernet.address, sizeof(ii->type_info.ethernet.address));
3516 spin_unlock_bh(&ecm_db_lock);
3517}
3518EXPORT_SYMBOL(ecm_db_iface_ethernet_address_get);
3519
3520/*
Gareth Williams83125b12014-05-26 19:58:09 +01003521 * ecm_db_iface_bridge_address_get()
3522 * Obtain the ethernet address for a bridge interface
3523 */
3524void ecm_db_iface_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
3525{
3526 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3527 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_BRIDGE, "%p: Bad type, expected bridge, actual: %d\n", ii, ii->type);
3528 spin_lock_bh(&ecm_db_lock);
3529 memcpy(address, ii->type_info.bridge.address, sizeof(ii->type_info.bridge.address));
3530 spin_unlock_bh(&ecm_db_lock);
3531}
3532EXPORT_SYMBOL(ecm_db_iface_bridge_address_get);
3533
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05303534struct 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 +00003535{
3536 ecm_db_iface_hash_t hash_index;
3537 struct ecm_db_iface_instance *ii;
3538
3539 DEBUG_TRACE("Lookup ethernet iface with addr %pM\n", address);
3540
3541 /*
3542 * Compute the hash chain index and prepare to walk the chain
3543 */
3544 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3545
3546 /*
3547 * Iterate the chain looking for a host with matching details
3548 */
3549 spin_lock_bh(&ecm_db_lock);
3550 ii = ecm_db_iface_table[hash_index];
3551 while (ii) {
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05303552 if ((ii->type != ECM_DB_IFACE_TYPE_ETHERNET)
3553 || memcmp(ii->type_info.ethernet.address, address, ETH_ALEN)
3554 || ii->interface_identifier != ifidx) {
Ben Menchaca84f36632014-02-28 20:57:38 +00003555 ii = ii->hash_next;
3556 continue;
3557 }
3558
3559 _ecm_db_iface_ref(ii);
3560 spin_unlock_bh(&ecm_db_lock);
3561 DEBUG_TRACE("iface found %p\n", ii);
3562 return ii;
3563 }
3564 spin_unlock_bh(&ecm_db_lock);
3565 DEBUG_TRACE("Iface not found\n");
3566 return NULL;
3567}
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05303568EXPORT_SYMBOL(ecm_db_iface_ifidx_find_and_ref_ethernet);
3569
3570
Ben Menchaca84f36632014-02-28 20:57:38 +00003571
3572/*
3573 * ecm_db_iface_vlan_info_get()
3574 * Get vlan interface specific information
3575 */
3576void ecm_db_iface_vlan_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_vlan *vlan_info)
3577{
3578 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3579 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_VLAN, "%p: Bad type, expected vlan, actual: %d\n", ii, ii->type);
3580 spin_lock_bh(&ecm_db_lock);
3581 memcpy(vlan_info->address, ii->type_info.vlan.address, sizeof(ii->type_info.vlan.address));
3582 vlan_info->vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303583 vlan_info->vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00003584 spin_unlock_bh(&ecm_db_lock);
3585}
3586EXPORT_SYMBOL(ecm_db_iface_vlan_info_get);
3587
3588/*
3589 * ecm_db_iface_find_and_ref_vlan()
3590 * Lookup and return a iface reference if any
3591 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303592struct 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 +00003593{
3594 ecm_db_iface_hash_t hash_index;
3595 struct ecm_db_iface_instance *ii;
3596
Sol Kavyd7583592014-06-05 18:51:46 -07003597 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 +00003598
3599 /*
3600 * Compute the hash chain index and prepare to walk the chain
3601 */
3602 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3603
3604 /*
3605 * Iterate the chain looking for a host with matching details
3606 */
3607 spin_lock_bh(&ecm_db_lock);
3608 ii = ecm_db_iface_table[hash_index];
3609 while (ii) {
3610 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 +05303611 || (ii->type_info.vlan.vlan_tpid != vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00003612 || memcmp(ii->type_info.vlan.address, address, ETH_ALEN)) {
3613 ii = ii->hash_next;
3614 continue;
3615 }
3616
3617 _ecm_db_iface_ref(ii);
3618 spin_unlock_bh(&ecm_db_lock);
3619 DEBUG_TRACE("iface found %p\n", ii);
3620 return ii;
3621 }
3622 spin_unlock_bh(&ecm_db_lock);
3623 DEBUG_TRACE("Iface not found\n");
3624 return NULL;
3625}
3626EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
3627
3628/*
3629 * ecm_db_iface_find_and_ref_bridge()
3630 * Lookup and return a iface reference if any
3631 */
3632struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_bridge(uint8_t *address)
3633{
3634 ecm_db_iface_hash_t hash_index;
3635 struct ecm_db_iface_instance *ii;
3636
3637 DEBUG_TRACE("Lookup bridge iface with addr %pM\n", address);
3638
3639 /*
3640 * Compute the hash chain index and prepare to walk the chain
3641 */
3642 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3643
3644 /*
3645 * Iterate the chain looking for a host with matching details
3646 */
3647 spin_lock_bh(&ecm_db_lock);
3648 ii = ecm_db_iface_table[hash_index];
3649 while (ii) {
3650 if ((ii->type != ECM_DB_IFACE_TYPE_BRIDGE) || memcmp(ii->type_info.bridge.address, address, ETH_ALEN)) {
3651 ii = ii->hash_next;
3652 continue;
3653 }
3654
3655 _ecm_db_iface_ref(ii);
3656 spin_unlock_bh(&ecm_db_lock);
3657 DEBUG_TRACE("iface found %p\n", ii);
3658 return ii;
3659 }
3660 spin_unlock_bh(&ecm_db_lock);
3661 DEBUG_TRACE("Iface not found\n");
3662 return NULL;
3663}
3664EXPORT_SYMBOL(ecm_db_iface_find_and_ref_bridge);
3665
3666/*
3667 * ecm_db_iface_find_and_ref_lag()
3668 * Lookup and return a iface reference if any
3669 */
3670struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_lag(uint8_t *address)
3671{
3672 ecm_db_iface_hash_t hash_index;
3673 struct ecm_db_iface_instance *ii;
3674
3675 DEBUG_TRACE("Lookup lag iface with addr %pM\n", address);
3676
3677 /*
3678 * Compute the hash chain index and prepare to walk the chain
3679 */
3680 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3681
3682 /*
3683 * Iterate the chain looking for a host with matching details
3684 */
3685 spin_lock_bh(&ecm_db_lock);
3686 ii = ecm_db_iface_table[hash_index];
3687 while (ii) {
3688 if ((ii->type != ECM_DB_IFACE_TYPE_LAG) || memcmp(ii->type_info.lag.address, address, ETH_ALEN)) {
3689 ii = ii->hash_next;
3690 continue;
3691 }
3692
3693 _ecm_db_iface_ref(ii);
3694 spin_unlock_bh(&ecm_db_lock);
3695 DEBUG_TRACE("iface found %p\n", ii);
3696 return ii;
3697 }
3698 spin_unlock_bh(&ecm_db_lock);
3699 DEBUG_TRACE("Iface not found\n");
3700 return NULL;
3701}
3702EXPORT_SYMBOL(ecm_db_iface_find_and_ref_lag);
3703
3704/*
3705 * ecm_db_iface_pppoe_session_info_get()
3706 * Get vlan interface specific information
3707 */
3708void ecm_db_iface_pppoe_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppoe *pppoe_info)
3709{
3710 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3711 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOE, "%p: Bad type, expected pppoe, actual: %d\n", ii, ii->type);
3712 spin_lock_bh(&ecm_db_lock);
3713 memcpy(pppoe_info->remote_mac, ii->type_info.pppoe.remote_mac, sizeof(ii->type_info.pppoe.remote_mac));
3714 pppoe_info->pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
3715 spin_unlock_bh(&ecm_db_lock);
3716}
3717EXPORT_SYMBOL(ecm_db_iface_pppoe_session_info_get);
3718
3719/*
3720 * ecm_db_iface_find_and_ref_pppoe()
3721 * Lookup and return a iface reference if any
3722 */
3723struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppoe(uint16_t pppoe_session_id, uint8_t *remote_mac)
3724{
3725 ecm_db_iface_hash_t hash_index;
3726 struct ecm_db_iface_instance *ii;
3727
3728 DEBUG_TRACE("Lookup pppoe iface with addr %x\n", pppoe_session_id);
3729
3730 /*
3731 * Compute the hash chain index and prepare to walk the chain
3732 */
3733 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
3734
3735 /*
3736 * Iterate the chain looking for a host with matching details
3737 */
3738 spin_lock_bh(&ecm_db_lock);
3739 ii = ecm_db_iface_table[hash_index];
3740 while (ii) {
3741 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOE)
3742 || (ii->type_info.pppoe.pppoe_session_id != pppoe_session_id)
3743 || memcmp(ii->type_info.pppoe.remote_mac, remote_mac, ETH_ALEN)) {
3744 ii = ii->hash_next;
3745 continue;
3746 }
3747
3748 _ecm_db_iface_ref(ii);
3749 spin_unlock_bh(&ecm_db_lock);
3750 DEBUG_TRACE("iface found %p\n", ii);
3751 return ii;
3752 }
3753 spin_unlock_bh(&ecm_db_lock);
3754 DEBUG_TRACE("Iface not found\n");
3755 return NULL;
3756}
3757EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppoe);
3758
3759/*
3760 * ecm_db_iface_find_and_ref_unknown()
3761 * Lookup and return a iface reference if any
3762 */
3763struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_unknown(uint32_t os_specific_ident)
3764{
3765 ecm_db_iface_hash_t hash_index;
3766 struct ecm_db_iface_instance *ii;
3767
3768 DEBUG_TRACE("Lookup unknown iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
3769
3770 /*
3771 * Compute the hash chain index and prepare to walk the chain
3772 */
3773 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
3774
3775 /*
3776 * Iterate the chain looking for a host with matching details
3777 */
3778 spin_lock_bh(&ecm_db_lock);
3779 ii = ecm_db_iface_table[hash_index];
3780 while (ii) {
3781 if ((ii->type != ECM_DB_IFACE_TYPE_UNKNOWN) || (ii->type_info.unknown.os_specific_ident != os_specific_ident)) {
3782 ii = ii->hash_next;
3783 continue;
3784 }
3785
3786 _ecm_db_iface_ref(ii);
3787 spin_unlock_bh(&ecm_db_lock);
3788 DEBUG_TRACE("iface found %p\n", ii);
3789 return ii;
3790 }
3791 spin_unlock_bh(&ecm_db_lock);
3792 DEBUG_TRACE("Iface not found\n");
3793 return NULL;
3794}
3795EXPORT_SYMBOL(ecm_db_iface_find_and_ref_unknown);
3796
3797/*
3798 * ecm_db_iface_find_and_ref_loopback()
3799 * Lookup and return a iface reference if any
3800 */
3801struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident)
3802{
3803 ecm_db_iface_hash_t hash_index;
3804 struct ecm_db_iface_instance *ii;
3805
3806 DEBUG_TRACE("Lookup loopback iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
3807
3808 /*
3809 * Compute the hash chain index and prepare to walk the chain
3810 */
3811 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
3812
3813 /*
3814 * Iterate the chain looking for a host with matching details
3815 */
3816 spin_lock_bh(&ecm_db_lock);
3817 ii = ecm_db_iface_table[hash_index];
3818 while (ii) {
3819 if ((ii->type != ECM_DB_IFACE_TYPE_LOOPBACK) || (ii->type_info.loopback.os_specific_ident != os_specific_ident)) {
3820 ii = ii->hash_next;
3821 continue;
3822 }
3823
3824 _ecm_db_iface_ref(ii);
3825 spin_unlock_bh(&ecm_db_lock);
3826 DEBUG_TRACE("iface found %p\n", ii);
3827 return ii;
3828 }
3829 spin_unlock_bh(&ecm_db_lock);
3830 DEBUG_TRACE("Iface not found\n");
3831 return NULL;
3832}
3833EXPORT_SYMBOL(ecm_db_iface_find_and_ref_loopback);
3834
3835/*
3836 * ecm_db_iface_find_and_ref_ipsec_tunnel()
3837 * Lookup and return a iface reference if any.
3838 * GGG TODO Flesh this out using tunnel endpoint keys
3839 */
3840struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident)
3841{
3842 ecm_db_iface_hash_t hash_index;
3843 struct ecm_db_iface_instance *ii;
3844
3845 DEBUG_TRACE("Lookup ipsec_tunnel iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
3846
3847 /*
3848 * Compute the hash chain index and prepare to walk the chain
3849 */
3850 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
3851
3852 /*
3853 * Iterate the chain looking for a host with matching details
3854 */
3855 spin_lock_bh(&ecm_db_lock);
3856 ii = ecm_db_iface_table[hash_index];
3857 while (ii) {
3858 if ((ii->type != ECM_DB_IFACE_TYPE_IPSEC_TUNNEL) || (ii->type_info.ipsec_tunnel.os_specific_ident != os_specific_ident)) {
3859 ii = ii->hash_next;
3860 continue;
3861 }
3862
3863 _ecm_db_iface_ref(ii);
3864 spin_unlock_bh(&ecm_db_lock);
3865 DEBUG_TRACE("iface found %p\n", ii);
3866 return ii;
3867 }
3868 spin_unlock_bh(&ecm_db_lock);
3869 DEBUG_TRACE("Iface not found\n");
3870 return NULL;
3871}
3872EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ipsec_tunnel);
3873
3874/*
3875 * ecm_db_iface_find_and_ref_sit()
3876 * Lookup and return a iface reference if any
3877 */
3878struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_sit(ip_addr_t saddr, ip_addr_t daddr)
3879{
3880 ecm_db_iface_hash_t hash_index;
3881 struct ecm_db_iface_instance *ii;
3882
3883 DEBUG_TRACE("Lookup sit (6-in-4) iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
3884 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
3885
3886 /*
3887 * Compute the hash chain index and prepare to walk the chain
3888 */
3889 hash_index = ecm_db_iface_generate_hash_index_sit(saddr, daddr);
3890
3891 /*
3892 * Iterate the chain looking for a host with matching details
3893 */
3894 spin_lock_bh(&ecm_db_lock);
3895 ii = ecm_db_iface_table[hash_index];
3896 while (ii) {
3897 if ((ii->type != ECM_DB_IFACE_TYPE_SIT)
3898 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.saddr, saddr)
3899 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.daddr, daddr)) {
3900 ii = ii->hash_next;
3901 continue;
3902 }
3903
3904 _ecm_db_iface_ref(ii);
3905 spin_unlock_bh(&ecm_db_lock);
3906 DEBUG_TRACE("iface found %p\n", ii);
3907 return ii;
3908 }
3909 spin_unlock_bh(&ecm_db_lock);
3910 DEBUG_TRACE("Iface not found\n");
3911 return NULL;
3912}
3913EXPORT_SYMBOL(ecm_db_iface_find_and_ref_sit);
3914
3915/*
3916 * ecm_db_iface_find_and_ref_tunipip6()
3917 * Lookup and return a iface reference if any
3918 */
3919struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
3920{
3921 ecm_db_iface_hash_t hash_index;
3922 struct ecm_db_iface_instance *ii;
3923
3924 DEBUG_TRACE("Lookup TUNIPIP6 iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
3925 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
3926
3927 /*
3928 * Compute the hash chain index and prepare to walk the chain
3929 */
3930 hash_index = ecm_db_iface_generate_hash_index_tunipip6(saddr, daddr);
3931
3932 /*
3933 * Iterate the chain looking for a host with matching details
3934 */
3935 spin_lock_bh(&ecm_db_lock);
3936 ii = ecm_db_iface_table[hash_index];
3937 while (ii) {
3938 if ((ii->type != ECM_DB_IFACE_TYPE_TUNIPIP6)
3939 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.saddr, saddr)
3940 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.daddr, daddr)) {
3941 ii = ii->hash_next;
3942 continue;
3943 }
3944
3945 _ecm_db_iface_ref(ii);
3946 spin_unlock_bh(&ecm_db_lock);
3947 DEBUG_TRACE("iface found %p\n", ii);
3948 return ii;
3949 }
3950 spin_unlock_bh(&ecm_db_lock);
3951 DEBUG_TRACE("Iface not found\n");
3952 return NULL;
3953}
3954EXPORT_SYMBOL(ecm_db_iface_find_and_ref_tunipip6);
3955
3956/*
3957 * ecm_db_mapping_find_and_ref()
3958 * Lookup and return a mapping reference if any.
3959 *
3960 * NOTE: For non-port based protocols the ports are expected to be -(protocol)
3961 */
3962struct ecm_db_mapping_instance *ecm_db_mapping_find_and_ref(ip_addr_t address, int port)
3963{
3964 ecm_db_mapping_hash_t hash_index;
3965 struct ecm_db_mapping_instance *mi;
3966
3967 DEBUG_TRACE("Lookup mapping with addr " ECM_IP_ADDR_OCTAL_FMT " and port %d\n", ECM_IP_ADDR_TO_OCTAL(address), port);
3968
3969 /*
3970 * Compute the hash chain index and prepare to walk the chain
3971 */
3972 hash_index = ecm_db_mapping_generate_hash_index(address, port);
3973
3974 /*
3975 * Iterate the chain looking for a mapping with matching details
3976 */
3977 spin_lock_bh(&ecm_db_lock);
3978 mi = ecm_db_mapping_table[hash_index];
3979 while (mi) {
3980 if (mi->port != port) {
3981 mi = mi->hash_next;
3982 continue;
3983 }
3984
3985 if (!ECM_IP_ADDR_MATCH(mi->host->address, address)) {
3986 mi = mi->hash_next;
3987 continue;
3988 }
3989
3990 _ecm_db_mapping_ref(mi);
3991 spin_unlock_bh(&ecm_db_lock);
3992 DEBUG_TRACE("Mapping found %p\n", mi);
3993 return mi;
3994 }
3995 spin_unlock_bh(&ecm_db_lock);
3996 DEBUG_TRACE("Mapping not found\n");
3997 return NULL;
3998}
3999EXPORT_SYMBOL(ecm_db_mapping_find_and_ref);
4000
4001/*
4002 * ecm_db_connection_find_and_ref()
4003 * Locate a connection instance based on addressing, protocol and optional port information.
4004 *
4005 * NOTE: For non-port based protocols then ports are expected to be -(protocol).
4006 */
4007struct 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)
4008{
4009 ecm_db_connection_hash_t hash_index;
4010 struct ecm_db_connection_instance *ci;
4011
4012 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);
4013
4014 /*
4015 * Compute the hash chain index and prepare to walk the chain
4016 */
4017 hash_index = ecm_db_connection_generate_hash_index(host1_addr, host1_port, host2_addr, host2_port, protocol);
4018
4019 /*
4020 * Iterate the chain looking for a connection with matching details
4021 */
4022 spin_lock_bh(&ecm_db_lock);
4023 ci = ecm_db_connection_table[hash_index];
4024 if (ci) {
4025 _ecm_db_connection_ref(ci);
4026 }
4027 spin_unlock_bh(&ecm_db_lock);
4028 while (ci) {
4029 struct ecm_db_connection_instance *cin;
4030
4031 /*
4032 * The use of unlikely() is liberally used because under fast-hit scenarios the connection would always be at the start of a chain
4033 */
4034 if (unlikely(ci->protocol != protocol)) {
4035 goto try_next;
4036 }
4037
4038 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_from->host->address))) {
4039 goto try_reverse;
4040 }
4041
4042 if (unlikely(host1_port != ci->mapping_from->port)) {
4043 goto try_reverse;
4044 }
4045
4046 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_to->host->address))) {
4047 goto try_reverse;
4048 }
4049
4050 if (unlikely(host2_port != ci->mapping_to->port)) {
4051 goto try_reverse;
4052 }
4053
4054 goto connection_found;
4055
4056try_reverse:
4057 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_to->host->address))) {
4058 goto try_next;
4059 }
4060
4061 if (unlikely(host1_port != ci->mapping_to->port)) {
4062 goto try_next;
4063 }
4064
4065 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_from->host->address))) {
4066 goto try_next;
4067 }
4068
4069 if (unlikely(host2_port != ci->mapping_from->port)) {
4070 goto try_next;
4071 }
4072
4073 goto connection_found;
4074
4075try_next:
4076 spin_lock_bh(&ecm_db_lock);
4077 cin = ci->hash_next;
4078 if (cin) {
4079 _ecm_db_connection_ref(cin);
4080 }
4081 spin_unlock_bh(&ecm_db_lock);
4082 ecm_db_connection_deref(ci);
4083 ci = cin;
4084 }
4085 DEBUG_TRACE("Connection not found\n");
4086 return NULL;
4087
4088connection_found:
4089 DEBUG_TRACE("Connection found %p\n", ci);
4090
4091 /*
4092 * Move this connection to the head of the hash chain.
4093 * This will win for us with heavy hit connections - we bubble MRU to the front of the list to
4094 * avoid too much chain walking.
4095 */
4096 spin_lock_bh(&ecm_db_lock);
4097 if (!ci->hash_prev) {
4098 /*
4099 * No prev pointer - ci is at the head of the list already
4100 */
4101 DEBUG_ASSERT(ecm_db_connection_table[hash_index] == ci, "%p: hash table bad\n", ci);
4102 spin_unlock_bh(&ecm_db_lock);
4103 return ci;
4104 }
4105
4106 /*
4107 * Link out
4108 */
4109 ci->hash_prev->hash_next = ci->hash_next;
4110 if (ci->hash_next) {
4111 ci->hash_next->hash_prev = ci->hash_prev;
4112 }
4113
4114 /*
4115 * Re-insert at the head.
4116 * NOTE: We know that there is a head already that is different to ci.
4117 */
4118 ci->hash_next = ecm_db_connection_table[hash_index];
4119 ecm_db_connection_table[hash_index]->hash_prev = ci;
4120 ecm_db_connection_table[hash_index] = ci;
4121 ci->hash_prev = NULL;
4122 spin_unlock_bh(&ecm_db_lock);
4123 return ci;
4124}
4125EXPORT_SYMBOL(ecm_db_connection_find_and_ref);
4126
4127/*
4128 * ecm_db_connection_serial_find_and_ref()
4129 * Locate a connection instance based on serial if it still exists
4130 */
4131struct ecm_db_connection_instance *ecm_db_connection_serial_find_and_ref(uint32_t serial)
4132{
4133 ecm_db_connection_serial_hash_t serial_hash_index;
4134 struct ecm_db_connection_instance *ci;
4135
4136 DEBUG_TRACE("Lookup connection serial: %u\n", serial);
4137
4138 /*
4139 * Compute the hash chain index and prepare to walk the chain
4140 */
4141 serial_hash_index = ecm_db_connection_generate_serial_hash_index(serial);
4142
4143 /*
4144 * Iterate the chain looking for a connection with matching serial
4145 */
4146 spin_lock_bh(&ecm_db_lock);
4147 ci = ecm_db_connection_serial_table[serial_hash_index];
4148 if (ci) {
4149 _ecm_db_connection_ref(ci);
4150 }
4151 spin_unlock_bh(&ecm_db_lock);
4152 while (ci) {
4153 struct ecm_db_connection_instance *cin;
4154
4155 /*
4156 * The use of likely() is used because under fast-hit scenarios the connection would always be at the start of a chain
4157 */
4158 if (likely(ci->serial == serial)) {
4159 goto connection_found;
4160 }
4161
4162 /*
4163 * Try next
4164 */
4165 spin_lock_bh(&ecm_db_lock);
4166 cin = ci->serial_hash_next;
4167 if (cin) {
4168 _ecm_db_connection_ref(cin);
4169 }
4170 spin_unlock_bh(&ecm_db_lock);
4171 ecm_db_connection_deref(ci);
4172 ci = cin;
4173 }
4174 DEBUG_TRACE("Connection not found\n");
4175 return NULL;
4176
4177connection_found:
4178 DEBUG_TRACE("Connection found %p\n", ci);
4179
4180 /*
4181 * Move this connection to the head of the hash chain.
4182 * This will win for us with heavy hit connections - we bubble MRU to the front of the list to
4183 * avoid too much chain walking.
4184 */
4185 spin_lock_bh(&ecm_db_lock);
4186 if (!ci->serial_hash_prev) {
4187 /*
4188 * No prev pointer - ci is at the head of the list already
4189 */
4190 DEBUG_ASSERT(ecm_db_connection_serial_table[serial_hash_index] == ci, "%p: hash table bad\n", ci);
4191 spin_unlock_bh(&ecm_db_lock);
4192 return ci;
4193 }
4194
4195 /*
4196 * Link out
4197 */
4198 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
4199 if (ci->serial_hash_next) {
4200 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
4201 }
4202
4203 /*
4204 * Re-insert at the head.
4205 * NOTE: We know that there is a head already that is different to ci.
4206 */
4207 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
4208 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
4209 ecm_db_connection_serial_table[serial_hash_index] = ci;
4210 ci->serial_hash_prev = NULL;
4211 spin_unlock_bh(&ecm_db_lock);
4212 return ci;
4213}
4214EXPORT_SYMBOL(ecm_db_connection_serial_find_and_ref);
4215
4216/*
4217 * ecm_db_mapping_connections_from_get_and_ref_first()
4218 * Return a reference to the first connection made from this mapping
4219 */
4220struct ecm_db_connection_instance *ecm_db_mapping_connections_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4221{
4222 struct ecm_db_connection_instance *ci;
4223
4224 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4225
4226 spin_lock_bh(&ecm_db_lock);
4227 ci = mi->from_connections;
4228 if (ci) {
4229 _ecm_db_connection_ref(ci);
4230 }
4231 spin_unlock_bh(&ecm_db_lock);
4232
4233 return ci;
4234}
4235EXPORT_SYMBOL(ecm_db_mapping_connections_from_get_and_ref_first);
4236
4237/*
4238 * ecm_db_mapping_connections_to_get_and_ref_first()
4239 * Return a reference to the first connection made to this mapping
4240 */
4241struct ecm_db_connection_instance *ecm_db_mapping_connections_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4242{
4243 struct ecm_db_connection_instance *ci;
4244
4245 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4246
4247 spin_lock_bh(&ecm_db_lock);
4248 ci = mi->to_connections;
4249 if (ci) {
4250 _ecm_db_connection_ref(ci);
4251 }
4252 spin_unlock_bh(&ecm_db_lock);
4253
4254 return ci;
4255}
4256EXPORT_SYMBOL(ecm_db_mapping_connections_to_get_and_ref_first);
4257
4258/*
4259 * ecm_db_mapping_connections_nat_from_get_and_ref_first()
4260 * Return a reference to the first NAT connection made from this mapping
4261 */
4262struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4263{
4264 struct ecm_db_connection_instance *ci;
4265
4266 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4267
4268 spin_lock_bh(&ecm_db_lock);
4269 ci = mi->from_nat_connections;
4270 if (ci) {
4271 _ecm_db_connection_ref(ci);
4272 }
4273 spin_unlock_bh(&ecm_db_lock);
4274
4275 return ci;
4276}
4277EXPORT_SYMBOL(ecm_db_mapping_connections_nat_from_get_and_ref_first);
4278
4279/*
4280 * ecm_db_mapping_connections_nat_to_get_and_ref_first()
4281 * Return a reference to the first NAT connection made to this mapping
4282 */
4283struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4284{
4285 struct ecm_db_connection_instance *ci;
4286
4287 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4288
4289 spin_lock_bh(&ecm_db_lock);
4290 ci = mi->to_nat_connections;
4291 if (ci) {
4292 _ecm_db_connection_ref(ci);
4293 }
4294 spin_unlock_bh(&ecm_db_lock);
4295
4296 return ci;
4297}
4298EXPORT_SYMBOL(ecm_db_mapping_connections_nat_to_get_and_ref_first);
4299
4300/*
4301 * ecm_db_connection_node_from_get_and_ref()
4302 * Return node reference
4303 */
4304struct ecm_db_node_instance *ecm_db_connection_node_to_get_and_ref(struct ecm_db_connection_instance *ci)
4305{
4306 struct ecm_db_node_instance *ni;
4307
4308 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304309
Ben Menchaca84f36632014-02-28 20:57:38 +00004310 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01004311 ni = ci->to_node;
Ben Menchaca84f36632014-02-28 20:57:38 +00004312 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
4313 _ecm_db_node_ref(ni);
4314 spin_unlock_bh(&ecm_db_lock);
4315 return ni;
4316}
4317EXPORT_SYMBOL(ecm_db_connection_node_to_get_and_ref);
4318
4319/*
4320 * ecm_db_connection_mapping_from_get_and_ref_next()
4321 * Return reference to next connection in from mapping chain
4322 */
4323struct ecm_db_connection_instance *ecm_db_connection_mapping_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4324{
4325 struct ecm_db_connection_instance *nci;
4326
4327 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4328
4329 spin_lock_bh(&ecm_db_lock);
4330 nci = ci->from_next;
4331 if (nci) {
4332 _ecm_db_connection_ref(nci);
4333 }
4334 spin_unlock_bh(&ecm_db_lock);
4335
4336 return nci;
4337}
4338EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref_next);
4339
4340/*
4341 * ecm_db_connection_mapping_to_get_and_ref_next()
4342 * Return reference to next connection in to mapping chain
4343 */
4344struct ecm_db_connection_instance *ecm_db_connection_mapping_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4345{
4346 struct ecm_db_connection_instance *nci;
4347
4348 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4349
4350 spin_lock_bh(&ecm_db_lock);
4351 nci = ci->to_next;
4352 if (nci) {
4353 _ecm_db_connection_ref(nci);
4354 }
4355 spin_unlock_bh(&ecm_db_lock);
4356
4357 return nci;
4358}
4359EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref_next);
4360
4361/*
4362 * ecm_db_connection_mapping_nat_from_get_and_ref_next()
4363 * Return reference to next connection in from NAT mapping chain
4364 */
4365struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4366{
4367 struct ecm_db_connection_instance *nci;
4368
4369 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4370
4371 spin_lock_bh(&ecm_db_lock);
4372 nci = ci->from_nat_next;
4373 if (nci) {
4374 _ecm_db_connection_ref(nci);
4375 }
4376 spin_unlock_bh(&ecm_db_lock);
4377
4378 return nci;
4379}
4380EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref_next);
4381
4382/*
4383 * ecm_db_connection_mapping_nat_to_get_and_ref_next()
4384 * Return reference to next connection in to NAT mapping chain
4385 */
4386struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4387{
4388 struct ecm_db_connection_instance *nci;
4389
4390 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4391
4392 spin_lock_bh(&ecm_db_lock);
4393 nci = ci->to_nat_next;
4394 if (nci) {
4395 _ecm_db_connection_ref(nci);
4396 }
4397 spin_unlock_bh(&ecm_db_lock);
4398
4399 return nci;
4400}
4401EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref_next);
4402
4403/*
4404 * ecm_db_iface_connections_from_get_and_ref_first()
4405 * Return a reference to the first connection made from this iface
4406 */
4407struct ecm_db_connection_instance *ecm_db_iface_connections_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
4408{
4409 struct ecm_db_connection_instance *ci;
4410
4411 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4412
4413 spin_lock_bh(&ecm_db_lock);
4414 ci = ii->from_connections;
4415 if (ci) {
4416 _ecm_db_connection_ref(ci);
4417 }
4418 spin_unlock_bh(&ecm_db_lock);
4419
4420 return ci;
4421}
4422EXPORT_SYMBOL(ecm_db_iface_connections_from_get_and_ref_first);
4423
4424/*
4425 * ecm_db_iface_connections_to_get_and_ref_first()
4426 * Return a reference to the first connection made to this iface
4427 */
4428struct ecm_db_connection_instance *ecm_db_iface_connections_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
4429{
4430 struct ecm_db_connection_instance *ci;
4431
4432 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4433
4434 spin_lock_bh(&ecm_db_lock);
4435 ci = ii->to_connections;
4436 if (ci) {
4437 _ecm_db_connection_ref(ci);
4438 }
4439 spin_unlock_bh(&ecm_db_lock);
4440
4441 return ci;
4442}
4443EXPORT_SYMBOL(ecm_db_iface_connections_to_get_and_ref_first);
4444
4445/*
4446 * ecm_db_iface_connections_nat_from_get_and_ref_first()
4447 * Return a reference to the first NAT connection made from this iface
4448 */
4449struct ecm_db_connection_instance *ecm_db_iface_connections_nat_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
4450{
4451 struct ecm_db_connection_instance *ci;
4452
4453 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4454
4455 spin_lock_bh(&ecm_db_lock);
4456 ci = ii->from_nat_connections;
4457 if (ci) {
4458 _ecm_db_connection_ref(ci);
4459 }
4460 spin_unlock_bh(&ecm_db_lock);
4461
4462 return ci;
4463}
4464EXPORT_SYMBOL(ecm_db_iface_connections_nat_from_get_and_ref_first);
4465
4466/*
4467 * ecm_db_iface_connections_nat_to_get_and_ref_first()
4468 * Return a reference to the first NAT connection made to this iface
4469 */
4470struct ecm_db_connection_instance *ecm_db_iface_connections_nat_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
4471{
4472 struct ecm_db_connection_instance *ci;
4473
4474 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4475
4476 spin_lock_bh(&ecm_db_lock);
4477 ci = ii->to_nat_connections;
4478 if (ci) {
4479 _ecm_db_connection_ref(ci);
4480 }
4481 spin_unlock_bh(&ecm_db_lock);
4482
4483 return ci;
4484}
4485EXPORT_SYMBOL(ecm_db_iface_connections_nat_to_get_and_ref_first);
4486
4487/*
4488 * ecm_db_connection_iface_from_get_and_ref_next()
4489 * Return reference to next connection in from iface chain
4490 */
4491struct ecm_db_connection_instance *ecm_db_connection_iface_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4492{
4493 struct ecm_db_connection_instance *nci;
4494
4495 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4496
4497 spin_lock_bh(&ecm_db_lock);
4498 nci = ci->iface_from_next;
4499 if (nci) {
4500 _ecm_db_connection_ref(nci);
4501 }
4502 spin_unlock_bh(&ecm_db_lock);
4503
4504 return nci;
4505}
4506EXPORT_SYMBOL(ecm_db_connection_iface_from_get_and_ref_next);
4507
4508/*
4509 * ecm_db_connection_iface_to_get_and_ref_next()
4510 * Return reference to next connection in to iface chain
4511 */
4512struct ecm_db_connection_instance *ecm_db_connection_iface_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4513{
4514 struct ecm_db_connection_instance *nci;
4515
4516 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4517
4518 spin_lock_bh(&ecm_db_lock);
4519 nci = ci->iface_to_next;
4520 if (nci) {
4521 _ecm_db_connection_ref(nci);
4522 }
4523 spin_unlock_bh(&ecm_db_lock);
4524
4525 return nci;
4526}
4527EXPORT_SYMBOL(ecm_db_connection_iface_to_get_and_ref_next);
4528
4529/*
4530 * ecm_db_connection_iface_nat_from_get_and_ref_next()
4531 * Return reference to next connection in from NAT iface chain
4532 */
4533struct ecm_db_connection_instance *ecm_db_connection_iface_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4534{
4535 struct ecm_db_connection_instance *nci;
4536
4537 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4538
4539 spin_lock_bh(&ecm_db_lock);
4540 nci = ci->iface_from_nat_next;
4541 if (nci) {
4542 _ecm_db_connection_ref(nci);
4543 }
4544 spin_unlock_bh(&ecm_db_lock);
4545
4546 return nci;
4547}
4548EXPORT_SYMBOL(ecm_db_connection_iface_nat_from_get_and_ref_next);
4549
4550/*
4551 * ecm_db_connection_iface_nat_to_get_and_ref_next()
4552 * Return reference to next connection in to NAT iface chain
4553 */
4554struct ecm_db_connection_instance *ecm_db_connection_iface_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4555{
4556 struct ecm_db_connection_instance *nci;
4557
4558 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4559
4560 spin_lock_bh(&ecm_db_lock);
4561 nci = ci->iface_to_nat_next;
4562 if (nci) {
4563 _ecm_db_connection_ref(nci);
4564 }
4565 spin_unlock_bh(&ecm_db_lock);
4566
4567 return nci;
4568}
4569EXPORT_SYMBOL(ecm_db_connection_iface_nat_to_get_and_ref_next);
4570
4571/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004572 * ecm_db_iface_nodes_get_and_ref_first()
4573 * Return a reference to the first node made from this iface
4574 */
4575struct ecm_db_node_instance *ecm_db_iface_nodes_get_and_ref_first(struct ecm_db_iface_instance *ii)
4576{
4577 struct ecm_db_node_instance *ni;
4578
4579 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4580
4581 spin_lock_bh(&ecm_db_lock);
4582 ni = ii->nodes;
4583 if (ni) {
4584 _ecm_db_node_ref(ni);
4585 }
4586 spin_unlock_bh(&ecm_db_lock);
4587
4588 return ni;
4589}
4590EXPORT_SYMBOL(ecm_db_iface_nodes_get_and_ref_first);
4591
4592/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004593 * ecm_db_mapping_host_get_and_ref()
4594 */
4595struct ecm_db_host_instance *ecm_db_mapping_host_get_and_ref(struct ecm_db_mapping_instance *mi)
4596{
4597 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
4598
4599 spin_lock_bh(&ecm_db_lock);
4600 _ecm_db_host_ref(mi->host);
4601 spin_unlock_bh(&ecm_db_lock);
4602 return mi->host;
4603}
4604EXPORT_SYMBOL(ecm_db_mapping_host_get_and_ref);
4605
4606/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004607 * ecm_db_node_iface_get_and_ref()
4608 */
4609struct ecm_db_iface_instance *ecm_db_node_iface_get_and_ref(struct ecm_db_node_instance *ni)
4610{
4611 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
4612
4613 spin_lock_bh(&ecm_db_lock);
4614 _ecm_db_iface_ref(ni->iface);
4615 spin_unlock_bh(&ecm_db_lock);
4616 return ni->iface;
4617}
4618EXPORT_SYMBOL(ecm_db_node_iface_get_and_ref);
4619
4620/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004621 * ecm_db_iface_node_count_get()
4622 * Return the number of nodes to this iface
4623 */
4624int ecm_db_iface_node_count_get(struct ecm_db_iface_instance *ii)
4625{
4626 int count;
4627
4628 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304629
Ben Menchaca84f36632014-02-28 20:57:38 +00004630 spin_lock_bh(&ecm_db_lock);
4631 count = ii->node_count;
4632 spin_unlock_bh(&ecm_db_lock);
4633 return count;
4634}
4635EXPORT_SYMBOL(ecm_db_iface_node_count_get);
4636
4637/*
4638 * ecm_db_host_mapping_count_get()
4639 * Return the number of mappings to this host
4640 */
4641int ecm_db_host_mapping_count_get(struct ecm_db_host_instance *hi)
4642{
4643 int count;
4644
4645 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304646
Ben Menchaca84f36632014-02-28 20:57:38 +00004647 spin_lock_bh(&ecm_db_lock);
4648 count = hi->mapping_count;
4649 spin_unlock_bh(&ecm_db_lock);
4650 return count;
4651}
4652EXPORT_SYMBOL(ecm_db_host_mapping_count_get);
4653
4654/*
4655 * ecm_db_mapping_connections_total_count_get()
4656 * Return the total number of connections (NAT and non-NAT) this mapping has
4657 */
4658int ecm_db_mapping_connections_total_count_get(struct ecm_db_mapping_instance *mi)
4659{
4660 int count;
4661
4662 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304663
Ben Menchaca84f36632014-02-28 20:57:38 +00004664 spin_lock_bh(&ecm_db_lock);
4665 count = mi->from + mi->to + mi->nat_from + mi->nat_to;
4666 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);
4667 spin_unlock_bh(&ecm_db_lock);
4668 return count;
4669}
4670EXPORT_SYMBOL(ecm_db_mapping_connections_total_count_get);
4671
4672/*
4673 * ecm_db_connection_mapping_from_get_and_ref()
4674 * Return a reference to the from mapping of the connection
4675 */
4676struct ecm_db_mapping_instance *ecm_db_connection_mapping_from_get_and_ref(struct ecm_db_connection_instance *ci)
4677{
4678 struct ecm_db_mapping_instance *mi;
4679
4680 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304681
Ben Menchaca84f36632014-02-28 20:57:38 +00004682 spin_lock_bh(&ecm_db_lock);
4683 mi = ci->mapping_from;
4684 _ecm_db_mapping_ref(mi);
4685 spin_unlock_bh(&ecm_db_lock);
4686 return mi;
4687}
4688EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref);
4689
4690/*
4691 * ecm_db_connection_mapping_nat_from_get_and_ref()
4692 * Return a reference to the from NAT mapping of the connection
4693 */
4694struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_from_get_and_ref(struct ecm_db_connection_instance *ci)
4695{
4696 struct ecm_db_mapping_instance *mi;
4697
4698 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304699
Ben Menchaca84f36632014-02-28 20:57:38 +00004700 spin_lock_bh(&ecm_db_lock);
4701 mi = ci->mapping_nat_from;
4702 _ecm_db_mapping_ref(mi);
4703 spin_unlock_bh(&ecm_db_lock);
4704 return mi;
4705}
4706EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref);
4707
4708/*
4709 * ecm_db_connection_mapping_to_get_and_ref()
4710 * Return a reference to the from mapping of the connection
4711 */
4712struct ecm_db_mapping_instance *ecm_db_connection_mapping_to_get_and_ref(struct ecm_db_connection_instance *ci)
4713{
4714 struct ecm_db_mapping_instance *mi;
4715
4716 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304717
Ben Menchaca84f36632014-02-28 20:57:38 +00004718 spin_lock_bh(&ecm_db_lock);
4719 mi = ci->mapping_to;
4720 _ecm_db_mapping_ref(mi);
4721 spin_unlock_bh(&ecm_db_lock);
4722 return mi;
4723}
4724EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref);
4725
4726/*
4727 * ecm_db_connection_mapping_to_nat_get_and_ref()
4728 * Return a reference to the from NAT mapping of the connection
4729 */
4730struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_to_get_and_ref(struct ecm_db_connection_instance *ci)
4731{
4732 struct ecm_db_mapping_instance *mi;
4733
4734 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304735
Ben Menchaca84f36632014-02-28 20:57:38 +00004736 spin_lock_bh(&ecm_db_lock);
4737 mi = ci->mapping_nat_to;
4738 _ecm_db_mapping_ref(mi);
4739 spin_unlock_bh(&ecm_db_lock);
4740 return mi;
4741}
4742EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref);
4743
4744/*
4745 * ecm_db_connection_node_from_get_and_ref()
4746 * Return node reference
4747 */
4748struct ecm_db_node_instance *ecm_db_connection_node_from_get_and_ref(struct ecm_db_connection_instance *ci)
4749{
4750 struct ecm_db_node_instance *ni;
4751
4752 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304753
Ben Menchaca84f36632014-02-28 20:57:38 +00004754 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01004755 ni = ci->from_node;
Ben Menchaca84f36632014-02-28 20:57:38 +00004756 _ecm_db_node_ref(ni);
4757 spin_unlock_bh(&ecm_db_lock);
4758 return ni;
4759}
4760EXPORT_SYMBOL(ecm_db_connection_node_from_get_and_ref);
4761
4762/*
4763 * ecm_db_timer_groups_check()
4764 * Check for expired group entries, returns the number that have expired
4765 */
4766static uint32_t ecm_db_timer_groups_check(uint32_t time_now)
4767{
4768 ecm_db_timer_group_t i;
4769 uint32_t expired = 0;
4770
4771 DEBUG_TRACE("Timer groups check start %u\n", time_now);
4772
4773 /*
4774 * Examine all timer groups for expired entries.
4775 */
4776 for (i = 0; i < ECM_DB_TIMER_GROUPS_MAX; ++i) {
4777 struct ecm_db_timer_group *timer_group;
4778
4779 /*
4780 * The group tail tracks the oldest entry so that is what we examine.
4781 */
4782 timer_group = &ecm_db_timer_groups[i];
4783 spin_lock_bh(&ecm_db_lock);
4784 while (timer_group->tail) {
4785 struct ecm_db_timer_group_entry *tge;
4786
4787 tge = timer_group->tail;
4788 if (tge->timeout > time_now) {
4789 /*
4790 * Not expired - and no further will be as they are in order
4791 */
4792 break;
4793 }
4794
4795 /*
4796 * Has expired - remove the entry from the list and invoke the callback
4797 * NOTE: We know the entry is at the tail of the group
4798 */
4799 if (tge->prev) {
4800 tge->prev->next = NULL;
4801 } else {
4802 /*
4803 * First in the group
4804 */
4805 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p got %p\n", timer_group, tge, timer_group->head);
4806 timer_group->head = NULL;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304807 }
Ben Menchaca84f36632014-02-28 20:57:38 +00004808 timer_group->tail = tge->prev;
4809 tge->group = ECM_DB_TIMER_GROUPS_MAX;
4810 spin_unlock_bh(&ecm_db_lock);
4811 expired++;
4812 DEBUG_TRACE("%p: Expired\n", tge);
4813 tge->fn(tge->arg);
4814 spin_lock_bh(&ecm_db_lock);
4815 }
4816 spin_unlock_bh(&ecm_db_lock);
4817 }
4818
4819 spin_lock_bh(&ecm_db_lock);
4820 time_now = ecm_db_time;
4821 spin_unlock_bh(&ecm_db_lock);
4822 DEBUG_TRACE("Timer groups check end %u, expired count %u\n", time_now, expired);
4823 return expired;
4824}
4825
4826/*
4827 * ecm_db_connection_classifier_assign()
4828 * Assign a classifier to the connection assigned classifier list.
4829 *
4830 * This adds the classifier in the ci->assignments list in priority order according to the classifier type.
4831 * Only assigned classifiers are in this list, allowing fast retrival of in-order current assignments, avoiding the need to skip over unassigned classifiers.
4832 * 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.
4833 * This allows fast lookup based on type too.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004834 * 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 +00004835 */
4836void ecm_db_connection_classifier_assign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *new_ca)
4837{
4838 struct ecm_classifier_instance *ca;
4839 struct ecm_classifier_instance *ca_prev;
4840 ecm_classifier_type_t new_ca_type;
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004841 struct ecm_db_connection_classifier_type_assignment *ta;
4842 struct ecm_db_connection_classifier_type_assignment_list *tal;
4843
Ben Menchaca84f36632014-02-28 20:57:38 +00004844 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4845
4846 /*
4847 * Get the type (which is also used as the priority)
4848 */
4849 new_ca_type = new_ca->type_get(new_ca);
4850
4851 /*
4852 * Connection holds ref to the classifier
4853 */
4854 new_ca->ref(new_ca);
4855
4856 /*
4857 * Find place to insert the classifier
4858 */
4859 spin_lock_bh(&ecm_db_lock);
4860 ca = ci->assignments;
4861 ca_prev = NULL;
4862 while (ca) {
4863 ecm_classifier_type_t ca_type;
4864 ca_type = ca->type_get(ca);
4865
4866 /*
4867 * If new ca is less important that the current assigned classifier insert here
4868 */
4869 if (new_ca_type < ca_type) {
4870 break;
4871 }
4872 ca_prev = ca;
4873 ca = ca->ca_next;
4874 }
4875
4876 /*
4877 * Insert new_ca before ca and after ca_prev.
4878 */
4879 new_ca->ca_prev = ca_prev;
4880 if (ca_prev) {
4881 ca_prev->ca_next = new_ca;
4882 } else {
4883 DEBUG_ASSERT(ci->assignments == ca, "%p: Bad assigmnment list, expecting: %p, got: %p\n", ci, ca, ci->assignments);
4884 ci->assignments = new_ca;
4885 }
4886
4887 new_ca->ca_next = ca;
4888 if (ca) {
4889 ca->ca_prev = new_ca;
4890 }
4891
4892 /*
4893 * Insert based on type too
4894 */
4895 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",
4896 ci, new_ca_type, new_ca, ci->assignments_by_type[new_ca_type]);
4897 ci->assignments_by_type[new_ca_type] = new_ca;
4898
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004899 /*
4900 * Add the connection into the type assignment list too.
4901 */
4902 ta = &ci->type_assignment[new_ca_type];
4903 if (ta->pending_unassign) {
4904 /*
4905 * The connection is pending unassignment / removal from list, but since it has been
4906 * re-assigned to the same type of classifier we can just clear the flag and avoid the removal.
4907 * NOTE: pending_unassign is only ever true if the iteration count is non-zero i.e. iteration is in progress.
4908 */
4909 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
4910 DEBUG_ASSERT(ta->iteration_count != 0, "%p: Bad pending_unassign: type: %d, Iteration count zero\n", ci, new_ca_type);
4911 ta->pending_unassign = false;
4912 spin_unlock_bh(&ecm_db_lock);
4913 return;
4914 }
4915
4916 /*
4917 * iteration_count should be zero as there should not be a duplicate assignment of the same type.
4918 * This is because if iteration_count was non-zero then pending_unassign should have been true.
4919 */
4920 DEBUG_ASSERT(ta->iteration_count == 0, "%p: Type: %d, Iteration count not zero: %d\n", ci, new_ca_type, ta->iteration_count);
4921
4922 /*
4923 * Insert the connection into the classifier type assignment list, at the head
4924 */
4925 tal = &ecm_db_connection_classifier_type_assignments[new_ca_type];
4926 ta->next = tal->type_assignments_list;
4927 ta->prev = NULL;
4928
4929 /*
4930 * If there is an existing head, it is no longer the head
4931 */
4932 if (tal->type_assignments_list) {
4933 struct ecm_db_connection_classifier_type_assignment *talh;
4934 talh = &tal->type_assignments_list->type_assignment[new_ca_type];
4935 talh->prev = ci;
4936 }
4937
4938 /*
4939 * Set new head
4940 */
4941 tal->type_assignments_list = ci;
4942
4943 /*
4944 * Set magic
4945 */
4946 DEBUG_SET_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC);
4947
4948 /*
4949 * Increment assignment count
4950 */
4951 tal->type_assignment_count++;
4952 DEBUG_ASSERT(tal->type_assignment_count > 0, "Bad iteration count: %d\n", tal->type_assignment_count);
4953
Ben Menchaca84f36632014-02-28 20:57:38 +00004954 spin_unlock_bh(&ecm_db_lock);
4955}
4956EXPORT_SYMBOL(ecm_db_connection_classifier_assign);
4957
4958/*
4959 * ecm_db_connection_classifier_assignments_get_and_ref()
4960 * Populate the given array with references to the currently assigned classifiers.
4961 *
4962 * This function returns the number of assignments starting from [0].
4963 * [0] is the lowest priority classifier, [return_val - 1] is the highest priority.
4964 * Release each classifier when you are done, for convenience use ecm_db_connection_assignments_release().
4965 *
4966 * NOTE: The array also contains the default classifier too which of course will always be at [0]
4967 *
4968 * WARNING: The array MUST be of size ECM_CLASSIFIER_TYPES.
4969 */
4970int ecm_db_connection_classifier_assignments_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *assignments[])
4971{
4972 int aci_count;
4973 struct ecm_classifier_instance *aci;
4974 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4975
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004976 aci_count = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00004977 spin_lock_bh(&ecm_db_lock);
4978 aci = ci->assignments;
4979 while (aci) {
4980 aci->ref(aci);
4981 assignments[aci_count++] = aci;
4982 aci = aci->ca_next;
4983 }
4984 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004985 DEBUG_ASSERT(aci_count >= 1, "%p: Must have at least default classifier!\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00004986 return aci_count;
4987}
4988EXPORT_SYMBOL(ecm_db_connection_classifier_assignments_get_and_ref);
4989
4990/*
4991 * ecm_db_connection_assignments_release()
4992 * Release references to classifiers in the assignments array
4993 */
4994void ecm_db_connection_assignments_release(int assignment_count, struct ecm_classifier_instance *assignments[])
4995{
4996 int i;
4997 for (i = 0; i < assignment_count; ++i) {
4998 struct ecm_classifier_instance *aci = assignments[i];
4999 if (aci) {
5000 aci->deref(aci);
5001 }
5002 }
5003}
5004EXPORT_SYMBOL(ecm_db_connection_assignments_release);
5005
5006/*
5007 * ecm_db_connection_assigned_classifier_find_and_ref()
5008 * Return a ref to classifier of the requested type, if found
5009 */
5010struct ecm_classifier_instance *ecm_db_connection_assigned_classifier_find_and_ref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t type)
5011{
5012 struct ecm_classifier_instance *ca;
5013 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5014 spin_lock_bh(&ecm_db_lock);
5015 ca = ci->assignments_by_type[type];
5016 if (ca) {
5017 ca->ref(ca);
5018 }
5019 spin_unlock_bh(&ecm_db_lock);
5020 return ca;
5021}
5022EXPORT_SYMBOL(ecm_db_connection_assigned_classifier_find_and_ref);
5023
5024/*
5025 * ecm_db_connection_classifier_unassign()
5026 * Unassign a classifier
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005027 *
5028 * The default classifier cannot be unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005029 */
5030void ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci)
5031{
5032 ecm_classifier_type_t ca_type;
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005033 struct ecm_db_connection_classifier_type_assignment *ta;
5034
Ben Menchaca84f36632014-02-28 20:57:38 +00005035 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5036
5037 DEBUG_ASSERT(cci->type_get(cci) != ECM_CLASSIFIER_TYPE_DEFAULT, "%p: Cannot unassign default", ci);
5038
Ben Menchaca84f36632014-02-28 20:57:38 +00005039 /*
5040 * Get the type
5041 */
5042 ca_type = cci->type_get(cci);
5043
5044 DEBUG_TRACE("%p: Unassign type: %d, classifier: %p\n", ci, ca_type, cci);
5045
5046 spin_lock_bh(&ecm_db_lock);
5047
5048 /*
5049 * Remove from assignments_by_type
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005050 * NOTE: It is possible that in SMP this classifier has already been unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005051 */
Gareth Williamsee0a38a2014-06-05 15:41:20 +01005052 if (ci->assignments_by_type[ca_type] == NULL) {
5053 spin_unlock_bh(&ecm_db_lock);
5054 DEBUG_TRACE("%p: Classifier type: %d already unassigned\n", ci, ca_type);
5055 return;
5056 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005057 ci->assignments_by_type[ca_type] = NULL;
5058
5059 /*
5060 * Link out of assignments list
5061 */
5062 if (cci->ca_prev) {
5063 cci->ca_prev->ca_next = cci->ca_next;
5064 } else {
5065 DEBUG_ASSERT(ci->assignments == cci, "%p: Bad assigmnment list, expecting: %p, got: %p", ci, cci, ci->assignments);
5066 ci->assignments = cci->ca_next;
5067 }
5068 if (cci->ca_next) {
5069 cci->ca_next->ca_prev = cci->ca_prev;
5070 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005071
5072 /*
5073 * Remove from the classifier type assignment list
5074 */
5075 ta = &ci->type_assignment[ca_type];
5076 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5077 if (ta->iteration_count > 0) {
5078 /*
5079 * The list entry is being iterated outside of db lock being held.
5080 * We cannot remove this entry since it would mess up iteration.
5081 * Set the pending flag to be actioned another time
5082 */
5083 ta->pending_unassign = true;
5084 spin_unlock_bh(&ecm_db_lock);
5085 cci->deref(cci);
5086 return;
5087 }
5088
5089 /*
5090 * Remove the list entry
5091 */
5092 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
5093 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
Ben Menchaca84f36632014-02-28 20:57:38 +00005094 spin_unlock_bh(&ecm_db_lock);
5095 cci->deref(cci);
5096}
5097EXPORT_SYMBOL(ecm_db_connection_classifier_unassign);
5098
5099/*
5100 * ecm_db_connection_classifier_default_get_and_ref()
5101 * Get a reference to default classifier associated with this connection
5102 */
5103struct ecm_classifier_default_instance *ecm_db_connection_classifier_default_get_and_ref(struct ecm_db_connection_instance *ci)
5104{
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005105 struct ecm_classifier_default_instance *dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005106 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5107
5108 /*
5109 * No need to lock this object - it cannot change
5110 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005111 dci = (struct ecm_classifier_default_instance *)ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT];
5112 DEBUG_ASSERT(dci, "%p: No default classifier!\n", ci);
5113 dci->base.ref((struct ecm_classifier_instance *)dci);
5114 return dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005115}
5116EXPORT_SYMBOL(ecm_db_connection_classifier_default_get_and_ref);
5117
5118/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005119 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_first()
5120 * Return a reference to the first connection for which a classifier of the given type is associated with
5121 *
5122 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5123 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5124 */
5125struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ecm_classifier_type_t ca_type)
5126{
5127 struct ecm_db_connection_classifier_type_assignment_list *tal;
5128 struct ecm_db_connection_instance *ci;
5129
5130 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5131
5132 DEBUG_TRACE("Get and ref first connection assigned with classifier type: %d\n", ca_type);
5133
5134 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
5135 spin_lock_bh(&ecm_db_lock);
5136 ci = tal->type_assignments_list;
5137 while (ci) {
5138 struct ecm_db_connection_classifier_type_assignment *ta;
5139 ta = &ci->type_assignment[ca_type];
5140 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5141
5142 if (ta->pending_unassign) {
5143 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", ci, ca_type);
5144 ci = ta->next;
5145 continue;
5146 }
5147
5148 /*
5149 * Take reference to this connection.
5150 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
5151 * and the type assignment list entry maintains integrity.
5152 */
5153 _ecm_db_connection_ref(ci);
5154 ta->iteration_count++;
5155 DEBUG_ASSERT(ta->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
5156 spin_unlock_bh(&ecm_db_lock);
5157 return ci;
5158 }
5159 spin_unlock_bh(&ecm_db_lock);
5160 return NULL;
5161}
5162EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_first);
5163
5164/*
5165 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_next()
5166 * Return a reference to the next connection for which a classifier of the given type is associated with.
5167 *
5168 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5169 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5170 */
5171struct 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)
5172{
5173 struct ecm_db_connection_classifier_type_assignment *ta;
5174 struct ecm_db_connection_instance *cin;
5175
5176 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5177 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5178
5179 DEBUG_TRACE("Get and ref next connection assigned with classifier type: %d and ci: %p\n", ca_type, ci);
5180
5181 spin_lock_bh(&ecm_db_lock);
5182 ta = &ci->type_assignment[ca_type];
5183 cin = ta->next;
5184 while (cin) {
5185 struct ecm_db_connection_classifier_type_assignment *tan;
5186
5187 tan = &cin->type_assignment[ca_type];
5188 DEBUG_CHECK_MAGIC(tan, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", tan, cin);
5189
5190 if (tan->pending_unassign) {
5191 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", cin, ca_type);
5192 cin = tan->next;
5193 continue;
5194 }
5195
5196 /*
5197 * Take reference to this connection.
5198 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
5199 * and the type assignment list entry maintains integrity.
5200 */
5201 _ecm_db_connection_ref(cin);
5202 tan->iteration_count++;
5203 DEBUG_ASSERT(tan->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", tan->iteration_count, ca_type, cin);
5204 spin_unlock_bh(&ecm_db_lock);
5205 return cin;
5206 }
5207 spin_unlock_bh(&ecm_db_lock);
5208 return NULL;
5209}
5210EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_next);
5211
5212/*
5213 * ecm_db_connection_by_classifier_type_assignment_deref()
5214 * Release a reference to a connection while iterating a classifier type assignment list
5215 */
5216void ecm_db_connection_by_classifier_type_assignment_deref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
5217{
5218 struct ecm_db_connection_classifier_type_assignment_list *tal;
5219 struct ecm_db_connection_classifier_type_assignment *ta;
5220
5221 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5222 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5223
5224 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
5225
5226 /*
5227 * Drop the iteration count
5228 */
5229 spin_lock_bh(&ecm_db_lock);
5230 ta = &ci->type_assignment[ca_type];
5231 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5232 ta->iteration_count--;
5233 DEBUG_ASSERT(ta->iteration_count >= 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
5234
5235 /*
5236 * If there are no more iterations on-going and this is pending unassign then we can remove it from the assignments list
5237 */
5238 if (ta->pending_unassign && (ta->iteration_count == 0)) {
5239 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
5240 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
5241 }
5242 spin_unlock_bh(&ecm_db_lock);
5243 ecm_db_connection_deref(ci);
5244}
5245EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_deref);
5246
5247/*
5248 * ecm_db_connection_make_defunct_by_assignment_type()
5249 * Make defunct all connections that are currently assigned to a classifier of the given type
5250 */
5251void ecm_db_connection_make_defunct_by_assignment_type(ecm_classifier_type_t ca_type)
5252{
5253 struct ecm_db_connection_instance *ci;
5254
5255 DEBUG_INFO("Make defunct all assigned to type: %d\n", ca_type);
5256
5257 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
5258 while (ci) {
5259 struct ecm_db_connection_instance *cin;
5260
5261 DEBUG_TRACE("%p: Make defunct: %d\n", ci, ca_type);
5262 ecm_db_connection_make_defunct(ci);
5263
5264 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
5265 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
5266 ci = cin;
5267 }
5268}
5269EXPORT_SYMBOL(ecm_db_connection_make_defunct_by_assignment_type);
5270
5271/*
5272 * ecm_db_connection_regenerate_by_assignment_type()
5273 * Cause regeneration all connections that are currently assigned to a classifier of the given type
5274 */
5275void ecm_db_connection_regenerate_by_assignment_type(ecm_classifier_type_t ca_type)
5276{
5277 struct ecm_db_connection_instance *ci;
5278
5279 DEBUG_INFO("Regenerate all assigned to type: %d\n", ca_type);
5280
5281 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
5282 while (ci) {
5283 struct ecm_db_connection_instance *cin;
5284
5285 DEBUG_TRACE("%p: Re-generate: %d\n", ci, ca_type);
5286 ecm_db_connection_classifier_generation_change(ci);
5287
5288 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
5289 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
5290 ci = cin;
5291 }
5292}
5293EXPORT_SYMBOL(ecm_db_connection_regenerate_by_assignment_type);
5294
5295/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005296 * ecm_db_connection_from_interfaces_get_and_ref()
5297 * Return the interface heirarchy from which this connection is established.
5298 *
5299 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5300 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5301 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5302 *
5303 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5304 */
5305int32_t ecm_db_connection_from_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5306{
5307 int32_t n;
5308 int32_t i;
5309 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5310
5311 spin_lock_bh(&ecm_db_lock);
5312 n = ci->from_interface_first;
5313 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5314 interfaces[i] = ci->from_interfaces[i];
5315 _ecm_db_iface_ref(interfaces[i]);
5316 }
5317 spin_unlock_bh(&ecm_db_lock);
5318 return n;
5319}
5320EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_and_ref);
5321
5322/*
5323 * ecm_db_connection_to_interfaces_get_and_ref()
5324 * Return the interface heirarchy to which this connection is established.
5325 *
5326 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5327 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5328 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5329 *
5330 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5331 */
5332int32_t ecm_db_connection_to_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5333{
5334 int32_t n;
5335 int32_t i;
5336 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5337
5338 spin_lock_bh(&ecm_db_lock);
5339 n = ci->to_interface_first;
5340 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5341 interfaces[i] = ci->to_interfaces[i];
5342 _ecm_db_iface_ref(interfaces[i]);
5343 }
5344 spin_unlock_bh(&ecm_db_lock);
5345 return n;
5346}
5347EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_and_ref);
5348
5349/*
5350 * ecm_db_connection_from_nat_interfaces_get_and_ref()
5351 * Return the interface heirarchy from (nat) which this connection is established.
5352 *
5353 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5354 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5355 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5356 *
5357 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5358 */
5359int32_t ecm_db_connection_from_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5360{
5361 int32_t n;
5362 int32_t i;
5363 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5364
5365 spin_lock_bh(&ecm_db_lock);
5366 n = ci->from_nat_interface_first;
5367 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5368 interfaces[i] = ci->from_nat_interfaces[i];
5369 _ecm_db_iface_ref(interfaces[i]);
5370 }
5371 spin_unlock_bh(&ecm_db_lock);
5372 return n;
5373}
5374EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_and_ref);
5375
5376/*
5377 * ecm_db_connection_to_nat_interfaces_get_and_ref()
5378 * Return the interface heirarchy to (nat) which this connection is established.
5379 *
5380 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5381 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5382 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5383 *
5384 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5385 */
5386int32_t ecm_db_connection_to_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5387{
5388 int32_t n;
5389 int32_t i;
5390 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5391
5392 spin_lock_bh(&ecm_db_lock);
5393 n = ci->to_nat_interface_first;
5394 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5395 interfaces[i] = ci->to_nat_interfaces[i];
5396 _ecm_db_iface_ref(interfaces[i]);
5397 }
5398 spin_unlock_bh(&ecm_db_lock);
5399 return n;
5400}
5401EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_and_ref);
5402
5403/*
5404 * ecm_db_connection_interfaces_deref()
5405 * Release all interfaces in the given interfaces heirarchy array.
5406 *
5407 * 'first' is the number returned by one of the ecm_db_connection_xx_interfaces_get_and_ref().
5408 * You should NOT have released any references to any of the interfaces in the array youself, this releases them all.
5409 */
5410void ecm_db_connection_interfaces_deref(struct ecm_db_iface_instance *interfaces[], int32_t first)
5411{
5412 int32_t i;
5413 DEBUG_ASSERT((first >= 0) && (first <= ECM_DB_IFACE_HEIRARCHY_MAX), "Bad first: %d\n", first);
5414
5415 for (i = first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5416 ecm_db_iface_deref(interfaces[i]);
5417 }
5418}
5419EXPORT_SYMBOL(ecm_db_connection_interfaces_deref);
5420
5421/*
5422 * ecm_db_connection_from_interfaces_reset()
5423 * Reset the from interfaces heirarchy with a new set of interfaces
5424 *
5425 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5426 * This is deliberate - it's stating that there is no list :-)
5427 */
5428void ecm_db_connection_from_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5429{
5430 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5431 int32_t old_first;
5432 int32_t i;
5433 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5434
5435 /*
5436 * Iterate the from interface list, removing the old and adding in the new
5437 */
5438 spin_lock_bh(&ecm_db_lock);
5439 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5440 /*
5441 * Put any previous interface into the old list
5442 */
5443 old[i] = ci->from_interfaces[i];
5444 ci->from_interfaces[i] = NULL;
5445 if (i < new_first) {
5446 continue;
5447 }
5448 ci->from_interfaces[i] = interfaces[i];
5449 _ecm_db_iface_ref(ci->from_interfaces[i]);
5450 }
5451
5452 /*
5453 * Get old first and update to new first
5454 */
5455 old_first = ci->from_interface_first;
5456 ci->from_interface_first = new_first;
5457 ci->from_interface_set = true;
5458 spin_unlock_bh(&ecm_db_lock);
5459
5460 /*
5461 * Release old
5462 */
5463 ecm_db_connection_interfaces_deref(old, old_first);
5464}
5465EXPORT_SYMBOL(ecm_db_connection_from_interfaces_reset);
5466
5467/*
5468 * ecm_db_connection_to_interfaces_reset()
5469 * Reset the to interfaces heirarchy with a new set of interfaces
5470 *
5471 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5472 * This is deliberate - it's stating that there is no list :-)
5473 */
5474void ecm_db_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5475{
5476 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5477 int32_t old_first;
5478 int32_t i;
5479 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5480
5481 /*
5482 * Iterate the to interface list, removing the old and adding in the new
5483 */
5484 spin_lock_bh(&ecm_db_lock);
5485 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5486 /*
5487 * Put any previous interface into the old list
5488 */
5489 old[i] = ci->to_interfaces[i];
5490 ci->to_interfaces[i] = NULL;
5491 if (i < new_first) {
5492 continue;
5493 }
5494 ci->to_interfaces[i] = interfaces[i];
5495 _ecm_db_iface_ref(ci->to_interfaces[i]);
5496 }
5497
5498 /*
5499 * Get old first and update to new first
5500 */
5501 old_first = ci->to_interface_first;
5502 ci->to_interface_first = new_first;
5503 ci->to_interface_set = true;
5504 spin_unlock_bh(&ecm_db_lock);
5505
5506 /*
5507 * Release old
5508 */
5509 ecm_db_connection_interfaces_deref(old, old_first);
5510}
5511EXPORT_SYMBOL(ecm_db_connection_to_interfaces_reset);
5512
5513/*
5514 * ecm_db_connection_from_nat_interfaces_reset()
5515 * Reset the from NAT interfaces heirarchy with a new set of interfaces
5516 *
5517 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5518 * This is deliberate - it's stating that there is no list :-)
5519 */
5520void ecm_db_connection_from_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5521{
5522 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5523 int32_t old_first;
5524 int32_t i;
5525 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5526
5527 /*
5528 * Iterate the from nat interface list, removing the old and adding in the new
5529 */
5530 spin_lock_bh(&ecm_db_lock);
5531 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5532 /*
5533 * Put any previous interface into the old list
5534 */
5535 old[i] = ci->from_nat_interfaces[i];
5536 ci->from_nat_interfaces[i] = NULL;
5537 if (i < new_first) {
5538 continue;
5539 }
5540 ci->from_nat_interfaces[i] = interfaces[i];
5541 _ecm_db_iface_ref(ci->from_nat_interfaces[i]);
5542 }
5543
5544 /*
5545 * Get old first and update to new first
5546 */
5547 old_first = ci->from_nat_interface_first;
5548 ci->from_nat_interface_first = new_first;
5549 ci->from_nat_interface_set = true;
5550 spin_unlock_bh(&ecm_db_lock);
5551
5552 /*
5553 * Release old
5554 */
5555 ecm_db_connection_interfaces_deref(old, old_first);
5556}
5557EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_reset);
5558
5559/*
5560 * ecm_db_connection_to_nat_interfaces_reset()
5561 * Reset the to NAT interfaces heirarchy with a new set of interfaces.
5562 *
5563 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5564 * This is deliberate - it's stating that there is no list :-)
5565 */
5566void ecm_db_connection_to_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5567{
5568 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5569 int32_t old_first;
5570 int32_t i;
5571 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5572
5573 /*
5574 * Iterate the to nat interface list, removing the old and adding in the new
5575 */
5576 spin_lock_bh(&ecm_db_lock);
5577 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5578 /*
5579 * Put any previous interface into the old list
5580 */
5581 old[i] = ci->to_nat_interfaces[i];
5582 ci->to_nat_interfaces[i] = NULL;
5583 if (i < new_first) {
5584 continue;
5585 }
5586 ci->to_nat_interfaces[i] = interfaces[i];
5587 _ecm_db_iface_ref(ci->to_nat_interfaces[i]);
5588 }
5589
5590 /*
5591 * Get old first and update to new first
5592 */
5593 old_first = ci->to_nat_interface_first;
5594 ci->to_nat_interface_first = new_first;
5595 ci->to_nat_interface_set = true;
5596 spin_unlock_bh(&ecm_db_lock);
5597
5598 /*
5599 * Release old
5600 */
5601 ecm_db_connection_interfaces_deref(old, old_first);
5602}
5603EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_reset);
5604
5605/*
5606 * ecm_db_connection_to_nat_interfaces_get_count()
5607 * Return the number of interfaces in the list
5608 */
5609int32_t ecm_db_connection_to_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
5610{
5611 int32_t first;
5612 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5613 spin_lock_bh(&ecm_db_lock);
5614 first = ci->to_nat_interface_first;
5615 spin_unlock_bh(&ecm_db_lock);
5616 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5617}
5618EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_count);
5619
5620/*
5621 * ecm_db_connection_from_nat_interfaces_get_count()
5622 * Return the number of interfaces in the list
5623 */
5624int32_t ecm_db_connection_from_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
5625{
5626 int32_t first;
5627 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5628 spin_lock_bh(&ecm_db_lock);
5629 first = ci->from_nat_interface_first;
5630 spin_unlock_bh(&ecm_db_lock);
5631 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5632}
5633EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_count);
5634
5635/*
5636 * ecm_db_connection_to_interfaces_get_count()
5637 * Return the number of interfaces in the list
5638 */
5639int32_t ecm_db_connection_to_interfaces_get_count(struct ecm_db_connection_instance *ci)
5640{
5641 int32_t first;
5642 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5643 spin_lock_bh(&ecm_db_lock);
5644 first = ci->to_interface_first;
5645 spin_unlock_bh(&ecm_db_lock);
5646 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5647}
5648EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_count);
5649
5650/*
5651 * ecm_db_connection_from_interfaces_get_count()
5652 * Return the number of interfaces in the list
5653 */
5654int32_t ecm_db_connection_from_interfaces_get_count(struct ecm_db_connection_instance *ci)
5655{
5656 int32_t first;
5657 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5658 spin_lock_bh(&ecm_db_lock);
5659 first = ci->from_interface_first;
5660 spin_unlock_bh(&ecm_db_lock);
5661 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5662}
5663EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_count);
5664
5665/*
5666 * ecm_db_connection_to_interfaces_set_check()
5667 * Returns true if the interface list has been set - even if set to an empty list!
5668 */
5669bool ecm_db_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
5670{
5671 bool set;
5672
5673 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5674 spin_lock_bh(&ecm_db_lock);
5675 set = ci->to_interface_set;
5676 spin_unlock_bh(&ecm_db_lock);
5677 return set;
5678}
5679EXPORT_SYMBOL(ecm_db_connection_to_interfaces_set_check);
5680
5681/*
5682 * ecm_db_connection_from_interfaces_set_check()
5683 * Returns true if the interface list has been set - even if set to an empty list!
5684 */
5685bool ecm_db_connection_from_interfaces_set_check(struct ecm_db_connection_instance *ci)
5686{
5687 bool set;
5688
5689 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5690 spin_lock_bh(&ecm_db_lock);
5691 set = ci->from_interface_set;
5692 spin_unlock_bh(&ecm_db_lock);
5693 return set;
5694}
5695EXPORT_SYMBOL(ecm_db_connection_from_interfaces_set_check);
5696
5697/*
5698 * ecm_db_connection_to_nat_interfaces_set_check()
5699 * Returns true if the interface list has been set - even if set to an empty list!
5700 */
5701bool ecm_db_connection_to_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
5702{
5703 bool set;
5704
5705 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5706 spin_lock_bh(&ecm_db_lock);
5707 set = ci->to_nat_interface_set;
5708 spin_unlock_bh(&ecm_db_lock);
5709 return set;
5710}
5711EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_set_check);
5712
5713/*
5714 * ecm_db_connection_from_nat_interfaces_set_check()
5715 * Returns true if the interface list has been set - even if set to an empty list!
5716 */
5717bool ecm_db_connection_from_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
5718{
5719 bool set;
5720
5721 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5722 spin_lock_bh(&ecm_db_lock);
5723 set = ci->from_nat_interface_set;
5724 spin_unlock_bh(&ecm_db_lock);
5725 return set;
5726}
5727EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_set_check);
5728
5729/*
5730 * ecm_db_connection_from_interfaces_clear()
5731 * Clear down the interfaces list, marking the list as not set
5732 */
5733void ecm_db_connection_from_interfaces_clear(struct ecm_db_connection_instance *ci)
5734{
5735 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5736 int32_t discard_first;
5737 int32_t i;
5738
5739 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5740
5741 spin_lock_bh(&ecm_db_lock);
5742 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5743 discard[i] = ci->from_interfaces[i];
5744 }
5745
5746 discard_first = ci->from_interface_first;
5747 ci->from_interface_set = false;
5748 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5749 spin_unlock_bh(&ecm_db_lock);
5750
5751 /*
5752 * Release previous
5753 */
5754 ecm_db_connection_interfaces_deref(discard, discard_first);
5755}
5756EXPORT_SYMBOL(ecm_db_connection_from_interfaces_clear);
5757
5758/*
5759 * ecm_db_connection_from_nat_interfaces_clear()
5760 * Clear down the interfaces list, marking the list as not set
5761 */
5762void ecm_db_connection_from_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
5763{
5764 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5765 int32_t discard_first;
5766 int32_t i;
5767
5768 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5769
5770 spin_lock_bh(&ecm_db_lock);
5771 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5772 discard[i] = ci->from_nat_interfaces[i];
5773 }
5774
5775 discard_first = ci->from_nat_interface_first;
5776 ci->from_nat_interface_set = false;
5777 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5778 spin_unlock_bh(&ecm_db_lock);
5779
5780 /*
5781 * Release previous
5782 */
5783 ecm_db_connection_interfaces_deref(discard, discard_first);
5784}
5785EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_clear);
5786
5787/*
5788 * ecm_db_connection_to_interfaces_clear()
5789 * Clear down the interfaces list, marking the list as not set
5790 */
5791void ecm_db_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
5792{
5793 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5794 int32_t discard_first;
5795 int32_t i;
5796
5797 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5798
5799 spin_lock_bh(&ecm_db_lock);
5800 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5801 discard[i] = ci->to_interfaces[i];
5802 }
5803
5804 discard_first = ci->to_interface_first;
5805 ci->to_interface_set = false;
5806 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5807 spin_unlock_bh(&ecm_db_lock);
5808
5809 /*
5810 * Release previous
5811 */
5812 ecm_db_connection_interfaces_deref(discard, discard_first);
5813}
5814EXPORT_SYMBOL(ecm_db_connection_to_interfaces_clear);
5815
5816/*
5817 * ecm_db_connection_to_nat_interfaces_clear()
5818 * Clear down the interfaces list, marking the list as not set
5819 */
5820void ecm_db_connection_to_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
5821{
5822 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5823 int32_t discard_first;
5824 int32_t i;
5825
5826 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5827
5828 spin_lock_bh(&ecm_db_lock);
5829 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5830 discard[i] = ci->to_nat_interfaces[i];
5831 }
5832
5833 discard_first = ci->to_nat_interface_first;
5834 ci->to_nat_interface_set = false;
5835 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5836 spin_unlock_bh(&ecm_db_lock);
5837
5838 /*
5839 * Release previous
5840 */
5841 ecm_db_connection_interfaces_deref(discard, discard_first);
5842}
5843EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_clear);
5844
5845/*
5846 * ecm_db_connection_add()
5847 * Add the connection into the database.
5848 *
5849 * NOTE: The parameters are DIRECTIONAL in terms of which mapping established the connection.
5850 * 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.
5851 */
5852void ecm_db_connection_add(struct ecm_db_connection_instance *ci,
5853 struct ecm_front_end_connection_instance *feci,
Ben Menchaca84f36632014-02-28 20:57:38 +00005854 struct ecm_db_mapping_instance *mapping_from, struct ecm_db_mapping_instance *mapping_to,
5855 struct ecm_db_mapping_instance *mapping_nat_from, struct ecm_db_mapping_instance *mapping_nat_to,
Gareth Williams90f2a282014-08-27 15:56:25 +01005856 struct ecm_db_node_instance *from_node, struct ecm_db_node_instance *to_node,
5857 struct ecm_db_node_instance *from_nat_node, struct ecm_db_node_instance *to_nat_node,
Ben Menchaca84f36632014-02-28 20:57:38 +00005858 int protocol, ecm_db_direction_t dir,
5859 ecm_db_connection_final_callback_t final,
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07005860 ecm_db_connection_defunct_callback_t defunct,
Ben Menchaca84f36632014-02-28 20:57:38 +00005861 ecm_db_timer_group_t tg, bool is_routed,
5862 void *arg)
5863{
5864 ecm_db_connection_hash_t hash_index;
5865 ecm_db_connection_serial_hash_t serial_hash_index;
5866 struct ecm_db_listener_instance *li;
5867 struct ecm_db_iface_instance *iface_from;
5868 struct ecm_db_iface_instance *iface_to;
5869 struct ecm_db_iface_instance *iface_nat_from;
5870 struct ecm_db_iface_instance *iface_nat_to;
5871
5872 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5873 DEBUG_CHECK_MAGIC(mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_from);
5874 DEBUG_CHECK_MAGIC(mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_to);
5875 DEBUG_CHECK_MAGIC(mapping_nat_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_from);
5876 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 +01005877 DEBUG_CHECK_MAGIC(from_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_node);
5878 DEBUG_CHECK_MAGIC(to_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_node);
5879 DEBUG_CHECK_MAGIC(from_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_nat_node);
5880 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 +00005881 DEBUG_ASSERT((protocol >= 0) && (protocol <= 255), "%p: invalid protocol number %d\n", ci, protocol);
5882
5883 spin_lock_bh(&ecm_db_lock);
5884 DEBUG_ASSERT(!(ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED), "%p: inserted\n", ci);
5885 spin_unlock_bh(&ecm_db_lock);
5886
5887 /*
5888 * Record owner arg and callbacks
5889 */
5890 ci->final = final;
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07005891 ci->defunct = defunct;
Ben Menchaca84f36632014-02-28 20:57:38 +00005892 ci->arg = arg;
5893
5894 /*
5895 * Take reference to the front end
5896 */
5897 feci->ref(feci);
5898 ci->feci = feci;
5899
5900 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005901 * Ensure default classifier has been assigned this is a must to ensure minimum level of classification
Ben Menchaca84f36632014-02-28 20:57:38 +00005902 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005903 DEBUG_ASSERT(ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT], "%p: No default classifier assigned\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005904
5905 /*
5906 * Connection takes references to the mappings
5907 */
5908 ecm_db_mapping_ref(mapping_from);
5909 ecm_db_mapping_ref(mapping_to);
5910 ci->mapping_from = mapping_from;
5911 ci->mapping_to = mapping_to;
5912
5913 ecm_db_mapping_ref(mapping_nat_from);
5914 ecm_db_mapping_ref(mapping_nat_to);
5915 ci->mapping_nat_from = mapping_nat_from;
5916 ci->mapping_nat_to = mapping_nat_to;
5917
5918 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01005919 * Take references to the nodes
5920 */
5921 ci->from_node = from_node;
5922 ecm_db_node_ref(from_node);
5923 ci->to_node = to_node;
5924 ecm_db_node_ref(to_node);
5925
5926 ci->from_nat_node = from_nat_node;
5927 ecm_db_node_ref(from_nat_node);
5928 ci->to_nat_node = to_nat_node;
5929 ecm_db_node_ref(to_nat_node);
5930
5931 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00005932 * Set the protocol and routed flag
5933 */
5934 ci->protocol = protocol;
5935 ci->is_routed = is_routed;
5936
5937 /*
5938 * Set direction of connection
5939 */
5940 ci->direction = dir;
5941
5942 /*
5943 * Identify which hash chain this connection will go into
5944 */
5945 hash_index = ecm_db_connection_generate_hash_index(mapping_from->host->address, mapping_from->port, mapping_to->host->address, mapping_to->port, protocol);
5946 ci->hash_index = hash_index;
5947
5948 /*
5949 * Identify which serial hash chain this connection will go into
5950 */
5951 serial_hash_index = ecm_db_connection_generate_serial_hash_index(ci->serial);
5952 ci->serial_hash_index = serial_hash_index;
5953
5954 /*
5955 * Now we need to lock
5956 */
5957 spin_lock_bh(&ecm_db_lock);
5958
5959 /*
5960 * Increment protocol counter stats
5961 */
5962 ecm_db_connection_count_by_protocol[protocol]++;
5963 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[protocol] > 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[protocol]);
5964
5965 DEBUG_TRACE("c\n");
5966
5967 /*
5968 * Set time
5969 */
5970 ci->time_added = ecm_db_time;
5971
5972 /*
5973 * Add connection into the global list
5974 */
5975 ci->prev = NULL;
5976 ci->next = ecm_db_connections;
5977 if (ecm_db_connections) {
5978 ecm_db_connections->prev = ci;
5979 }
5980 ecm_db_connections = ci;
5981
5982 /*
5983 * Add this connection into the connections hash table
5984 */
5985 ci->flags |= ECM_DB_CONNECTION_FLAGS_INSERTED;
5986
5987 /*
5988 * Insert mapping into the connections hash table
5989 */
5990 ci->hash_next = ecm_db_connection_table[hash_index];
5991 if (ecm_db_connection_table[hash_index]) {
5992 ecm_db_connection_table[hash_index]->hash_prev = ci;
5993 }
5994 ecm_db_connection_table[hash_index] = ci;
5995 ecm_db_connection_table_lengths[hash_index]++;
5996 DEBUG_ASSERT(ecm_db_connection_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[hash_index]);
5997
5998 /*
5999 * Insert connection into the connections serial hash table
6000 */
6001 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
6002 if (ecm_db_connection_serial_table[serial_hash_index]) {
6003 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
6004 }
6005 ecm_db_connection_serial_table[serial_hash_index] = ci;
6006 ecm_db_connection_serial_table_lengths[serial_hash_index]++;
6007 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]);
6008
6009 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01006010 * Add this connection into the FROM node
6011 */
6012 ci->node_from_prev = NULL;
6013 ci->node_from_next = from_node->from_connections;
6014 if (from_node->from_connections) {
6015 from_node->from_connections->node_from_prev = ci;
6016 }
6017 from_node->from_connections = ci;
6018 from_node->from_connections_count++;
6019 DEBUG_ASSERT(from_node->from_connections_count > 0, "%p: invalid count\n", ci);
6020
6021 /*
6022 * Add this connection into the TO node
6023 */
6024 ci->node_to_prev = NULL;
6025 ci->node_to_next = to_node->to_connections;
6026 if (to_node->to_connections) {
6027 to_node->to_connections->node_to_prev = ci;
6028 }
6029 to_node->to_connections = ci;
6030 to_node->to_connections_count++;
6031 DEBUG_ASSERT(to_node->to_connections_count > 0, "%p: invalid count\n", ci);
6032
6033 /*
6034 * Add this connection into the FROM NAT node
6035 */
6036 ci->node_from_nat_prev = NULL;
6037 ci->node_from_nat_next = from_nat_node->from_nat_connections;
6038 if (from_nat_node->from_nat_connections) {
6039 from_nat_node->from_nat_connections->node_from_nat_prev = ci;
6040 }
6041 from_nat_node->from_nat_connections = ci;
6042 from_nat_node->from_nat_connections_count++;
6043 DEBUG_ASSERT(from_nat_node->from_nat_connections_count > 0, "%p: invalid count\n", ci);
6044
6045 /*
6046 * Add this connection into the TO NAT node
6047 */
6048 ci->node_to_nat_prev = NULL;
6049 ci->node_to_nat_next = to_nat_node->to_nat_connections;
6050 if (to_nat_node->to_nat_connections) {
6051 to_nat_node->to_nat_connections->node_to_nat_prev = ci;
6052 }
6053 to_nat_node->to_nat_connections = ci;
6054 to_nat_node->to_nat_connections_count++;
6055 DEBUG_ASSERT(to_nat_node->to_nat_connections_count > 0, "%p: invalid count\n", ci);
6056
6057 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00006058 * Add this connection into the FROM mapping
6059 */
6060 ci->from_prev = NULL;
6061 ci->from_next = mapping_from->from_connections;
6062 if (mapping_from->from_connections) {
6063 mapping_from->from_connections->from_prev = ci;
6064 }
6065 mapping_from->from_connections = ci;
6066
6067 /*
6068 * Add this connection into the TO mapping
6069 */
6070 ci->to_prev = NULL;
6071 ci->to_next = mapping_to->to_connections;
6072 if (mapping_to->to_connections) {
6073 mapping_to->to_connections->to_prev = ci;
6074 }
6075 mapping_to->to_connections = ci;
6076
6077 /*
6078 * Add this connection into the FROM NAT mapping
6079 */
6080 ci->from_nat_prev = NULL;
6081 ci->from_nat_next = mapping_nat_from->from_nat_connections;
6082 if (mapping_nat_from->from_nat_connections) {
6083 mapping_nat_from->from_nat_connections->from_nat_prev = ci;
6084 }
6085 mapping_nat_from->from_nat_connections = ci;
6086
6087 /*
6088 * Add this connection into the TO NAT mapping
6089 */
6090 ci->to_nat_prev = NULL;
6091 ci->to_nat_next = mapping_nat_to->to_nat_connections;
6092 if (mapping_nat_to->to_nat_connections) {
6093 mapping_nat_to->to_nat_connections->to_nat_prev = ci;
6094 }
6095 mapping_nat_to->to_nat_connections = ci;
6096
6097 /*
6098 * Add this connection into the FROM iface list of connections
6099 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6100 * due to the heirarchy of dependencies being kept by the database.
6101 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006102 iface_from = from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006103 ci->iface_from_prev = NULL;
6104 ci->iface_from_next = iface_from->from_connections;
6105 if (iface_from->from_connections) {
6106 iface_from->from_connections->iface_from_prev = ci;
6107 }
6108 iface_from->from_connections = ci;
6109
6110 /*
6111 * Add this connection into the TO iface list of connections
6112 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6113 * due to the heirarchy of dependencies being kept by the database.
6114 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006115 iface_to = to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006116 ci->iface_to_prev = NULL;
6117 ci->iface_to_next = iface_to->to_connections;
6118 if (iface_to->to_connections) {
6119 iface_to->to_connections->iface_to_prev = ci;
6120 }
6121 iface_to->to_connections = ci;
6122
6123 /*
6124 * Add this connection into the FROM NAT iface list of connections
6125 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6126 * due to the heirarchy of dependencies being kept by the database.
6127 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006128 iface_nat_from = from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006129 ci->iface_from_nat_prev = NULL;
6130 ci->iface_from_nat_next = iface_nat_from->from_nat_connections;
6131 if (iface_nat_from->from_nat_connections) {
6132 iface_nat_from->from_nat_connections->iface_from_nat_prev = ci;
6133 }
6134 iface_nat_from->from_nat_connections = ci;
6135
6136 /*
6137 * Add this connection into the TO NAT iface list of connections
6138 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6139 * due to the heirarchy of dependencies being kept by the database.
6140 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006141 iface_nat_to = to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006142 ci->iface_to_nat_prev = NULL;
6143 ci->iface_to_nat_next = iface_nat_to->to_nat_connections;
6144 if (iface_nat_to->to_nat_connections) {
6145 iface_nat_to->to_nat_connections->iface_to_nat_prev = ci;
6146 }
6147 iface_nat_to->to_nat_connections = ci;
6148
Gareth Williams90f2a282014-08-27 15:56:25 +01006149
Ben Menchaca84f36632014-02-28 20:57:38 +00006150 /*
6151 * NOTE: The interface heirarchy lists are deliberately left empty - these are completed
6152 * by the front end if it is appropriate to do so.
6153 */
6154
6155 /*
6156 * Update the counters in the mapping
6157 */
6158 if (protocol == IPPROTO_UDP) {
6159 mapping_from->udp_from++;
6160 mapping_to->udp_to++;
6161 mapping_nat_from->udp_nat_from++;
6162 mapping_nat_to->udp_nat_to++;
6163 } else if (protocol == IPPROTO_TCP) {
6164 mapping_from->tcp_from++;
6165 mapping_to->tcp_to++;
6166 mapping_nat_from->tcp_nat_from++;
6167 mapping_nat_to->tcp_nat_to++;
6168 }
6169
6170 mapping_from->from++;
6171 mapping_to->to++;
6172 mapping_nat_from->nat_from++;
6173 mapping_nat_to->nat_to++;
6174
6175 /*
6176 * Set the generation number
6177 */
6178 ci->classifier_generation = ecm_db_classifier_generation;
6179
6180 spin_unlock_bh(&ecm_db_lock);
6181
6182 /*
6183 * Throw add event to the listeners
6184 */
6185 DEBUG_TRACE("%p: Throw connection added event\n", ci);
6186 li = ecm_db_listeners_get_and_ref_first();
6187 while (li) {
6188 struct ecm_db_listener_instance *lin;
6189 if (li->connection_added) {
6190 li->connection_added(li->arg, ci);
6191 }
6192
6193 /*
6194 * Get next listener
6195 */
6196 lin = ecm_db_listener_get_and_ref_next(li);
6197 ecm_db_listener_deref(li);
6198 li = lin;
6199 }
6200
6201 /*
6202 * Set timer group. 'ref' the connection to ensure it persists for the timer.
6203 */
6204 ecm_db_connection_ref(ci);
6205 ecm_db_timer_group_entry_set(&ci->defunct_timer, tg);
6206}
6207EXPORT_SYMBOL(ecm_db_connection_add);
6208
6209/*
6210 * ecm_db_mapping_add()
6211 * Add a mapping instance into the database
6212 *
6213 * NOTE: The mapping will take a reference to the host instance.
6214 */
6215void ecm_db_mapping_add(struct ecm_db_mapping_instance *mi, struct ecm_db_host_instance *hi, int port,
6216 ecm_db_mapping_final_callback_t final, void *arg)
6217{
6218 ecm_db_mapping_hash_t hash_index;
6219 struct ecm_db_listener_instance *li;
6220
6221 spin_lock_bh(&ecm_db_lock);
6222 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
6223 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
6224 DEBUG_ASSERT(mi->from_connections == NULL, "%p: connections not null\n", mi);
6225 DEBUG_ASSERT(mi->to_connections == NULL, "%p: connections not null\n", mi);
6226 DEBUG_ASSERT(!(mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED), "%p: inserted\n", mi);
6227 DEBUG_ASSERT((hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: not inserted\n", hi);
6228 DEBUG_ASSERT(!mi->from && !mi->to && !mi->tcp_from && !mi->tcp_to && !mi->udp_from && !mi->udp_to, "%p: count errors\n", mi);
6229 spin_unlock_bh(&ecm_db_lock);
6230
6231 mi->arg = arg;
6232 mi->final = final;
6233
6234 /*
6235 * Compute hash table position for insertion
6236 */
6237 hash_index = ecm_db_mapping_generate_hash_index(hi->address, port);
6238 mi->hash_index = hash_index;
6239
6240 /*
6241 * Record port
6242 */
6243 mi->port = port;
6244
6245 /*
6246 * Mapping takes a ref to the host
6247 */
6248 ecm_db_host_ref(hi);
6249 mi->host = hi;
6250
6251 /*
6252 * Set time
6253 */
6254 spin_lock_bh(&ecm_db_lock);
6255 mi->time_added = ecm_db_time;
6256
6257 /*
6258 * Record the mapping is inserted
6259 */
6260 mi->flags |= ECM_DB_MAPPING_FLAGS_INSERTED;
6261
6262 /*
6263 * Add into the global list
6264 */
6265 mi->prev = NULL;
6266 mi->next = ecm_db_mappings;
6267 if (ecm_db_mappings) {
6268 ecm_db_mappings->prev = mi;
6269 }
6270 ecm_db_mappings = mi;
6271
6272 /*
6273 * Insert mapping into the mappings hash table
6274 */
6275 mi->hash_next = ecm_db_mapping_table[hash_index];
6276 if (ecm_db_mapping_table[hash_index]) {
6277 ecm_db_mapping_table[hash_index]->hash_prev = mi;
6278 }
6279 ecm_db_mapping_table[hash_index] = mi;
6280 ecm_db_mapping_table_lengths[hash_index]++;
6281 DEBUG_ASSERT(ecm_db_mapping_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_mapping_table_lengths[hash_index]);
6282
6283 /*
6284 * Insert mapping into the host mapping list
6285 */
6286 mi->mapping_prev = NULL;
6287 mi->mapping_next = hi->mappings;
6288 if (hi->mappings) {
6289 hi->mappings->mapping_prev = mi;
6290 }
6291 hi->mappings = mi;
6292 hi->mapping_count++;
6293 spin_unlock_bh(&ecm_db_lock);
6294
6295 /*
6296 * Throw add event to the listeners
6297 */
6298 DEBUG_TRACE("%p: Throw mapping added event\n", mi);
6299 li = ecm_db_listeners_get_and_ref_first();
6300 while (li) {
6301 struct ecm_db_listener_instance *lin;
6302 if (li->mapping_added) {
6303 li->mapping_added(li->arg, mi);
6304 }
6305
6306 /*
6307 * Get next listener
6308 */
6309 lin = ecm_db_listener_get_and_ref_next(li);
6310 ecm_db_listener_deref(li);
6311 li = lin;
6312 }
6313}
6314EXPORT_SYMBOL(ecm_db_mapping_add);
6315
6316/*
6317 * ecm_db_host_add()
6318 * Add a host instance into the database
6319 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006320void 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 +00006321{
6322 ecm_db_host_hash_t hash_index;
6323 struct ecm_db_listener_instance *li;
6324
6325 spin_lock_bh(&ecm_db_lock);
6326 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00006327 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00006328 DEBUG_ASSERT(!(hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: inserted\n", hi);
6329 spin_unlock_bh(&ecm_db_lock);
6330
6331 hi->arg = arg;
6332 hi->final = final;
6333 ECM_IP_ADDR_COPY(hi->address, address);
6334 hi->on_link = on_link;
6335
6336 /*
6337 * Compute hash index into which host will be added
6338 */
6339 hash_index = ecm_db_host_generate_hash_index(address);
6340 hi->hash_index = hash_index;
6341
6342 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00006343 * Add into the global list
6344 */
6345 spin_lock_bh(&ecm_db_lock);
6346 hi->flags |= ECM_DB_HOST_FLAGS_INSERTED;
6347 hi->prev = NULL;
6348 hi->next = ecm_db_hosts;
6349 if (ecm_db_hosts) {
6350 ecm_db_hosts->prev = hi;
6351 }
6352 ecm_db_hosts = hi;
6353
6354 /*
6355 * Add host into the hash table
6356 */
6357 hi->hash_next = ecm_db_host_table[hash_index];
6358 if (ecm_db_host_table[hash_index]) {
6359 ecm_db_host_table[hash_index]->hash_prev = hi;
6360 }
6361 ecm_db_host_table[hash_index] = hi;
6362 ecm_db_host_table_lengths[hash_index]++;
6363 DEBUG_ASSERT(ecm_db_host_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hash_index]);
6364
6365 /*
6366 * Set time of add
6367 */
6368 hi->time_added = ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00006369 spin_unlock_bh(&ecm_db_lock);
6370
6371 /*
6372 * Throw add event to the listeners
6373 */
6374 DEBUG_TRACE("%p: Throw host added event\n", hi);
6375 li = ecm_db_listeners_get_and_ref_first();
6376 while (li) {
6377 struct ecm_db_listener_instance *lin;
6378 if (li->host_added) {
6379 li->host_added(li->arg, hi);
6380 }
6381
6382 /*
6383 * Get next listener
6384 */
6385 lin = ecm_db_listener_get_and_ref_next(li);
6386 ecm_db_listener_deref(li);
6387 li = lin;
6388 }
6389}
6390EXPORT_SYMBOL(ecm_db_host_add);
6391
6392/*
6393 * ecm_db_node_add()
6394 * Add a node instance into the database
6395 */
6396void ecm_db_node_add(struct ecm_db_node_instance *ni, struct ecm_db_iface_instance *ii, uint8_t *address,
6397 ecm_db_node_final_callback_t final, void *arg)
6398{
6399 ecm_db_node_hash_t hash_index;
6400 struct ecm_db_listener_instance *li;
6401
6402 spin_lock_bh(&ecm_db_lock);
6403 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
6404 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6405 DEBUG_ASSERT(address, "%p: address null\n", ni);
Gareth Williams90f2a282014-08-27 15:56:25 +01006406 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
6407 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
6408 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
6409 DEBUG_ASSERT((ni->to_nat_connections == NULL) && (ni->to_nat_connections_count == 0), "%p: to_nat_connections not null\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00006410 DEBUG_ASSERT((ni->iface == NULL), "%p: iface not null\n", ni);
6411 DEBUG_ASSERT(!(ni->flags & ECM_DB_NODE_FLAGS_INSERTED), "%p: inserted\n", ni);
6412 spin_unlock_bh(&ecm_db_lock);
6413
6414 memcpy(ni->address, address, ETH_ALEN);
6415 ni->arg = arg;
6416 ni->final = final;
6417
6418 /*
6419 * Compute hash chain for insertion
6420 */
6421 hash_index = ecm_db_node_generate_hash_index(address);
6422 ni->hash_index = hash_index;
6423
6424 /*
6425 * Node takes a ref to the iface
6426 */
6427 ecm_db_iface_ref(ii);
6428 ni->iface = ii;
6429
6430 /*
6431 * Add into the global list
6432 */
6433 spin_lock_bh(&ecm_db_lock);
6434 ni->flags |= ECM_DB_NODE_FLAGS_INSERTED;
6435 ni->prev = NULL;
6436 ni->next = ecm_db_nodes;
6437 if (ecm_db_nodes) {
6438 ecm_db_nodes->prev = ni;
6439 }
6440 ecm_db_nodes = ni;
6441
6442 /*
6443 * Insert into the hash chain
6444 */
6445 ni->hash_next = ecm_db_node_table[hash_index];
6446 if (ecm_db_node_table[hash_index]) {
6447 ecm_db_node_table[hash_index]->hash_prev = ni;
6448 }
6449 ecm_db_node_table[hash_index] = ni;
6450 ecm_db_node_table_lengths[hash_index]++;
6451 DEBUG_ASSERT(ecm_db_node_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[hash_index]);
6452
6453 /*
6454 * Set time of add
6455 */
6456 ni->time_added = ecm_db_time;
6457
6458 /*
6459 * Insert node into the iface nodes list
6460 */
6461 ni->node_prev = NULL;
6462 ni->node_next = ii->nodes;
6463 if (ii->nodes) {
6464 ii->nodes->node_prev = ni;
6465 }
6466 ii->nodes = ni;
6467 ii->node_count++;
6468 spin_unlock_bh(&ecm_db_lock);
6469
6470 /*
6471 * Throw add event to the listeners
6472 */
6473 DEBUG_TRACE("%p: Throw node added event\n", ni);
6474 li = ecm_db_listeners_get_and_ref_first();
6475 while (li) {
6476 struct ecm_db_listener_instance *lin;
6477 if (li->node_added) {
6478 li->node_added(li->arg, ni);
6479 }
6480
6481 /*
6482 * Get next listener
6483 */
6484 lin = ecm_db_listener_get_and_ref_next(li);
6485 ecm_db_listener_deref(li);
6486 li = lin;
6487 }
6488}
6489EXPORT_SYMBOL(ecm_db_node_add);
6490
6491/*
6492 * ecm_db_iface_xml_state_get_open()
6493 * Get the start of XML state for an interface object
6494 */
6495static int ecm_db_iface_xml_state_get_open(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6496{
6497 int count;
6498 int node_count;
6499 uint32_t time_added;
6500 uint64_t from_data_total;
6501 uint64_t to_data_total;
6502 uint64_t from_packet_total;
6503 uint64_t to_packet_total;
6504 uint64_t from_data_total_dropped;
6505 uint64_t to_data_total_dropped;
6506 uint64_t from_packet_total_dropped;
6507 uint64_t to_packet_total_dropped;
6508 int32_t interface_identifier;
6509 int32_t nss_interface_identifier;
6510 char name[IFNAMSIZ];
6511 int32_t mtu;
6512 ecm_db_iface_type_t type;
6513
6514 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6515 DEBUG_TRACE("%p: Open iface msg\n", ii);
6516
6517 /*
6518 * Create a small xml stats block, like:
6519 * <iface blah="" ... >
6520 * Extract general information from the iface for inclusion into the message
6521 */
6522 node_count = ecm_db_iface_node_count_get(ii);
6523 time_added = ii->time_added;
6524 ecm_db_iface_data_stats_get(ii, &from_data_total, &to_data_total,
6525 &from_packet_total, &to_packet_total,
6526 &from_data_total_dropped, &to_data_total_dropped,
6527 &from_packet_total_dropped, &to_packet_total_dropped);
6528 type = ii->type;
6529 spin_lock_bh(&ecm_db_lock);
6530 strcpy(name, ii->name);
6531 mtu = ii->mtu;
6532 interface_identifier = ii->interface_identifier;
6533 nss_interface_identifier = ii->nss_interface_identifier;
6534 spin_unlock_bh(&ecm_db_lock);
6535
6536 /*
6537 * Prep the message
6538 */
6539 count = snprintf(buf, buf_sz,
6540 "<iface type=\"%d\" name=\"%s\" nodes=\"%d\" time_added=\"%u\""
6541 " mtu=\"%d\" interface_identifier=\"%d\" nss_interface_identifier=\"%d\""
6542 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
6543 " from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\">\n",
6544 type,
6545 name,
6546 node_count,
6547 time_added,
6548 mtu,
6549 interface_identifier,
6550 nss_interface_identifier,
6551 from_data_total,
6552 to_data_total,
6553 from_packet_total,
6554 to_packet_total,
6555 from_data_total_dropped,
6556 to_data_total_dropped,
6557 from_packet_total_dropped,
6558 to_packet_total_dropped);
6559
6560 if ((count <= 0) || (count >= buf_sz)) {
6561 return -1;
6562 }
6563
6564 return count;
6565}
6566
6567/*
6568 * ecm_db_iface_xml_state_get_close()
6569 * Get the end of XML state for an interface object
6570 */
6571static int ecm_db_iface_xml_state_get_close(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6572{
6573 int count;
6574
6575 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6576 DEBUG_TRACE("%p: Close iface msg\n", ii);
6577
6578 /*
6579 * Create a small xml stats block, like:
6580 * </iface>
6581 */
6582
6583 /*
6584 * Prep the message
6585 */
6586 count = snprintf(buf, buf_sz, "</iface>\n");
6587
6588 if ((count <= 0) || (count >= buf_sz)) {
6589 return -1;
6590 }
6591
6592 return count;
6593}
6594
6595/*
6596 * ecm_db_iface_ethernet_xml_state_get()
6597 * Return interface type specific state
6598 */
6599static int ecm_db_iface_ethernet_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6600{
6601 int count;
6602 int total;
6603 uint8_t address[ETH_ALEN];
6604
6605 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6606 spin_lock_bh(&ecm_db_lock);
6607 memcpy(address, ii->type_info.ethernet.address, ETH_ALEN);
6608 spin_unlock_bh(&ecm_db_lock);
6609
6610 /*
6611 * Write out opening element
6612 */
6613 total = 0;
6614 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
6615 if ((count <= 0) || (count >= (buf_sz - total))) {
6616 return -1;
6617 }
6618 total += count;
6619
6620 /*
6621 * Write out type specific data
6622 */
6623 count = snprintf(buf + total, buf_sz - total, "<ethernet address=\"%pM\"/>\n", address);
6624 if ((count <= 0) || (count >= (buf_sz - total))) {
6625 return -1;
6626 }
6627 total += count;
6628
6629 /*
6630 * Write out closing element
6631 */
6632 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
6633 if ((count <= 0) || (count >= (buf_sz - total))) {
6634 return -1;
6635 }
6636 total += count;
6637 return total;
6638}
6639
6640/*
6641 * ecm_db_iface_add_ethernet()
6642 * Add a iface instance into the database
6643 */
6644void ecm_db_iface_add_ethernet(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
6645 int32_t interface_identifier, int32_t nss_interface_identifier,
6646 ecm_db_iface_final_callback_t final, void *arg)
6647{
6648 ecm_db_iface_hash_t hash_index;
6649 struct ecm_db_listener_instance *li;
6650 struct ecm_db_interface_info_ethernet *type_info;
6651
6652 spin_lock_bh(&ecm_db_lock);
6653 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6654 DEBUG_ASSERT(address, "%p: address null\n", ii);
6655 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
6656 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
6657 DEBUG_ASSERT(name, "%p: no name given\n", ii);
6658 spin_unlock_bh(&ecm_db_lock);
6659
6660 /*
6661 * Record general info
6662 */
6663 ii->type = ECM_DB_IFACE_TYPE_ETHERNET;
6664 ii->xml_state_get = ecm_db_iface_ethernet_xml_state_get;
6665 ii->arg = arg;
6666 ii->final = final;
6667 strcpy(ii->name, name);
6668 ii->mtu = mtu;
6669 ii->interface_identifier = interface_identifier;
6670 ii->nss_interface_identifier = nss_interface_identifier;
6671
6672 /*
6673 * Type specific info
6674 */
6675 type_info = &ii->type_info.ethernet;
6676 memcpy(type_info->address, address, ETH_ALEN);
6677
6678 /*
6679 * Compute hash chain for insertion
6680 */
6681 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
6682 ii->hash_index = hash_index;
6683
6684 /*
6685 * Add into the global list
6686 */
6687 spin_lock_bh(&ecm_db_lock);
6688 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
6689 ii->prev = NULL;
6690 ii->next = ecm_db_interfaces;
6691 if (ecm_db_interfaces) {
6692 ecm_db_interfaces->prev = ii;
6693 }
6694 ecm_db_interfaces = ii;
6695
6696 /*
6697 * Insert into chain
6698 */
6699 ii->hash_next = ecm_db_iface_table[hash_index];
6700 if (ecm_db_iface_table[hash_index]) {
6701 ecm_db_iface_table[hash_index]->hash_prev = ii;
6702 }
6703 ecm_db_iface_table[hash_index] = ii;
6704 ecm_db_iface_table_lengths[hash_index]++;
6705 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
6706
6707 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);
6708
6709 /*
6710 * Set time of addition
6711 */
6712 ii->time_added = ecm_db_time;
6713 spin_unlock_bh(&ecm_db_lock);
6714
6715 /*
6716 * Throw add event to the listeners
6717 */
6718 DEBUG_TRACE("%p: Throw iface added event\n", ii);
6719 li = ecm_db_listeners_get_and_ref_first();
6720 while (li) {
6721 struct ecm_db_listener_instance *lin;
6722 if (li->iface_added) {
6723 li->iface_added(li->arg, ii);
6724 }
6725
6726 /*
6727 * Get next listener
6728 */
6729 lin = ecm_db_listener_get_and_ref_next(li);
6730 ecm_db_listener_deref(li);
6731 li = lin;
6732 }
6733}
6734EXPORT_SYMBOL(ecm_db_iface_add_ethernet);
6735
6736/*
6737 * ecm_db_iface_lag_xml_state_get()
6738 * Return interface type specific state
6739 */
6740static int ecm_db_iface_lag_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6741{
6742 int count;
6743 int total;
6744 uint8_t address[ETH_ALEN];
6745
6746 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6747 spin_lock_bh(&ecm_db_lock);
6748 memcpy(address, ii->type_info.lag.address, ETH_ALEN);
6749 spin_unlock_bh(&ecm_db_lock);
6750
6751 /*
6752 * Write out opening element
6753 */
6754 total = 0;
6755 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
6756 if ((count <= 0) || (count >= (buf_sz - total))) {
6757 return -1;
6758 }
6759 total += count;
6760
6761 /*
6762 * Write out type specific data
6763 */
6764 count = snprintf(buf + total, buf_sz - total, "<lag address=\"%pM\"/>\n", address);
6765 if ((count <= 0) || (count >= (buf_sz - total))) {
6766 return -1;
6767 }
6768 total += count;
6769
6770 /*
6771 * Write out closing element
6772 */
6773 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
6774 if ((count <= 0) || (count == (buf_sz - total))) {
6775 return -1;
6776 }
6777 total += count;
6778 return total;
6779}
6780
6781/*
6782 * ecm_db_iface_add_lag()
6783 * Add a iface instance into the database
6784 */
6785void ecm_db_iface_add_lag(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
6786 int32_t interface_identifier, int32_t nss_interface_identifier,
6787 ecm_db_iface_final_callback_t final, void *arg)
6788{
6789 ecm_db_iface_hash_t hash_index;
6790 struct ecm_db_listener_instance *li;
6791 struct ecm_db_interface_info_lag *type_info;
6792
6793 spin_lock_bh(&ecm_db_lock);
6794 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6795 DEBUG_ASSERT(address, "%p: address null\n", ii);
6796 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
6797 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
6798 DEBUG_ASSERT(name, "%p: no name given\n", ii);
6799 spin_unlock_bh(&ecm_db_lock);
6800
6801 /*
6802 * Record general info
6803 */
6804 ii->type = ECM_DB_IFACE_TYPE_LAG;
6805 ii->xml_state_get = ecm_db_iface_lag_xml_state_get;
6806 ii->arg = arg;
6807 ii->final = final;
6808 strcpy(ii->name, name);
6809 ii->mtu = mtu;
6810 ii->interface_identifier = interface_identifier;
6811 ii->nss_interface_identifier = nss_interface_identifier;
6812
6813 /*
6814 * Type specific info
6815 */
6816 type_info = &ii->type_info.lag;
6817 memcpy(type_info->address, address, ETH_ALEN);
6818
6819 /*
6820 * Compute hash chain for insertion
6821 */
6822 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
6823 ii->hash_index = hash_index;
6824
6825 /*
6826 * Add into the global list
6827 */
6828 spin_lock_bh(&ecm_db_lock);
6829 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
6830 ii->prev = NULL;
6831 ii->next = ecm_db_interfaces;
6832 if (ecm_db_interfaces) {
6833 ecm_db_interfaces->prev = ii;
6834 }
6835 ecm_db_interfaces = ii;
6836
6837 /*
6838 * Insert into chain
6839 */
6840 ii->hash_next = ecm_db_iface_table[hash_index];
6841 if (ecm_db_iface_table[hash_index]) {
6842 ecm_db_iface_table[hash_index]->hash_prev = ii;
6843 }
6844 ecm_db_iface_table[hash_index] = ii;
6845 ecm_db_iface_table_lengths[hash_index]++;
6846 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
6847
6848 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);
6849
6850 /*
6851 * Set time of addition
6852 */
6853 ii->time_added = ecm_db_time;
6854 spin_unlock_bh(&ecm_db_lock);
6855
6856 /*
6857 * Throw add event to the listeners
6858 */
6859 DEBUG_TRACE("%p: Throw iface added event\n", ii);
6860 li = ecm_db_listeners_get_and_ref_first();
6861 while (li) {
6862 struct ecm_db_listener_instance *lin;
6863 if (li->iface_added) {
6864 li->iface_added(li->arg, ii);
6865 }
6866
6867 /*
6868 * Get next listener
6869 */
6870 lin = ecm_db_listener_get_and_ref_next(li);
6871 ecm_db_listener_deref(li);
6872 li = lin;
6873 }
6874}
6875EXPORT_SYMBOL(ecm_db_iface_add_lag);
6876
6877/*
6878 * ecm_db_iface_bridge_xml_state_get()
6879 * Return interface type specific state
6880 */
6881static int ecm_db_iface_bridge_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6882{
6883 int count;
6884 int total;
6885 uint8_t address[ETH_ALEN];
6886
6887 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6888 spin_lock_bh(&ecm_db_lock);
6889 memcpy(address, ii->type_info.bridge.address, ETH_ALEN);
6890 spin_unlock_bh(&ecm_db_lock);
6891
6892 /*
6893 * Write out opening element
6894 */
6895 total = 0;
6896 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
6897 if ((count <= 0) || (count >= (buf_sz - total))) {
6898 return -1;
6899 }
6900 total += count;
6901
6902 /*
6903 * Write out type specific data
6904 */
6905 count = snprintf(buf + total, buf_sz - total, "<bridge address=\"%pM\"/>\n", address);
6906 if ((count <= 0) || (count >= (buf_sz - total))) {
6907 return -1;
6908 }
6909 total += count;
6910
6911 /*
6912 * Write out closing element
6913 */
6914 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
6915 if ((count <= 0) || (count >= (buf_sz - total))) {
6916 return -1;
6917 }
6918 total += count;
6919 return total;
6920}
6921
6922/*
6923 * ecm_db_iface_add_bridge()
6924 * Add a iface instance into the database
6925 */
6926void ecm_db_iface_add_bridge(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
6927 int32_t interface_identifier, int32_t nss_interface_identifier,
6928 ecm_db_iface_final_callback_t final, void *arg)
6929{
6930 ecm_db_iface_hash_t hash_index;
6931 struct ecm_db_listener_instance *li;
6932 struct ecm_db_interface_info_bridge *type_info;
6933
6934 spin_lock_bh(&ecm_db_lock);
6935 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6936 DEBUG_ASSERT(address, "%p: address null\n", ii);
6937 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
6938 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
6939 DEBUG_ASSERT(name, "%p: no name given\n", ii);
6940 spin_unlock_bh(&ecm_db_lock);
6941
6942 /*
6943 * Record general info
6944 */
6945 ii->type = ECM_DB_IFACE_TYPE_BRIDGE;
6946 ii->xml_state_get = ecm_db_iface_bridge_xml_state_get;
6947 ii->arg = arg;
6948 ii->final = final;
6949 strcpy(ii->name, name);
6950 ii->mtu = mtu;
6951 ii->interface_identifier = interface_identifier;
6952 ii->nss_interface_identifier = nss_interface_identifier;
6953
6954 /*
6955 * Type specific info
6956 */
6957 type_info = &ii->type_info.bridge;
6958 memcpy(type_info->address, address, ETH_ALEN);
6959
6960 /*
6961 * Compute hash chain for insertion
6962 */
6963 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
6964 ii->hash_index = hash_index;
6965
6966 /*
6967 * Add into the global list
6968 */
6969 spin_lock_bh(&ecm_db_lock);
6970 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
6971 ii->prev = NULL;
6972 ii->next = ecm_db_interfaces;
6973 if (ecm_db_interfaces) {
6974 ecm_db_interfaces->prev = ii;
6975 }
6976 ecm_db_interfaces = ii;
6977
6978 /*
6979 * Insert into chain
6980 */
6981 ii->hash_next = ecm_db_iface_table[hash_index];
6982 if (ecm_db_iface_table[hash_index]) {
6983 ecm_db_iface_table[hash_index]->hash_prev = ii;
6984 }
6985 ecm_db_iface_table[hash_index] = ii;
6986 ecm_db_iface_table_lengths[hash_index]++;
6987 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
6988
6989 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);
6990
6991 /*
6992 * Set time of addition
6993 */
6994 ii->time_added = ecm_db_time;
6995 spin_unlock_bh(&ecm_db_lock);
6996
6997 /*
6998 * Throw add event to the listeners
6999 */
7000 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7001 li = ecm_db_listeners_get_and_ref_first();
7002 while (li) {
7003 struct ecm_db_listener_instance *lin;
7004 if (li->iface_added) {
7005 li->iface_added(li->arg, ii);
7006 }
7007
7008 /*
7009 * Get next listener
7010 */
7011 lin = ecm_db_listener_get_and_ref_next(li);
7012 ecm_db_listener_deref(li);
7013 li = lin;
7014 }
7015}
7016EXPORT_SYMBOL(ecm_db_iface_add_bridge);
7017
7018/*
7019 * ecm_db_iface_vlan_xml_state_get()
7020 * Return interface type specific state
7021 */
7022static int ecm_db_iface_vlan_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7023{
7024 int count;
7025 int total;
7026 uint8_t address[ETH_ALEN];
7027 uint16_t vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307028 uint16_t vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007029
7030 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7031 spin_lock_bh(&ecm_db_lock);
7032 memcpy(address, ii->type_info.vlan.address, ETH_ALEN);
7033 vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307034 vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007035 spin_unlock_bh(&ecm_db_lock);
7036
7037 /*
7038 * Write out opening element
7039 */
7040 total = 0;
7041 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7042 if ((count <= 0) || (count >= (buf_sz - total))) {
7043 return -1;
7044 }
7045 total += count;
7046
7047 /*
7048 * Write out type specific data
7049 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307050 count = snprintf(buf + total, buf_sz - total, "<vlan address=\"%pM\" vlan_tag=\"%x\" vlan_tpid=\"%x\"/>\n", address, vlan_tag, vlan_tpid);
Ben Menchaca84f36632014-02-28 20:57:38 +00007051 if ((count <= 0) || (count >= (buf_sz - total))) {
7052 return -1;
7053 }
7054 total += count;
7055
7056 /*
7057 * Write out closing element
7058 */
7059 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7060 if ((count <= 0) || (count >= (buf_sz - total))) {
7061 return -1;
7062 }
7063 total += count;
7064 return total;
7065}
7066
7067/*
7068 * ecm_db_iface_add_vlan()
7069 * Add a iface instance into the database
7070 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307071void 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,
Ben Menchaca84f36632014-02-28 20:57:38 +00007072 int32_t interface_identifier, int32_t nss_interface_identifier,
7073 ecm_db_iface_final_callback_t final, void *arg)
7074{
7075 ecm_db_iface_hash_t hash_index;
7076 struct ecm_db_listener_instance *li;
7077 struct ecm_db_interface_info_vlan *type_info;
7078
7079 spin_lock_bh(&ecm_db_lock);
7080 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7081 DEBUG_ASSERT(address, "%p: address null\n", ii);
7082 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7083 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7084 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7085 spin_unlock_bh(&ecm_db_lock);
7086
7087 /*
7088 * Record general info
7089 */
7090 ii->type = ECM_DB_IFACE_TYPE_VLAN;
7091 ii->xml_state_get = ecm_db_iface_vlan_xml_state_get;
7092 ii->arg = arg;
7093 ii->final = final;
7094 strcpy(ii->name, name);
7095 ii->mtu = mtu;
7096 ii->interface_identifier = interface_identifier;
7097 ii->nss_interface_identifier = nss_interface_identifier;
7098
7099 /*
7100 * Type specific info
7101 */
7102 type_info = &ii->type_info.vlan;
7103 type_info->vlan_tag = vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307104 type_info->vlan_tpid = vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007105 memcpy(type_info->address, address, ETH_ALEN);
7106
7107 /*
7108 * Compute hash chain for insertion
7109 */
7110 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
7111 ii->hash_index = hash_index;
7112
7113 /*
7114 * Add into the global list
7115 */
7116 spin_lock_bh(&ecm_db_lock);
7117 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7118 ii->prev = NULL;
7119 ii->next = ecm_db_interfaces;
7120 if (ecm_db_interfaces) {
7121 ecm_db_interfaces->prev = ii;
7122 }
7123 ecm_db_interfaces = ii;
7124
7125 /*
7126 * Insert into chain
7127 */
7128 ii->hash_next = ecm_db_iface_table[hash_index];
7129 if (ecm_db_iface_table[hash_index]) {
7130 ecm_db_iface_table[hash_index]->hash_prev = ii;
7131 }
7132 ecm_db_iface_table[hash_index] = ii;
7133 ecm_db_iface_table_lengths[hash_index]++;
7134 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7135
7136 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);
7137
7138 /*
7139 * Set time of addition
7140 */
7141 ii->time_added = ecm_db_time;
7142 spin_unlock_bh(&ecm_db_lock);
7143
7144 /*
7145 * Throw add event to the listeners
7146 */
7147 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7148 li = ecm_db_listeners_get_and_ref_first();
7149 while (li) {
7150 struct ecm_db_listener_instance *lin;
7151 if (li->iface_added) {
7152 li->iface_added(li->arg, ii);
7153 }
7154
7155 /*
7156 * Get next listener
7157 */
7158 lin = ecm_db_listener_get_and_ref_next(li);
7159 ecm_db_listener_deref(li);
7160 li = lin;
7161 }
7162}
7163EXPORT_SYMBOL(ecm_db_iface_add_vlan);
7164
7165/*
7166 * ecm_db_iface_pppoe_xml_state_get()
7167 * Return interface type specific state
7168 */
7169static int ecm_db_iface_pppoe_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7170{
7171 int count;
7172 int total;
7173 uint16_t pppoe_session_id;
7174 uint8_t remote_mac[ETH_ALEN];
7175
7176 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7177 spin_lock_bh(&ecm_db_lock);
7178 pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
7179 memcpy(remote_mac, ii->type_info.pppoe.remote_mac, ETH_ALEN);
7180 spin_unlock_bh(&ecm_db_lock);
7181
7182 /*
7183 * Write out opening element
7184 */
7185 total = 0;
7186 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7187 if ((count <= 0) || (count >= (buf_sz - total))) {
7188 return -1;
7189 }
7190 total += count;
7191
7192 /*
7193 * Write out type specific data
7194 */
7195 count = snprintf(buf + total, buf_sz - total, "<pppoe pppoe_session_id=\"%u\" remote_mac=\"%pM\"/>\n",
7196 pppoe_session_id, remote_mac);
7197 if ((count <= 0) || (count >= (buf_sz - total))) {
7198 return -1;
7199 }
7200 total += count;
7201
7202 /*
7203 * Write out closing element
7204 */
7205 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7206 if ((count <= 0) || (count >= (buf_sz - total))) {
7207 return -1;
7208 }
7209 total += count;
7210 return total;
7211}
7212
7213/*
7214 * ecm_db_iface_add_pppoe()
7215 * Add a iface instance into the database
7216 */
7217void ecm_db_iface_add_pppoe(struct ecm_db_iface_instance *ii, uint16_t pppoe_session_id, uint8_t *remote_mac,
7218 char *name, int32_t mtu, int32_t interface_identifier,
7219 int32_t nss_interface_identifier, ecm_db_iface_final_callback_t final,
7220 void *arg)
7221{
7222 ecm_db_iface_hash_t hash_index;
7223 struct ecm_db_listener_instance *li;
7224 struct ecm_db_interface_info_pppoe *type_info;
7225
7226 spin_lock_bh(&ecm_db_lock);
7227 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7228 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7229 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7230 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7231 spin_unlock_bh(&ecm_db_lock);
7232
7233 /*
7234 * Record general info
7235 */
7236 ii->type = ECM_DB_IFACE_TYPE_PPPOE;
7237 ii->xml_state_get = ecm_db_iface_pppoe_xml_state_get;
7238 ii->arg = arg;
7239 ii->final = final;
7240 strcpy(ii->name, name);
7241 ii->mtu = mtu;
7242 ii->interface_identifier = interface_identifier;
7243 ii->nss_interface_identifier = nss_interface_identifier;
7244
7245 /*
7246 * Type specific info
7247 */
7248 type_info = &ii->type_info.pppoe;
7249 type_info->pppoe_session_id = pppoe_session_id;
7250 memcpy(type_info->remote_mac, remote_mac, ETH_ALEN);
7251
7252 /*
7253 * Compute hash chain for insertion
7254 */
7255 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
7256 ii->hash_index = hash_index;
7257
7258 /*
7259 * Add into the global list
7260 */
7261 spin_lock_bh(&ecm_db_lock);
7262 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7263 ii->prev = NULL;
7264 ii->next = ecm_db_interfaces;
7265 if (ecm_db_interfaces) {
7266 ecm_db_interfaces->prev = ii;
7267 }
7268 ecm_db_interfaces = ii;
7269
7270 /*
7271 * Insert into chain
7272 */
7273 ii->hash_next = ecm_db_iface_table[hash_index];
7274 if (ecm_db_iface_table[hash_index]) {
7275 ecm_db_iface_table[hash_index]->hash_prev = ii;
7276 }
7277 ecm_db_iface_table[hash_index] = ii;
7278 ecm_db_iface_table_lengths[hash_index]++;
7279 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7280
7281 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);
7282
7283 /*
7284 * Set time of addition
7285 */
7286 ii->time_added = ecm_db_time;
7287 spin_unlock_bh(&ecm_db_lock);
7288
7289 /*
7290 * Throw add event to the listeners
7291 */
7292 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7293 li = ecm_db_listeners_get_and_ref_first();
7294 while (li) {
7295 struct ecm_db_listener_instance *lin;
7296 if (li->iface_added) {
7297 li->iface_added(li->arg, ii);
7298 }
7299
7300 /*
7301 * Get next listener
7302 */
7303 lin = ecm_db_listener_get_and_ref_next(li);
7304 ecm_db_listener_deref(li);
7305 li = lin;
7306 }
7307}
7308EXPORT_SYMBOL(ecm_db_iface_add_pppoe);
7309
7310/*
7311 * ecm_db_iface_unknown_xml_state_get()
7312 * Return interface type specific state
7313 */
7314static int ecm_db_iface_unknown_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7315{
7316 int count;
7317 int total;
7318 uint32_t os_specific_ident;
7319
7320 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7321 spin_lock_bh(&ecm_db_lock);
7322 os_specific_ident = ii->type_info.unknown.os_specific_ident;
7323 spin_unlock_bh(&ecm_db_lock);
7324
7325 /*
7326 * Write out opening element
7327 */
7328 total = 0;
7329 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7330 if ((count <= 0) || (count >= (buf_sz - total))) {
7331 return -1;
7332 }
7333 total += count;
7334
7335 /*
7336 * Write out type specific data
7337 */
7338 count = snprintf(buf + total, buf_sz - total, "<unknown os_specific_ident=\"%u\"/>\n", os_specific_ident);
7339 if ((count <= 0) || (count >= (buf_sz - total))) {
7340 return -1;
7341 }
7342 total += count;
7343
7344 /*
7345 * Write out closing element
7346 */
7347 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7348 if ((count <= 0) || (count >= (buf_sz - total))) {
7349 return -1;
7350 }
7351 total += count;
7352 return total;
7353}
7354
7355/*
7356 * ecm_db_iface_loopback_xml_state_get()
7357 * Return interface type specific state
7358 */
7359static int ecm_db_iface_loopback_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7360{
7361 int count;
7362 int total;
7363 uint32_t os_specific_ident;
7364
7365 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7366 spin_lock_bh(&ecm_db_lock);
7367 os_specific_ident = ii->type_info.loopback.os_specific_ident;
7368 spin_unlock_bh(&ecm_db_lock);
7369
7370 /*
7371 * Write out opening element
7372 */
7373 total = 0;
7374 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7375 if ((count <= 0) || (count >= (buf_sz - total))) {
7376 return -1;
7377 }
7378 total += count;
7379
7380 /*
7381 * Write out type specific data
7382 */
7383 count = snprintf(buf + total, buf_sz - total, "<loopback os_specific_ident=\"%u\"/>\n", os_specific_ident);
7384 if ((count <= 0) || (count >= (buf_sz - total))) {
7385 return -1;
7386 }
7387 total += count;
7388
7389 /*
7390 * Write out closing element
7391 */
7392 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7393 if ((count <= 0) || (count >= (buf_sz - total))) {
7394 return -1;
7395 }
7396 total += count;
7397 return total;
7398}
7399
7400/*
7401 * ecm_db_iface_ipsec_tunnel_xml_state_get()
7402 * Return interface type specific state
7403 *
7404 * GGG TODO Output state on ipsec tunnel specific data
7405 */
7406static int ecm_db_iface_ipsec_tunnel_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7407{
7408 int count;
7409 int total;
7410 uint32_t os_specific_ident;
7411
7412 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7413 spin_lock_bh(&ecm_db_lock);
7414 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7415 spin_unlock_bh(&ecm_db_lock);
7416
7417 /*
7418 * Write out opening element
7419 */
7420 total = 0;
7421 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7422 if ((count <= 0) || (count >= (buf_sz - total))) {
7423 return -1;
7424 }
7425 total += count;
7426
7427 /*
7428 * Write out type specific data
7429 */
7430 count = snprintf(buf + total, buf_sz - total, "<ipsec_tunnel os_specific_ident=\"%u\"/>\n", os_specific_ident);
7431 if ((count <= 0) || (count >= (buf_sz - total))) {
7432 return -1;
7433 }
7434 total += count;
7435
7436 /*
7437 * Write out closing element
7438 */
7439 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7440 if ((count <= 0) || (count >= (buf_sz - total))) {
7441 return -1;
7442 }
7443 total += count;
7444 return total;
7445}
7446
7447/*
7448 * ecm_db_iface_add_unknown()
7449 * Add a iface instance into the database
7450 */
7451void ecm_db_iface_add_unknown(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
7452 int32_t interface_identifier, int32_t nss_interface_identifier,
7453 ecm_db_iface_final_callback_t final, void *arg)
7454{
7455 ecm_db_iface_hash_t hash_index;
7456 struct ecm_db_listener_instance *li;
7457 struct ecm_db_interface_info_unknown *type_info;
7458
7459 spin_lock_bh(&ecm_db_lock);
7460 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7461 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7462 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7463 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7464 spin_unlock_bh(&ecm_db_lock);
7465
7466 /*
7467 * Record general info
7468 */
7469 ii->type = ECM_DB_IFACE_TYPE_UNKNOWN;
7470 ii->xml_state_get = ecm_db_iface_unknown_xml_state_get;
7471 ii->arg = arg;
7472 ii->final = final;
7473 strcpy(ii->name, name);
7474 ii->mtu = mtu;
7475 ii->interface_identifier = interface_identifier;
7476 ii->nss_interface_identifier = nss_interface_identifier;
7477
7478 /*
7479 * Type specific info
7480 */
7481 type_info = &ii->type_info.unknown;
7482 type_info->os_specific_ident = os_specific_ident;
7483
7484 /*
7485 * Compute hash chain for insertion
7486 */
7487 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
7488 ii->hash_index = hash_index;
7489
7490 /*
7491 * Add into the global list
7492 */
7493 spin_lock_bh(&ecm_db_lock);
7494 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7495 ii->prev = NULL;
7496 ii->next = ecm_db_interfaces;
7497 if (ecm_db_interfaces) {
7498 ecm_db_interfaces->prev = ii;
7499 }
7500 ecm_db_interfaces = ii;
7501
7502 /*
7503 * Insert into chain
7504 */
7505 ii->hash_next = ecm_db_iface_table[hash_index];
7506 if (ecm_db_iface_table[hash_index]) {
7507 ecm_db_iface_table[hash_index]->hash_prev = ii;
7508 }
7509 ecm_db_iface_table[hash_index] = ii;
7510 ecm_db_iface_table_lengths[hash_index]++;
7511 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7512
7513 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);
7514
7515 /*
7516 * Set time of addition
7517 */
7518 ii->time_added = ecm_db_time;
7519 spin_unlock_bh(&ecm_db_lock);
7520
7521 /*
7522 * Throw add event to the listeners
7523 */
7524 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7525 li = ecm_db_listeners_get_and_ref_first();
7526 while (li) {
7527 struct ecm_db_listener_instance *lin;
7528 if (li->iface_added) {
7529 li->iface_added(li->arg, ii);
7530 }
7531
7532 /*
7533 * Get next listener
7534 */
7535 lin = ecm_db_listener_get_and_ref_next(li);
7536 ecm_db_listener_deref(li);
7537 li = lin;
7538 }
7539}
7540EXPORT_SYMBOL(ecm_db_iface_add_unknown);
7541
7542/*
7543 * ecm_db_iface_add_loopback()
7544 * Add a iface instance into the database
7545 */
7546void ecm_db_iface_add_loopback(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
7547 int32_t interface_identifier, int32_t nss_interface_identifier,
7548 ecm_db_iface_final_callback_t final, void *arg)
7549{
7550 ecm_db_iface_hash_t hash_index;
7551 struct ecm_db_listener_instance *li;
7552 struct ecm_db_interface_info_loopback *type_info;
7553
7554 spin_lock_bh(&ecm_db_lock);
7555 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7556 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7557 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7558 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7559 spin_unlock_bh(&ecm_db_lock);
7560
7561 /*
7562 * Record general info
7563 */
7564 ii->type = ECM_DB_IFACE_TYPE_LOOPBACK;
7565 ii->xml_state_get = ecm_db_iface_loopback_xml_state_get;
7566 ii->arg = arg;
7567 ii->final = final;
7568 strcpy(ii->name, name);
7569 ii->mtu = mtu;
7570 ii->interface_identifier = interface_identifier;
7571 ii->nss_interface_identifier = nss_interface_identifier;
7572
7573 /*
7574 * Type specific info
7575 */
7576 type_info = &ii->type_info.loopback;
7577 type_info->os_specific_ident = os_specific_ident;
7578
7579 /*
7580 * Compute hash chain for insertion
7581 */
7582 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
7583 ii->hash_index = hash_index;
7584
7585 /*
7586 * Add into the global list
7587 */
7588 spin_lock_bh(&ecm_db_lock);
7589 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7590 ii->prev = NULL;
7591 ii->next = ecm_db_interfaces;
7592 if (ecm_db_interfaces) {
7593 ecm_db_interfaces->prev = ii;
7594 }
7595 ecm_db_interfaces = ii;
7596
7597 /*
7598 * Insert into chain
7599 */
7600 ii->hash_next = ecm_db_iface_table[hash_index];
7601 if (ecm_db_iface_table[hash_index]) {
7602 ecm_db_iface_table[hash_index]->hash_prev = ii;
7603 }
7604 ecm_db_iface_table[hash_index] = ii;
7605 ecm_db_iface_table_lengths[hash_index]++;
7606 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7607
7608 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);
7609
7610 /*
7611 * Set time of addition
7612 */
7613 ii->time_added = ecm_db_time;
7614 spin_unlock_bh(&ecm_db_lock);
7615
7616 /*
7617 * Throw add event to the listeners
7618 */
7619 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7620 li = ecm_db_listeners_get_and_ref_first();
7621 while (li) {
7622 struct ecm_db_listener_instance *lin;
7623 if (li->iface_added) {
7624 li->iface_added(li->arg, ii);
7625 }
7626
7627 /*
7628 * Get next listener
7629 */
7630 lin = ecm_db_listener_get_and_ref_next(li);
7631 ecm_db_listener_deref(li);
7632 li = lin;
7633 }
7634}
7635EXPORT_SYMBOL(ecm_db_iface_add_loopback);
7636
7637/*
Zhu Ken56477be2014-08-05 17:50:28 +08007638 * ecm_db_iface_sit_daddr_is_null()
7639 * The sit addr is null or not
7640 */
7641bool ecm_db_iface_sit_daddr_is_null(struct ecm_db_iface_instance *ii)
7642{
7643 return ii->type_info.sit.daddr[0] == 0;
7644}
7645EXPORT_SYMBOL(ecm_db_iface_sit_daddr_is_null);
7646
7647/*
Ben Menchaca84f36632014-02-28 20:57:38 +00007648 * ecm_db_iface_add_sit()
7649 * Add a iface instance into the database
7650 */
7651void ecm_db_iface_add_sit(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_sit *type_info, char *name, int32_t mtu,
7652 int32_t interface_identifier, int32_t nss_interface_identifier,
7653 ecm_db_iface_final_callback_t final, void *arg)
7654{
7655 ecm_db_iface_hash_t hash_index;
7656 struct ecm_db_listener_instance *li;
7657
7658 spin_lock_bh(&ecm_db_lock);
7659 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7660 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7661 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7662 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7663 spin_unlock_bh(&ecm_db_lock);
7664
7665 /*
7666 * Record general info
7667 */
7668 ii->type = ECM_DB_IFACE_TYPE_SIT;
7669 ii->xml_state_get = ecm_db_iface_loopback_xml_state_get;
7670 ii->arg = arg;
7671 ii->final = final;
7672 strcpy(ii->name, name);
7673 ii->mtu = mtu;
7674 ii->interface_identifier = interface_identifier;
7675 ii->nss_interface_identifier = nss_interface_identifier;
7676
7677 /*
7678 * Type specific info to be copied
7679 */
7680 ii->type_info.sit = *type_info;
7681
7682 /*
7683 * Compute hash chain for insertion
7684 */
7685 hash_index = ecm_db_iface_generate_hash_index_sit(type_info->saddr, type_info->daddr);
7686 ii->hash_index = hash_index;
7687
7688 /*
7689 * Add into the global list
7690 */
7691 spin_lock_bh(&ecm_db_lock);
7692 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7693 ii->prev = NULL;
7694 ii->next = ecm_db_interfaces;
7695 if (ecm_db_interfaces) {
7696 ecm_db_interfaces->prev = ii;
7697 }
7698 ecm_db_interfaces = ii;
7699
7700 /*
7701 * Insert into chain
7702 */
7703 ii->hash_next = ecm_db_iface_table[hash_index];
7704 if (ecm_db_iface_table[hash_index]) {
7705 ecm_db_iface_table[hash_index]->hash_prev = ii;
7706 }
7707 ecm_db_iface_table[hash_index] = ii;
7708 ecm_db_iface_table_lengths[hash_index]++;
7709 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7710
7711 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);
7712
7713 /*
7714 * Set time of addition
7715 */
7716 ii->time_added = ecm_db_time;
7717 spin_unlock_bh(&ecm_db_lock);
7718
7719 /*
7720 * Throw add event to the listeners
7721 */
7722 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7723 li = ecm_db_listeners_get_and_ref_first();
7724 while (li) {
7725 struct ecm_db_listener_instance *lin;
7726 if (li->iface_added) {
7727 li->iface_added(li->arg, ii);
7728 }
7729
7730 /*
7731 * Get next listener
7732 */
7733 lin = ecm_db_listener_get_and_ref_next(li);
7734 ecm_db_listener_deref(li);
7735 li = lin;
7736 }
7737}
7738EXPORT_SYMBOL(ecm_db_iface_add_sit);
7739
7740/*
7741 * ecm_db_iface_add_tunipip6()
7742 * Add a iface instance into the database
7743 */
7744void ecm_db_iface_add_tunipip6(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_tunipip6 *type_info, char *name, int32_t mtu,
7745 int32_t interface_identifier, int32_t nss_interface_identifier,
7746 ecm_db_iface_final_callback_t final, void *arg)
7747{
7748 ecm_db_iface_hash_t hash_index;
7749 struct ecm_db_listener_instance *li;
7750
7751 spin_lock_bh(&ecm_db_lock);
7752 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7753 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7754 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7755 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7756 spin_unlock_bh(&ecm_db_lock);
7757
7758 /*
7759 * Record general info
7760 */
7761 ii->type = ECM_DB_IFACE_TYPE_TUNIPIP6;
7762 ii->xml_state_get = ecm_db_iface_loopback_xml_state_get;
7763 ii->arg = arg;
7764 ii->final = final;
7765 strcpy(ii->name, name);
7766 ii->mtu = mtu;
7767 ii->interface_identifier = interface_identifier;
7768 ii->nss_interface_identifier = nss_interface_identifier;
7769
7770 /*
7771 * Type specific info to be copied
7772 */
7773 ii->type_info.tunipip6 = *type_info;
7774
7775 /*
7776 * Compute hash chain for insertion
7777 */
7778 hash_index = ecm_db_iface_generate_hash_index_tunipip6(type_info->saddr, type_info->daddr);
7779 ii->hash_index = hash_index;
7780
7781 /*
7782 * Add into the global list
7783 */
7784 spin_lock_bh(&ecm_db_lock);
7785 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7786 ii->prev = NULL;
7787 ii->next = ecm_db_interfaces;
7788 if (ecm_db_interfaces) {
7789 ecm_db_interfaces->prev = ii;
7790 }
7791 ecm_db_interfaces = ii;
7792
7793 /*
7794 * Insert into chain
7795 */
7796 ii->hash_next = ecm_db_iface_table[hash_index];
7797 if (ecm_db_iface_table[hash_index]) {
7798 ecm_db_iface_table[hash_index]->hash_prev = ii;
7799 }
7800 ecm_db_iface_table[hash_index] = ii;
7801 ecm_db_iface_table_lengths[hash_index]++;
7802 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7803
7804 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);
7805
7806 /*
7807 * Set time of addition
7808 */
7809 ii->time_added = ecm_db_time;
7810 spin_unlock_bh(&ecm_db_lock);
7811
7812 /*
7813 * Throw add event to the listeners
7814 */
7815 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7816 li = ecm_db_listeners_get_and_ref_first();
7817 while (li) {
7818 struct ecm_db_listener_instance *lin;
7819 if (li->iface_added) {
7820 li->iface_added(li->arg, ii);
7821 }
7822
7823 /*
7824 * Get next listener
7825 */
7826 lin = ecm_db_listener_get_and_ref_next(li);
7827 ecm_db_listener_deref(li);
7828 li = lin;
7829 }
7830}
7831EXPORT_SYMBOL(ecm_db_iface_add_tunipip6);
7832
7833/*
7834 * ecm_db_iface_add_ipsec_tunnel()
7835 * Add a iface instance into the database
7836 *
7837 * GGG TODO This needs to take ipsec tunnel endpoint information etc. something very appropriate for ipsec tunnels, anyhow.
7838 */
7839void ecm_db_iface_add_ipsec_tunnel(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
7840 int32_t interface_identifier, int32_t nss_interface_identifier,
7841 ecm_db_iface_final_callback_t final, void *arg)
7842{
7843 ecm_db_iface_hash_t hash_index;
7844 struct ecm_db_listener_instance *li;
7845 struct ecm_db_interface_info_ipsec_tunnel *type_info;
7846
7847 spin_lock_bh(&ecm_db_lock);
7848 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7849 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7850 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7851 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7852 spin_unlock_bh(&ecm_db_lock);
7853
7854 /*
7855 * Record general info
7856 */
Ankit Dhanuka60683c52014-06-09 17:43:38 +05307857 ii->type = ECM_DB_IFACE_TYPE_IPSEC_TUNNEL;
Ben Menchaca84f36632014-02-28 20:57:38 +00007858 ii->xml_state_get = ecm_db_iface_ipsec_tunnel_xml_state_get;
7859 ii->arg = arg;
7860 ii->final = final;
7861 strcpy(ii->name, name);
7862 ii->mtu = mtu;
7863 ii->interface_identifier = interface_identifier;
7864 ii->nss_interface_identifier = nss_interface_identifier;
7865
7866 /*
7867 * Type specific info
7868 */
7869 type_info = &ii->type_info.ipsec_tunnel;
7870 type_info->os_specific_ident = os_specific_ident;
7871
7872 /*
7873 * Compute hash chain for insertion
7874 */
7875 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
7876 ii->hash_index = hash_index;
7877
7878 /*
7879 * Add into the global list
7880 */
7881 spin_lock_bh(&ecm_db_lock);
7882 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7883 ii->prev = NULL;
7884 ii->next = ecm_db_interfaces;
7885 if (ecm_db_interfaces) {
7886 ecm_db_interfaces->prev = ii;
7887 }
7888 ecm_db_interfaces = ii;
7889
7890 /*
7891 * Insert into chain
7892 */
7893 ii->hash_next = ecm_db_iface_table[hash_index];
7894 if (ecm_db_iface_table[hash_index]) {
7895 ecm_db_iface_table[hash_index]->hash_prev = ii;
7896 }
7897 ecm_db_iface_table[hash_index] = ii;
7898 ecm_db_iface_table_lengths[hash_index]++;
7899 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7900
7901 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);
7902
7903 /*
7904 * Set time of addition
7905 */
7906 ii->time_added = ecm_db_time;
7907 spin_unlock_bh(&ecm_db_lock);
7908
7909 /*
7910 * Throw add event to the listeners
7911 */
7912 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7913 li = ecm_db_listeners_get_and_ref_first();
7914 while (li) {
7915 struct ecm_db_listener_instance *lin;
7916 if (li->iface_added) {
7917 li->iface_added(li->arg, ii);
7918 }
7919
7920 /*
7921 * Get next listener
7922 */
7923 lin = ecm_db_listener_get_and_ref_next(li);
7924 ecm_db_listener_deref(li);
7925 li = lin;
7926 }
7927}
7928EXPORT_SYMBOL(ecm_db_iface_add_ipsec_tunnel);
7929
7930/*
7931 * ecm_db_listener_add()
7932 * Add a listener instance into the database.
7933 */
7934void ecm_db_listener_add(struct ecm_db_listener_instance *li,
7935 ecm_db_iface_listener_added_callback_t iface_added,
7936 ecm_db_iface_listener_removed_callback_t iface_removed,
7937 ecm_db_node_listener_added_callback_t node_added,
7938 ecm_db_node_listener_removed_callback_t node_removed,
7939 ecm_db_host_listener_added_callback_t host_added,
7940 ecm_db_host_listener_removed_callback_t host_removed,
7941 ecm_db_mapping_listener_added_callback_t mapping_added,
7942 ecm_db_mapping_listener_removed_callback_t mapping_removed,
7943 ecm_db_connection_listener_added_callback_t connection_added,
7944 ecm_db_connection_listener_removed_callback_t connection_removed,
7945 ecm_db_listener_final_callback_t final,
7946 void *arg)
7947{
7948 spin_lock_bh(&ecm_db_lock);
7949 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed\n", li);
7950 DEBUG_ASSERT(!(li->flags & ECM_DB_LISTENER_FLAGS_INSERTED), "%p: inserted\n", li);
7951 spin_unlock_bh(&ecm_db_lock);
7952
7953 li->arg = arg;
7954 li->final = final;
7955 li->iface_added = iface_added;
7956 li->iface_removed = iface_removed;
7957 li->node_added = node_added;
7958 li->node_removed = node_removed;
7959 li->host_added = host_added;
7960 li->host_removed = host_removed;
7961 li->mapping_added = mapping_added;
7962 li->mapping_removed = mapping_removed;
7963 li->connection_added = connection_added;
7964 li->connection_removed = connection_removed;
7965
7966 /*
7967 * Add instance into listener list
7968 */
7969 spin_lock_bh(&ecm_db_lock);
7970 li->flags |= ECM_DB_LISTENER_FLAGS_INSERTED;
7971 li->next = ecm_db_listeners;
7972 ecm_db_listeners = li;
7973 spin_unlock_bh(&ecm_db_lock);
7974}
7975EXPORT_SYMBOL(ecm_db_listener_add);
7976
7977/*
7978 * ecm_db_connection_alloc()
7979 * Allocate a connection instance
7980 */
7981struct ecm_db_connection_instance *ecm_db_connection_alloc(void)
7982{
7983 struct ecm_db_connection_instance *ci;
7984
7985 /*
7986 * Allocate the connection
7987 */
7988 ci = (struct ecm_db_connection_instance *)kzalloc(sizeof(struct ecm_db_connection_instance), GFP_ATOMIC | __GFP_NOWARN);
7989 if (!ci) {
7990 DEBUG_WARN("Connection alloc failed\n");
7991 return NULL;
7992 }
7993
7994 /*
7995 * Initialise the defunct timer entry
7996 */
7997 ecm_db_timer_group_entry_init(&ci->defunct_timer, ecm_db_connection_defunct_callback, ci);
7998
7999 /*
8000 * Refs is 1 for the creator of the connection
8001 */
8002 ci->refs = 1;
8003 DEBUG_SET_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC);
8004
8005 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05008006 * Initialise the interfaces from/to lists.
8007 * Interfaces are added from end of array.
8008 */
8009 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
8010 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
8011 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
8012 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
8013
8014 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00008015 * If the master thread is terminating then we cannot create new instances
8016 */
8017 spin_lock_bh(&ecm_db_lock);
8018 if (ecm_db_terminate_pending) {
8019 spin_unlock_bh(&ecm_db_lock);
8020 DEBUG_WARN("Thread terminating\n");
8021 kfree(ci);
8022 return NULL;
8023 }
8024
8025 /*
8026 * Assign runtime unique serial
8027 */
8028 ci->serial = ecm_db_connection_serial++;
8029
Ben Menchaca84f36632014-02-28 20:57:38 +00008030 ecm_db_connection_count++;
8031 DEBUG_ASSERT(ecm_db_connection_count > 0, "%p: connection count wrap\n", ci);
8032 spin_unlock_bh(&ecm_db_lock);
8033
8034 DEBUG_TRACE("Connection created %p\n", ci);
8035 return ci;
8036}
8037EXPORT_SYMBOL(ecm_db_connection_alloc);
8038
8039/*
8040 * ecm_db_mapping_alloc()
8041 * Allocate a mapping instance
8042 */
8043struct ecm_db_mapping_instance *ecm_db_mapping_alloc(void)
8044{
8045 struct ecm_db_mapping_instance *mi;
8046
8047 mi = (struct ecm_db_mapping_instance *)kzalloc(sizeof(struct ecm_db_mapping_instance), GFP_ATOMIC | __GFP_NOWARN);
8048 if (!mi) {
8049 DEBUG_WARN("Alloc failed\n");
8050 return NULL;
8051 }
8052
8053 mi->refs = 1;
8054 DEBUG_SET_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC);
8055
8056 /*
8057 * Alloc operation must be atomic to ensure thread and module can be held
8058 */
8059 spin_lock_bh(&ecm_db_lock);
8060
8061 /*
8062 * If the event processing thread is terminating then we cannot create new instances
8063 */
8064 if (ecm_db_terminate_pending) {
8065 spin_unlock_bh(&ecm_db_lock);
8066 DEBUG_WARN("Thread terminating\n");
8067 kfree(mi);
8068 return NULL;
8069 }
8070
Ben Menchaca84f36632014-02-28 20:57:38 +00008071 ecm_db_mapping_count++;
8072 spin_unlock_bh(&ecm_db_lock);
8073
8074 DEBUG_TRACE("Mapping created %p\n", mi);
8075 return mi;
8076}
8077EXPORT_SYMBOL(ecm_db_mapping_alloc);
8078
8079
8080/*
8081 * ecm_db_host_alloc()
8082 * Allocate a host instance
8083 */
8084struct ecm_db_host_instance *ecm_db_host_alloc(void)
8085{
8086 struct ecm_db_host_instance *hi;
8087 hi = (struct ecm_db_host_instance *)kzalloc(sizeof(struct ecm_db_host_instance), GFP_ATOMIC | __GFP_NOWARN);
8088 if (!hi) {
8089 DEBUG_WARN("Alloc failed\n");
8090 return NULL;
8091 }
8092
8093 hi->refs = 1;
8094 DEBUG_SET_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC);
8095
8096 /*
8097 * Alloc operation must be atomic to ensure thread and module can be held
8098 */
8099 spin_lock_bh(&ecm_db_lock);
8100
8101 /*
8102 * If the event processing thread is terminating then we cannot create new instances
8103 */
8104 if (ecm_db_terminate_pending) {
8105 spin_unlock_bh(&ecm_db_lock);
8106 DEBUG_WARN("Thread terminating\n");
8107 kfree(hi);
8108 return NULL;
8109 }
8110
Ben Menchaca84f36632014-02-28 20:57:38 +00008111 ecm_db_host_count++;
8112 spin_unlock_bh(&ecm_db_lock);
8113
8114 DEBUG_TRACE("Host created %p\n", hi);
8115 return hi;
8116}
8117EXPORT_SYMBOL(ecm_db_host_alloc);
8118
8119/*
8120 * ecm_db_node_alloc()
8121 * Allocate a node instance
8122 */
8123struct ecm_db_node_instance *ecm_db_node_alloc(void)
8124{
8125 struct ecm_db_node_instance *ni;
8126
8127 ni = (struct ecm_db_node_instance *)kzalloc(sizeof(struct ecm_db_node_instance), GFP_ATOMIC | __GFP_NOWARN);
8128 if (!ni) {
8129 DEBUG_WARN("Alloc failed\n");
8130 return NULL;
8131 }
8132
8133 ni->refs = 1;
8134 DEBUG_SET_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC);
8135
8136 /*
8137 * Alloc operation must be atomic to ensure thread and module can be held
8138 */
8139 spin_lock_bh(&ecm_db_lock);
8140
8141 /*
8142 * If the event processing thread is terminating then we cannot create new instances
8143 */
8144 if (ecm_db_terminate_pending) {
8145 spin_unlock_bh(&ecm_db_lock);
8146 DEBUG_WARN("Thread terminating\n");
8147 kfree(ni);
8148 return NULL;
8149 }
8150
Ben Menchaca84f36632014-02-28 20:57:38 +00008151 ecm_db_node_count++;
8152 spin_unlock_bh(&ecm_db_lock);
8153
8154 DEBUG_TRACE("Node created %p\n", ni);
8155 return ni;
8156}
8157EXPORT_SYMBOL(ecm_db_node_alloc);
8158
8159/*
8160 * ecm_db_iface_alloc()
8161 * Allocate a iface instance
8162 */
8163struct ecm_db_iface_instance *ecm_db_iface_alloc(void)
8164{
8165 struct ecm_db_iface_instance *ii;
8166
8167 ii = (struct ecm_db_iface_instance *)kzalloc(sizeof(struct ecm_db_iface_instance), GFP_ATOMIC | __GFP_NOWARN);
8168 if (!ii) {
8169 DEBUG_WARN("Alloc failed\n");
8170 return NULL;
8171 }
8172
8173 ii->refs = 1;
8174 DEBUG_SET_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC);
8175
8176 /*
8177 * Alloc operation must be atomic to ensure thread and module can be held
8178 */
8179 spin_lock_bh(&ecm_db_lock);
8180
8181 /*
8182 * If the event processing thread is terminating then we cannot create new instances
8183 */
8184 if (ecm_db_terminate_pending) {
8185 spin_unlock_bh(&ecm_db_lock);
8186 DEBUG_WARN("Thread terminating\n");
8187 kfree(ii);
8188 return NULL;
8189 }
8190
Ben Menchaca84f36632014-02-28 20:57:38 +00008191 ecm_db_iface_count++;
8192 spin_unlock_bh(&ecm_db_lock);
8193
8194 DEBUG_TRACE("iface created %p\n", ii);
8195 return ii;
8196}
8197EXPORT_SYMBOL(ecm_db_iface_alloc);
8198
8199/*
8200 * ecm_db_listener_alloc()
8201 * Allocate a listener instance
8202 */
8203struct ecm_db_listener_instance *ecm_db_listener_alloc(void)
8204{
8205 struct ecm_db_listener_instance *li;
8206
8207 li = (struct ecm_db_listener_instance *)kzalloc(sizeof(struct ecm_db_listener_instance), GFP_ATOMIC | __GFP_NOWARN);
8208 if (!li) {
8209 DEBUG_WARN("Alloc failed\n");
8210 return NULL;
8211 }
8212
8213 li->refs = 1;
8214 DEBUG_SET_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC);
8215
8216 /*
8217 * Alloc operation must be atomic to ensure thread and module can be held
8218 */
8219 spin_lock_bh(&ecm_db_lock);
8220
8221 /*
8222 * If the event processing thread is terminating then we cannot create new instances
8223 */
8224 if (ecm_db_terminate_pending) {
8225 spin_unlock_bh(&ecm_db_lock);
8226 DEBUG_WARN("Thread terminating\n");
8227 kfree(li);
8228 return NULL;
8229 }
8230
Ben Menchaca84f36632014-02-28 20:57:38 +00008231 ecm_db_listeners_count++;
8232 DEBUG_ASSERT(ecm_db_listeners_count > 0, "%p: listener count wrap\n", li);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05008233 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00008234
8235 DEBUG_TRACE("Listener created %p\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00008236 return li;
8237}
8238EXPORT_SYMBOL(ecm_db_listener_alloc);
8239
8240/*
8241 * ecm_db_time_get()
8242 * Return database time, in seconds since the database started.
8243 */
8244uint32_t ecm_db_time_get(void)
8245{
8246 uint32_t time_now;
8247 spin_lock_bh(&ecm_db_lock);
8248 time_now = ecm_db_time;
8249 spin_unlock_bh(&ecm_db_lock);
8250 return time_now;
8251}
8252EXPORT_SYMBOL(ecm_db_time_get);
8253
8254/*
Ben Menchaca84f36632014-02-28 20:57:38 +00008255 * ecm_db_get_state_dev_major()
8256 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008257static ssize_t ecm_db_get_state_dev_major(struct device *dev,
8258 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008259 char *buf)
8260{
8261 ssize_t count;
8262 int major;
8263
8264 spin_lock_bh(&ecm_db_lock);
8265 major = ecm_db_dev_major_id;
8266 spin_unlock_bh(&ecm_db_lock);
8267
8268 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", major);
8269
8270 return count;
8271}
8272
8273/*
8274 * ecm_db_get_connection_count()
8275 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008276static ssize_t ecm_db_get_connection_count(struct device *dev,
8277 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008278 char *buf)
8279{
8280 ssize_t count;
8281 int num;
8282
8283 /*
8284 * Operate under our locks
8285 */
8286 spin_lock_bh(&ecm_db_lock);
8287 num = ecm_db_connection_count;
8288 spin_unlock_bh(&ecm_db_lock);
8289
8290 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8291 return count;
8292}
8293
8294/*
8295 * ecm_db_get_host_count()
8296 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008297static ssize_t ecm_db_get_host_count(struct device *dev,
8298 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008299 char *buf)
8300{
8301 ssize_t count;
8302 int num;
8303
8304 /*
8305 * Operate under our locks
8306 */
8307 spin_lock_bh(&ecm_db_lock);
8308 num = ecm_db_host_count;
8309 spin_unlock_bh(&ecm_db_lock);
8310
8311 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8312 return count;
8313}
8314
8315/*
8316 * ecm_db_get_mapping_count()
8317 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008318static ssize_t ecm_db_get_mapping_count(struct device *dev,
8319 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008320 char *buf)
8321{
8322 ssize_t count;
8323 int num;
8324
8325 /*
8326 * Operate under our locks
8327 */
8328 spin_lock_bh(&ecm_db_lock);
8329 num = ecm_db_mapping_count;
8330 spin_unlock_bh(&ecm_db_lock);
8331
8332 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8333 return count;
8334}
8335
8336/*
8337 * ecm_db_get_node_count()
8338 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008339static ssize_t ecm_db_get_node_count(struct device *dev,
8340 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008341 char *buf)
8342{
8343 ssize_t count;
8344 int num;
8345
8346 /*
8347 * Operate under our locks
8348 */
8349 spin_lock_bh(&ecm_db_lock);
8350 num = ecm_db_node_count;
8351 spin_unlock_bh(&ecm_db_lock);
8352
8353 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8354 return count;
8355}
8356
8357/*
8358 * ecm_db_get_iface_count()
8359 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008360static ssize_t ecm_db_get_iface_count(struct device *dev,
8361 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008362 char *buf)
8363{
8364 ssize_t count;
8365 int num;
8366
8367 /*
8368 * Operate under our locks
8369 */
8370 spin_lock_bh(&ecm_db_lock);
8371 num = ecm_db_iface_count;
8372 spin_unlock_bh(&ecm_db_lock);
8373
8374 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8375 return count;
8376}
8377
8378/*
8379 * ecm_db_get_defunct_all()
8380 * Reading this file returns the accumulated total of all objects
8381 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008382static ssize_t ecm_db_get_defunct_all(struct device *dev,
8383 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008384 char *buf)
8385{
8386 ssize_t count;
8387 int num;
8388
8389 /*
8390 * Operate under our locks
8391 */
8392 spin_lock_bh(&ecm_db_lock);
8393 num = ecm_db_connection_count + ecm_db_mapping_count + ecm_db_host_count
8394 + ecm_db_node_count + ecm_db_iface_count;
8395 spin_unlock_bh(&ecm_db_lock);
8396
8397 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8398 return count;
8399}
8400
8401/*
8402 * ecm_db_set_defunct_all()
8403 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008404static ssize_t ecm_db_set_defunct_all(struct device *dev,
8405 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008406 const char *buf, size_t count)
8407{
8408 ecm_db_connection_defunct_all();
8409 return count;
8410}
8411
8412/*
8413 * ecm_db_get_connection_counts_simple()
8414 * Return total of connections for each simple protocol (tcp, udp, other). Primarily for use by the luci-bwc service.
8415 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008416static ssize_t ecm_db_get_connection_counts_simple(struct device *dev,
8417 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008418 char *buf)
8419{
8420 int tcp_count;
8421 int udp_count;
8422 int other_count;
8423 int total_count;
8424 ssize_t count;
8425
8426 /*
8427 * Get snapshot of the protocol counts
8428 */
8429 spin_lock_bh(&ecm_db_lock);
8430 tcp_count = ecm_db_connection_count_by_protocol[IPPROTO_TCP];
8431 udp_count = ecm_db_connection_count_by_protocol[IPPROTO_UDP];
8432 total_count = ecm_db_connection_count;
8433 other_count = total_count - (tcp_count + udp_count);
8434 spin_unlock_bh(&ecm_db_lock);
8435
8436 count = snprintf(buf, (ssize_t)PAGE_SIZE, "tcp %d udp %d other %d total %d\n", tcp_count, udp_count, other_count, total_count);
8437 return count;
8438}
8439
8440/*
8441 * ecm_db_get_state_file_output_mask()
8442 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008443static ssize_t ecm_db_get_state_file_output_mask(struct device *dev,
8444 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008445 char *buf)
8446{
8447 ssize_t count;
8448 int num;
8449
8450 /*
8451 * Operate under our locks
8452 */
8453 spin_lock_bh(&ecm_db_lock);
8454 num = ecm_db_state_file_output_mask;
8455 spin_unlock_bh(&ecm_db_lock);
8456
8457 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8458 return count;
8459}
8460
8461/*
8462 * ecm_db_set_state_file_output_mask()
8463 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008464static ssize_t ecm_db_set_state_file_output_mask(struct device *dev,
8465 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008466 const char *buf, size_t count)
8467{
8468 char num_buf[12];
8469 int num;
8470
8471 /*
8472 * Get the number from buf into a properly z-termed number buffer
8473 */
8474 if (count > 11) return 0;
8475 memcpy(num_buf, buf, count);
8476 num_buf[count] = '\0';
8477 sscanf(num_buf, "%d", &num);
8478 DEBUG_TRACE("ecm_db_state_file_output_mask = %x\n", num);
8479
8480 /*
8481 * Operate under our locks
8482 */
8483 spin_lock_bh(&ecm_db_lock);
8484 ecm_db_state_file_output_mask = num;
8485 spin_unlock_bh(&ecm_db_lock);
8486
8487 return count;
8488}
8489
8490/*
8491 * SysFS attributes for the default classifier itself.
8492 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008493static DEVICE_ATTR(state_dev_major, 0444, ecm_db_get_state_dev_major, NULL);
8494static DEVICE_ATTR(connection_count, 0444, ecm_db_get_connection_count, NULL);
8495static DEVICE_ATTR(host_count, 0444, ecm_db_get_host_count, NULL);
8496static DEVICE_ATTR(mapping_count, 0444, ecm_db_get_mapping_count, NULL);
8497static DEVICE_ATTR(node_count, 0444, ecm_db_get_node_count, NULL);
8498static DEVICE_ATTR(iface_count, 0444, ecm_db_get_iface_count, NULL);
8499static DEVICE_ATTR(defunct_all, 0644, ecm_db_get_defunct_all, ecm_db_set_defunct_all);
8500static DEVICE_ATTR(connection_counts_simple, 0444, ecm_db_get_connection_counts_simple, NULL);
8501static DEVICE_ATTR(state_file_output_mask, 0644, ecm_db_get_state_file_output_mask, ecm_db_set_state_file_output_mask);
Ben Menchaca84f36632014-02-28 20:57:38 +00008502
8503/*
Murat Sezgin1f381852014-11-20 09:51:07 -08008504 * System device attribute array.
Ben Menchaca84f36632014-02-28 20:57:38 +00008505 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008506static struct device_attribute *ecm_db_attrs[] = {
8507 &dev_attr_state_dev_major,
8508 &dev_attr_connection_count,
8509 &dev_attr_host_count,
8510 &dev_attr_mapping_count,
8511 &dev_attr_node_count,
8512 &dev_attr_iface_count,
8513 &dev_attr_defunct_all,
8514 &dev_attr_connection_counts_simple,
8515 &dev_attr_state_file_output_mask,
Ben Menchaca84f36632014-02-28 20:57:38 +00008516};
8517
8518/*
Murat Sezgin1f381852014-11-20 09:51:07 -08008519 * Sub system node of the ECM default classifier
8520 * Sys device control points can be found at /sys/devices/system/ecm_db/ecm_dbX/
8521 */
8522static struct bus_type ecm_db_subsys = {
8523 .name = "ecm_db",
8524 .dev_name = "ecm_db",
8525};
8526
8527/*
8528 * ecm_db_dev_release()
8529 * This is a dummy release function for device.
8530 */
8531static void ecm_db_dev_release(struct device *dev)
8532{
8533
8534}
8535
8536/*
Ben Menchaca84f36632014-02-28 20:57:38 +00008537 * ecm_db_connection_heirarchy_xml_state_get()
8538 * Output XML state for an interface heirarchy list.
8539 *
8540 * Return value is comptible with snprintf()
8541 */
8542static int ecm_db_connection_heirarchy_xml_state_get(char *element, struct ecm_db_iface_instance *interfaces[], int32_t first_interface,
8543 char *buf, int buf_sz)
8544{
8545 int count;
8546 int total;
8547 int i;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308548
Ben Menchaca84f36632014-02-28 20:57:38 +00008549 /*
8550 * Output the opening element
8551 */
8552 total = 0;
8553 count = snprintf(buf + total,
8554 buf_sz - total,
8555 "<%s count=\"%d\">\n",
8556 element,
8557 ECM_DB_IFACE_HEIRARCHY_MAX - first_interface);
8558 if ((count <= 0) || (count >= (buf_sz - total))) {
8559 return -1;
8560 }
8561 total += count;
8562
8563 /*
8564 * Iterate the interface heirarchy list and output the information
8565 */
8566 for (i = first_interface; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
8567 struct ecm_db_iface_instance *ii = interfaces[i];
8568 DEBUG_TRACE("Element: %s, Output interface @ %d: %p\n", element, i, ii);
8569 count = ii->xml_state_get(ii, buf + total, buf_sz - total);
8570 if ((count <= 0) || (count >= (buf_sz - total))) {
8571 return -1;
8572 }
8573 total += count;
8574 }
8575
8576 /*
8577 * Output closing element
8578 */
8579 count = snprintf(buf + total,
8580 buf_sz - total,
8581 "</%s>\n",
8582 element);
8583 if ((count <= 0) || (count >= (buf_sz - total))) {
8584 return -1;
8585 }
8586 total += count;
8587 return total;
8588}
8589
8590/*
8591 * ecm_db_char_dev_conn_msg_prep()
8592 * Prepare a connection message
8593 */
8594static bool ecm_db_char_dev_conn_msg_prep(struct ecm_db_state_file_instance *sfi)
8595{
8596 int msg_len;
8597 int extra_msg_len;
8598 long int expires_in;
8599 int sport;
8600 int sport_nat;
8601 char snode_address[25];
Gareth Williams2b87acb2014-05-26 19:12:58 +01008602 char snode_address_nat[25];
Ben Menchaca84f36632014-02-28 20:57:38 +00008603 char sip_address[50];
8604 char sip_address_nat[50];
8605 char dnode_address[25];
Gareth Williams2b87acb2014-05-26 19:12:58 +01008606 char dnode_address_nat[25];
Ben Menchaca84f36632014-02-28 20:57:38 +00008607 int dport;
8608 int dport_nat;
8609 char dip_address[50];
8610 char dip_address_nat[50];
8611 ecm_db_direction_t direction;
8612 int protocol;
8613 bool is_routed;
Gareth Williamsda721272014-11-13 17:48:12 -08008614 uint32_t generations;
Ben Menchaca84f36632014-02-28 20:57:38 +00008615 uint32_t time_added;
8616 uint32_t serial;
8617 uint64_t from_data_total;
8618 uint64_t to_data_total;
8619 uint64_t from_packet_total;
8620 uint64_t to_packet_total;
8621 uint64_t from_data_total_dropped;
8622 uint64_t to_data_total_dropped;
8623 uint64_t from_packet_total_dropped;
8624 uint64_t to_packet_total_dropped;
8625 struct ecm_db_host_instance *hi;
Gareth Williams90f2a282014-08-27 15:56:25 +01008626 struct ecm_db_node_instance *ni;
Ben Menchaca84f36632014-02-28 20:57:38 +00008627 int aci_index;
8628 int aci_count;
8629 struct ecm_front_end_connection_instance *feci;
8630 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
8631 int32_t first_interface;
8632 struct ecm_db_iface_instance *interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
8633
Gareth Williams72b43ed2014-05-14 18:23:43 +01008634 DEBUG_TRACE("%p: Prep conn msg for %p\n", sfi, sfi->ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00008635
8636 /*
8637 * Identify expiration
8638 */
8639 spin_lock_bh(&ecm_db_lock);
8640 if (sfi->ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX) {
8641 expires_in = -1;
8642 } else {
8643 expires_in = (long int)(sfi->ci->defunct_timer.timeout - ecm_db_time);
8644 if (expires_in <= 0) {
8645 expires_in = 0;
8646 }
8647 }
8648 spin_unlock_bh(&ecm_db_lock);
8649
8650 /*
8651 * Extract information from the connection for inclusion into the message
8652 */
8653 sport = sfi->ci->mapping_from->port;
8654 sport_nat = sfi->ci->mapping_nat_from->port;
8655 dport = sfi->ci->mapping_to->port;
8656 dport_nat = sfi->ci->mapping_nat_to->port;
8657
8658 hi = sfi->ci->mapping_to->host;
8659 ecm_ip_addr_to_string(dip_address, hi->address);
Gareth Williams90f2a282014-08-27 15:56:25 +01008660 ni = sfi->ci->to_node;
8661 sprintf(dnode_address, "%pM", ni->address);
Ben Menchaca84f36632014-02-28 20:57:38 +00008662 hi = sfi->ci->mapping_nat_to->host;
8663 ecm_ip_addr_to_string(dip_address_nat, hi->address);
8664
8665 hi = sfi->ci->mapping_from->host;
8666 ecm_ip_addr_to_string(sip_address, hi->address);
Gareth Williams90f2a282014-08-27 15:56:25 +01008667 ni = sfi->ci->from_node;
8668 sprintf(snode_address, "%pM", ni->address);
Ben Menchaca84f36632014-02-28 20:57:38 +00008669 hi = sfi->ci->mapping_nat_from->host;
8670 ecm_ip_addr_to_string(sip_address_nat, hi->address);
8671
Gareth Williams90f2a282014-08-27 15:56:25 +01008672 ni = sfi->ci->to_nat_node;
8673 sprintf(dnode_address_nat, "%pM", ni->address);
Gareth Williams2b87acb2014-05-26 19:12:58 +01008674
Gareth Williams90f2a282014-08-27 15:56:25 +01008675 ni = sfi->ci->from_nat_node;
8676 sprintf(snode_address_nat, "%pM", ni->address);
Gareth Williams2b87acb2014-05-26 19:12:58 +01008677
Ben Menchaca84f36632014-02-28 20:57:38 +00008678 direction = sfi->ci->direction;
8679 protocol = sfi->ci->protocol;
8680 is_routed = sfi->ci->is_routed;
Gareth Williamsda721272014-11-13 17:48:12 -08008681 generations = sfi->ci->generations;
Ben Menchaca84f36632014-02-28 20:57:38 +00008682 time_added = sfi->ci->time_added;
8683 serial = sfi->ci->serial;
8684 ecm_db_connection_data_stats_get(sfi->ci, &from_data_total, &to_data_total,
8685 &from_packet_total, &to_packet_total,
8686 &from_data_total_dropped, &to_data_total_dropped,
8687 &from_packet_total_dropped, &to_packet_total_dropped);
8688
8689 /*
8690 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308691 */
Ben Menchaca84f36632014-02-28 20:57:38 +00008692 sfi->msgp = sfi->msg_buffer;
8693
8694 /*
8695 * Prep the message
8696 */
8697 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
Gareth Williams2b87acb2014-05-26 19:12:58 +01008698 "<conn serial=\"%u\" sip_address=\"%s\" sip_address_nat=\"%s\" sport=\"%d\" sport_nat=\"%d\" snode_address=\"%s\" snode_address_nat=\"%s\""
8699 " dip_address=\"%s\" dip_address_nat=\"%s\" dport=\"%d\" dport_nat=\"%d\" dnode_address=\"%s\" dnode_address_nat=\"%s\""
Gareth Williamsda721272014-11-13 17:48:12 -08008700 " protocol=\"%d\" is_routed=\"%d\" expires=\"%ld\" direction=\"%d\" time_added=\"%u\" generations=\"%u\""
Ben Menchaca84f36632014-02-28 20:57:38 +00008701 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\" from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\">\n",
8702 serial,
8703 sip_address,
8704 sip_address_nat,
8705 sport,
8706 sport_nat,
8707 snode_address,
Gareth Williams2b87acb2014-05-26 19:12:58 +01008708 snode_address_nat,
Ben Menchaca84f36632014-02-28 20:57:38 +00008709 dip_address,
8710 dip_address_nat,
8711 dport,
8712 dport_nat,
8713 dnode_address,
Gareth Williams2b87acb2014-05-26 19:12:58 +01008714 dnode_address_nat,
Ben Menchaca84f36632014-02-28 20:57:38 +00008715 protocol,
8716 is_routed,
8717 expires_in,
8718 direction,
8719 time_added,
Gareth Williamsda721272014-11-13 17:48:12 -08008720 generations,
Ben Menchaca84f36632014-02-28 20:57:38 +00008721 from_data_total,
8722 to_data_total,
8723 from_packet_total,
8724 to_packet_total,
8725 from_data_total_dropped,
8726 to_data_total_dropped,
8727 from_packet_total_dropped,
8728 to_packet_total_dropped);
8729
8730 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
8731 return false;
8732 }
8733
8734 /*
8735 * Output interface heirarchy information for this connection
8736 */
8737 first_interface = ecm_db_connection_from_interfaces_get_and_ref(sfi->ci, interfaces);
8738 extra_msg_len = ecm_db_connection_heirarchy_xml_state_get("from_interfaces", interfaces, first_interface, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8739 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8740 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8741 return false;
8742 }
8743 msg_len += extra_msg_len;
8744
8745 first_interface = ecm_db_connection_to_interfaces_get_and_ref(sfi->ci, interfaces);
8746 extra_msg_len = ecm_db_connection_heirarchy_xml_state_get("to_interfaces", interfaces, first_interface, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8747 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8748 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8749 return false;
8750 }
8751 msg_len += extra_msg_len;
8752
8753 first_interface = ecm_db_connection_from_nat_interfaces_get_and_ref(sfi->ci, interfaces);
8754 extra_msg_len = ecm_db_connection_heirarchy_xml_state_get("from_nat_interfaces", interfaces, first_interface, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8755 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8756 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8757 return false;
8758 }
8759 msg_len += extra_msg_len;
8760
8761 first_interface = ecm_db_connection_to_nat_interfaces_get_and_ref(sfi->ci, interfaces);
8762 extra_msg_len = ecm_db_connection_heirarchy_xml_state_get("to_nat_interfaces", interfaces, first_interface, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8763 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8764 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8765 return false;
8766 }
8767 msg_len += extra_msg_len;
8768
8769 /*
8770 * Output front end state
8771 */
8772 feci = ecm_db_connection_front_end_get_and_ref(sfi->ci);
8773 extra_msg_len = feci->xml_state_get(feci, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8774 feci->deref(feci);
8775 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8776 return false;
8777 }
8778 msg_len += extra_msg_len;
8779
8780 /*
8781 * Grab references to the assigned classifiers so we can produce state for them
8782 */
8783 aci_count = ecm_db_connection_classifier_assignments_get_and_ref(sfi->ci, assignments);
8784
8785 /*
8786 * Iterate the assigned classifiers and provide a state record for each
8787 */
8788 for (aci_index = 0; aci_index < aci_count; ++aci_index) {
8789 struct ecm_classifier_instance *aci;
8790
8791 aci = assignments[aci_index];
8792 extra_msg_len = aci->xml_state_get(aci, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8793
8794 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8795 ecm_db_connection_assignments_release(aci_count, assignments);
8796 return false;
8797 }
8798
8799 msg_len += extra_msg_len;
8800 }
8801 ecm_db_connection_assignments_release(aci_count, assignments);
8802
8803 /*
8804 * Write out end element
8805 */
8806 extra_msg_len = snprintf(sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len, "</conn>\n");
8807 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8808 return false;
8809 }
8810 msg_len += extra_msg_len;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308811
Ben Menchaca84f36632014-02-28 20:57:38 +00008812 /*
8813 * Record the message length
8814 */
8815 sfi->msg_len = msg_len;
8816 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
8817 return true;
8818}
8819
8820/*
8821 * ecm_db_char_dev_mapping_msg_prep()
8822 * Prepare a mapping message
8823 */
8824static bool ecm_db_char_dev_mapping_msg_prep(struct ecm_db_state_file_instance *sfi)
8825{
8826 int msg_len;
8827 int port;
8828 char address[25];
8829 int tcp_from;
8830 int tcp_to;
8831 int udp_from;
8832 int udp_to;
8833 int from;
8834 int to;
8835 int tcp_nat_from;
8836 int tcp_nat_to;
8837 int udp_nat_from;
8838 int udp_nat_to;
8839 int nat_from;
8840 int nat_to;
8841 uint32_t time_added;
8842 uint64_t from_data_total;
8843 uint64_t to_data_total;
8844 uint64_t from_packet_total;
8845 uint64_t to_packet_total;
8846 uint64_t from_data_total_dropped;
8847 uint64_t to_data_total_dropped;
8848 uint64_t from_packet_total_dropped;
8849 uint64_t to_packet_total_dropped;
Ben Menchaca84f36632014-02-28 20:57:38 +00008850 struct ecm_db_host_instance *hi;
8851
8852 DEBUG_TRACE("%p: Prep mapping msg for %p\n", sfi, sfi->mi);
8853
8854 /*
8855 * Create a small xml stats element for our mapping.
8856 * Extract information from the mapping for inclusion into the message
8857 */
8858 ecm_db_mapping_port_count_get(sfi->mi, &tcp_from, &tcp_to, &udp_from, &udp_to, &from, &to,
8859 &tcp_nat_from, &tcp_nat_to, &udp_nat_from, &udp_nat_to, &nat_from, &nat_to);
8860 port = sfi->mi->port;
8861 time_added = sfi->mi->time_added;
8862 ecm_db_mapping_data_stats_get(sfi->mi, &from_data_total, &to_data_total,
8863 &from_packet_total, &to_packet_total,
8864 &from_data_total_dropped, &to_data_total_dropped,
8865 &from_packet_total_dropped, &to_packet_total_dropped);
8866 hi = sfi->mi->host;
8867 ecm_ip_addr_to_string(address, hi->address);
Ben Menchaca84f36632014-02-28 20:57:38 +00008868
8869 /*
8870 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308871 */
Ben Menchaca84f36632014-02-28 20:57:38 +00008872 sfi->msgp = sfi->msg_buffer;
8873
8874 /*
8875 * Prep the message
8876 */
8877 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
8878 "<mapping address=\"%s\" port=\"%d\" from=\"%d\" to=\"%d\" tcp_from=\"%d\" tcp_to=\"%d\" udp_from=\"%d\" udp_to=\"%d\""
8879 " nat_from=\"%d\" nat_to=\"%d\" tcp_nat_from=\"%d\" tcp_nat_to=\"%d\" udp_nat_from=\"%d\" udp_nat_to=\"%d\""
8880 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
8881 " from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\""
Gareth Williams90f2a282014-08-27 15:56:25 +01008882 " time_added=\"%u\"/>\n",
Ben Menchaca84f36632014-02-28 20:57:38 +00008883 address,
8884 port,
8885 from,
8886 to,
8887 tcp_from,
8888 tcp_to,
8889 udp_from,
8890 udp_to,
8891 nat_from,
8892 nat_to,
8893 tcp_nat_from,
8894 tcp_nat_to,
8895 udp_nat_from,
8896 udp_nat_to,
8897 from_data_total,
8898 to_data_total,
8899 from_packet_total,
8900 to_packet_total,
8901 from_data_total_dropped,
8902 to_data_total_dropped,
8903 from_packet_total_dropped,
8904 to_packet_total_dropped,
Gareth Williams90f2a282014-08-27 15:56:25 +01008905 time_added);
Ben Menchaca84f36632014-02-28 20:57:38 +00008906
8907 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
8908 return false;
8909 }
8910
8911 sfi->msg_len = msg_len;
8912 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
8913 return true;
8914}
8915
8916/*
8917 * ecm_db_char_dev_host_msg_prep()
8918 * Prepare a host message
8919 */
8920static bool ecm_db_char_dev_host_msg_prep(struct ecm_db_state_file_instance *sfi)
8921{
8922 int msg_len;
8923 char address[50];
8924 int mapping_count;
8925 uint32_t time_added;
8926 uint64_t from_data_total;
8927 uint64_t to_data_total;
8928 uint64_t from_packet_total;
8929 uint64_t to_packet_total;
8930 uint64_t from_data_total_dropped;
8931 uint64_t to_data_total_dropped;
8932 uint64_t from_packet_total_dropped;
8933 uint64_t to_packet_total_dropped;
Ben Menchaca84f36632014-02-28 20:57:38 +00008934 bool on_link;
8935
8936 DEBUG_TRACE("%p: Prep host msg for %p\n", sfi, sfi->hi);
8937
8938 /*
8939 * Create a small xml stats element for our host.
8940 * Extract information from the host for inclusion into the message
8941 */
8942 mapping_count = ecm_db_host_mapping_count_get(sfi->hi);
8943 ecm_ip_addr_to_string(address, sfi->hi->address);
8944 time_added = sfi->hi->time_added;
8945 ecm_db_host_data_stats_get(sfi->hi, &from_data_total, &to_data_total,
8946 &from_packet_total, &to_packet_total,
8947 &from_data_total_dropped, &to_data_total_dropped,
8948 &from_packet_total_dropped, &to_packet_total_dropped);
Ben Menchaca84f36632014-02-28 20:57:38 +00008949 on_link = sfi->hi->on_link;
8950
8951 /*
8952 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308953 */
Ben Menchaca84f36632014-02-28 20:57:38 +00008954 sfi->msgp = sfi->msg_buffer;
8955
8956 /*
8957 * Prep the message
8958 */
8959 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
Gareth Williams90f2a282014-08-27 15:56:25 +01008960 "<host address=\"%s\" mappings=\"%d\" time_added=\"%u\" on_link=\"%d\""
Ben Menchaca84f36632014-02-28 20:57:38 +00008961 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
8962 " from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\"/>\n",
8963 address,
8964 mapping_count,
8965 time_added,
Ben Menchaca84f36632014-02-28 20:57:38 +00008966 on_link,
8967 from_data_total,
8968 to_data_total,
8969 from_packet_total,
8970 to_packet_total,
8971 from_data_total_dropped,
8972 to_data_total_dropped,
8973 from_packet_total_dropped,
8974 to_packet_total_dropped);
8975
8976 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
8977 return false;
8978 }
8979
8980 sfi->msg_len = msg_len;
8981 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
8982 return true;
8983}
8984
8985/*
8986 * ecm_db_char_dev_nod__msg_prep()
8987 * Prepare a node message
8988 */
8989static bool ecm_db_char_dev_node_msg_prep(struct ecm_db_state_file_instance *sfi)
8990{
8991 int msg_len;
8992 char address[25];
Gareth Williams90f2a282014-08-27 15:56:25 +01008993 int from_connections_count;
8994 int to_connections_count;
8995 int from_nat_connections_count;
8996 int to_nat_connections_count;
Ben Menchaca84f36632014-02-28 20:57:38 +00008997 uint32_t time_added;
8998 uint64_t from_data_total;
8999 uint64_t to_data_total;
9000 uint64_t from_packet_total;
9001 uint64_t to_packet_total;
9002 uint64_t from_data_total_dropped;
9003 uint64_t to_data_total_dropped;
9004 uint64_t from_packet_total_dropped;
9005 uint64_t to_packet_total_dropped;
9006
9007 DEBUG_TRACE("%p: Prep node msg for %p\n", sfi, sfi->ni);
9008
9009 /*
9010 * Create a small xml stats block for our managed node, like:
9011 * <node address="" hosts="" time_added="" from_data_total="" to_data_total="" />
9012 *
9013 * Extract information from the node for inclusion into the message
9014 */
Gareth Williams90f2a282014-08-27 15:56:25 +01009015 spin_lock_bh(&ecm_db_lock);
9016 from_connections_count = sfi->ni->from_connections_count;
9017 to_connections_count = sfi->ni->to_connections_count;
9018 from_nat_connections_count = sfi->ni->from_nat_connections_count;
9019 to_nat_connections_count = sfi->ni->to_nat_connections_count;
9020 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00009021 time_added = sfi->ni->time_added;
9022 ecm_db_node_data_stats_get(sfi->ni, &from_data_total, &to_data_total,
9023 &from_packet_total, &to_packet_total,
9024 &from_data_total_dropped, &to_data_total_dropped,
9025 &from_packet_total_dropped, &to_packet_total_dropped);
9026 sprintf(address, "%pM", sfi->ni->address);
9027
9028 /*
9029 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309030 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009031 sfi->msgp = sfi->msg_buffer;
9032
9033 /*
9034 * Prep the message
9035 */
9036 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
Gareth Williams90f2a282014-08-27 15:56:25 +01009037 "<node address=\"%s\" from_connections_count=\"%d\" to_connections_count=\"%d\" from_nat_connections_count=\"%d\" to_nat_connections_count=\"%d\" time_added=\"%u\""
Ben Menchaca84f36632014-02-28 20:57:38 +00009038 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
9039 " from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\" />\n",
9040 address,
Gareth Williams90f2a282014-08-27 15:56:25 +01009041 from_connections_count,
9042 to_connections_count,
9043 from_nat_connections_count,
9044 to_nat_connections_count,
Ben Menchaca84f36632014-02-28 20:57:38 +00009045 time_added,
9046 from_data_total,
9047 to_data_total,
9048 from_packet_total,
9049 to_packet_total,
9050 from_data_total_dropped,
9051 to_data_total_dropped,
9052 from_packet_total_dropped,
9053 to_packet_total_dropped);
9054
9055 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9056 return false;
9057 }
9058
9059 sfi->msg_len = msg_len;
9060 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9061 return true;
9062}
9063
9064/*
9065 * ecm_db_char_dev_iface_msg_prep()
9066 * Prepare an interface message
9067 */
9068static bool ecm_db_char_dev_iface_msg_prep(struct ecm_db_state_file_instance *sfi)
9069{
9070 int msg_len;
9071
9072 DEBUG_TRACE("%p: Prep iface msg for %p\n", sfi, sfi->ii);
9073
9074 /*
9075 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309076 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009077 sfi->msgp = sfi->msg_buffer;
9078
9079 /*
9080 * Prep the message
9081 */
9082 msg_len = sfi->ii->xml_state_get(sfi->ii, sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE);
9083
9084 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9085 return false;
9086 }
9087
9088 /*
9089 * Record the message length
9090 */
9091 sfi->msg_len = msg_len;
9092 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9093 return true;
9094}
9095
9096/*
9097 * ecm_db_char_dev_conn_chain_msg_prep()
9098 * Generate an conn hash table chain message
9099 */
9100static bool ecm_db_char_dev_conn_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9101{
9102 int chain_len;
9103 int msg_len;
9104 DEBUG_TRACE("%p: Prep conn chain msg\n", sfi);
9105
9106 /*
9107 * Get hash table chain length
9108 */
9109 spin_lock_bh(&ecm_db_lock);
9110 chain_len = ecm_db_connection_table_lengths[sfi->connection_hash_index];
9111 spin_unlock_bh(&ecm_db_lock);
9112
9113 /*
9114 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309115 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009116 sfi->msgp = sfi->msg_buffer;
9117
9118 /*
9119 * Create a small xml stats block like:
9120 * <conn_chain hash_index="" chain_length=""/>
9121 */
9122 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9123 "<conn_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9124 sfi->connection_hash_index,
9125 chain_len);
9126 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9127 return false;
9128 }
9129
9130 sfi->msg_len = msg_len;
9131 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9132 return true;
9133}
9134
9135/*
9136 * ecm_db_char_dev_mapping_chain_msg_prep()
9137 * Generate an mapping hash table chain message
9138 */
9139static bool ecm_db_char_dev_mapping_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9140{
9141 int chain_len;
9142 int msg_len;
9143 DEBUG_TRACE("%p: Prep mapping chain msg\n", sfi);
9144
9145 /*
9146 * Get hash table chain length
9147 */
9148 spin_lock_bh(&ecm_db_lock);
9149 chain_len = ecm_db_mapping_table_lengths[sfi->mapping_hash_index];
9150 spin_unlock_bh(&ecm_db_lock);
9151
9152 /*
9153 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309154 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009155 sfi->msgp = sfi->msg_buffer;
9156
9157 /*
9158 * Create a small xml stats block like:
9159 * <mapping_chain hash_index="" chain_length=""/>
9160 */
9161 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9162 "<mapping_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9163 sfi->mapping_hash_index,
9164 chain_len);
9165 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9166 return false;
9167 }
9168
9169 sfi->msg_len = msg_len;
9170 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9171 return true;
9172}
9173
9174/*
9175 * ecm_db_char_dev_host_chain_msg_prep()
9176 * Generate an host hash table chain message
9177 */
9178static bool ecm_db_char_dev_host_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9179{
9180 int chain_len;
9181 int msg_len;
9182 DEBUG_TRACE("%p: Prep host chain msg\n", sfi);
9183
9184 /*
9185 * Get hash table chain length
9186 */
9187 spin_lock_bh(&ecm_db_lock);
9188 chain_len = ecm_db_host_table_lengths[sfi->host_hash_index];
9189 spin_unlock_bh(&ecm_db_lock);
9190
9191 /*
9192 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309193 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009194 sfi->msgp = sfi->msg_buffer;
9195
9196 /*
9197 * Create a small xml stats block like:
9198 * <host_chain hash_index="" chain_length=""/>
9199 */
9200 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9201 "<host_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9202 sfi->host_hash_index,
9203 chain_len);
9204 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9205 return false;
9206 }
9207
9208 sfi->msg_len = msg_len;
9209 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9210 return true;
9211}
9212
9213/*
9214 * ecm_db_char_dev_node_chain_msg_prep()
9215 * Generate an node hash table chain message
9216 */
9217static bool ecm_db_char_dev_node_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9218{
9219 int chain_len;
9220 int msg_len;
9221 DEBUG_TRACE("%p: Prep node chain msg\n", sfi);
9222
9223 /*
9224 * Get hash table chain length
9225 */
9226 spin_lock_bh(&ecm_db_lock);
9227 chain_len = ecm_db_node_table_lengths[sfi->node_hash_index];
9228 spin_unlock_bh(&ecm_db_lock);
9229
9230 /*
9231 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309232 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009233 sfi->msgp = sfi->msg_buffer;
9234
9235 /*
9236 * Create a small xml stats block like:
9237 * <node_chain hash_index="" chain_length=""/>
9238 */
9239 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9240 "<node_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9241 sfi->node_hash_index,
9242 chain_len);
9243 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9244 return false;
9245 }
9246
9247 sfi->msg_len = msg_len;
9248 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9249 return true;
9250}
9251
9252/*
9253 * ecm_db_char_dev_iface_chain_msg_prep()
9254 * Generate an interface hash table chain message
9255 */
9256static bool ecm_db_char_dev_iface_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9257{
9258 int chain_len;
9259 int msg_len;
9260 DEBUG_TRACE("%p: Prep iface chain msg\n", sfi);
9261
9262 /*
9263 * Get hash table chain length
9264 */
9265 spin_lock_bh(&ecm_db_lock);
9266 chain_len = ecm_db_iface_table_lengths[sfi->iface_hash_index];
9267 spin_unlock_bh(&ecm_db_lock);
9268
9269 /*
9270 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309271 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009272 sfi->msgp = sfi->msg_buffer;
9273
9274 /*
9275 * Create a small xml stats block like:
9276 * <iface_chain hash_index="" chain_length=""/>
9277 */
9278 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9279 "<iface_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9280 sfi->iface_hash_index,
9281 chain_len);
9282 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9283 return false;
9284 }
9285
9286 sfi->msg_len = msg_len;
9287 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9288 return true;
9289}
9290
9291/*
9292 * ecm_db_char_dev_protocol_count_msg_prep()
9293 * Generate a protocol usage message
9294 */
9295static bool ecm_db_char_dev_protocol_count_msg_prep(struct ecm_db_state_file_instance *sfi)
9296{
9297 int count;
9298 int msg_len;
9299 DEBUG_TRACE("%p: Prep protocol msg\n", sfi);
9300
9301 /*
9302 * Get protocol connection total count
9303 */
9304 spin_lock_bh(&ecm_db_lock);
9305 count = ecm_db_connection_count_by_protocol[sfi->protocol];
9306 spin_unlock_bh(&ecm_db_lock);
9307
9308 /*
9309 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309310 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009311 sfi->msgp = sfi->msg_buffer;
9312
9313 /*
9314 * Create a small xml stats block like:
9315 * <conn_proto_count protocol="" count=""/>
9316 */
9317 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9318 "<conn_proto_count protocol=\"%d\" count=\"%d\"/>\n",
9319 sfi->protocol,
9320 count);
9321 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9322 return false;
9323 }
9324 sfi->msg_len = msg_len;
9325 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9326 return true;
9327}
9328
9329/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009330 * ecm_db_char_dev_cta_msg_prep()
9331 * Generate a classifier type assignment message
9332 */
9333static bool ecm_db_char_dev_cta_msg_prep(struct ecm_db_state_file_instance *sfi, ecm_classifier_type_t ca_type)
9334{
9335 int msg_len;
9336 struct ecm_db_connection_instance *ci;
9337 int flags;
9338
9339 DEBUG_TRACE("%p: Prep classifier type assignment msg: %d\n", sfi, ca_type);
9340
9341 /*
9342 * Use fresh buffer
9343 */
9344 sfi->msgp = sfi->msg_buffer;
9345
9346 /*
9347 * Output message according to where we are with iteration.
9348 * Output element start?
9349 * We are producing an element like:
9350 * <classifier_conn_type_assignment ca_type="2">
9351 * <connection serial="1625"/>
9352 * ...
9353 * </classifier_conn_type_assignment>
9354 */
9355 flags = sfi->classifier_type_assignments_flags[ca_type];
9356 if (flags & ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN) {
9357 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9358 "<classifier_conn_type_assignment ca_type=\"%d\">\n",
9359 ca_type);
9360 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9361 return false;
9362 }
9363 sfi->msg_len = msg_len;
9364 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9365
9366 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN;
9367 return true;
9368 }
9369
9370 /*
9371 * Output connection detail, if any further to output for this type.
9372 */
9373 ci = sfi->classifier_type_assignments[ca_type];
9374 if (ci) {
9375 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
9376 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9377 "<connection serial=\"%u\"/>\n",
9378 ci->serial);
9379 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9380 return false;
9381 }
9382 sfi->msg_len = msg_len;
9383 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9384
9385 /*
9386 * Prep next connection for when we are called again, releasing this one.
9387 */
9388 if (!(sfi->classifier_type_assignments[ca_type] = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type))) {
9389 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_DB_STATE_FILE_CTA_FLAG_CONTENT_UNWRITTEN;
9390 }
9391 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
9392 return true;
9393 }
9394
9395 /*
9396 * Output closing element?
9397 */
9398 if (flags & ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN) {
9399 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9400 "</classifier_conn_type_assignment>\n");
9401 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9402 return false;
9403 }
9404 sfi->msg_len = msg_len;
9405 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9406
9407 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN;
9408 return true;
9409 }
9410
9411 return true;
9412}
9413
9414/*
9415 * ecm_db_state_file_classifier_type_assignments_release()
9416 * Releases any uniterated classifier assignments
9417 */
9418static void ecm_db_state_file_classifier_type_assignments_release(struct ecm_db_state_file_instance *sfi)
9419{
9420 ecm_classifier_type_t ca_type;
9421
9422 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
9423 struct ecm_db_connection_instance *ci;
9424
9425 ci = sfi->classifier_type_assignments[ca_type];
9426 if (!ci) {
9427 continue;
9428 }
9429
9430 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
9431 }
9432}
9433
9434/*
Ben Menchaca84f36632014-02-28 20:57:38 +00009435 * ecm_db_char_device_open()
9436 * Opens the special char device file which we use to dump our state.
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309437 *
Ben Menchaca84f36632014-02-28 20:57:38 +00009438 */
9439static int ecm_db_char_device_open(struct inode *inode, struct file *file)
9440{
9441 struct ecm_db_state_file_instance *sfi;
9442
9443 DEBUG_INFO("State open\n");
9444
9445 /*
9446 * Allocate state information for the reading
9447 */
9448 DEBUG_ASSERT(file->private_data == NULL, "unexpected double open: %p?\n", file->private_data);
9449
9450 sfi = (struct ecm_db_state_file_instance *)kzalloc(sizeof(struct ecm_db_state_file_instance), GFP_ATOMIC | __GFP_NOWARN);
9451 if (!sfi) {
9452 return -ENOMEM;
9453 }
9454 DEBUG_SET_MAGIC(sfi, ECM_DB_STATE_FILE_INSTANCE_MAGIC);
9455 file->private_data = sfi;
9456
9457 /*
9458 * Snapshot output mask for this file
9459 */
9460 spin_lock_bh(&ecm_db_lock);
9461 sfi->output_mask = ecm_db_state_file_output_mask;
9462 spin_unlock_bh(&ecm_db_lock);
9463
9464 /*
9465 * Take references to each object list that we are going to generate state for.
9466 */
9467 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_CONNECTIONS) {
9468 sfi->ci = ecm_db_connections_get_and_ref_first();
9469 }
9470 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_MAPPINGS) {
9471 sfi->mi = ecm_db_mappings_get_and_ref_first();
9472 }
9473 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_HOSTS) {
9474 sfi->hi = ecm_db_hosts_get_and_ref_first();
9475 }
9476 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_NODES) {
9477 sfi->ni = ecm_db_nodes_get_and_ref_first();
9478 }
9479 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_INTERFACES) {
9480 sfi->ii = ecm_db_interfaces_get_and_ref_first();
9481 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009482 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_CLASSIFIER_TYPE_ASSIGNMENTS) {
9483 ecm_classifier_type_t ca_type;
9484
9485 /*
9486 * Iterate all classifier type assignments.
9487 * Hold the head of each list to start us off on our iterating process.
9488 */
9489 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
9490 if ((sfi->classifier_type_assignments[ca_type] = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type))) {
9491 /*
9492 * There is some content to write for this ca_type
9493 */
9494 sfi->classifier_type_assignments_flags[ca_type] =
9495 ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN | ECM_DB_STATE_FILE_CTA_FLAG_CONTENT_UNWRITTEN | ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN;
9496
9497 }
9498 }
9499 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009500
9501 /*
9502 * Cannot do this if the event processing thread is exiting
9503 */
9504 spin_lock_bh(&ecm_db_lock);
9505 if (ecm_db_terminate_pending) {
9506 spin_unlock_bh(&ecm_db_lock);
9507
9508 if (sfi->ci) {
9509 ecm_db_connection_deref(sfi->ci);
9510 }
9511 if (sfi->mi) {
9512 ecm_db_mapping_deref(sfi->mi);
9513 }
9514 if (sfi->hi) {
9515 ecm_db_host_deref(sfi->hi);
9516 }
9517 if (sfi->ni) {
9518 ecm_db_node_deref(sfi->ni);
9519 }
9520 if (sfi->ii) {
9521 ecm_db_iface_deref(sfi->ii);
9522 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009523 ecm_db_state_file_classifier_type_assignments_release(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00009524
9525 kfree(sfi);
9526 DEBUG_WARN("Terminating\n");
9527 return -EBUSY;
9528 }
9529 spin_unlock_bh(&ecm_db_lock);
9530
9531 DEBUG_INFO("State opened %p\n", sfi);
9532
9533 return 0;
9534}
9535
9536/*
9537 * ecm_db_char_device_release()
9538 * Called when a process closes the device file.
9539 */
9540static int ecm_db_char_device_release(struct inode *inode, struct file *file)
9541{
9542 struct ecm_db_state_file_instance *sfi;
9543
9544 sfi = (struct ecm_db_state_file_instance *)file->private_data;
9545 DEBUG_CHECK_MAGIC(sfi, ECM_DB_STATE_FILE_INSTANCE_MAGIC, "%p: magic failed", sfi);
9546 DEBUG_INFO("%p: State close\n", sfi);
9547
9548 /*
9549 * Release any references held
9550 */
9551 if (sfi->ci) {
9552 ecm_db_connection_deref(sfi->ci);
9553 }
9554 if (sfi->mi) {
9555 ecm_db_mapping_deref(sfi->mi);
9556 }
9557 if (sfi->hi) {
9558 ecm_db_host_deref(sfi->hi);
9559 }
9560 if (sfi->ni) {
9561 ecm_db_node_deref(sfi->ni);
9562 }
9563 if (sfi->ii) {
9564 ecm_db_iface_deref(sfi->ii);
9565 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009566 ecm_db_state_file_classifier_type_assignments_release(sfi);
9567
Ben Menchaca84f36632014-02-28 20:57:38 +00009568 DEBUG_CLEAR_MAGIC(sfi);
9569 kfree(sfi);
9570
9571 return 0;
9572}
9573
9574/*
9575 * ecm_db_char_device_read()
9576 * Called to read the state
9577 */
9578static ssize_t ecm_db_char_device_read(struct file *file, /* see include/linux/fs.h */
9579 char *buffer, /* buffer to fill with data */
9580 size_t length, /* length of the buffer */
9581 loff_t *offset) /* Doesn't apply - this is a char file */
9582{
9583 struct ecm_db_state_file_instance *sfi;
9584 int bytes_read = 0; /* Number of bytes actually written to the buffer */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009585 ecm_classifier_type_t ca_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00009586
9587 sfi = (struct ecm_db_state_file_instance *)file->private_data;
9588 DEBUG_CHECK_MAGIC(sfi, ECM_DB_STATE_FILE_INSTANCE_MAGIC, "%p: magic failed", sfi);
9589 DEBUG_TRACE("%p: State read up to length %d bytes\n", sfi, length);
9590
Ben Menchaca84f36632014-02-28 20:57:38 +00009591
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009592 /*
9593 * If there is still some message remaining to be output then complete that first
9594 */
9595 if (sfi->msg_len) {
9596 goto char_device_read_output;
9597 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009598
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009599 if (!sfi->doc_start_written) {
9600 sfi->msgp = sfi->msg_buffer;
9601 sfi->msg_len = sprintf(sfi->msgp, "<ecm_db>\n");
9602 sfi->doc_start_written = true;
9603 goto char_device_read_output;
9604 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009605
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009606 if (sfi->ci) {
9607 struct ecm_db_connection_instance *cin;
9608 if (!ecm_db_char_dev_conn_msg_prep(sfi)) {
9609 return -EIO;
Ben Menchaca84f36632014-02-28 20:57:38 +00009610 }
9611
9612 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009613 * Next connection for when we return
Ben Menchaca84f36632014-02-28 20:57:38 +00009614 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009615 cin = ecm_db_connection_get_and_ref_next(sfi->ci);
9616 ecm_db_connection_deref(sfi->ci);
9617 sfi->ci = cin;
9618
9619 goto char_device_read_output;
9620 }
9621
9622 if (sfi->mi) {
9623 struct ecm_db_mapping_instance *min;
9624 if (!ecm_db_char_dev_mapping_msg_prep(sfi)) {
9625 return -EIO;
9626 }
9627
9628 /*
9629 * Next mapping for when we return
9630 */
9631 min = ecm_db_mapping_get_and_ref_next(sfi->mi);
9632 ecm_db_mapping_deref(sfi->mi);
9633 sfi->mi = min;
9634
9635 goto char_device_read_output;
9636 }
9637
9638 if (sfi->hi) {
9639 struct ecm_db_host_instance *hin;
9640 if (!ecm_db_char_dev_host_msg_prep(sfi)) {
9641 return -EIO;
9642 }
9643
9644 /*
9645 * Next host for when we return
9646 */
9647 hin = ecm_db_host_get_and_ref_next(sfi->hi);
9648 ecm_db_host_deref(sfi->hi);
9649 sfi->hi = hin;
9650
9651 goto char_device_read_output;
9652 }
9653
9654 if (sfi->ni) {
9655 struct ecm_db_node_instance *nin;
9656 if (!ecm_db_char_dev_node_msg_prep(sfi)) {
9657 return -EIO;
9658 }
9659
9660 /*
9661 * Next node for when we return
9662 */
9663 nin = ecm_db_node_get_and_ref_next(sfi->ni);
9664 ecm_db_node_deref(sfi->ni);
9665 sfi->ni = nin;
9666
9667 goto char_device_read_output;
9668 }
9669
9670 if (sfi->ii) {
9671 struct ecm_db_iface_instance *iin;
9672 if (!ecm_db_char_dev_iface_msg_prep(sfi)) {
9673 return -EIO;
9674 }
9675
9676 /*
9677 * Next iface for when we return
9678 */
9679 iin = ecm_db_interface_get_and_ref_next(sfi->ii);
9680 ecm_db_iface_deref(sfi->ii);
9681 sfi->ii = iin;
9682
9683 goto char_device_read_output;
9684 }
9685
9686 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_CONNECTIONS_CHAIN) && (sfi->connection_hash_index < ECM_DB_CONNECTION_HASH_SLOTS)) {
9687 if (!ecm_db_char_dev_conn_chain_msg_prep(sfi)) {
9688 return -EIO;
9689 }
9690 sfi->connection_hash_index++;
9691 goto char_device_read_output;
9692 }
9693
9694 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_MAPPINGS_CHAIN) && (sfi->mapping_hash_index < ECM_DB_MAPPING_HASH_SLOTS)) {
9695 if (!ecm_db_char_dev_mapping_chain_msg_prep(sfi)) {
9696 return -EIO;
9697 }
9698 sfi->mapping_hash_index++;
9699 goto char_device_read_output;
9700 }
9701
9702 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_HOSTS_CHAIN) && (sfi->host_hash_index < ECM_DB_HOST_HASH_SLOTS)) {
9703 if (!ecm_db_char_dev_host_chain_msg_prep(sfi)) {
9704 return -EIO;
9705 }
9706 sfi->host_hash_index++;
9707 goto char_device_read_output;
9708 }
9709
9710 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_NODES_CHAIN) && (sfi->node_hash_index < ECM_DB_NODE_HASH_SLOTS)) {
9711 if (!ecm_db_char_dev_node_chain_msg_prep(sfi)) {
9712 return -EIO;
9713 }
9714 sfi->node_hash_index++;
9715 goto char_device_read_output;
9716 }
9717
9718 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_INTERFACES_CHAIN) && (sfi->iface_hash_index < ECM_DB_IFACE_HASH_SLOTS)) {
9719 if (!ecm_db_char_dev_iface_chain_msg_prep(sfi)) {
9720 return -EIO;
9721 }
9722 sfi->iface_hash_index++;
9723 goto char_device_read_output;
9724 }
9725
9726 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_PROTOCOL_COUNTS) && (sfi->protocol < 256)) {
9727 if (!ecm_db_char_dev_protocol_count_msg_prep(sfi)) {
9728 return -EIO;
9729 }
9730 sfi->protocol++;
9731 goto char_device_read_output;
9732 }
9733
9734 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
9735 int flags;
9736
9737 flags = sfi->classifier_type_assignments_flags[ca_type];
9738
9739 if (!flags) {
9740 /*
9741 * Nothing further to write out for this ca_type
9742 */
9743 continue;
9744 }
9745 if (!ecm_db_char_dev_cta_msg_prep(sfi, ca_type)) {
9746 return -EIO;
9747 }
9748 goto char_device_read_output;
9749 }
9750
9751 if (!sfi->doc_end_written) {
9752 sfi->msgp = sfi->msg_buffer;
9753 sfi->msg_len = sprintf(sfi->msgp, "</ecm_db>\n");
9754 sfi->doc_end_written = true;
9755 goto char_device_read_output;
9756 }
9757
9758 /*
9759 * EOF
9760 */
9761 return 0;
9762
9763char_device_read_output:
Ben Menchaca84f36632014-02-28 20:57:38 +00009764
9765 /*
9766 * If supplied buffer is small we limit what we output
9767 */
9768 bytes_read = sfi->msg_len;
9769 if (bytes_read > length) {
9770 bytes_read = length;
9771 }
9772 if (copy_to_user(buffer, sfi->msgp, bytes_read)) {
9773 return -EIO;
9774 }
9775 sfi->msg_len -= bytes_read;
9776 sfi->msgp += bytes_read;
9777
9778 DEBUG_TRACE("State read done, bytes_read %d bytes\n", bytes_read);
9779
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309780 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00009781 * Most read functions return the number of bytes put into the buffer
9782 */
9783 return bytes_read;
9784}
9785
9786/*
9787 * ecm_db_char_device_write()
9788 */
9789static ssize_t ecm_db_char_device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
9790{
9791 return -EINVAL;
9792}
9793
9794/*
9795 * File operations used in the char device
9796 * NOTE: The char device is a simple file that allows us to dump our connection tracking state
9797 */
9798static struct file_operations ecm_db_fops = {
9799 .read = ecm_db_char_device_read,
9800 .write = ecm_db_char_device_write,
9801 .open = ecm_db_char_device_open,
9802 .release = ecm_db_char_device_release
9803};
9804
9805/*
9806 * ecm_db_timer_callback()
9807 * Manage expiration of connections
9808 * NOTE: This is softirq context
9809 */
9810static void ecm_db_timer_callback(unsigned long data)
9811{
9812 uint32_t timer;
9813
9814 /*
9815 * Increment timer.
9816 */
9817 spin_lock_bh(&ecm_db_lock);
9818 timer = ++ecm_db_time;
9819 spin_unlock_bh(&ecm_db_lock);
9820 DEBUG_TRACE("Garbage timer tick %d\n", timer);
9821
9822 /*
9823 * Check timer groups
9824 */
9825 ecm_db_timer_groups_check(timer);
9826
9827 /*
9828 * Set the timer for the next second
9829 */
9830 ecm_db_timer.expires += HZ;
9831 if (ecm_db_timer.expires <= jiffies) {
9832 DEBUG_WARN("losing time %lu, jiffies = %lu\n", ecm_db_timer.expires, jiffies);
9833 ecm_db_timer.expires = jiffies + HZ;
9834 }
9835 add_timer(&ecm_db_timer);
9836}
9837
9838/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009839 * ecm_db_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00009840 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009841int ecm_db_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00009842{
9843 int result;
Murat Sezgin1f381852014-11-20 09:51:07 -08009844 int i;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009845 DEBUG_INFO("ECM Module init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00009846
9847 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009848 * Initialise our global database lock
Ben Menchaca84f36632014-02-28 20:57:38 +00009849 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009850 spin_lock_init(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00009851
9852 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08009853 * Register System device control
Ben Menchaca84f36632014-02-28 20:57:38 +00009854 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009855 result = subsys_system_register(&ecm_db_subsys, NULL);
Ben Menchaca84f36632014-02-28 20:57:38 +00009856 if (result) {
9857 DEBUG_ERROR("Failed to register SysFS class %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009858 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00009859 }
9860
9861 /*
9862 * Register SYSFS device control
9863 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009864 memset(&ecm_db_dev, 0, sizeof(ecm_db_dev));
9865 ecm_db_dev.id = 0;
9866 ecm_db_dev.bus = &ecm_db_subsys;
9867 ecm_db_dev.release = ecm_db_dev_release;
9868 result = device_register(&ecm_db_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00009869 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08009870 DEBUG_ERROR("Failed to register System device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009871 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00009872 }
9873
9874 /*
9875 * Create files, one for each parameter supported by this module
9876 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009877 for (i = 0; i < ARRAY_SIZE(ecm_db_attrs); i++) {
9878 result = device_create_file(&ecm_db_dev, ecm_db_attrs[i]);
9879 if (result) {
9880 DEBUG_ERROR("Failed to create attribute file %d\n", result);
9881 goto task_cleanup_2;
9882 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009883 }
9884
9885 /*
9886 * Register a char device that we will use to provide a dump of our state
9887 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009888 result = register_chrdev(0, ecm_db_subsys.name, &ecm_db_fops);
Ben Menchaca84f36632014-02-28 20:57:38 +00009889 if (result < 0) {
9890 DEBUG_ERROR("Failed to register chrdev %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009891 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00009892 }
9893 ecm_db_dev_major_id = result;
9894 DEBUG_TRACE("registered chr dev major id assigned %d\n", ecm_db_dev_major_id);
9895
Ben Menchaca84f36632014-02-28 20:57:38 +00009896 /*
9897 * Set a timer to manage cleanup of expired connections
9898 */
9899 init_timer(&ecm_db_timer);
9900 ecm_db_timer.function = ecm_db_timer_callback;
9901 ecm_db_timer.data = 0;
9902 ecm_db_timer.expires = jiffies + HZ;
9903 add_timer(&ecm_db_timer);
9904
9905 /*
9906 * Initialise timer groups with time values
9907 */
9908 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].time = ECM_DB_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
9909 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
9910 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_GENERIC_TIMEOUT;
9911 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT;
9912 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].time = ECM_DB_CONNECTION_IGMP_TIMEOUT;
9913 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT;
9914 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
9915 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT;
9916 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
9917 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT;
9918 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].time = ECM_DB_CONNECTION_ICMP_TIMEOUT;
9919 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT;
9920 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].time = ECM_DB_CONNECTION_TCP_SHORT_TIMEOUT;
9921 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT;
9922 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].time = ECM_DB_CONNECTION_TCP_RST_TIMEOUT;
9923 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT;
9924 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
9925 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT;
9926 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].time = ECM_DB_CONNECTION_PPTP_DATA_TIMEOUT;
9927 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT;
9928 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].time = ECM_DB_CONNECTION_RTCP_TIMEOUT;
9929 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT;
9930 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
9931 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT;
9932 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_FAST_TIMEOUT;
9933 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT;
9934 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_SLOW_TIMEOUT;
9935 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT;
9936 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].time = ECM_DB_CONNECTION_DNS_TIMEOUT;
9937 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT;
9938 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].time = ECM_DB_CONNECTION_FTP_TIMEOUT;
9939 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT;
9940 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].time = ECM_DB_CONNECTION_BITTORRENT_TIMEOUT;
9941 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT;
9942
9943 /*
9944 * H323 timeout value is 8 hours (8h * 60m * 60s == 28800 seconds).
9945 */
9946 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].time = ECM_DB_CONNECTION_H323_TIMEOUT;
9947 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT;
9948
9949 /*
9950 * IKE Timeout (seconds) = 15 hours
9951 */
9952 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].time = ECM_DB_CONNECTION_IKE_TIMEOUT;
9953 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT;
9954
9955 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].time = ECM_DB_CONNECTION_ESP_TIMEOUT;
9956 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT;
9957 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].time = ECM_DB_CONNECTION_ESP_PENDING_TIMEOUT;
9958 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT;
9959
9960 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].time = ECM_DB_CONNECTION_SDP_TIMEOUT;
9961 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT;
9962 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].time = ECM_DB_CONNECTION_SIP_TIMEOUT;
9963 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT;
9964
9965 /*
9966 * Reset connection by protocol counters
9967 */
9968 memset(ecm_db_connection_count_by_protocol, 0, sizeof(ecm_db_connection_count_by_protocol));
9969
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009970 /*
9971 * Reset classifier type assignment lists
9972 */
9973 memset(ecm_db_connection_classifier_type_assignments, 0, sizeof(ecm_db_connection_classifier_type_assignments));
9974
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009975 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00009976
Ben Menchaca84f36632014-02-28 20:57:38 +00009977task_cleanup_2:
Murat Sezgin1f381852014-11-20 09:51:07 -08009978 while (--i >= 0) {
9979 device_remove_file(&ecm_db_dev, ecm_db_attrs[i]);
9980 }
9981 device_unregister(&ecm_db_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00009982task_cleanup_1:
Murat Sezgin1f381852014-11-20 09:51:07 -08009983 bus_unregister(&ecm_db_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00009984
Ben Menchaca84f36632014-02-28 20:57:38 +00009985 return result;
9986}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009987EXPORT_SYMBOL(ecm_db_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00009988
9989/*
9990 * ecm_db_exit()
9991 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009992void ecm_db_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00009993{
Murat Sezgin1f381852014-11-20 09:51:07 -08009994 int i;
Ben Menchaca84f36632014-02-28 20:57:38 +00009995 DEBUG_INFO("ECM DB Module exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009996
9997 spin_lock_bh(&ecm_db_lock);
9998 ecm_db_terminate_pending = true;
9999 spin_unlock_bh(&ecm_db_lock);
10000
10001 ecm_db_connection_defunct_all();
10002
10003 /*
10004 * Destroy garbage timer
10005 * Timer must be cancelled outside of holding db lock - if the
10006 * timer callback runs on another CPU we would deadlock
10007 * as we would wait for the callback to finish and it would wait
10008 * indefinately for the lock to be released!
10009 */
10010 del_timer_sync(&ecm_db_timer);
Murat Sezgin1f381852014-11-20 09:51:07 -080010011 unregister_chrdev(ecm_db_dev_major_id, ecm_db_subsys.name);
10012
10013 for (i = 0; i < ARRAY_SIZE(ecm_db_attrs); i++) {
10014 device_remove_file(&ecm_db_dev, ecm_db_attrs[i]);
10015 }
10016
10017 device_unregister(&ecm_db_dev);
10018 bus_unregister(&ecm_db_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +000010019}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010020EXPORT_SYMBOL(ecm_db_exit);