blob: 2774f9b282490c9784c0ab12aebd2aedeef57c91 [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/*
762 * ecm_db_interface_type_to_string()
763 * Return a string buffer containing the type name of the interface
764 */
765char *ecm_db_interface_type_to_string(ecm_db_iface_type_t type)
766{
767 DEBUG_ASSERT((type >= 0) && (type < ECM_DB_IFACE_TYPE_COUNT), "Invalid type: %d\n", type);
768 return ecm_db_interface_type_names[(int)type];
769}
770EXPORT_SYMBOL(ecm_db_interface_type_to_string);
771
772/*
773 * ecm_db_iface_nss_interface_identifier_get()
774 * Return the NSS interface number of this ecm interface
775 */
776int32_t ecm_db_iface_nss_interface_identifier_get(struct ecm_db_iface_instance *ii)
777{
778 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
779 return ii->nss_interface_identifier;
780}
781EXPORT_SYMBOL(ecm_db_iface_nss_interface_identifier_get);
782
783/*
Kiran Kumar C. S. K451b62e2014-05-19 20:34:06 +0530784 * ecm_db_iface_interface_identifier_get()
785 * Return the interface number of this ecm interface
786 */
787int32_t ecm_db_iface_interface_identifier_get(struct ecm_db_iface_instance *ii)
788{
789 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
790 return ii->interface_identifier;
791}
792EXPORT_SYMBOL(ecm_db_iface_interface_identifier_get);
793
794/*
Ben Menchaca84f36632014-02-28 20:57:38 +0000795 * ecm_db_iface_mtu_reset()
796 * Reset the mtu
797 */
798int32_t ecm_db_iface_mtu_reset(struct ecm_db_iface_instance *ii, int32_t mtu)
799{
800 int32_t mtu_old;
801 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
802 spin_lock_bh(&ecm_db_lock);
803 mtu_old = ii->mtu;
804 ii->mtu = mtu;
805 spin_unlock_bh(&ecm_db_lock);
806 DEBUG_INFO("%p: Mtu change from %d to %d\n", ii, mtu_old, mtu);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +0530807
Ben Menchaca84f36632014-02-28 20:57:38 +0000808 return mtu_old;
809}
810EXPORT_SYMBOL(ecm_db_iface_mtu_reset);
811
812/*
813 * ecm_db_connection_front_end_get_and_ref()
814 * Return ref to the front end instance of the connection
815 */
816struct ecm_front_end_connection_instance *ecm_db_connection_front_end_get_and_ref(struct ecm_db_connection_instance *ci)
817{
818 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
819 ci->feci->ref(ci->feci);
820 return ci->feci;
821}
822EXPORT_SYMBOL(ecm_db_connection_front_end_get_and_ref);
823
824/*
825 * ecm_db_connection_defunct_callback()
826 * Invoked by the expiration of the defunct_timer contained in a connection instance
827 */
828static void ecm_db_connection_defunct_callback(void *arg)
829{
830 struct ecm_db_connection_instance *ci = (struct ecm_db_connection_instance *)arg;
831 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
832
833 DEBUG_INFO("%p: defunct timer expired\n", ci);
834 ecm_db_connection_deref(ci);
835}
836
837/*
838 * ecm_db_connection_defunct_timer_reset()
839 * 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.
840 */
841bool ecm_db_connection_defunct_timer_reset(struct ecm_db_connection_instance *ci, ecm_db_timer_group_t tg)
842{
843 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
844 return ecm_db_timer_group_entry_reset(&ci->defunct_timer, tg);
845}
846EXPORT_SYMBOL(ecm_db_connection_defunct_timer_reset);
847
848/*
849 * ecm_db_connection_defunct_timer_touch()
850 * Update the connections defunct timer to stop it timing out. Returns false if the connection defunct timer has expired.
851 */
852bool ecm_db_connection_defunct_timer_touch(struct ecm_db_connection_instance *ci)
853{
854 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
855 return ecm_db_timer_group_entry_touch(&ci->defunct_timer);
856}
857EXPORT_SYMBOL(ecm_db_connection_defunct_timer_touch);
858
859/*
860 * ecm_db_connection_timer_group_get()
861 * Return the timer group id
862 */
863ecm_db_timer_group_t ecm_db_connection_timer_group_get(struct ecm_db_connection_instance *ci)
864{
865 ecm_db_timer_group_t tg;
866 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
867
868 spin_lock_bh(&ecm_db_lock);
869 tg = ci->defunct_timer.group;
870 spin_unlock_bh(&ecm_db_lock);
871 return tg;
872}
873EXPORT_SYMBOL(ecm_db_connection_timer_group_get);
874
875/*
876 * ecm_db_connection_make_defunct()
877 * Make connection defunct.
878 */
879void ecm_db_connection_make_defunct(struct ecm_db_connection_instance *ci)
880{
881 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Murat Sezgin7f6cdf62014-09-11 13:41:06 -0700882
883 if (ci->defunct) {
884 ci->defunct(ci->feci);
885 }
886
Ben Menchaca84f36632014-02-28 20:57:38 +0000887 if (ecm_db_timer_group_entry_remove(&ci->defunct_timer)) {
888 ecm_db_connection_deref(ci);
889 }
890}
891EXPORT_SYMBOL(ecm_db_connection_make_defunct);
892
893/*
894 * ecm_db_connection_data_totals_update()
895 * Update the total data (and packets) sent/received by the given host
896 */
897void ecm_db_connection_data_totals_update(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
898{
899 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
900
901 spin_lock_bh(&ecm_db_lock);
902
903 if (is_from) {
904 /*
905 * Update totals sent by the FROM side of connection
906 */
907 ci->from_data_total += size;
908 ci->mapping_from->from_data_total += size;
909 ci->mapping_from->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100910 ci->from_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000911 ci->from_packet_total += packets;
912 ci->mapping_from->from_packet_total += packets;
913 ci->mapping_from->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100914 ci->from_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000915
916 /*
917 * Data from the host is essentially TO the interface on which the host is reachable
918 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100919 ci->from_node->iface->to_data_total += size;
920 ci->from_node->iface->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000921
922 /*
923 * Update totals sent TO the other side of the connection
924 */
925 ci->mapping_to->to_data_total += size;
926 ci->mapping_to->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100927 ci->to_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000928 ci->mapping_to->to_packet_total += packets;
929 ci->mapping_to->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100930 ci->to_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000931
932 /*
933 * Sending to the other side means FROM the interface we reach that host
934 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100935 ci->to_node->iface->from_data_total += size;
936 ci->to_node->iface->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000937 spin_unlock_bh(&ecm_db_lock);
938 return;
939 }
940
941 /*
942 * Update totals sent by the TO side of this connection
943 */
944 ci->to_data_total += size;
945 ci->mapping_to->from_data_total += size;
946 ci->mapping_to->host->from_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100947 ci->to_node->from_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000948 ci->to_packet_total += packets;
949 ci->mapping_to->from_packet_total += packets;
950 ci->mapping_to->host->from_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100951 ci->to_node->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000952
953 /*
954 * Data from the host is essentially TO the interface on which the host is reachable
955 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100956 ci->to_node->iface->to_data_total += size;
957 ci->to_node->iface->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000958
959 /*
960 * Update totals sent TO the other side of the connection
961 */
962 ci->mapping_from->to_data_total += size;
963 ci->mapping_from->host->to_data_total += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100964 ci->from_node->to_data_total += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000965 ci->mapping_from->to_packet_total += packets;
966 ci->mapping_from->host->to_packet_total += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100967 ci->from_node->to_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000968
969 /*
970 * Sending to the other side means FROM the interface we reach that host
971 */
Gareth Williams90f2a282014-08-27 15:56:25 +0100972 ci->from_node->iface->from_data_total += size;
973 ci->from_node->iface->from_packet_total += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000974 spin_unlock_bh(&ecm_db_lock);
975}
976EXPORT_SYMBOL(ecm_db_connection_data_totals_update);
977
978/*
979 * ecm_db_connection_data_totals_update_dropped()
980 * Update the total data (and packets) sent by the given host but which we dropped
981 */
982void ecm_db_connection_data_totals_update_dropped(struct ecm_db_connection_instance *ci, bool is_from, uint64_t size, uint64_t packets)
983{
984 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
985
986 if (is_from) {
987 /*
988 * Update dropped totals sent by the FROM side
989 */
990 spin_lock_bh(&ecm_db_lock);
991 ci->from_data_total_dropped += size;
992 ci->mapping_from->from_data_total_dropped += size;
993 ci->mapping_from->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +0100994 ci->from_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +0000995 ci->from_packet_total_dropped += packets;
996 ci->mapping_from->from_packet_total_dropped += packets;
997 ci->mapping_from->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +0100998 ci->from_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +0000999
1000 /*
1001 * Data from the host is essentially TO the interface on which the host is reachable
1002 */
Gareth Williams90f2a282014-08-27 15:56:25 +01001003 ci->from_node->iface->to_data_total_dropped += size;
1004 ci->from_node->iface->to_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001005 spin_unlock_bh(&ecm_db_lock);
1006 return;
1007 }
1008
1009 /*
1010 * Update dropped totals sent by the TO side of this connection
1011 */
1012 spin_lock_bh(&ecm_db_lock);
1013 ci->to_data_total_dropped += size;
1014 ci->mapping_to->from_data_total_dropped += size;
1015 ci->mapping_to->host->from_data_total_dropped += size;
Gareth Williams90f2a282014-08-27 15:56:25 +01001016 ci->to_node->from_data_total_dropped += size;
Ben Menchaca84f36632014-02-28 20:57:38 +00001017 ci->to_packet_total_dropped += packets;
1018 ci->mapping_to->from_packet_total_dropped += packets;
1019 ci->mapping_to->host->from_packet_total_dropped += packets;
Gareth Williams90f2a282014-08-27 15:56:25 +01001020 ci->to_node->from_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001021
1022 /*
1023 * Data from the host is essentially TO the interface on which the host is reachable
1024 */
Gareth Williams90f2a282014-08-27 15:56:25 +01001025 ci->to_node->iface->to_data_total_dropped += size;
1026 ci->to_node->iface->to_packet_total_dropped += packets;
Ben Menchaca84f36632014-02-28 20:57:38 +00001027 spin_unlock_bh(&ecm_db_lock);
1028}
1029EXPORT_SYMBOL(ecm_db_connection_data_totals_update_dropped);
1030
1031/*
1032 * ecm_db_connection_data_stats_get()
1033 * Return data stats for the instance
1034 */
1035void ecm_db_connection_data_stats_get(struct ecm_db_connection_instance *ci, uint64_t *from_data_total, uint64_t *to_data_total,
1036 uint64_t *from_packet_total, uint64_t *to_packet_total,
1037 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1038 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1039{
1040 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1041
1042 spin_lock_bh(&ecm_db_lock);
1043 if (from_data_total) {
1044 *from_data_total = ci->from_data_total;
1045 }
1046 if (to_data_total) {
1047 *to_data_total = ci->to_data_total;
1048 }
1049 if (from_packet_total) {
1050 *from_packet_total = ci->from_packet_total;
1051 }
1052 if (to_packet_total) {
1053 *to_packet_total = ci->to_packet_total;
1054 }
1055 if (from_data_total_dropped) {
1056 *from_data_total_dropped = ci->from_data_total_dropped;
1057 }
1058 if (to_data_total_dropped) {
1059 *to_data_total_dropped = ci->to_data_total_dropped;
1060 }
1061 if (from_packet_total_dropped) {
1062 *from_packet_total_dropped = ci->from_packet_total_dropped;
1063 }
1064 if (to_packet_total_dropped) {
1065 *to_packet_total_dropped = ci->to_packet_total_dropped;
1066 }
1067 spin_unlock_bh(&ecm_db_lock);
1068}
1069EXPORT_SYMBOL(ecm_db_connection_data_stats_get);
1070
1071/*
1072 * ecm_db_mapping_data_stats_get()
1073 * Return data stats for the instance
1074 */
1075void ecm_db_mapping_data_stats_get(struct ecm_db_mapping_instance *mi, uint64_t *from_data_total, uint64_t *to_data_total,
1076 uint64_t *from_packet_total, uint64_t *to_packet_total,
1077 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1078 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1079{
1080 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1081 spin_lock_bh(&ecm_db_lock);
1082 if (from_data_total) {
1083 *from_data_total = mi->from_data_total;
1084 }
1085 if (to_data_total) {
1086 *to_data_total = mi->to_data_total;
1087 }
1088 if (from_packet_total) {
1089 *from_packet_total = mi->from_packet_total;
1090 }
1091 if (to_packet_total) {
1092 *to_packet_total = mi->to_packet_total;
1093 }
1094 if (from_data_total_dropped) {
1095 *from_data_total_dropped = mi->from_data_total_dropped;
1096 }
1097 if (to_data_total_dropped) {
1098 *to_data_total_dropped = mi->to_data_total_dropped;
1099 }
1100 if (from_packet_total_dropped) {
1101 *from_packet_total_dropped = mi->from_packet_total_dropped;
1102 }
1103 if (to_packet_total_dropped) {
1104 *to_packet_total_dropped = mi->to_packet_total_dropped;
1105 }
1106 spin_unlock_bh(&ecm_db_lock);
1107}
1108EXPORT_SYMBOL(ecm_db_mapping_data_stats_get);
1109
1110/*
1111 * ecm_db_host_data_stats_get()
1112 * Return data stats for the instance
1113 */
1114void ecm_db_host_data_stats_get(struct ecm_db_host_instance *hi, uint64_t *from_data_total, uint64_t *to_data_total,
1115 uint64_t *from_packet_total, uint64_t *to_packet_total,
1116 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1117 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1118{
1119 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1120 spin_lock_bh(&ecm_db_lock);
1121 if (from_data_total) {
1122 *from_data_total = hi->from_data_total;
1123 }
1124 if (to_data_total) {
1125 *to_data_total = hi->to_data_total;
1126 }
1127 if (from_packet_total) {
1128 *from_packet_total = hi->from_packet_total;
1129 }
1130 if (to_packet_total) {
1131 *to_packet_total = hi->to_packet_total;
1132 }
1133 if (from_data_total_dropped) {
1134 *from_data_total_dropped = hi->from_data_total_dropped;
1135 }
1136 if (to_data_total_dropped) {
1137 *to_data_total_dropped = hi->to_data_total_dropped;
1138 }
1139 if (from_packet_total_dropped) {
1140 *from_packet_total_dropped = hi->from_packet_total_dropped;
1141 }
1142 if (to_packet_total_dropped) {
1143 *to_packet_total_dropped = hi->to_packet_total_dropped;
1144 }
1145 spin_unlock_bh(&ecm_db_lock);
1146}
1147EXPORT_SYMBOL(ecm_db_host_data_stats_get);
1148
1149/*
1150 * ecm_db_node_data_stats_get()
1151 * Return data stats for the instance
1152 */
1153void ecm_db_node_data_stats_get(struct ecm_db_node_instance *ni, uint64_t *from_data_total, uint64_t *to_data_total,
1154 uint64_t *from_packet_total, uint64_t *to_packet_total,
1155 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1156 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1157{
1158 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1159 spin_lock_bh(&ecm_db_lock);
1160 if (from_data_total) {
1161 *from_data_total = ni->from_data_total;
1162 }
1163 if (to_data_total) {
1164 *to_data_total = ni->to_data_total;
1165 }
1166 if (from_packet_total) {
1167 *from_packet_total = ni->from_packet_total;
1168 }
1169 if (to_packet_total) {
1170 *to_packet_total = ni->to_packet_total;
1171 }
1172 if (from_data_total_dropped) {
1173 *from_data_total_dropped = ni->from_data_total_dropped;
1174 }
1175 if (to_data_total_dropped) {
1176 *to_data_total_dropped = ni->to_data_total_dropped;
1177 }
1178 if (from_packet_total_dropped) {
1179 *from_packet_total_dropped = ni->from_packet_total_dropped;
1180 }
1181 if (to_packet_total_dropped) {
1182 *to_packet_total_dropped = ni->to_packet_total_dropped;
1183 }
1184 spin_unlock_bh(&ecm_db_lock);
1185}
1186EXPORT_SYMBOL(ecm_db_node_data_stats_get);
1187
1188/*
1189 * ecm_db_iface_data_stats_get()
1190 * Return data stats for the instance
1191 */
1192void ecm_db_iface_data_stats_get(struct ecm_db_iface_instance *ii, uint64_t *from_data_total, uint64_t *to_data_total,
1193 uint64_t *from_packet_total, uint64_t *to_packet_total,
1194 uint64_t *from_data_total_dropped, uint64_t *to_data_total_dropped,
1195 uint64_t *from_packet_total_dropped, uint64_t *to_packet_total_dropped)
1196{
1197 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1198 spin_lock_bh(&ecm_db_lock);
1199 if (from_data_total) {
1200 *from_data_total = ii->from_data_total;
1201 }
1202 if (to_data_total) {
1203 *to_data_total = ii->to_data_total;
1204 }
1205 if (from_packet_total) {
1206 *from_packet_total = ii->from_packet_total;
1207 }
1208 if (to_packet_total) {
1209 *to_packet_total = ii->to_packet_total;
1210 }
1211 if (from_data_total_dropped) {
1212 *from_data_total_dropped = ii->from_data_total_dropped;
1213 }
1214 if (to_data_total_dropped) {
1215 *to_data_total_dropped = ii->to_data_total_dropped;
1216 }
1217 if (from_packet_total_dropped) {
1218 *from_packet_total_dropped = ii->from_packet_total_dropped;
1219 }
1220 if (to_packet_total_dropped) {
1221 *to_packet_total_dropped = ii->to_packet_total_dropped;
1222 }
1223 spin_unlock_bh(&ecm_db_lock);
1224}
1225EXPORT_SYMBOL(ecm_db_iface_data_stats_get);
1226
1227/*
1228 * ecm_db_connection_serial_get()
1229 * Return serial
1230 */
1231uint32_t ecm_db_connection_serial_get(struct ecm_db_connection_instance *ci)
1232{
1233 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1234 return ci->serial;
1235}
1236EXPORT_SYMBOL(ecm_db_connection_serial_get);
1237
1238/*
1239 * ecm_db_connection_from_address_get()
1240 * Return ip address address
1241 */
1242void ecm_db_connection_from_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1243{
1244 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1245 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1246 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1247 ECM_IP_ADDR_COPY(addr, ci->mapping_from->host->address);
1248}
1249EXPORT_SYMBOL(ecm_db_connection_from_address_get);
1250
1251/*
1252 * ecm_db_connection_from_address_nat_get()
1253 * Return NAT ip address address
1254 */
1255void ecm_db_connection_from_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1256{
1257 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1258 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1259 DEBUG_CHECK_MAGIC(ci->mapping_from->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from->host);
1260 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_from->host->address);
1261}
1262EXPORT_SYMBOL(ecm_db_connection_from_address_nat_get);
1263
1264/*
1265 * ecm_db_connection_to_address_get()
1266 * Return ip address address
1267 */
1268void ecm_db_connection_to_address_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1269{
1270 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1271 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1272 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1273 ECM_IP_ADDR_COPY(addr, ci->mapping_to->host->address);
1274}
1275EXPORT_SYMBOL(ecm_db_connection_to_address_get);
1276
1277/*
1278 * ecm_db_connection_to_address_nat_get()
1279 * Return NAT ip address address
1280 */
1281void ecm_db_connection_to_address_nat_get(struct ecm_db_connection_instance *ci, ip_addr_t addr)
1282{
1283 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1284 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1285 DEBUG_CHECK_MAGIC(ci->mapping_to->host, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to->host);
1286 ECM_IP_ADDR_COPY(addr, ci->mapping_nat_to->host->address);
1287}
1288EXPORT_SYMBOL(ecm_db_connection_to_address_nat_get);
1289
1290/*
1291 * ecm_db_connection_to_port_get()
1292 * Return port
1293 */
1294int ecm_db_connection_to_port_get(struct ecm_db_connection_instance *ci)
1295{
1296 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1297 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1298 return ci->mapping_to->port;
1299}
1300EXPORT_SYMBOL(ecm_db_connection_to_port_get);
1301
1302/*
1303 * ecm_db_connection_to_port_nat_get()
1304 * Return port
1305 */
1306int ecm_db_connection_to_port_nat_get(struct ecm_db_connection_instance *ci)
1307{
1308 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1309 DEBUG_CHECK_MAGIC(ci->mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_to);
1310 return ci->mapping_nat_to->port;
1311}
1312EXPORT_SYMBOL(ecm_db_connection_to_port_nat_get);
1313
1314/*
1315 * ecm_db_connection_from_port_get()
1316 * Return port
1317 */
1318int ecm_db_connection_from_port_get(struct ecm_db_connection_instance *ci)
1319{
1320 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1321 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1322 return ci->mapping_from->port;
1323}
1324EXPORT_SYMBOL(ecm_db_connection_from_port_get);
1325
1326/*
1327 * ecm_db_connection_from_port_nat_get()
1328 * Return port
1329 */
1330int ecm_db_connection_from_port_nat_get(struct ecm_db_connection_instance *ci)
1331{
1332 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1333 DEBUG_CHECK_MAGIC(ci->mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", ci->mapping_from);
1334 return ci->mapping_nat_from->port;
1335}
1336EXPORT_SYMBOL(ecm_db_connection_from_port_nat_get);
1337
1338/*
1339 * ecm_db_connection_to_node_address_get()
1340 * Return address of the node used when sending packets to the 'to' side.
1341 */
1342void ecm_db_connection_to_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1343{
1344 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001345 memcpy(address_buffer, ci->to_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001346}
1347EXPORT_SYMBOL(ecm_db_connection_to_node_address_get);
1348
1349/*
1350 * ecm_db_connection_from_node_address_get()
1351 * Return address of the node used when sending packets to the 'from' side.
1352 */
1353void ecm_db_connection_from_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1354{
1355 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001356 memcpy(address_buffer, ci->from_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001357}
1358EXPORT_SYMBOL(ecm_db_connection_from_node_address_get);
1359
1360/*
1361 * ecm_db_connection_to_nat_node_address_get()
1362 * Return address of the node used when sending packets to the 'to' NAT side.
1363 */
1364void ecm_db_connection_to_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1365{
1366 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001367 memcpy(address_buffer, ci->to_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001368}
1369EXPORT_SYMBOL(ecm_db_connection_to_nat_node_address_get);
1370
1371/*
1372 * ecm_db_connection_from_nat_node_address_get()
1373 * Return address of the node used when sending packets to the 'from' NAT side.
1374 */
1375void ecm_db_connection_from_nat_node_address_get(struct ecm_db_connection_instance *ci, uint8_t *address_buffer)
1376{
1377 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001378 memcpy(address_buffer, ci->from_nat_node->address, ETH_ALEN);
Ben Menchaca84f36632014-02-28 20:57:38 +00001379}
1380EXPORT_SYMBOL(ecm_db_connection_from_nat_node_address_get);
1381
1382/*
1383 * ecm_db_connection_to_iface_name_get()
1384 * Return name of interface on which the 'to' side may be reached
1385 */
1386void ecm_db_connection_to_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1387{
1388 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001389 strcpy(name_buffer, ci->to_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001390}
1391EXPORT_SYMBOL(ecm_db_connection_to_iface_name_get);
1392
1393/*
1394 * ecm_db_connection_from_iface_name_get()
1395 * Return name of interface on which the 'from' side may be reached
1396 */
1397void ecm_db_connection_from_iface_name_get(struct ecm_db_connection_instance *ci, char *name_buffer)
1398{
1399 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
Gareth Williams90f2a282014-08-27 15:56:25 +01001400 strcpy(name_buffer, ci->from_node->iface->name);
Ben Menchaca84f36632014-02-28 20:57:38 +00001401}
1402EXPORT_SYMBOL(ecm_db_connection_from_iface_name_get);
1403
1404/*
1405 * ecm_db_connection_to_iface_mtu_get()
1406 * Return MTU of interface on which the 'to' side may be reached
1407 */
1408int ecm_db_connection_to_iface_mtu_get(struct ecm_db_connection_instance *ci)
1409{
1410 int mtu;
1411 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1412 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001413 mtu = ci->to_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001414 spin_unlock_bh(&ecm_db_lock);
1415 return mtu;
1416}
1417EXPORT_SYMBOL(ecm_db_connection_to_iface_mtu_get);
1418
1419/*
1420 * ecm_db_connection_to_iface_type_get()
1421 * Return type of interface on which the 'to' side may be reached
1422 */
1423ecm_db_iface_type_t ecm_db_connection_to_iface_type_get(struct ecm_db_connection_instance *ci)
1424{
1425 ecm_db_iface_type_t type;
1426
1427 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1428 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001429 type = ci->to_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001430 spin_unlock_bh(&ecm_db_lock);
1431 return type;
1432}
1433EXPORT_SYMBOL(ecm_db_connection_to_iface_type_get);
1434
1435/*
1436 * ecm_db_connection_from_iface_mtu_get()
1437 * Return MTU of interface on which the 'from' side may be reached
1438 */
1439int ecm_db_connection_from_iface_mtu_get(struct ecm_db_connection_instance *ci)
1440{
1441 int mtu;
1442 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1443 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001444 mtu = ci->from_node->iface->mtu;
Ben Menchaca84f36632014-02-28 20:57:38 +00001445 spin_unlock_bh(&ecm_db_lock);
1446 return mtu;
1447}
1448EXPORT_SYMBOL(ecm_db_connection_from_iface_mtu_get);
1449
1450/*
1451 * ecm_db_connection_from_iface_type_get()
1452 * Return type of interface on which the 'from' side may be reached
1453 */
1454ecm_db_iface_type_t ecm_db_connection_from_iface_type_get(struct ecm_db_connection_instance *ci)
1455{
1456 ecm_db_iface_type_t type;
1457
1458 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1459 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01001460 type = ci->from_node->iface->type;
Ben Menchaca84f36632014-02-28 20:57:38 +00001461 spin_unlock_bh(&ecm_db_lock);
1462 return type;
1463}
1464EXPORT_SYMBOL(ecm_db_connection_from_iface_type_get);
1465
1466/*
1467 * ecm_db_connection_iface_type_get()
1468 * Return type of interface
1469 */
1470ecm_db_iface_type_t ecm_db_connection_iface_type_get(struct ecm_db_iface_instance *ii)
1471{
1472 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
1473 return ii->type;
1474}
1475EXPORT_SYMBOL(ecm_db_connection_iface_type_get);
1476
1477/*
1478 * ecm_db_connection_classifier_generation_changed()
1479 * Returns true if the classifier generation has changed for this connection.
1480 *
1481 * NOTE: The generation index will be reset on return from this call so action any true result immediately.
1482 */
1483bool ecm_db_connection_classifier_generation_changed(struct ecm_db_connection_instance *ci)
1484{
1485 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1486
1487 spin_lock_bh(&ecm_db_lock);
1488 if (ci->classifier_generation == ecm_db_classifier_generation) {
1489 spin_unlock_bh(&ecm_db_lock);
1490 return false;
1491 }
Gareth Williamsda721272014-11-13 17:48:12 -08001492 ci->generations++;
Ben Menchaca84f36632014-02-28 20:57:38 +00001493 ci->classifier_generation = ecm_db_classifier_generation;
1494 spin_unlock_bh(&ecm_db_lock);
1495 return true;
1496}
1497EXPORT_SYMBOL(ecm_db_connection_classifier_generation_changed);
1498
1499/*
1500 * ecm_db_connection_classifier_peek_generation_changed()
1501 * Returns true if the classifier generation has changed for this connection.
1502 *
1503 * NOTE: The generation index will NOT be reset on return from this call.
1504 */
1505bool ecm_db_connection_classifier_peek_generation_changed(struct ecm_db_connection_instance *ci)
1506{
1507 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1508
1509 spin_lock_bh(&ecm_db_lock);
1510 if (ci->classifier_generation == ecm_db_classifier_generation) {
1511 spin_unlock_bh(&ecm_db_lock);
1512 return false;
1513 }
1514 spin_unlock_bh(&ecm_db_lock);
1515 return true;
1516}
1517EXPORT_SYMBOL(ecm_db_connection_classifier_peek_generation_changed);
1518
1519/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01001520 * _ecm_db_connection_classifier_generation_change()
1521 * Cause a specific connection to be re-generated
1522 */
1523static void _ecm_db_connection_classifier_generation_change(struct ecm_db_connection_instance *ci)
1524{
1525 ci->classifier_generation = ecm_db_classifier_generation - 1;
1526}
1527
1528/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001529 * ecm_db_connection_classifier_generation_change()
1530 * Cause a specific connection to be re-generated
1531 */
1532void ecm_db_connection_classifier_generation_change(struct ecm_db_connection_instance *ci)
1533{
1534 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1535
1536 spin_lock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01001537 _ecm_db_connection_classifier_generation_change(ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00001538 spin_unlock_bh(&ecm_db_lock);
1539}
1540EXPORT_SYMBOL(ecm_db_connection_classifier_generation_change);
1541
1542/*
1543 * ecm_db_classifier_generation_change()
1544 * Bump the generation index to cause a re-classification of connections
1545 *
1546 * NOTE: Any connections that see activity after a call to this could be put back to undetermined qos state
1547 * and driven back through the classifiers.
1548 */
1549void ecm_db_classifier_generation_change(void)
1550{
1551 spin_lock_bh(&ecm_db_lock);
1552 ecm_db_classifier_generation++;
1553 spin_unlock_bh(&ecm_db_lock);
1554}
1555EXPORT_SYMBOL(ecm_db_classifier_generation_change);
1556
1557/*
1558 * ecm_db_connection_direction_get()
1559 * Return direction of the connection.
1560 *
1561 * NOTE: an EGRESS connection means that packets being sent to mapping_to should have qos applied.
1562 * INGRESS means that packets being sent to mapping_from should have qos applied.
1563 */
1564ecm_db_direction_t ecm_db_connection_direction_get(struct ecm_db_connection_instance *ci)
1565{
1566 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1567 return ci->direction;
1568}
1569EXPORT_SYMBOL(ecm_db_connection_direction_get);
1570
1571/*
1572 * ecm_db_mapping_port_count_get()
1573 * Return port count stats for a mapping.
1574 */
1575void ecm_db_mapping_port_count_get(struct ecm_db_mapping_instance *mi,
1576 int *tcp_from, int *tcp_to, int *udp_from, int *udp_to, int *from, int *to,
1577 int *tcp_nat_from, int *tcp_nat_to, int *udp_nat_from, int *udp_nat_to, int *nat_from, int *nat_to)
1578{
1579 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1580
1581 spin_lock_bh(&ecm_db_lock);
1582
1583 *tcp_from = mi->tcp_from;
1584 *tcp_to = mi->tcp_to;
1585 *udp_from = mi->udp_from;
1586 *udp_to = mi->udp_to;
1587 *from = mi->from;
1588 *to = mi->to;
1589
1590 *tcp_nat_from = mi->tcp_nat_from;
1591 *tcp_nat_to = mi->tcp_nat_to;
1592 *udp_nat_from = mi->udp_nat_from;
1593 *udp_nat_to = mi->udp_nat_to;
1594 *nat_from = mi->nat_from;
1595 *nat_to = mi->nat_to;
1596
1597 spin_unlock_bh(&ecm_db_lock);
1598}
1599EXPORT_SYMBOL(ecm_db_mapping_port_count_get);
1600
1601/*
1602 * ecm_db_connection_is_routed_get()
1603 * Return whether connection is a routed path or not
1604 */
1605bool ecm_db_connection_is_routed_get(struct ecm_db_connection_instance *ci)
1606{
1607 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1608 return ci->is_routed;
1609}
1610EXPORT_SYMBOL(ecm_db_connection_is_routed_get);
1611
1612/*
1613 * ecm_db_connection_protocol_get()
1614 * Return protocol of connection
1615 */
1616int ecm_db_connection_protocol_get(struct ecm_db_connection_instance *ci)
1617{
1618 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1619 return ci->protocol;
1620}
1621EXPORT_SYMBOL(ecm_db_connection_protocol_get);
1622
1623/*
1624 * ecm_db_host_address_get()
1625 * Return address of host
1626 */
1627void ecm_db_host_address_get(struct ecm_db_host_instance *hi, ip_addr_t addr)
1628{
1629 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1630 ECM_IP_ADDR_COPY(addr, hi->address);
1631}
1632EXPORT_SYMBOL(ecm_db_host_address_get);
1633
1634/*
Ben Menchaca84f36632014-02-28 20:57:38 +00001635 * ecm_db_host_on_link_get()
1636 * Return on link status of host
1637 */
1638bool ecm_db_host_on_link_get(struct ecm_db_host_instance *hi)
1639{
1640 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
1641 return hi->on_link;
1642}
1643EXPORT_SYMBOL(ecm_db_host_on_link_get);
1644
1645/*
1646 * ecm_db_mapping_adress_get()
1647 * Return address
1648 */
1649void ecm_db_mapping_adress_get(struct ecm_db_mapping_instance *mi, ip_addr_t addr)
1650{
1651 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1652 ECM_IP_ADDR_COPY(addr, mi->host->address);
1653}
1654EXPORT_SYMBOL(ecm_db_mapping_adress_get);
1655
1656/*
1657 * ecm_db_mapping_port_get()
1658 * Return port
1659 */
1660int ecm_db_mapping_port_get(struct ecm_db_mapping_instance *mi)
1661{
1662 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
1663 return mi->port;
1664}
1665EXPORT_SYMBOL(ecm_db_mapping_port_get);
1666
1667/*
1668 * ecm_db_node_adress_get()
1669 * Return address
1670 */
1671void ecm_db_node_adress_get(struct ecm_db_node_instance *ni, uint8_t *address_buffer)
1672{
1673 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
1674 memcpy(address_buffer, ni->address, ETH_ALEN);
1675}
1676EXPORT_SYMBOL(ecm_db_node_adress_get);
1677
1678/*
1679 * _ecm_db_timer_group_entry_remove()
1680 * Remove the entry from its timer group, returns false if the entry has already expired.
1681 */
1682static bool _ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
1683{
1684 struct ecm_db_timer_group *timer_group;
1685
1686 /*
1687 * If not in a timer group then it is already removed
1688 */
1689 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
1690 return false;
1691 }
1692
1693 /*
1694 * Remove the connection from its current group
1695 */
1696 timer_group = &ecm_db_timer_groups[tge->group];
1697
1698 /*
1699 * Somewhere in the list?
1700 */
1701 if (tge->prev) {
1702 tge->prev->next = tge->next;
1703 } else {
1704 /*
1705 * First in the group
1706 */
1707 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p, got %p\n", timer_group, tge, timer_group->head);
1708 timer_group->head = tge->next;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05301709 }
Ben Menchaca84f36632014-02-28 20:57:38 +00001710
1711 if (tge->next) {
1712 tge->next->prev = tge->prev;
1713 } else {
1714 /*
1715 * No next so this must be the last item - we need to adjust the tail pointer
1716 */
1717 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
1718 timer_group->tail = tge->prev;
1719 }
1720
1721 /*
1722 * No longer a part of a timer group
1723 */
1724 tge->group = ECM_DB_TIMER_GROUPS_MAX;
1725 return true;
1726}
1727
1728/*
1729 * ecm_db_timer_group_entry_remove()
1730 * Remove the connection from its timer group, returns false if the entry has already expired.
1731 */
1732bool ecm_db_timer_group_entry_remove(struct ecm_db_timer_group_entry *tge)
1733{
1734 bool res;
1735 spin_lock_bh(&ecm_db_lock);
1736 res = _ecm_db_timer_group_entry_remove(tge);
1737 spin_unlock_bh(&ecm_db_lock);
1738 return res;
1739}
1740EXPORT_SYMBOL(ecm_db_timer_group_entry_remove);
1741
1742/*
1743 * _ecm_db_timer_group_entry_set()
1744 * Set the timer group to which this entry will be a member
1745 */
1746void _ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
1747{
1748 struct ecm_db_timer_group *timer_group;
1749
1750 DEBUG_ASSERT(tge->group == ECM_DB_TIMER_GROUPS_MAX, "%p: already set\n", tge);
1751
1752 /*
1753 * Set group
1754 */
1755 tge->group = tg;
1756 timer_group = &ecm_db_timer_groups[tge->group];
1757 tge->timeout = timer_group->time + ecm_db_time;
1758
1759 /*
1760 * Insert into a timer group at the head (as this is now touched)
1761 */
1762 tge->prev = NULL;
1763 tge->next = timer_group->head;
1764 if (!timer_group->head) {
1765 /*
1766 * As there is no head there is also no tail so we need to set that
1767 */
1768 timer_group->tail = tge;
1769 } else {
1770 /*
1771 * As there is a head already there must be a tail. Since we insert before
1772 * the current head we don't adjust the tail.
1773 */
1774 timer_group->head->prev = tge;
1775 }
1776 timer_group->head = tge;
1777}
1778
1779/*
1780 * ecm_db_timer_group_entry_reset()
1781 * Re-set the timer group to which this entry will be a member.
1782 *
1783 * Returns false if the timer cannot be reset because it has expired
1784 */
1785bool ecm_db_timer_group_entry_reset(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
1786{
1787 spin_lock_bh(&ecm_db_lock);
1788
1789 /*
1790 * Remove it from its current group, if any
1791 */
1792 if (!_ecm_db_timer_group_entry_remove(tge)) {
1793 spin_unlock_bh(&ecm_db_lock);
1794 return false;
1795 }
1796
1797 /*
1798 * Set new group
1799 */
1800 _ecm_db_timer_group_entry_set(tge, tg);
1801 spin_unlock_bh(&ecm_db_lock);
1802 return true;
1803}
1804EXPORT_SYMBOL(ecm_db_timer_group_entry_reset);
1805
1806/*
1807 * ecm_db_timer_group_entry_set()
1808 * Set the timer group to which this entry will be a member
1809 */
1810void ecm_db_timer_group_entry_set(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_t tg)
1811{
1812 spin_lock_bh(&ecm_db_lock);
1813 _ecm_db_timer_group_entry_set(tge, tg);
1814 spin_unlock_bh(&ecm_db_lock);
1815}
1816EXPORT_SYMBOL(ecm_db_timer_group_entry_set);
1817
1818/*
1819 * ecm_db_timer_group_entry_init()
1820 * Initialise a timer entry ready for setting
1821 */
1822void ecm_db_timer_group_entry_init(struct ecm_db_timer_group_entry *tge, ecm_db_timer_group_entry_callback_t fn, void *arg)
1823{
1824 memset(tge, 0, sizeof(struct ecm_db_timer_group_entry));
1825 tge->group = ECM_DB_TIMER_GROUPS_MAX;
1826 tge->arg = arg;
1827 tge->fn = fn;
1828}
1829EXPORT_SYMBOL(ecm_db_timer_group_entry_init);
1830
1831/*
1832 * ecm_db_timer_group_entry_touch()
1833 * Update the timeout, if the timer is not running this has no effect.
1834 * It returns false if the timer is not running.
1835 */
1836bool ecm_db_timer_group_entry_touch(struct ecm_db_timer_group_entry *tge)
1837{
1838 struct ecm_db_timer_group *timer_group;
1839
1840 spin_lock_bh(&ecm_db_lock);
1841
1842 /*
1843 * If not in a timer group then do nothing
1844 */
1845 if (tge->group == ECM_DB_TIMER_GROUPS_MAX) {
1846 spin_unlock_bh(&ecm_db_lock);
1847 return false;
1848 }
1849
1850 /*
1851 * Update time to live
1852 */
1853 timer_group = &ecm_db_timer_groups[tge->group];
1854
1855 /*
1856 * Link out of its current position.
1857 */
1858 if (!tge->prev) {
1859 /*
1860 * Already at the head, just update the time
1861 */
1862 tge->timeout = timer_group->time + ecm_db_time;
1863 spin_unlock_bh(&ecm_db_lock);
1864 return true;
1865 }
1866
1867 /*
1868 * tge->prev is not null, so:
1869 * 1) it is in a timer list
1870 * 2) is not at the head of the list
1871 * 3) there is a head already (so more than one item on the list)
1872 * 4) there is a prev pointer.
1873 * Somewhere in the group list - unlink it.
1874 */
1875 tge->prev->next = tge->next;
1876
1877 if (tge->next) {
1878 tge->next->prev = tge->prev;
1879 } else {
1880 /*
1881 * Since there is no next this must be the tail
1882 */
1883 DEBUG_ASSERT(timer_group->tail == tge, "%p: bad tail, expecting %p got %p\n", timer_group, tge, timer_group->tail);
1884 timer_group->tail = tge->prev;
1885 }
1886
1887 /*
1888 * Link in to head.
1889 */
Sol Kavy213e45d2014-06-05 18:04:07 -07001890 tge->timeout = timer_group->time + ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00001891 tge->prev = NULL;
1892 tge->next = timer_group->head;
1893 timer_group->head->prev = tge;
1894 timer_group->head = tge;
1895 spin_unlock_bh(&ecm_db_lock);
1896 return true;
1897}
1898EXPORT_SYMBOL(ecm_db_timer_group_entry_touch);
1899
1900/*
1901 * _ecm_db_connection_ref()
1902 */
1903static void _ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
1904{
1905 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
1906 ci->refs++;
1907 DEBUG_TRACE("%p: connection ref %d\n", ci, ci->refs);
1908 DEBUG_ASSERT(ci->refs > 0, "%p: ref wrap\n", ci);
1909}
1910
1911/*
1912 * ecm_db_connection_ref()
1913 */
1914void ecm_db_connection_ref(struct ecm_db_connection_instance *ci)
1915{
1916 spin_lock_bh(&ecm_db_lock);
1917 _ecm_db_connection_ref(ci);
1918 spin_unlock_bh(&ecm_db_lock);
1919}
1920EXPORT_SYMBOL(ecm_db_connection_ref);
1921
1922/*
1923 * _ecm_db_mapping_ref()
1924 */
1925static void _ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
1926{
1927 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
1928 mi->refs++;
1929 DEBUG_TRACE("%p: mapping ref %d\n", mi, mi->refs);
1930 DEBUG_ASSERT(mi->refs > 0, "%p: ref wrap\n", mi);
1931}
1932
1933/*
1934 * ecm_db_mapping_ref()
1935 */
1936void ecm_db_mapping_ref(struct ecm_db_mapping_instance *mi)
1937{
1938 spin_lock_bh(&ecm_db_lock);
1939 _ecm_db_mapping_ref(mi);
1940 spin_unlock_bh(&ecm_db_lock);
1941}
1942EXPORT_SYMBOL(ecm_db_mapping_ref);
1943
1944/*
1945 * _ecm_db_host_ref()
1946 */
1947static void _ecm_db_host_ref(struct ecm_db_host_instance *hi)
1948{
1949 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
1950 hi->refs++;
1951 DEBUG_TRACE("%p: host ref %d\n", hi, hi->refs);
1952 DEBUG_ASSERT(hi->refs > 0, "%p: ref wrap\n", hi);
1953}
1954
1955/*
1956 * ecm_db_host_ref()
1957 */
1958void ecm_db_host_ref(struct ecm_db_host_instance *hi)
1959{
1960 spin_lock_bh(&ecm_db_lock);
1961 _ecm_db_host_ref(hi);
1962 spin_unlock_bh(&ecm_db_lock);
1963}
1964EXPORT_SYMBOL(ecm_db_host_ref);
1965
1966/*
1967 * _ecm_db_node_ref()
1968 */
1969static void _ecm_db_node_ref(struct ecm_db_node_instance *ni)
1970{
1971 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
1972 ni->refs++;
1973 DEBUG_TRACE("%p: node ref %d\n", ni, ni->refs);
1974 DEBUG_ASSERT(ni->refs > 0, "%p: ref wrap\n", ni);
1975}
1976
1977/*
1978 * ecm_db_node_ref()
1979 */
1980void ecm_db_node_ref(struct ecm_db_node_instance *ni)
1981{
1982 spin_lock_bh(&ecm_db_lock);
1983 _ecm_db_node_ref(ni);
1984 spin_unlock_bh(&ecm_db_lock);
1985}
1986EXPORT_SYMBOL(ecm_db_node_ref);
1987
1988/*
1989 * _ecm_db_iface_ref()
1990 */
1991static void _ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
1992{
1993 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
1994 ii->refs++;
1995 DEBUG_TRACE("%p: iface ref %d\n", ii, ii->refs);
1996 DEBUG_ASSERT(ii->refs > 0, "%p: ref wrap\n", ii);
1997}
1998
1999/*
2000 * ecm_db_iface_ref()
2001 */
2002void ecm_db_iface_ref(struct ecm_db_iface_instance *ii)
2003{
2004 spin_lock_bh(&ecm_db_lock);
2005 _ecm_db_iface_ref(ii);
2006 spin_unlock_bh(&ecm_db_lock);
2007}
2008EXPORT_SYMBOL(ecm_db_iface_ref);
2009
2010/*
2011 * _ecm_db_listener_ref()
2012 */
2013static void _ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2014{
2015 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2016 li->refs++;
2017 DEBUG_ASSERT(li->refs > 0, "%p: ref wrap\n", li);
2018}
2019
2020/*
2021 * ecm_db_listener_ref()
2022 */
2023void ecm_db_listener_ref(struct ecm_db_listener_instance *li)
2024{
2025 spin_lock_bh(&ecm_db_lock);
2026 _ecm_db_listener_ref(li);
2027 spin_unlock_bh(&ecm_db_lock);
2028}
2029EXPORT_SYMBOL(ecm_db_listener_ref);
2030
2031/*
2032 * ecm_db_connections_get_and_ref_first()
2033 * Obtain a ref to the first connection instance, if any
2034 */
2035static struct ecm_db_connection_instance *ecm_db_connections_get_and_ref_first(void)
2036{
2037 struct ecm_db_connection_instance *ci;
2038 spin_lock_bh(&ecm_db_lock);
2039 ci = ecm_db_connections;
2040 if (ci) {
2041 _ecm_db_connection_ref(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302042 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002043 spin_unlock_bh(&ecm_db_lock);
2044 return ci;
2045}
2046EXPORT_SYMBOL(ecm_db_connections_get_and_ref_first);
2047
2048/*
2049 * ecm_db_connection_get_and_ref_next()
2050 * Return the next connection in the list given a connection
2051 */
2052struct ecm_db_connection_instance *ecm_db_connection_get_and_ref_next(struct ecm_db_connection_instance *ci)
2053{
2054 struct ecm_db_connection_instance *cin;
2055 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2056 spin_lock_bh(&ecm_db_lock);
2057 cin = ci->next;
2058 if (cin) {
2059 _ecm_db_connection_ref(cin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302060 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002061 spin_unlock_bh(&ecm_db_lock);
2062 return cin;
2063}
2064EXPORT_SYMBOL(ecm_db_connection_get_and_ref_next);
2065
2066/*
2067 * ecm_db_mappings_get_and_ref_first()
2068 * Obtain a ref to the first mapping instance, if any
2069 */
2070struct ecm_db_mapping_instance *ecm_db_mappings_get_and_ref_first(void)
2071{
2072 struct ecm_db_mapping_instance *mi;
2073 spin_lock_bh(&ecm_db_lock);
2074 mi = ecm_db_mappings;
2075 if (mi) {
2076 _ecm_db_mapping_ref(mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302077 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002078 spin_unlock_bh(&ecm_db_lock);
2079 return mi;
2080}
2081EXPORT_SYMBOL(ecm_db_mappings_get_and_ref_first);
2082
2083/*
2084 * ecm_db_mapping_get_and_ref_next()
2085 * Return the next mapping in the list given a mapping
2086 */
2087struct ecm_db_mapping_instance *ecm_db_mapping_get_and_ref_next(struct ecm_db_mapping_instance *mi)
2088{
2089 struct ecm_db_mapping_instance *min;
2090 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
2091 spin_lock_bh(&ecm_db_lock);
2092 min = mi->next;
2093 if (min) {
2094 _ecm_db_mapping_ref(min);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302095 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002096 spin_unlock_bh(&ecm_db_lock);
2097 return min;
2098}
2099EXPORT_SYMBOL(ecm_db_mapping_get_and_ref_next);
2100
2101/*
2102 * ecm_db_hosts_get_and_ref_first()
2103 * Obtain a ref to the first host instance, if any
2104 */
2105struct ecm_db_host_instance *ecm_db_hosts_get_and_ref_first(void)
2106{
2107 struct ecm_db_host_instance *hi;
2108 spin_lock_bh(&ecm_db_lock);
2109 hi = ecm_db_hosts;
2110 if (hi) {
2111 _ecm_db_host_ref(hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302112 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002113 spin_unlock_bh(&ecm_db_lock);
2114 return hi;
2115}
2116EXPORT_SYMBOL(ecm_db_hosts_get_and_ref_first);
2117
2118/*
2119 * ecm_db_host_get_and_ref_next()
2120 * Return the next host in the list given a host
2121 */
2122struct ecm_db_host_instance *ecm_db_host_get_and_ref_next(struct ecm_db_host_instance *hi)
2123{
2124 struct ecm_db_host_instance *hin;
2125 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed", hi);
2126 spin_lock_bh(&ecm_db_lock);
2127 hin = hi->next;
2128 if (hin) {
2129 _ecm_db_host_ref(hin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302130 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002131 spin_unlock_bh(&ecm_db_lock);
2132 return hin;
2133}
2134EXPORT_SYMBOL(ecm_db_host_get_and_ref_next);
2135
2136/*
2137 * ecm_db_listeners_get_and_ref_first()
2138 * Obtain a ref to the first listener instance, if any
2139 */
2140static struct ecm_db_listener_instance *ecm_db_listeners_get_and_ref_first(void)
2141{
2142 struct ecm_db_listener_instance *li;
2143 spin_lock_bh(&ecm_db_lock);
2144 li = ecm_db_listeners;
2145 if (li) {
2146 _ecm_db_listener_ref(li);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302147 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002148 spin_unlock_bh(&ecm_db_lock);
2149 return li;
2150}
2151
2152/*
2153 * ecm_db_listener_get_and_ref_next()
2154 * Return the next listener in the list given a listener
2155 */
2156static struct ecm_db_listener_instance *ecm_db_listener_get_and_ref_next(struct ecm_db_listener_instance *li)
2157{
2158 struct ecm_db_listener_instance *lin;
2159 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
2160 spin_lock_bh(&ecm_db_lock);
2161 lin = li->next;
2162 if (lin) {
2163 _ecm_db_listener_ref(lin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302164 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002165 spin_unlock_bh(&ecm_db_lock);
2166 return lin;
2167}
2168
2169/*
2170 * ecm_db_nodes_get_and_ref_first()
2171 * Obtain a ref to the first node instance, if any
2172 */
2173struct ecm_db_node_instance *ecm_db_nodes_get_and_ref_first(void)
2174{
2175 struct ecm_db_node_instance *ni;
2176 spin_lock_bh(&ecm_db_lock);
2177 ni = ecm_db_nodes;
2178 if (ni) {
2179 _ecm_db_node_ref(ni);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302180 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002181 spin_unlock_bh(&ecm_db_lock);
2182 return ni;
2183}
2184EXPORT_SYMBOL(ecm_db_nodes_get_and_ref_first);
2185
2186/*
2187 * ecm_db_node_get_and_ref_next()
2188 * Return the next node in the list given a node
2189 */
2190struct ecm_db_node_instance *ecm_db_node_get_and_ref_next(struct ecm_db_node_instance *ni)
2191{
2192 struct ecm_db_node_instance *nin;
2193 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed", ni);
2194 spin_lock_bh(&ecm_db_lock);
2195 nin = ni->next;
2196 if (nin) {
2197 _ecm_db_node_ref(nin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302198 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002199 spin_unlock_bh(&ecm_db_lock);
2200 return nin;
2201}
2202EXPORT_SYMBOL(ecm_db_node_get_and_ref_next);
2203
2204/*
2205 * ecm_db_interfaces_get_and_ref_first()
2206 * Obtain a ref to the first iface instance, if any
2207 */
2208struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void)
2209{
2210 struct ecm_db_iface_instance *ii;
2211 spin_lock_bh(&ecm_db_lock);
2212 ii = ecm_db_interfaces;
2213 if (ii) {
2214 _ecm_db_iface_ref(ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302215 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002216 spin_unlock_bh(&ecm_db_lock);
2217 return ii;
2218}
2219EXPORT_SYMBOL(ecm_db_interfaces_get_and_ref_first);
2220
2221/*
2222 * ecm_db_interface_get_and_ref_next()
2223 * Return the next iface in the list given a iface
2224 */
2225struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii)
2226{
2227 struct ecm_db_iface_instance *iin;
2228 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
2229 spin_lock_bh(&ecm_db_lock);
2230 iin = ii->next;
2231 if (iin) {
2232 _ecm_db_iface_ref(iin);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05302233 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002234 spin_unlock_bh(&ecm_db_lock);
2235 return iin;
2236}
2237EXPORT_SYMBOL(ecm_db_interface_get_and_ref_next);
2238
2239/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01002240 * _ecm_db_classifier_type_assignment_remove()
2241 * Remove the connection from the classifier type assignment list (of the given type)
2242 */
2243static void _ecm_db_classifier_type_assignment_remove(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
2244{
2245 struct ecm_db_connection_classifier_type_assignment *ta;
2246 struct ecm_db_connection_classifier_type_assignment_list *tal;
2247
2248 DEBUG_TRACE("%p: Classifier type assignment remove: %d\n", ci, ca_type);
2249 ta = &ci->type_assignment[ca_type];
2250 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p\n", ta, ci);
2251 DEBUG_ASSERT(ta->iteration_count == 0, "%p: iteration count: %d, type: %d\n", ci, ta->iteration_count, ca_type);
2252
2253 if (ta->next) {
2254 struct ecm_db_connection_classifier_type_assignment *tan = &ta->next->type_assignment[ca_type];
2255 DEBUG_ASSERT(tan->prev == ci, "Bad list, expecting: %p, got: %p\n", ci, tan->prev);
2256 tan->prev = ta->prev;
2257 }
2258
2259 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
2260 if (ta->prev) {
2261 struct ecm_db_connection_classifier_type_assignment *tap = &ta->prev->type_assignment[ca_type];
2262 DEBUG_ASSERT(tap->next == ci, "Bad list, expecting: %p, got: %p\n", ci, tap->next);
2263 tap->next = ta->next;
2264 } else {
2265 /*
2266 * Set new head of list
2267 */
2268 DEBUG_ASSERT(tal->type_assignments_list == ci, "Bad head, expecting %p, got %p, type: %d\n", ci, tal->type_assignments_list, ca_type);
2269 tal->type_assignments_list = ta->next;
2270 }
2271 ta->next = NULL;
2272 ta->prev = NULL;
2273 ta->pending_unassign = false;
2274
2275 /*
2276 * Decrement assignment count
2277 */
2278 tal->type_assignment_count--;
2279 DEBUG_ASSERT(tal->type_assignment_count >= 0, "Bad type assignment count: %d, type: %d\n", tal->type_assignment_count, ca_type);
2280
2281 DEBUG_CLEAR_MAGIC(ta);
2282}
2283
2284/*
Ben Menchaca84f36632014-02-28 20:57:38 +00002285 * ecm_db_connection_deref()
2286 * Release reference to connection. Connection is removed from database on final deref and destroyed.
2287 */
2288int ecm_db_connection_deref(struct ecm_db_connection_instance *ci)
2289{
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002290 ecm_classifier_type_t ca_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00002291 int32_t i;
2292
2293 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
2294
2295 spin_lock_bh(&ecm_db_lock);
2296 ci->refs--;
2297 DEBUG_TRACE("%p: connection deref %d\n", ci, ci->refs);
2298 DEBUG_ASSERT(ci->refs >= 0, "%p: ref wrap\n", ci);
2299
2300 if (ci->refs > 0) {
2301 int refs = ci->refs;
2302 spin_unlock_bh(&ecm_db_lock);
2303 return refs;
2304 }
2305
2306 /*
Gareth Williams2ac3c9f2014-10-30 14:27:03 +00002307 * Unlink from the "assignments by classifier type" lists.
2308 *
2309 * This is done whether the connection is inserted into the database or not - this is because
2310 * classifier assignments take place before adding into the db.
2311 *
2312 * NOTE: We know that the ci is not being iterated in any of these lists because otherwise
2313 * ci would be being held as part of iteration and so we would not be here!
2314 * Equally we know that if the assignments_by_type[] element is non-null then it must also be in the relevant list too.
2315 */
2316 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
2317 if (!ci->assignments_by_type[ca_type]) {
2318 /*
2319 * No assignment of this type, so would not be in the classifier type assignments list
2320 */
2321 continue;
2322 }
2323 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
2324 }
2325
2326 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002327 * Remove from database if inserted
2328 */
2329 if (!ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED) {
2330 spin_unlock_bh(&ecm_db_lock);
2331 } else {
2332 struct ecm_db_listener_instance *li;
2333 struct ecm_db_iface_instance *iface_from;
2334 struct ecm_db_iface_instance *iface_to;
2335 struct ecm_db_iface_instance *iface_nat_from;
2336 struct ecm_db_iface_instance *iface_nat_to;
2337
2338 /*
2339 * Remove it from the connection hash table
2340 */
2341 if (!ci->hash_prev) {
2342 DEBUG_ASSERT(ecm_db_connection_table[ci->hash_index] == ci, "%p: hash table bad\n", ci);
2343 ecm_db_connection_table[ci->hash_index] = ci->hash_next;
2344 } else {
2345 ci->hash_prev->hash_next = ci->hash_next;
2346 }
2347 if (ci->hash_next) {
2348 ci->hash_next->hash_prev = ci->hash_prev;
2349 }
2350 ecm_db_connection_table_lengths[ci->hash_index]--;
2351 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]);
2352
2353 /*
2354 * Remove it from the connection serial hash table
2355 */
2356 if (!ci->serial_hash_prev) {
2357 DEBUG_ASSERT(ecm_db_connection_serial_table[ci->serial_hash_index] == ci, "%p: hash table bad\n", ci);
2358 ecm_db_connection_serial_table[ci->serial_hash_index] = ci->serial_hash_next;
2359 } else {
2360 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
2361 }
2362 if (ci->serial_hash_next) {
2363 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
2364 }
2365 ecm_db_connection_serial_table_lengths[ci->serial_hash_index]--;
2366 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]);
2367
2368 /*
2369 * Remove from the global list
2370 */
2371 if (!ci->prev) {
2372 DEBUG_ASSERT(ecm_db_connections == ci, "%p: conn table bad\n", ci);
2373 ecm_db_connections = ci->next;
2374 } else {
2375 ci->prev->next = ci->next;
2376 }
2377 if (ci->next) {
2378 ci->next->prev = ci->prev;
2379 }
2380
2381 /*
2382 * Remove connection from the "from" mapping connection list
2383 */
2384 if (!ci->from_prev) {
2385 DEBUG_ASSERT(ci->mapping_from->from_connections == ci, "%p: from conn table bad\n", ci);
2386 ci->mapping_from->from_connections = ci->from_next;
2387 } else {
2388 ci->from_prev->from_next = ci->from_next;
2389 }
2390 if (ci->from_next) {
2391 ci->from_next->from_prev = ci->from_prev;
2392 }
2393
2394 /*
2395 * Remove connection from the "to" mapping connection list
2396 */
2397 if (!ci->to_prev) {
2398 DEBUG_ASSERT(ci->mapping_to->to_connections == ci, "%p: to conn table bad\n", ci);
2399 ci->mapping_to->to_connections = ci->to_next;
2400 } else {
2401 ci->to_prev->to_next = ci->to_next;
2402 }
2403 if (ci->to_next) {
2404 ci->to_next->to_prev = ci->to_prev;
2405 }
2406
2407 /*
2408 * Remove connection from the "from" NAT mapping connection list
2409 */
2410 if (!ci->from_nat_prev) {
2411 DEBUG_ASSERT(ci->mapping_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2412 ci->mapping_nat_from->from_nat_connections = ci->from_nat_next;
2413 } else {
2414 ci->from_nat_prev->from_nat_next = ci->from_nat_next;
2415 }
2416 if (ci->from_nat_next) {
2417 ci->from_nat_next->from_nat_prev = ci->from_nat_prev;
2418 }
2419
2420 /*
2421 * Remove connection from the "to" NAT mapping connection list
2422 */
2423 if (!ci->to_nat_prev) {
2424 DEBUG_ASSERT(ci->mapping_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2425 ci->mapping_nat_to->to_nat_connections = ci->to_nat_next;
2426 } else {
2427 ci->to_nat_prev->to_nat_next = ci->to_nat_next;
2428 }
2429 if (ci->to_nat_next) {
2430 ci->to_nat_next->to_nat_prev = ci->to_nat_prev;
2431 }
2432
2433 /*
2434 * Remove connection from the "from" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002435 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002436 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002437 iface_from = ci->from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002438 if (!ci->iface_from_prev) {
2439 DEBUG_ASSERT(iface_from->from_connections == ci, "%p: iface from conn table bad\n", ci);
2440 iface_from->from_connections = ci->iface_from_next;
2441 } else {
2442 ci->iface_from_prev->iface_from_next = ci->iface_from_next;
2443 }
2444 if (ci->iface_from_next) {
2445 ci->iface_from_next->iface_from_prev = ci->iface_from_prev;
2446 }
2447
2448 /*
2449 * Remove connection from the "to" iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002450 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002451 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002452 iface_to = ci->to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002453 if (!ci->iface_to_prev) {
2454 DEBUG_ASSERT(iface_to->to_connections == ci, "%p: to conn table bad\n", ci);
2455 iface_to->to_connections = ci->iface_to_next;
2456 } else {
2457 ci->iface_to_prev->iface_to_next = ci->iface_to_next;
2458 }
2459 if (ci->iface_to_next) {
2460 ci->iface_to_next->iface_to_prev = ci->iface_to_prev;
2461 }
2462
2463 /*
2464 * Remove connection from the "from" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002465 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002466 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002467 iface_nat_from = ci->from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002468 if (!ci->iface_from_nat_prev) {
2469 DEBUG_ASSERT(iface_nat_from->from_nat_connections == ci, "%p: nat from conn table bad\n", ci);
2470 iface_nat_from->from_nat_connections = ci->iface_from_nat_next;
2471 } else {
2472 ci->iface_from_nat_prev->iface_from_nat_next = ci->iface_from_nat_next;
2473 }
2474 if (ci->iface_from_nat_next) {
2475 ci->iface_from_nat_next->iface_from_nat_prev = ci->iface_from_nat_prev;
2476 }
2477
2478 /*
2479 * Remove connection from the "to" NAT iface connection list
Gareth Williams90f2a282014-08-27 15:56:25 +01002480 * GGG TODO Deprecated. Interface lists will be used instead. To be deleted.
Ben Menchaca84f36632014-02-28 20:57:38 +00002481 */
Gareth Williams90f2a282014-08-27 15:56:25 +01002482 iface_nat_to = ci->to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00002483 if (!ci->iface_to_nat_prev) {
2484 DEBUG_ASSERT(iface_nat_to->to_nat_connections == ci, "%p: nat to conn table bad\n", ci);
2485 iface_nat_to->to_nat_connections = ci->iface_to_nat_next;
2486 } else {
2487 ci->iface_to_nat_prev->iface_to_nat_next = ci->iface_to_nat_next;
2488 }
2489 if (ci->iface_to_nat_next) {
2490 ci->iface_to_nat_next->iface_to_nat_prev = ci->iface_to_nat_prev;
2491 }
2492
2493 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01002494 * Remove connection from its "from node" node connection list
2495 */
2496 if (!ci->node_from_prev) {
2497 DEBUG_ASSERT(ci->from_node->from_connections == ci, "%p: from node conn table bad, got: %p\n", ci, ci->from_node->from_connections);
2498 ci->from_node->from_connections = ci->node_from_next;
2499 } else {
2500 ci->node_from_prev->node_from_next = ci->node_from_next;
2501 }
2502 if (ci->node_from_next) {
2503 ci->node_from_next->node_from_prev = ci->node_from_prev;
2504 }
2505 ci->from_node->from_connections_count--;
2506 DEBUG_ASSERT(ci->from_node->from_connections_count >= 0, "%p: bad count\n", ci);
2507
2508 /*
2509 * Remove connection from its "to node" node connection list
2510 */
2511 if (!ci->node_to_prev) {
2512 DEBUG_ASSERT(ci->to_node->to_connections == ci, "%p: to node conn table bad, got: %p\n", ci, ci->to_node->to_connections);
2513 ci->to_node->to_connections = ci->node_to_next;
2514 } else {
2515 ci->node_to_prev->node_to_next = ci->node_to_next;
2516 }
2517 if (ci->node_to_next) {
2518 ci->node_to_next->node_to_prev = ci->node_to_prev;
2519 }
2520 ci->to_node->to_connections_count--;
2521 DEBUG_ASSERT(ci->to_node->to_connections_count >= 0, "%p: bad count\n", ci);
2522
2523 /*
2524 * Remove connection from its "from nat node" node connection list
2525 */
2526 if (!ci->node_from_nat_prev) {
2527 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);
2528 ci->from_nat_node->from_nat_connections = ci->node_from_nat_next;
2529 } else {
2530 ci->node_from_nat_prev->node_from_nat_next = ci->node_from_nat_next;
2531 }
2532 if (ci->node_from_nat_next) {
2533 ci->node_from_nat_next->node_from_nat_prev = ci->node_from_nat_prev;
2534 }
2535 ci->from_nat_node->from_nat_connections_count--;
2536 DEBUG_ASSERT(ci->from_nat_node->from_nat_connections_count >= 0, "%p: bad count\n", ci);
2537
2538 /*
2539 * Remove connection from its "to nat node" node connection list
2540 */
2541 if (!ci->node_to_nat_prev) {
2542 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);
2543 ci->to_nat_node->to_nat_connections = ci->node_to_nat_next;
2544 } else {
2545 ci->node_to_nat_prev->node_to_nat_next = ci->node_to_nat_next;
2546 }
2547 if (ci->node_to_nat_next) {
2548 ci->node_to_nat_next->node_to_nat_prev = ci->node_to_nat_prev;
2549 }
2550 ci->to_nat_node->to_nat_connections_count--;
2551 DEBUG_ASSERT(ci->to_nat_node->to_nat_connections_count >= 0, "%p: bad count\n", ci);
2552
2553 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002554 * Update the counters in the mappings
2555 */
2556 if (ci->protocol == IPPROTO_UDP) {
2557 ci->mapping_from->udp_from--;
2558 ci->mapping_to->udp_to--;
2559 ci->mapping_nat_from->udp_nat_from--;
2560 ci->mapping_nat_to->udp_nat_to--;
2561 } else if (ci->protocol == IPPROTO_TCP) {
2562 ci->mapping_from->tcp_from--;
2563 ci->mapping_to->tcp_to--;
2564 ci->mapping_nat_from->tcp_nat_from--;
2565 ci->mapping_nat_to->tcp_nat_to--;
2566 }
2567
2568 ci->mapping_from->from--;
2569 ci->mapping_to->to--;
2570 ci->mapping_nat_from->nat_from--;
2571 ci->mapping_nat_to->nat_to--;
2572
2573 /*
2574 * Assert that the defunt timer has been detached
2575 */
2576 DEBUG_ASSERT(ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX, "%p: unexpected timer group %d\n", ci, ci->defunct_timer.group);
2577
2578 /*
2579 * Decrement protocol counter stats
2580 */
2581 ecm_db_connection_count_by_protocol[ci->protocol]--;
2582 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 +01002583
Ben Menchaca84f36632014-02-28 20:57:38 +00002584 spin_unlock_bh(&ecm_db_lock);
2585
2586 /*
2587 * Throw removed event to listeners
2588 */
2589 DEBUG_TRACE("%p: Throw connection removed event\n", ci);
2590 li = ecm_db_listeners_get_and_ref_first();
2591 while (li) {
2592 struct ecm_db_listener_instance *lin;
2593 if (li->connection_removed) {
2594 li->connection_removed(li->arg, ci);
2595 }
2596
2597 /*
2598 * Get next listener
2599 */
2600 lin = ecm_db_listener_get_and_ref_next(li);
2601 ecm_db_listener_deref(li);
2602 li = lin;
2603 }
2604 }
2605
2606 /*
2607 * Throw final event
2608 */
2609 if (ci->final) {
2610 ci->final(ci->arg);
2611 }
2612
2613 /*
2614 * Release instances to the objects referenced by the connection
2615 */
2616 while (ci->assignments) {
2617 struct ecm_classifier_instance *classi = ci->assignments;
2618 ci->assignments = classi->ca_next;
2619 classi->deref(classi);
2620 }
2621
Ben Menchaca84f36632014-02-28 20:57:38 +00002622 if (ci->mapping_from) {
2623 ecm_db_mapping_deref(ci->mapping_from);
2624 }
2625 if (ci->mapping_to) {
2626 ecm_db_mapping_deref(ci->mapping_to);
2627 }
2628 if (ci->mapping_nat_from) {
2629 ecm_db_mapping_deref(ci->mapping_nat_from);
2630 }
2631 if (ci->mapping_nat_to) {
2632 ecm_db_mapping_deref(ci->mapping_nat_to);
2633 }
2634 if (ci->feci) {
2635 ci->feci->deref(ci->feci);
2636 }
Gareth Williams90f2a282014-08-27 15:56:25 +01002637 if (ci->from_node) {
2638 ecm_db_node_deref(ci->from_node);
2639 }
2640 if (ci->to_node) {
2641 ecm_db_node_deref(ci->to_node);
2642 }
2643 if (ci->from_nat_node) {
2644 ecm_db_node_deref(ci->from_nat_node);
2645 }
2646 if (ci->to_nat_node) {
2647 ecm_db_node_deref(ci->to_nat_node);
2648 }
Ben Menchaca84f36632014-02-28 20:57:38 +00002649
2650 /*
2651 * Remove references to the interfaces in our heirarchy lists
2652 */
2653 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2654 DEBUG_TRACE("%p: from interface %d remove: %p\n", ci, i, ci->from_interfaces[i]);
2655 ecm_db_iface_deref(ci->from_interfaces[i]);
2656 }
2657 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2658 DEBUG_TRACE("%p: to interface %d remove: %p\n", ci, i, ci->to_interfaces[i]);
2659 ecm_db_iface_deref(ci->to_interfaces[i]);
2660 }
2661 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2662 DEBUG_TRACE("%p: from nat interface %d remove: %p\n", ci, i, ci->from_nat_interfaces[i]);
2663 ecm_db_iface_deref(ci->from_nat_interfaces[i]);
2664 }
2665 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
2666 DEBUG_TRACE("%p: to nat interface %d remove: %p\n", ci, i, ci->to_nat_interfaces[i]);
2667 ecm_db_iface_deref(ci->to_nat_interfaces[i]);
2668 }
2669
2670 /*
2671 * We can now destroy the instance
2672 */
2673 DEBUG_CLEAR_MAGIC(ci);
2674 kfree(ci);
2675
2676 /*
2677 * Decrease global connection count
2678 */
2679 spin_lock_bh(&ecm_db_lock);
2680 ecm_db_connection_count--;
2681 DEBUG_ASSERT(ecm_db_connection_count >= 0, "%p: connection count wrap\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00002682 spin_unlock_bh(&ecm_db_lock);
2683
Ben Menchaca84f36632014-02-28 20:57:38 +00002684 return 0;
2685}
2686EXPORT_SYMBOL(ecm_db_connection_deref);
2687
2688/*
2689 * ecm_db_mapping_deref()
2690 * Release ref to mapping, possibly removing it from the database and destroying it.
2691 */
2692int ecm_db_mapping_deref(struct ecm_db_mapping_instance *mi)
2693{
2694 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
2695
2696 spin_lock_bh(&ecm_db_lock);
2697 mi->refs--;
2698 DEBUG_TRACE("%p: mapping deref %d\n", mi, mi->refs);
2699 DEBUG_ASSERT(mi->refs >= 0, "%p: ref wrap\n", mi);
2700
2701 if (mi->refs > 0) {
2702 int refs = mi->refs;
2703 spin_unlock_bh(&ecm_db_lock);
2704 return refs;
2705 }
2706
2707 DEBUG_ASSERT(!mi->from_connections && !mi->tcp_from && !mi->udp_from && !mi->from, "%p: from not null: %p, %d, %d, %d\n",
2708 mi, mi->from_connections, mi->tcp_from, mi->udp_from, mi->from);
2709 DEBUG_ASSERT(!mi->to_connections && !mi->tcp_to && !mi->udp_to && !mi->to, "%p: to not null: %p, %d, %d, %d\n",
2710 mi, mi->to_connections, mi->tcp_to, mi->udp_to, mi->to);
2711 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",
2712 mi, mi->from_nat_connections, mi->tcp_nat_from, mi->udp_nat_from, mi->nat_from);
2713 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",
2714 mi, mi->to_nat_connections, mi->tcp_nat_to, mi->udp_nat_to, mi->nat_to);
2715
2716 /*
2717 * Remove from database if inserted
2718 */
2719 if (!mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED) {
2720 spin_unlock_bh(&ecm_db_lock);
2721 } else {
2722 struct ecm_db_listener_instance *li;
2723
2724 /*
2725 * Remove from the global list
2726 */
2727 if (!mi->prev) {
2728 DEBUG_ASSERT(ecm_db_mappings == mi, "%p: mapping table bad\n", mi);
2729 ecm_db_mappings = mi->next;
2730 } else {
2731 mi->prev->next = mi->next;
2732 }
2733 if (mi->next) {
2734 mi->next->prev = mi->prev;
2735 }
2736
2737 /*
2738 * Unlink it from the mapping hash table
2739 */
2740 if (!mi->hash_prev) {
2741 DEBUG_ASSERT(ecm_db_mapping_table[mi->hash_index] == mi, "%p: hash table bad\n", mi);
2742 ecm_db_mapping_table[mi->hash_index] = mi->hash_next;
2743 } else {
2744 mi->hash_prev->hash_next = mi->hash_next;
2745 }
2746 if (mi->hash_next) {
2747 mi->hash_next->hash_prev = mi->hash_prev;
2748 }
2749 mi->hash_next = NULL;
2750 mi->hash_prev = NULL;
2751 ecm_db_mapping_table_lengths[mi->hash_index]--;
2752 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]);
2753
2754 /*
2755 * Unlink it from the host mapping list
2756 */
2757 if (!mi->mapping_prev) {
2758 DEBUG_ASSERT(mi->host->mappings == mi, "%p: mapping table bad\n", mi);
2759 mi->host->mappings = mi->mapping_next;
2760 } else {
2761 mi->mapping_prev->mapping_next = mi->mapping_next;
2762 }
2763 if (mi->mapping_next) {
2764 mi->mapping_next->mapping_prev = mi->mapping_prev;
2765 }
2766 mi->mapping_next = NULL;
2767 mi->mapping_prev = NULL;
2768
2769 mi->host->mapping_count--;
2770 spin_unlock_bh(&ecm_db_lock);
2771
2772 /*
2773 * Throw removed event to listeners
2774 */
2775 DEBUG_TRACE("%p: Throw mapping removed event\n", mi);
2776 li = ecm_db_listeners_get_and_ref_first();
2777 while (li) {
2778 struct ecm_db_listener_instance *lin;
2779 if (li->mapping_removed) {
2780 li->mapping_removed(li->arg, mi);
2781 }
2782
2783 /*
2784 * Get next listener
2785 */
2786 lin = ecm_db_listener_get_and_ref_next(li);
2787 ecm_db_listener_deref(li);
2788 li = lin;
2789 }
2790 }
2791
2792 /*
2793 * Throw final event
2794 */
2795 if (mi->final) {
2796 mi->final(mi->arg);
2797 }
2798
2799 /*
2800 * Now release the host instance if the mapping had one
2801 */
2802 if (mi->host) {
2803 ecm_db_host_deref(mi->host);
2804 }
2805
2806 /*
2807 * We can now destroy the instance
2808 */
2809 DEBUG_CLEAR_MAGIC(mi);
2810 kfree(mi);
2811
2812 /*
2813 * Decrease global mapping count
2814 */
2815 spin_lock_bh(&ecm_db_lock);
2816 ecm_db_mapping_count--;
2817 DEBUG_ASSERT(ecm_db_mapping_count >= 0, "%p: mapping count wrap\n", mi);
Ben Menchaca84f36632014-02-28 20:57:38 +00002818 spin_unlock_bh(&ecm_db_lock);
2819
Ben Menchaca84f36632014-02-28 20:57:38 +00002820 return 0;
2821}
2822EXPORT_SYMBOL(ecm_db_mapping_deref);
2823
2824/*
2825 * ecm_db_host_deref()
2826 * Release a ref to a host instance, possibly causing removal from the database and destruction of the instance
2827 */
2828int ecm_db_host_deref(struct ecm_db_host_instance *hi)
2829{
2830 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
2831
2832 spin_lock_bh(&ecm_db_lock);
2833 hi->refs--;
2834 DEBUG_TRACE("%p: host deref %d\n", hi, hi->refs);
2835 DEBUG_ASSERT(hi->refs >= 0, "%p: ref wrap\n", hi);
2836
2837 if (hi->refs > 0) {
2838 int refs = hi->refs;
2839 spin_unlock_bh(&ecm_db_lock);
2840 return refs;
2841 }
2842
2843 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
2844
2845 /*
2846 * Remove from database if inserted
2847 */
2848 if (!hi->flags & ECM_DB_HOST_FLAGS_INSERTED) {
2849 spin_unlock_bh(&ecm_db_lock);
2850 } else {
2851 struct ecm_db_listener_instance *li;
2852
2853 /*
2854 * Remove from the global list
2855 */
2856 if (!hi->prev) {
2857 DEBUG_ASSERT(ecm_db_hosts == hi, "%p: host table bad\n", hi);
2858 ecm_db_hosts = hi->next;
2859 } else {
2860 hi->prev->next = hi->next;
2861 }
2862 if (hi->next) {
2863 hi->next->prev = hi->prev;
2864 }
2865
2866 /*
2867 * Unlink it from the host hash table
2868 */
2869 if (!hi->hash_prev) {
2870 DEBUG_ASSERT(ecm_db_host_table[hi->hash_index] == hi, "%p: hash table bad\n", hi);
2871 ecm_db_host_table[hi->hash_index] = hi->hash_next;
2872 } else {
2873 hi->hash_prev->hash_next = hi->hash_next;
2874 }
2875 if (hi->hash_next) {
2876 hi->hash_next->hash_prev = hi->hash_prev;
2877 }
2878 hi->hash_next = NULL;
2879 hi->hash_prev = NULL;
2880 ecm_db_host_table_lengths[hi->hash_index]--;
2881 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]);
2882
Ben Menchaca84f36632014-02-28 20:57:38 +00002883 spin_unlock_bh(&ecm_db_lock);
2884
2885 /*
2886 * Throw removed event to listeners
2887 */
2888 DEBUG_TRACE("%p: Throw host removed event\n", hi);
2889 li = ecm_db_listeners_get_and_ref_first();
2890 while (li) {
2891 struct ecm_db_listener_instance *lin;
2892 if (li->host_removed) {
2893 li->host_removed(li->arg, hi);
2894 }
2895
2896 /*
2897 * Get next listener
2898 */
2899 lin = ecm_db_listener_get_and_ref_next(li);
2900 ecm_db_listener_deref(li);
2901 li = lin;
2902 }
2903 }
2904
2905 /*
2906 * Throw final event
2907 */
2908 if (hi->final) {
2909 hi->final(hi->arg);
2910 }
2911
2912 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00002913 * We can now destroy the instance
2914 */
2915 DEBUG_CLEAR_MAGIC(hi);
2916 kfree(hi);
2917
2918 /*
2919 * Decrease global host count
2920 */
2921 spin_lock_bh(&ecm_db_lock);
2922 ecm_db_host_count--;
2923 DEBUG_ASSERT(ecm_db_host_count >= 0, "%p: host count wrap\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00002924 spin_unlock_bh(&ecm_db_lock);
2925
Ben Menchaca84f36632014-02-28 20:57:38 +00002926 return 0;
2927}
2928EXPORT_SYMBOL(ecm_db_host_deref);
2929
2930/*
2931 * ecm_db_node_deref()
2932 * Deref a node. Removing it on the last ref and destroying it.
2933 */
2934int ecm_db_node_deref(struct ecm_db_node_instance *ni)
2935{
2936 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
2937
2938 spin_lock_bh(&ecm_db_lock);
2939 ni->refs--;
2940 DEBUG_TRACE("%p: node deref %d\n", ni, ni->refs);
2941 DEBUG_ASSERT(ni->refs >= 0, "%p: ref wrap\n", ni);
2942
2943 if (ni->refs > 0) {
2944 int refs = ni->refs;
2945 spin_unlock_bh(&ecm_db_lock);
2946 return refs;
2947 }
2948
Gareth Williams90f2a282014-08-27 15:56:25 +01002949 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
2950 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
2951 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
2952 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 +00002953
2954 /*
2955 * Remove from database if inserted
2956 */
2957 if (!ni->flags & ECM_DB_NODE_FLAGS_INSERTED) {
2958 spin_unlock_bh(&ecm_db_lock);
2959 } else {
2960 struct ecm_db_listener_instance *li;
2961
2962 /*
2963 * Remove from the global list
2964 */
2965 if (!ni->prev) {
2966 DEBUG_ASSERT(ecm_db_nodes == ni, "%p: node table bad\n", ni);
2967 ecm_db_nodes = ni->next;
2968 } else {
2969 ni->prev->next = ni->next;
2970 }
2971 if (ni->next) {
2972 ni->next->prev = ni->prev;
2973 }
2974
2975 /*
2976 * Link out of hash table
2977 */
2978 if (!ni->hash_prev) {
2979 DEBUG_ASSERT(ecm_db_node_table[ni->hash_index] == ni, "%p: hash table bad\n", ni);
2980 ecm_db_node_table[ni->hash_index] = ni->hash_next;
2981 } else {
2982 ni->hash_prev->hash_next = ni->hash_next;
2983 }
2984 if (ni->hash_next) {
2985 ni->hash_next->hash_prev = ni->hash_prev;
2986 }
2987 ni->hash_next = NULL;
2988 ni->hash_prev = NULL;
2989 ecm_db_node_table_lengths[ni->hash_index]--;
2990 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]);
2991
2992 /*
2993 * Unlink it from the iface node list
2994 */
2995 if (!ni->node_prev) {
2996 DEBUG_ASSERT(ni->iface->nodes == ni, "%p: nodes table bad\n", ni);
2997 ni->iface->nodes = ni->node_next;
2998 } else {
2999 ni->node_prev->node_next = ni->node_next;
3000 }
3001 if (ni->node_next) {
3002 ni->node_next->node_prev = ni->node_prev;
3003 }
3004 ni->node_next = NULL;
3005 ni->node_prev = NULL;
3006 ni->iface->node_count--;
3007 spin_unlock_bh(&ecm_db_lock);
3008
3009 /*
3010 * Throw removed event to listeners
3011 */
3012 DEBUG_TRACE("%p: Throw node removed event\n", ni);
3013 li = ecm_db_listeners_get_and_ref_first();
3014 while (li) {
3015 struct ecm_db_listener_instance *lin;
3016 if (li->node_removed) {
3017 li->node_removed(li->arg, ni);
3018 }
3019
3020 /*
3021 * Get next listener
3022 */
3023 lin = ecm_db_listener_get_and_ref_next(li);
3024 ecm_db_listener_deref(li);
3025 li = lin;
3026 }
3027 }
3028
3029 /*
3030 * Throw final event
3031 */
3032 if (ni->final) {
3033 ni->final(ni->arg);
3034 }
3035
3036 /*
3037 * Now release the iface instance if the node had one
3038 */
3039 if (ni->iface) {
3040 ecm_db_iface_deref(ni->iface);
3041 }
3042
3043 /*
3044 * We can now destroy the instance
3045 */
3046 DEBUG_CLEAR_MAGIC(ni);
3047 kfree(ni);
3048
3049 /*
3050 * Decrease global node count
3051 */
3052 spin_lock_bh(&ecm_db_lock);
3053 ecm_db_node_count--;
3054 DEBUG_ASSERT(ecm_db_node_count >= 0, "%p: node count wrap\n", ni);
Ben Menchaca84f36632014-02-28 20:57:38 +00003055 spin_unlock_bh(&ecm_db_lock);
3056
Ben Menchaca84f36632014-02-28 20:57:38 +00003057 return 0;
3058}
3059EXPORT_SYMBOL(ecm_db_node_deref);
3060
3061/*
3062 * ecm_db_iface_deref()
3063 * Deref a interface instance, removing it from the database on the last ref release
3064 */
3065int ecm_db_iface_deref(struct ecm_db_iface_instance *ii)
3066{
3067 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
3068
3069 /*
3070 * Decrement reference count
3071 */
3072 spin_lock_bh(&ecm_db_lock);
3073 ii->refs--;
3074 DEBUG_TRACE("%p: iface deref %d\n", ii, ii->refs);
3075 DEBUG_ASSERT(ii->refs >= 0, "%p: ref wrap\n", ii);
3076
3077 if (ii->refs > 0) {
3078 int refs = ii->refs;
3079 spin_unlock_bh(&ecm_db_lock);
3080 return refs;
3081 }
3082
3083 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
3084
3085 /*
3086 * Remove from database if inserted
3087 */
3088 if (!ii->flags & ECM_DB_IFACE_FLAGS_INSERTED) {
3089 spin_unlock_bh(&ecm_db_lock);
3090 } else {
3091 struct ecm_db_listener_instance *li;
3092
3093 /*
3094 * Remove from the global list
3095 */
3096 if (!ii->prev) {
3097 DEBUG_ASSERT(ecm_db_interfaces == ii, "%p: interface table bad\n", ii);
3098 ecm_db_interfaces = ii->next;
3099 } else {
3100 ii->prev->next = ii->next;
3101 }
3102 if (ii->next) {
3103 ii->next->prev = ii->prev;
3104 }
3105
3106 /*
3107 * Link out of hash table
3108 */
3109 if (!ii->hash_prev) {
3110 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);
3111 ecm_db_iface_table[ii->hash_index] = ii->hash_next;
3112 } else {
3113 ii->hash_prev->hash_next = ii->hash_next;
3114 }
3115 if (ii->hash_next) {
3116 ii->hash_next->hash_prev = ii->hash_prev;
3117 }
3118 ii->hash_next = NULL;
3119 ii->hash_prev = NULL;
3120 ecm_db_iface_table_lengths[ii->hash_index]--;
3121 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]);
3122 spin_unlock_bh(&ecm_db_lock);
3123
3124 /*
3125 * Throw removed event to listeners
3126 */
3127 DEBUG_TRACE("%p: Throw iface removed event\n", ii);
3128 li = ecm_db_listeners_get_and_ref_first();
3129 while (li) {
3130 struct ecm_db_listener_instance *lin;
3131 if (li->iface_removed) {
3132 li->iface_removed(li->arg, ii);
3133 }
3134
3135 /*
3136 * Get next listener
3137 */
3138 lin = ecm_db_listener_get_and_ref_next(li);
3139 ecm_db_listener_deref(li);
3140 li = lin;
3141 }
3142 }
3143
3144 /*
3145 * Throw final event
3146 */
3147 if (ii->final) {
3148 ii->final(ii->arg);
3149 }
3150
3151 /*
3152 * We can now destroy the instance
3153 */
3154 DEBUG_CLEAR_MAGIC(ii);
3155 kfree(ii);
3156
3157 /*
3158 * Decrease global interface count
3159 */
3160 spin_lock_bh(&ecm_db_lock);
3161 ecm_db_iface_count--;
3162 DEBUG_ASSERT(ecm_db_iface_count >= 0, "%p: iface count wrap\n", ii);
Ben Menchaca84f36632014-02-28 20:57:38 +00003163 spin_unlock_bh(&ecm_db_lock);
3164
Ben Menchaca84f36632014-02-28 20:57:38 +00003165 return 0;
3166}
3167EXPORT_SYMBOL(ecm_db_iface_deref);
3168
3169/*
3170 * ecm_db_listener_deref()
3171 * Release reference to listener.
3172 *
3173 * On final reference release listener shall be removed from the database.
3174 */
3175int ecm_db_listener_deref(struct ecm_db_listener_instance *li)
3176{
3177 struct ecm_db_listener_instance *cli;
3178 struct ecm_db_listener_instance **cli_prev;
3179
3180 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed", li);
3181
3182 spin_lock_bh(&ecm_db_lock);
3183 li->refs--;
3184 DEBUG_ASSERT(li->refs >= 0, "%p: ref wrap\n", li);
3185 if (li->refs > 0) {
3186 int refs;
3187 refs = li->refs;
3188 spin_unlock_bh(&ecm_db_lock);
3189 return refs;
3190 }
3191
3192 /*
3193 * Instance is to be removed and destroyed.
3194 * Link the listener out of the listener list.
3195 */
3196 cli = ecm_db_listeners;
3197 cli_prev = &ecm_db_listeners;
3198 while (cli) {
3199 if (cli == li) {
3200 *cli_prev = cli->next;
3201 break;
3202 }
3203 cli_prev = &cli->next;
3204 cli = cli->next;
3205 }
3206 DEBUG_ASSERT(cli, "%p: not found\n", li);
3207 spin_unlock_bh(&ecm_db_lock);
3208
3209 /*
3210 * Invoke final callback
3211 */
3212 if (li->final) {
3213 li->final(li->arg);
3214 }
3215 DEBUG_CLEAR_MAGIC(li);
3216 kfree(li);
3217
3218 /*
3219 * Decrease global listener count
3220 */
3221 spin_lock_bh(&ecm_db_lock);
3222 ecm_db_listeners_count--;
3223 DEBUG_ASSERT(ecm_db_listeners_count >= 0, "%p: listener count wrap\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00003224 spin_unlock_bh(&ecm_db_lock);
3225
Ben Menchaca84f36632014-02-28 20:57:38 +00003226 return 0;
3227}
3228EXPORT_SYMBOL(ecm_db_listener_deref);
3229
3230/*
3231 * ecm_db_connection_defunct_all()
3232 * Make defunct ALL connections.
3233 *
3234 * This API is typically used in shutdown situations commanded by the user.
3235 * NOTE: Ensure all front ends are stopped to avoid further connections being created while this is running.
3236 */
3237void ecm_db_connection_defunct_all(void)
3238{
3239 struct ecm_db_connection_instance *ci;
3240
3241 DEBUG_INFO("Defuncting all\n");
3242
3243 /*
3244 * Iterate all connections
3245 */
3246 ci = ecm_db_connections_get_and_ref_first();
3247 while (ci) {
3248 struct ecm_db_connection_instance *cin;
3249
3250 DEBUG_TRACE("%p: defunct\n", ci);
3251 ecm_db_connection_make_defunct(ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303252
Ben Menchaca84f36632014-02-28 20:57:38 +00003253 cin = ecm_db_connection_get_and_ref_next(ci);
3254 ecm_db_connection_deref(ci);
3255 ci = cin;
3256 }
3257 DEBUG_INFO("Defuncting complete\n");
3258}
3259EXPORT_SYMBOL(ecm_db_connection_defunct_all);
3260
3261/*
3262 * ecm_db_connection_generate_hash_index()
3263 * Calculate the hash index.
3264 *
3265 * Note: The hash we produce is symmetric - i.e. we can swap the "from" and "to"
3266 * details without generating a different hash index!
3267 */
3268static 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)
3269{
3270 uint32_t temp;
3271 uint32_t hash_val;
3272
3273 /*
3274 * The hash function only uses both host 1 address/port, host 2 address/port
3275 * and protocol fields.
3276 */
3277 temp = (u32)host1_addr[0] + host1_port + (u32)host2_addr[0] + host2_port + (uint32_t)protocol;
3278 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3279
3280 return (ecm_db_connection_hash_t)(hash_val & (ECM_DB_CONNECTION_HASH_SLOTS - 1));
3281}
3282
3283/*
3284 * ecm_db_connection_generate_serial_hash_index()
3285 * Calculate the serial hash index.
3286 */
3287static inline ecm_db_connection_serial_hash_t ecm_db_connection_generate_serial_hash_index(uint32_t serial)
3288{
3289 return (ecm_db_connection_serial_hash_t)(serial & (ECM_DB_CONNECTION_SERIAL_HASH_SLOTS - 1));
3290}
3291
3292/*
3293 * ecm_db_mapping_generate_hash_index()
3294 * Calculate the hash index.
3295 */
3296static inline ecm_db_mapping_hash_t ecm_db_mapping_generate_hash_index(ip_addr_t address, uint32_t port)
3297{
3298 uint32_t temp;
3299 uint32_t hash_val;
3300
3301 temp = (u32)address[0] + port;
3302 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3303
3304 return (ecm_db_mapping_hash_t)(hash_val & (ECM_DB_MAPPING_HASH_SLOTS - 1));
3305}
3306
3307/*
3308 * ecm_db_host_generate_hash_index()
3309 * Calculate the hash index.
3310 */
3311static inline ecm_db_host_hash_t ecm_db_host_generate_hash_index(ip_addr_t address)
3312{
3313 uint32_t temp;
3314 uint32_t hash_val;
3315
3316 temp = (uint32_t)address[0];
3317 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3318
3319 return (ecm_db_host_hash_t)(hash_val & (ECM_DB_HOST_HASH_SLOTS - 1));
3320}
3321
3322/*
3323 * ecm_db_node_generate_hash_index()
3324 * Calculate the hash index.
3325 */
3326static inline ecm_db_node_hash_t ecm_db_node_generate_hash_index(uint8_t *address)
3327{
3328 uint32_t hash_val;
3329
3330 hash_val = (((uint32_t)(address[2] ^ address[4])) << 8) | (address[3] ^ address[5]);
3331 hash_val &= (ECM_DB_NODE_HASH_SLOTS - 1);
3332
3333 return (ecm_db_node_hash_t)hash_val;
3334}
3335
3336/*
3337 * ecm_db_iface_generate_hash_index_sit()
3338 * Calculate the hash index.
3339 */
3340static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_sit(ip_addr_t saddr, ip_addr_t daddr)
3341{
3342 uint32_t temp;
3343 uint32_t hash_val;
3344
3345 temp = (uint32_t )(saddr[0] ^ daddr[0]);
3346 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3347 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3348}
3349
3350/*
3351 * ecm_db_iface_generate_hash_index_tunipip6()
3352 * Calculate the hash index.
3353 */
3354static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
3355{
3356 uint32_t temp;
3357 uint32_t hash_val;
3358
3359 temp = (uint32_t )(saddr[0] ^ daddr[0]);
3360 hash_val = (temp >> 24) ^ (temp >> 16) ^ (temp >> 8) ^ temp;
3361 return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
3362}
3363
3364/*
3365 * ecm_db_iface_generate_hash_index_ethernet()
3366 * Calculate the hash index.
3367 */
3368static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ethernet(uint8_t *address)
3369{
3370 return (ecm_db_iface_hash_t)(address[5] & (ECM_DB_IFACE_HASH_SLOTS - 1));
3371}
3372
3373/*
3374 * ecm_db_iface_generate_hash_index_pppoe()
3375 * Calculate the hash index.
3376 */
3377static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_pppoe(uint16_t pppoe_session_id)
3378{
3379 return (ecm_db_iface_hash_t)(pppoe_session_id & (ECM_DB_IFACE_HASH_SLOTS - 1));
3380}
3381
3382/*
3383 * ecm_db_iface_generate_hash_index_unknown()
3384 * Calculate the hash index.
3385 */
3386static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_unknown(uint32_t os_specific_ident)
3387{
3388 return (ecm_db_iface_hash_t)(os_specific_ident & (ECM_DB_IFACE_HASH_SLOTS - 1));
3389}
3390
3391/*
3392 * ecm_db_iface_generate_hash_index_loopback()
3393 * Calculate the hash index.
3394 */
3395static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_loopback(uint32_t os_specific_ident)
3396{
3397 return (ecm_db_iface_hash_t)(os_specific_ident & (ECM_DB_IFACE_HASH_SLOTS - 1));
3398}
3399
3400/*
3401 * ecm_db_iface_generate_hash_index_ipsec_tunnel()
3402 * Calculate the hash index.
3403 * GGG TODO Flesh this out using actual tunnel endpoint keys
3404 */
3405static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_ipsec_tunnel(uint32_t os_specific_ident)
3406{
3407 return (ecm_db_iface_hash_t)(os_specific_ident & (ECM_DB_IFACE_HASH_SLOTS - 1));
3408}
3409
3410/*
3411 * ecm_db_host_find_and_ref()
3412 * Lookup and return a host reference if any
3413 */
3414struct ecm_db_host_instance *ecm_db_host_find_and_ref(ip_addr_t address)
3415{
3416 ecm_db_host_hash_t hash_index;
3417 struct ecm_db_host_instance *hi;
3418
3419 DEBUG_TRACE("Lookup host with addr " ECM_IP_ADDR_OCTAL_FMT "\n", ECM_IP_ADDR_TO_OCTAL(address));
3420
3421 /*
3422 * Compute the hash chain index and prepare to walk the chain
3423 */
3424 hash_index = ecm_db_host_generate_hash_index(address);
3425
3426 /*
3427 * Iterate the chain looking for a host with matching details
3428 */
3429 spin_lock_bh(&ecm_db_lock);
3430 hi = ecm_db_host_table[hash_index];
3431 while (hi) {
3432 if (!ECM_IP_ADDR_MATCH(hi->address, address)) {
3433 hi = hi->hash_next;
3434 continue;
3435 }
3436
3437 _ecm_db_host_ref(hi);
3438 spin_unlock_bh(&ecm_db_lock);
3439 DEBUG_TRACE("host found %p\n", hi);
3440 return hi;
3441 }
3442 spin_unlock_bh(&ecm_db_lock);
3443 DEBUG_TRACE("Host not found\n");
3444 return NULL;
3445}
3446EXPORT_SYMBOL(ecm_db_host_find_and_ref);
3447
3448/*
3449 * ecm_db_node_find_and_ref()
3450 * Lookup and return a node reference if any
3451 */
3452struct ecm_db_node_instance *ecm_db_node_find_and_ref(uint8_t *address)
3453{
3454 ecm_db_node_hash_t hash_index;
3455 struct ecm_db_node_instance *ni;
3456
3457 DEBUG_TRACE("Lookup node with addr %pM\n", address);
3458
3459 /*
3460 * Compute the hash chain index and prepare to walk the chain
3461 */
3462 hash_index = ecm_db_node_generate_hash_index(address);
3463
3464 /*
3465 * Iterate the chain looking for a host with matching details
3466 */
3467 spin_lock_bh(&ecm_db_lock);
3468 ni = ecm_db_node_table[hash_index];
3469 while (ni) {
3470 if (memcmp(ni->address, address, ETH_ALEN)) {
3471 ni = ni->hash_next;
3472 continue;
3473 }
3474
3475 _ecm_db_node_ref(ni);
3476 spin_unlock_bh(&ecm_db_lock);
3477 DEBUG_TRACE("node found %p\n", ni);
3478 return ni;
3479 }
3480 spin_unlock_bh(&ecm_db_lock);
3481 DEBUG_TRACE("Node not found\n");
3482 return NULL;
3483}
3484EXPORT_SYMBOL(ecm_db_node_find_and_ref);
3485
3486/*
3487 * ecm_db_iface_ethernet_address_get()
3488 * Obtain the ethernet address for an ethernet interface
3489 */
3490void ecm_db_iface_ethernet_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
3491{
3492 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3493 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_ETHERNET, "%p: Bad type, expected ethernet, actual: %d\n", ii, ii->type);
3494 spin_lock_bh(&ecm_db_lock);
3495 memcpy(address, ii->type_info.ethernet.address, sizeof(ii->type_info.ethernet.address));
3496 spin_unlock_bh(&ecm_db_lock);
3497}
3498EXPORT_SYMBOL(ecm_db_iface_ethernet_address_get);
3499
3500/*
Gareth Williams83125b12014-05-26 19:58:09 +01003501 * ecm_db_iface_bridge_address_get()
3502 * Obtain the ethernet address for a bridge interface
3503 */
3504void ecm_db_iface_bridge_address_get(struct ecm_db_iface_instance *ii, uint8_t *address)
3505{
3506 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3507 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_BRIDGE, "%p: Bad type, expected bridge, actual: %d\n", ii, ii->type);
3508 spin_lock_bh(&ecm_db_lock);
3509 memcpy(address, ii->type_info.bridge.address, sizeof(ii->type_info.bridge.address));
3510 spin_unlock_bh(&ecm_db_lock);
3511}
3512EXPORT_SYMBOL(ecm_db_iface_bridge_address_get);
3513
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05303514struct 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 +00003515{
3516 ecm_db_iface_hash_t hash_index;
3517 struct ecm_db_iface_instance *ii;
3518
3519 DEBUG_TRACE("Lookup ethernet iface with addr %pM\n", address);
3520
3521 /*
3522 * Compute the hash chain index and prepare to walk the chain
3523 */
3524 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3525
3526 /*
3527 * Iterate the chain looking for a host with matching details
3528 */
3529 spin_lock_bh(&ecm_db_lock);
3530 ii = ecm_db_iface_table[hash_index];
3531 while (ii) {
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05303532 if ((ii->type != ECM_DB_IFACE_TYPE_ETHERNET)
3533 || memcmp(ii->type_info.ethernet.address, address, ETH_ALEN)
3534 || ii->interface_identifier != ifidx) {
Ben Menchaca84f36632014-02-28 20:57:38 +00003535 ii = ii->hash_next;
3536 continue;
3537 }
3538
3539 _ecm_db_iface_ref(ii);
3540 spin_unlock_bh(&ecm_db_lock);
3541 DEBUG_TRACE("iface found %p\n", ii);
3542 return ii;
3543 }
3544 spin_unlock_bh(&ecm_db_lock);
3545 DEBUG_TRACE("Iface not found\n");
3546 return NULL;
3547}
Tushar Mathur4ab0bf92014-06-10 20:37:07 +05303548EXPORT_SYMBOL(ecm_db_iface_ifidx_find_and_ref_ethernet);
3549
3550
Ben Menchaca84f36632014-02-28 20:57:38 +00003551
3552/*
3553 * ecm_db_iface_vlan_info_get()
3554 * Get vlan interface specific information
3555 */
3556void ecm_db_iface_vlan_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_vlan *vlan_info)
3557{
3558 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3559 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_VLAN, "%p: Bad type, expected vlan, actual: %d\n", ii, ii->type);
3560 spin_lock_bh(&ecm_db_lock);
3561 memcpy(vlan_info->address, ii->type_info.vlan.address, sizeof(ii->type_info.vlan.address));
3562 vlan_info->vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303563 vlan_info->vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00003564 spin_unlock_bh(&ecm_db_lock);
3565}
3566EXPORT_SYMBOL(ecm_db_iface_vlan_info_get);
3567
3568/*
3569 * ecm_db_iface_find_and_ref_vlan()
3570 * Lookup and return a iface reference if any
3571 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05303572struct 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 +00003573{
3574 ecm_db_iface_hash_t hash_index;
3575 struct ecm_db_iface_instance *ii;
3576
Sol Kavyd7583592014-06-05 18:51:46 -07003577 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 +00003578
3579 /*
3580 * Compute the hash chain index and prepare to walk the chain
3581 */
3582 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3583
3584 /*
3585 * Iterate the chain looking for a host with matching details
3586 */
3587 spin_lock_bh(&ecm_db_lock);
3588 ii = ecm_db_iface_table[hash_index];
3589 while (ii) {
3590 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 +05303591 || (ii->type_info.vlan.vlan_tpid != vlan_tpid)
Ben Menchaca84f36632014-02-28 20:57:38 +00003592 || memcmp(ii->type_info.vlan.address, address, ETH_ALEN)) {
3593 ii = ii->hash_next;
3594 continue;
3595 }
3596
3597 _ecm_db_iface_ref(ii);
3598 spin_unlock_bh(&ecm_db_lock);
3599 DEBUG_TRACE("iface found %p\n", ii);
3600 return ii;
3601 }
3602 spin_unlock_bh(&ecm_db_lock);
3603 DEBUG_TRACE("Iface not found\n");
3604 return NULL;
3605}
3606EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
3607
3608/*
3609 * ecm_db_iface_find_and_ref_bridge()
3610 * Lookup and return a iface reference if any
3611 */
3612struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_bridge(uint8_t *address)
3613{
3614 ecm_db_iface_hash_t hash_index;
3615 struct ecm_db_iface_instance *ii;
3616
3617 DEBUG_TRACE("Lookup bridge iface with addr %pM\n", address);
3618
3619 /*
3620 * Compute the hash chain index and prepare to walk the chain
3621 */
3622 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3623
3624 /*
3625 * Iterate the chain looking for a host with matching details
3626 */
3627 spin_lock_bh(&ecm_db_lock);
3628 ii = ecm_db_iface_table[hash_index];
3629 while (ii) {
3630 if ((ii->type != ECM_DB_IFACE_TYPE_BRIDGE) || memcmp(ii->type_info.bridge.address, address, ETH_ALEN)) {
3631 ii = ii->hash_next;
3632 continue;
3633 }
3634
3635 _ecm_db_iface_ref(ii);
3636 spin_unlock_bh(&ecm_db_lock);
3637 DEBUG_TRACE("iface found %p\n", ii);
3638 return ii;
3639 }
3640 spin_unlock_bh(&ecm_db_lock);
3641 DEBUG_TRACE("Iface not found\n");
3642 return NULL;
3643}
3644EXPORT_SYMBOL(ecm_db_iface_find_and_ref_bridge);
3645
3646/*
3647 * ecm_db_iface_find_and_ref_lag()
3648 * Lookup and return a iface reference if any
3649 */
3650struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_lag(uint8_t *address)
3651{
3652 ecm_db_iface_hash_t hash_index;
3653 struct ecm_db_iface_instance *ii;
3654
3655 DEBUG_TRACE("Lookup lag iface with addr %pM\n", address);
3656
3657 /*
3658 * Compute the hash chain index and prepare to walk the chain
3659 */
3660 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
3661
3662 /*
3663 * Iterate the chain looking for a host with matching details
3664 */
3665 spin_lock_bh(&ecm_db_lock);
3666 ii = ecm_db_iface_table[hash_index];
3667 while (ii) {
3668 if ((ii->type != ECM_DB_IFACE_TYPE_LAG) || memcmp(ii->type_info.lag.address, address, ETH_ALEN)) {
3669 ii = ii->hash_next;
3670 continue;
3671 }
3672
3673 _ecm_db_iface_ref(ii);
3674 spin_unlock_bh(&ecm_db_lock);
3675 DEBUG_TRACE("iface found %p\n", ii);
3676 return ii;
3677 }
3678 spin_unlock_bh(&ecm_db_lock);
3679 DEBUG_TRACE("Iface not found\n");
3680 return NULL;
3681}
3682EXPORT_SYMBOL(ecm_db_iface_find_and_ref_lag);
3683
3684/*
3685 * ecm_db_iface_pppoe_session_info_get()
3686 * Get vlan interface specific information
3687 */
3688void ecm_db_iface_pppoe_session_info_get(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_pppoe *pppoe_info)
3689{
3690 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
3691 DEBUG_ASSERT(ii->type == ECM_DB_IFACE_TYPE_PPPOE, "%p: Bad type, expected pppoe, actual: %d\n", ii, ii->type);
3692 spin_lock_bh(&ecm_db_lock);
3693 memcpy(pppoe_info->remote_mac, ii->type_info.pppoe.remote_mac, sizeof(ii->type_info.pppoe.remote_mac));
3694 pppoe_info->pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
3695 spin_unlock_bh(&ecm_db_lock);
3696}
3697EXPORT_SYMBOL(ecm_db_iface_pppoe_session_info_get);
3698
3699/*
3700 * ecm_db_iface_find_and_ref_pppoe()
3701 * Lookup and return a iface reference if any
3702 */
3703struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_pppoe(uint16_t pppoe_session_id, uint8_t *remote_mac)
3704{
3705 ecm_db_iface_hash_t hash_index;
3706 struct ecm_db_iface_instance *ii;
3707
3708 DEBUG_TRACE("Lookup pppoe iface with addr %x\n", pppoe_session_id);
3709
3710 /*
3711 * Compute the hash chain index and prepare to walk the chain
3712 */
3713 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
3714
3715 /*
3716 * Iterate the chain looking for a host with matching details
3717 */
3718 spin_lock_bh(&ecm_db_lock);
3719 ii = ecm_db_iface_table[hash_index];
3720 while (ii) {
3721 if ((ii->type != ECM_DB_IFACE_TYPE_PPPOE)
3722 || (ii->type_info.pppoe.pppoe_session_id != pppoe_session_id)
3723 || memcmp(ii->type_info.pppoe.remote_mac, remote_mac, ETH_ALEN)) {
3724 ii = ii->hash_next;
3725 continue;
3726 }
3727
3728 _ecm_db_iface_ref(ii);
3729 spin_unlock_bh(&ecm_db_lock);
3730 DEBUG_TRACE("iface found %p\n", ii);
3731 return ii;
3732 }
3733 spin_unlock_bh(&ecm_db_lock);
3734 DEBUG_TRACE("Iface not found\n");
3735 return NULL;
3736}
3737EXPORT_SYMBOL(ecm_db_iface_find_and_ref_pppoe);
3738
3739/*
3740 * ecm_db_iface_find_and_ref_unknown()
3741 * Lookup and return a iface reference if any
3742 */
3743struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_unknown(uint32_t os_specific_ident)
3744{
3745 ecm_db_iface_hash_t hash_index;
3746 struct ecm_db_iface_instance *ii;
3747
3748 DEBUG_TRACE("Lookup unknown iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
3749
3750 /*
3751 * Compute the hash chain index and prepare to walk the chain
3752 */
3753 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
3754
3755 /*
3756 * Iterate the chain looking for a host with matching details
3757 */
3758 spin_lock_bh(&ecm_db_lock);
3759 ii = ecm_db_iface_table[hash_index];
3760 while (ii) {
3761 if ((ii->type != ECM_DB_IFACE_TYPE_UNKNOWN) || (ii->type_info.unknown.os_specific_ident != os_specific_ident)) {
3762 ii = ii->hash_next;
3763 continue;
3764 }
3765
3766 _ecm_db_iface_ref(ii);
3767 spin_unlock_bh(&ecm_db_lock);
3768 DEBUG_TRACE("iface found %p\n", ii);
3769 return ii;
3770 }
3771 spin_unlock_bh(&ecm_db_lock);
3772 DEBUG_TRACE("Iface not found\n");
3773 return NULL;
3774}
3775EXPORT_SYMBOL(ecm_db_iface_find_and_ref_unknown);
3776
3777/*
3778 * ecm_db_iface_find_and_ref_loopback()
3779 * Lookup and return a iface reference if any
3780 */
3781struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_loopback(uint32_t os_specific_ident)
3782{
3783 ecm_db_iface_hash_t hash_index;
3784 struct ecm_db_iface_instance *ii;
3785
3786 DEBUG_TRACE("Lookup loopback iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
3787
3788 /*
3789 * Compute the hash chain index and prepare to walk the chain
3790 */
3791 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
3792
3793 /*
3794 * Iterate the chain looking for a host with matching details
3795 */
3796 spin_lock_bh(&ecm_db_lock);
3797 ii = ecm_db_iface_table[hash_index];
3798 while (ii) {
3799 if ((ii->type != ECM_DB_IFACE_TYPE_LOOPBACK) || (ii->type_info.loopback.os_specific_ident != os_specific_ident)) {
3800 ii = ii->hash_next;
3801 continue;
3802 }
3803
3804 _ecm_db_iface_ref(ii);
3805 spin_unlock_bh(&ecm_db_lock);
3806 DEBUG_TRACE("iface found %p\n", ii);
3807 return ii;
3808 }
3809 spin_unlock_bh(&ecm_db_lock);
3810 DEBUG_TRACE("Iface not found\n");
3811 return NULL;
3812}
3813EXPORT_SYMBOL(ecm_db_iface_find_and_ref_loopback);
3814
3815/*
3816 * ecm_db_iface_find_and_ref_ipsec_tunnel()
3817 * Lookup and return a iface reference if any.
3818 * GGG TODO Flesh this out using tunnel endpoint keys
3819 */
3820struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_ipsec_tunnel(uint32_t os_specific_ident)
3821{
3822 ecm_db_iface_hash_t hash_index;
3823 struct ecm_db_iface_instance *ii;
3824
3825 DEBUG_TRACE("Lookup ipsec_tunnel iface with addr %x (%u)\n", os_specific_ident, os_specific_ident);
3826
3827 /*
3828 * Compute the hash chain index and prepare to walk the chain
3829 */
3830 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
3831
3832 /*
3833 * Iterate the chain looking for a host with matching details
3834 */
3835 spin_lock_bh(&ecm_db_lock);
3836 ii = ecm_db_iface_table[hash_index];
3837 while (ii) {
3838 if ((ii->type != ECM_DB_IFACE_TYPE_IPSEC_TUNNEL) || (ii->type_info.ipsec_tunnel.os_specific_ident != os_specific_ident)) {
3839 ii = ii->hash_next;
3840 continue;
3841 }
3842
3843 _ecm_db_iface_ref(ii);
3844 spin_unlock_bh(&ecm_db_lock);
3845 DEBUG_TRACE("iface found %p\n", ii);
3846 return ii;
3847 }
3848 spin_unlock_bh(&ecm_db_lock);
3849 DEBUG_TRACE("Iface not found\n");
3850 return NULL;
3851}
3852EXPORT_SYMBOL(ecm_db_iface_find_and_ref_ipsec_tunnel);
3853
3854/*
3855 * ecm_db_iface_find_and_ref_sit()
3856 * Lookup and return a iface reference if any
3857 */
3858struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_sit(ip_addr_t saddr, ip_addr_t daddr)
3859{
3860 ecm_db_iface_hash_t hash_index;
3861 struct ecm_db_iface_instance *ii;
3862
3863 DEBUG_TRACE("Lookup sit (6-in-4) iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
3864 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
3865
3866 /*
3867 * Compute the hash chain index and prepare to walk the chain
3868 */
3869 hash_index = ecm_db_iface_generate_hash_index_sit(saddr, daddr);
3870
3871 /*
3872 * Iterate the chain looking for a host with matching details
3873 */
3874 spin_lock_bh(&ecm_db_lock);
3875 ii = ecm_db_iface_table[hash_index];
3876 while (ii) {
3877 if ((ii->type != ECM_DB_IFACE_TYPE_SIT)
3878 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.saddr, saddr)
3879 || !ECM_IP_ADDR_MATCH(ii->type_info.sit.daddr, daddr)) {
3880 ii = ii->hash_next;
3881 continue;
3882 }
3883
3884 _ecm_db_iface_ref(ii);
3885 spin_unlock_bh(&ecm_db_lock);
3886 DEBUG_TRACE("iface found %p\n", ii);
3887 return ii;
3888 }
3889 spin_unlock_bh(&ecm_db_lock);
3890 DEBUG_TRACE("Iface not found\n");
3891 return NULL;
3892}
3893EXPORT_SYMBOL(ecm_db_iface_find_and_ref_sit);
3894
3895/*
3896 * ecm_db_iface_find_and_ref_tunipip6()
3897 * Lookup and return a iface reference if any
3898 */
3899struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_tunipip6(ip_addr_t saddr, ip_addr_t daddr)
3900{
3901 ecm_db_iface_hash_t hash_index;
3902 struct ecm_db_iface_instance *ii;
3903
3904 DEBUG_TRACE("Lookup TUNIPIP6 iface with saddr: " ECM_IP_ADDR_OCTAL_FMT ", daddr: " ECM_IP_ADDR_OCTAL_FMT "\n",
3905 ECM_IP_ADDR_TO_OCTAL(saddr), ECM_IP_ADDR_TO_OCTAL(daddr));
3906
3907 /*
3908 * Compute the hash chain index and prepare to walk the chain
3909 */
3910 hash_index = ecm_db_iface_generate_hash_index_tunipip6(saddr, daddr);
3911
3912 /*
3913 * Iterate the chain looking for a host with matching details
3914 */
3915 spin_lock_bh(&ecm_db_lock);
3916 ii = ecm_db_iface_table[hash_index];
3917 while (ii) {
3918 if ((ii->type != ECM_DB_IFACE_TYPE_TUNIPIP6)
3919 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.saddr, saddr)
3920 || !ECM_IP_ADDR_MATCH(ii->type_info.tunipip6.daddr, daddr)) {
3921 ii = ii->hash_next;
3922 continue;
3923 }
3924
3925 _ecm_db_iface_ref(ii);
3926 spin_unlock_bh(&ecm_db_lock);
3927 DEBUG_TRACE("iface found %p\n", ii);
3928 return ii;
3929 }
3930 spin_unlock_bh(&ecm_db_lock);
3931 DEBUG_TRACE("Iface not found\n");
3932 return NULL;
3933}
3934EXPORT_SYMBOL(ecm_db_iface_find_and_ref_tunipip6);
3935
3936/*
3937 * ecm_db_mapping_find_and_ref()
3938 * Lookup and return a mapping reference if any.
3939 *
3940 * NOTE: For non-port based protocols the ports are expected to be -(protocol)
3941 */
3942struct ecm_db_mapping_instance *ecm_db_mapping_find_and_ref(ip_addr_t address, int port)
3943{
3944 ecm_db_mapping_hash_t hash_index;
3945 struct ecm_db_mapping_instance *mi;
3946
3947 DEBUG_TRACE("Lookup mapping with addr " ECM_IP_ADDR_OCTAL_FMT " and port %d\n", ECM_IP_ADDR_TO_OCTAL(address), port);
3948
3949 /*
3950 * Compute the hash chain index and prepare to walk the chain
3951 */
3952 hash_index = ecm_db_mapping_generate_hash_index(address, port);
3953
3954 /*
3955 * Iterate the chain looking for a mapping with matching details
3956 */
3957 spin_lock_bh(&ecm_db_lock);
3958 mi = ecm_db_mapping_table[hash_index];
3959 while (mi) {
3960 if (mi->port != port) {
3961 mi = mi->hash_next;
3962 continue;
3963 }
3964
3965 if (!ECM_IP_ADDR_MATCH(mi->host->address, address)) {
3966 mi = mi->hash_next;
3967 continue;
3968 }
3969
3970 _ecm_db_mapping_ref(mi);
3971 spin_unlock_bh(&ecm_db_lock);
3972 DEBUG_TRACE("Mapping found %p\n", mi);
3973 return mi;
3974 }
3975 spin_unlock_bh(&ecm_db_lock);
3976 DEBUG_TRACE("Mapping not found\n");
3977 return NULL;
3978}
3979EXPORT_SYMBOL(ecm_db_mapping_find_and_ref);
3980
3981/*
3982 * ecm_db_connection_find_and_ref()
3983 * Locate a connection instance based on addressing, protocol and optional port information.
3984 *
3985 * NOTE: For non-port based protocols then ports are expected to be -(protocol).
3986 */
3987struct 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)
3988{
3989 ecm_db_connection_hash_t hash_index;
3990 struct ecm_db_connection_instance *ci;
3991
3992 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);
3993
3994 /*
3995 * Compute the hash chain index and prepare to walk the chain
3996 */
3997 hash_index = ecm_db_connection_generate_hash_index(host1_addr, host1_port, host2_addr, host2_port, protocol);
3998
3999 /*
4000 * Iterate the chain looking for a connection with matching details
4001 */
4002 spin_lock_bh(&ecm_db_lock);
4003 ci = ecm_db_connection_table[hash_index];
4004 if (ci) {
4005 _ecm_db_connection_ref(ci);
4006 }
4007 spin_unlock_bh(&ecm_db_lock);
4008 while (ci) {
4009 struct ecm_db_connection_instance *cin;
4010
4011 /*
4012 * The use of unlikely() is liberally used because under fast-hit scenarios the connection would always be at the start of a chain
4013 */
4014 if (unlikely(ci->protocol != protocol)) {
4015 goto try_next;
4016 }
4017
4018 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_from->host->address))) {
4019 goto try_reverse;
4020 }
4021
4022 if (unlikely(host1_port != ci->mapping_from->port)) {
4023 goto try_reverse;
4024 }
4025
4026 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_to->host->address))) {
4027 goto try_reverse;
4028 }
4029
4030 if (unlikely(host2_port != ci->mapping_to->port)) {
4031 goto try_reverse;
4032 }
4033
4034 goto connection_found;
4035
4036try_reverse:
4037 if (unlikely(!ECM_IP_ADDR_MATCH(host1_addr, ci->mapping_to->host->address))) {
4038 goto try_next;
4039 }
4040
4041 if (unlikely(host1_port != ci->mapping_to->port)) {
4042 goto try_next;
4043 }
4044
4045 if (unlikely(!ECM_IP_ADDR_MATCH(host2_addr, ci->mapping_from->host->address))) {
4046 goto try_next;
4047 }
4048
4049 if (unlikely(host2_port != ci->mapping_from->port)) {
4050 goto try_next;
4051 }
4052
4053 goto connection_found;
4054
4055try_next:
4056 spin_lock_bh(&ecm_db_lock);
4057 cin = ci->hash_next;
4058 if (cin) {
4059 _ecm_db_connection_ref(cin);
4060 }
4061 spin_unlock_bh(&ecm_db_lock);
4062 ecm_db_connection_deref(ci);
4063 ci = cin;
4064 }
4065 DEBUG_TRACE("Connection not found\n");
4066 return NULL;
4067
4068connection_found:
4069 DEBUG_TRACE("Connection found %p\n", ci);
4070
4071 /*
4072 * Move this connection to the head of the hash chain.
4073 * This will win for us with heavy hit connections - we bubble MRU to the front of the list to
4074 * avoid too much chain walking.
4075 */
4076 spin_lock_bh(&ecm_db_lock);
4077 if (!ci->hash_prev) {
4078 /*
4079 * No prev pointer - ci is at the head of the list already
4080 */
4081 DEBUG_ASSERT(ecm_db_connection_table[hash_index] == ci, "%p: hash table bad\n", ci);
4082 spin_unlock_bh(&ecm_db_lock);
4083 return ci;
4084 }
4085
4086 /*
4087 * Link out
4088 */
4089 ci->hash_prev->hash_next = ci->hash_next;
4090 if (ci->hash_next) {
4091 ci->hash_next->hash_prev = ci->hash_prev;
4092 }
4093
4094 /*
4095 * Re-insert at the head.
4096 * NOTE: We know that there is a head already that is different to ci.
4097 */
4098 ci->hash_next = ecm_db_connection_table[hash_index];
4099 ecm_db_connection_table[hash_index]->hash_prev = ci;
4100 ecm_db_connection_table[hash_index] = ci;
4101 ci->hash_prev = NULL;
4102 spin_unlock_bh(&ecm_db_lock);
4103 return ci;
4104}
4105EXPORT_SYMBOL(ecm_db_connection_find_and_ref);
4106
4107/*
4108 * ecm_db_connection_serial_find_and_ref()
4109 * Locate a connection instance based on serial if it still exists
4110 */
4111struct ecm_db_connection_instance *ecm_db_connection_serial_find_and_ref(uint32_t serial)
4112{
4113 ecm_db_connection_serial_hash_t serial_hash_index;
4114 struct ecm_db_connection_instance *ci;
4115
4116 DEBUG_TRACE("Lookup connection serial: %u\n", serial);
4117
4118 /*
4119 * Compute the hash chain index and prepare to walk the chain
4120 */
4121 serial_hash_index = ecm_db_connection_generate_serial_hash_index(serial);
4122
4123 /*
4124 * Iterate the chain looking for a connection with matching serial
4125 */
4126 spin_lock_bh(&ecm_db_lock);
4127 ci = ecm_db_connection_serial_table[serial_hash_index];
4128 if (ci) {
4129 _ecm_db_connection_ref(ci);
4130 }
4131 spin_unlock_bh(&ecm_db_lock);
4132 while (ci) {
4133 struct ecm_db_connection_instance *cin;
4134
4135 /*
4136 * The use of likely() is used because under fast-hit scenarios the connection would always be at the start of a chain
4137 */
4138 if (likely(ci->serial == serial)) {
4139 goto connection_found;
4140 }
4141
4142 /*
4143 * Try next
4144 */
4145 spin_lock_bh(&ecm_db_lock);
4146 cin = ci->serial_hash_next;
4147 if (cin) {
4148 _ecm_db_connection_ref(cin);
4149 }
4150 spin_unlock_bh(&ecm_db_lock);
4151 ecm_db_connection_deref(ci);
4152 ci = cin;
4153 }
4154 DEBUG_TRACE("Connection not found\n");
4155 return NULL;
4156
4157connection_found:
4158 DEBUG_TRACE("Connection found %p\n", ci);
4159
4160 /*
4161 * Move this connection to the head of the hash chain.
4162 * This will win for us with heavy hit connections - we bubble MRU to the front of the list to
4163 * avoid too much chain walking.
4164 */
4165 spin_lock_bh(&ecm_db_lock);
4166 if (!ci->serial_hash_prev) {
4167 /*
4168 * No prev pointer - ci is at the head of the list already
4169 */
4170 DEBUG_ASSERT(ecm_db_connection_serial_table[serial_hash_index] == ci, "%p: hash table bad\n", ci);
4171 spin_unlock_bh(&ecm_db_lock);
4172 return ci;
4173 }
4174
4175 /*
4176 * Link out
4177 */
4178 ci->serial_hash_prev->serial_hash_next = ci->serial_hash_next;
4179 if (ci->serial_hash_next) {
4180 ci->serial_hash_next->serial_hash_prev = ci->serial_hash_prev;
4181 }
4182
4183 /*
4184 * Re-insert at the head.
4185 * NOTE: We know that there is a head already that is different to ci.
4186 */
4187 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
4188 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
4189 ecm_db_connection_serial_table[serial_hash_index] = ci;
4190 ci->serial_hash_prev = NULL;
4191 spin_unlock_bh(&ecm_db_lock);
4192 return ci;
4193}
4194EXPORT_SYMBOL(ecm_db_connection_serial_find_and_ref);
4195
4196/*
4197 * ecm_db_mapping_connections_from_get_and_ref_first()
4198 * Return a reference to the first connection made from this mapping
4199 */
4200struct ecm_db_connection_instance *ecm_db_mapping_connections_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4201{
4202 struct ecm_db_connection_instance *ci;
4203
4204 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4205
4206 spin_lock_bh(&ecm_db_lock);
4207 ci = mi->from_connections;
4208 if (ci) {
4209 _ecm_db_connection_ref(ci);
4210 }
4211 spin_unlock_bh(&ecm_db_lock);
4212
4213 return ci;
4214}
4215EXPORT_SYMBOL(ecm_db_mapping_connections_from_get_and_ref_first);
4216
4217/*
4218 * ecm_db_mapping_connections_to_get_and_ref_first()
4219 * Return a reference to the first connection made to this mapping
4220 */
4221struct ecm_db_connection_instance *ecm_db_mapping_connections_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4222{
4223 struct ecm_db_connection_instance *ci;
4224
4225 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4226
4227 spin_lock_bh(&ecm_db_lock);
4228 ci = mi->to_connections;
4229 if (ci) {
4230 _ecm_db_connection_ref(ci);
4231 }
4232 spin_unlock_bh(&ecm_db_lock);
4233
4234 return ci;
4235}
4236EXPORT_SYMBOL(ecm_db_mapping_connections_to_get_and_ref_first);
4237
4238/*
4239 * ecm_db_mapping_connections_nat_from_get_and_ref_first()
4240 * Return a reference to the first NAT connection made from this mapping
4241 */
4242struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_from_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4243{
4244 struct ecm_db_connection_instance *ci;
4245
4246 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4247
4248 spin_lock_bh(&ecm_db_lock);
4249 ci = mi->from_nat_connections;
4250 if (ci) {
4251 _ecm_db_connection_ref(ci);
4252 }
4253 spin_unlock_bh(&ecm_db_lock);
4254
4255 return ci;
4256}
4257EXPORT_SYMBOL(ecm_db_mapping_connections_nat_from_get_and_ref_first);
4258
4259/*
4260 * ecm_db_mapping_connections_nat_to_get_and_ref_first()
4261 * Return a reference to the first NAT connection made to this mapping
4262 */
4263struct ecm_db_connection_instance *ecm_db_mapping_connections_nat_to_get_and_ref_first(struct ecm_db_mapping_instance *mi)
4264{
4265 struct ecm_db_connection_instance *ci;
4266
4267 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed", mi);
4268
4269 spin_lock_bh(&ecm_db_lock);
4270 ci = mi->to_nat_connections;
4271 if (ci) {
4272 _ecm_db_connection_ref(ci);
4273 }
4274 spin_unlock_bh(&ecm_db_lock);
4275
4276 return ci;
4277}
4278EXPORT_SYMBOL(ecm_db_mapping_connections_nat_to_get_and_ref_first);
4279
4280/*
4281 * ecm_db_connection_node_from_get_and_ref()
4282 * Return node reference
4283 */
4284struct ecm_db_node_instance *ecm_db_connection_node_to_get_and_ref(struct ecm_db_connection_instance *ci)
4285{
4286 struct ecm_db_node_instance *ni;
4287
4288 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304289
Ben Menchaca84f36632014-02-28 20:57:38 +00004290 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01004291 ni = ci->to_node;
Ben Menchaca84f36632014-02-28 20:57:38 +00004292 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
4293 _ecm_db_node_ref(ni);
4294 spin_unlock_bh(&ecm_db_lock);
4295 return ni;
4296}
4297EXPORT_SYMBOL(ecm_db_connection_node_to_get_and_ref);
4298
4299/*
4300 * ecm_db_connection_mapping_from_get_and_ref_next()
4301 * Return reference to next connection in from mapping chain
4302 */
4303struct ecm_db_connection_instance *ecm_db_connection_mapping_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4304{
4305 struct ecm_db_connection_instance *nci;
4306
4307 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4308
4309 spin_lock_bh(&ecm_db_lock);
4310 nci = ci->from_next;
4311 if (nci) {
4312 _ecm_db_connection_ref(nci);
4313 }
4314 spin_unlock_bh(&ecm_db_lock);
4315
4316 return nci;
4317}
4318EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref_next);
4319
4320/*
4321 * ecm_db_connection_mapping_to_get_and_ref_next()
4322 * Return reference to next connection in to mapping chain
4323 */
4324struct ecm_db_connection_instance *ecm_db_connection_mapping_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4325{
4326 struct ecm_db_connection_instance *nci;
4327
4328 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4329
4330 spin_lock_bh(&ecm_db_lock);
4331 nci = ci->to_next;
4332 if (nci) {
4333 _ecm_db_connection_ref(nci);
4334 }
4335 spin_unlock_bh(&ecm_db_lock);
4336
4337 return nci;
4338}
4339EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref_next);
4340
4341/*
4342 * ecm_db_connection_mapping_nat_from_get_and_ref_next()
4343 * Return reference to next connection in from NAT mapping chain
4344 */
4345struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4346{
4347 struct ecm_db_connection_instance *nci;
4348
4349 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4350
4351 spin_lock_bh(&ecm_db_lock);
4352 nci = ci->from_nat_next;
4353 if (nci) {
4354 _ecm_db_connection_ref(nci);
4355 }
4356 spin_unlock_bh(&ecm_db_lock);
4357
4358 return nci;
4359}
4360EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref_next);
4361
4362/*
4363 * ecm_db_connection_mapping_nat_to_get_and_ref_next()
4364 * Return reference to next connection in to NAT mapping chain
4365 */
4366struct ecm_db_connection_instance *ecm_db_connection_mapping_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4367{
4368 struct ecm_db_connection_instance *nci;
4369
4370 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4371
4372 spin_lock_bh(&ecm_db_lock);
4373 nci = ci->to_nat_next;
4374 if (nci) {
4375 _ecm_db_connection_ref(nci);
4376 }
4377 spin_unlock_bh(&ecm_db_lock);
4378
4379 return nci;
4380}
4381EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref_next);
4382
4383/*
4384 * ecm_db_iface_connections_from_get_and_ref_first()
4385 * Return a reference to the first connection made from this iface
4386 */
4387struct ecm_db_connection_instance *ecm_db_iface_connections_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
4388{
4389 struct ecm_db_connection_instance *ci;
4390
4391 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4392
4393 spin_lock_bh(&ecm_db_lock);
4394 ci = ii->from_connections;
4395 if (ci) {
4396 _ecm_db_connection_ref(ci);
4397 }
4398 spin_unlock_bh(&ecm_db_lock);
4399
4400 return ci;
4401}
4402EXPORT_SYMBOL(ecm_db_iface_connections_from_get_and_ref_first);
4403
4404/*
4405 * ecm_db_iface_connections_to_get_and_ref_first()
4406 * Return a reference to the first connection made to this iface
4407 */
4408struct ecm_db_connection_instance *ecm_db_iface_connections_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
4409{
4410 struct ecm_db_connection_instance *ci;
4411
4412 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4413
4414 spin_lock_bh(&ecm_db_lock);
4415 ci = ii->to_connections;
4416 if (ci) {
4417 _ecm_db_connection_ref(ci);
4418 }
4419 spin_unlock_bh(&ecm_db_lock);
4420
4421 return ci;
4422}
4423EXPORT_SYMBOL(ecm_db_iface_connections_to_get_and_ref_first);
4424
4425/*
4426 * ecm_db_iface_connections_nat_from_get_and_ref_first()
4427 * Return a reference to the first NAT connection made from this iface
4428 */
4429struct ecm_db_connection_instance *ecm_db_iface_connections_nat_from_get_and_ref_first(struct ecm_db_iface_instance *ii)
4430{
4431 struct ecm_db_connection_instance *ci;
4432
4433 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4434
4435 spin_lock_bh(&ecm_db_lock);
4436 ci = ii->from_nat_connections;
4437 if (ci) {
4438 _ecm_db_connection_ref(ci);
4439 }
4440 spin_unlock_bh(&ecm_db_lock);
4441
4442 return ci;
4443}
4444EXPORT_SYMBOL(ecm_db_iface_connections_nat_from_get_and_ref_first);
4445
4446/*
4447 * ecm_db_iface_connections_nat_to_get_and_ref_first()
4448 * Return a reference to the first NAT connection made to this iface
4449 */
4450struct ecm_db_connection_instance *ecm_db_iface_connections_nat_to_get_and_ref_first(struct ecm_db_iface_instance *ii)
4451{
4452 struct ecm_db_connection_instance *ci;
4453
4454 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4455
4456 spin_lock_bh(&ecm_db_lock);
4457 ci = ii->to_nat_connections;
4458 if (ci) {
4459 _ecm_db_connection_ref(ci);
4460 }
4461 spin_unlock_bh(&ecm_db_lock);
4462
4463 return ci;
4464}
4465EXPORT_SYMBOL(ecm_db_iface_connections_nat_to_get_and_ref_first);
4466
4467/*
4468 * ecm_db_connection_iface_from_get_and_ref_next()
4469 * Return reference to next connection in from iface chain
4470 */
4471struct ecm_db_connection_instance *ecm_db_connection_iface_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4472{
4473 struct ecm_db_connection_instance *nci;
4474
4475 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4476
4477 spin_lock_bh(&ecm_db_lock);
4478 nci = ci->iface_from_next;
4479 if (nci) {
4480 _ecm_db_connection_ref(nci);
4481 }
4482 spin_unlock_bh(&ecm_db_lock);
4483
4484 return nci;
4485}
4486EXPORT_SYMBOL(ecm_db_connection_iface_from_get_and_ref_next);
4487
4488/*
4489 * ecm_db_connection_iface_to_get_and_ref_next()
4490 * Return reference to next connection in to iface chain
4491 */
4492struct ecm_db_connection_instance *ecm_db_connection_iface_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4493{
4494 struct ecm_db_connection_instance *nci;
4495
4496 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4497
4498 spin_lock_bh(&ecm_db_lock);
4499 nci = ci->iface_to_next;
4500 if (nci) {
4501 _ecm_db_connection_ref(nci);
4502 }
4503 spin_unlock_bh(&ecm_db_lock);
4504
4505 return nci;
4506}
4507EXPORT_SYMBOL(ecm_db_connection_iface_to_get_and_ref_next);
4508
4509/*
4510 * ecm_db_connection_iface_nat_from_get_and_ref_next()
4511 * Return reference to next connection in from NAT iface chain
4512 */
4513struct ecm_db_connection_instance *ecm_db_connection_iface_nat_from_get_and_ref_next(struct ecm_db_connection_instance *ci)
4514{
4515 struct ecm_db_connection_instance *nci;
4516
4517 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4518
4519 spin_lock_bh(&ecm_db_lock);
4520 nci = ci->iface_from_nat_next;
4521 if (nci) {
4522 _ecm_db_connection_ref(nci);
4523 }
4524 spin_unlock_bh(&ecm_db_lock);
4525
4526 return nci;
4527}
4528EXPORT_SYMBOL(ecm_db_connection_iface_nat_from_get_and_ref_next);
4529
4530/*
4531 * ecm_db_connection_iface_nat_to_get_and_ref_next()
4532 * Return reference to next connection in to NAT iface chain
4533 */
4534struct ecm_db_connection_instance *ecm_db_connection_iface_nat_to_get_and_ref_next(struct ecm_db_connection_instance *ci)
4535{
4536 struct ecm_db_connection_instance *nci;
4537
4538 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4539
4540 spin_lock_bh(&ecm_db_lock);
4541 nci = ci->iface_to_nat_next;
4542 if (nci) {
4543 _ecm_db_connection_ref(nci);
4544 }
4545 spin_unlock_bh(&ecm_db_lock);
4546
4547 return nci;
4548}
4549EXPORT_SYMBOL(ecm_db_connection_iface_nat_to_get_and_ref_next);
4550
4551/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004552 * ecm_db_iface_nodes_get_and_ref_first()
4553 * Return a reference to the first node made from this iface
4554 */
4555struct ecm_db_node_instance *ecm_db_iface_nodes_get_and_ref_first(struct ecm_db_iface_instance *ii)
4556{
4557 struct ecm_db_node_instance *ni;
4558
4559 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed", ii);
4560
4561 spin_lock_bh(&ecm_db_lock);
4562 ni = ii->nodes;
4563 if (ni) {
4564 _ecm_db_node_ref(ni);
4565 }
4566 spin_unlock_bh(&ecm_db_lock);
4567
4568 return ni;
4569}
4570EXPORT_SYMBOL(ecm_db_iface_nodes_get_and_ref_first);
4571
4572/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004573 * ecm_db_mapping_host_get_and_ref()
4574 */
4575struct ecm_db_host_instance *ecm_db_mapping_host_get_and_ref(struct ecm_db_mapping_instance *mi)
4576{
4577 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
4578
4579 spin_lock_bh(&ecm_db_lock);
4580 _ecm_db_host_ref(mi->host);
4581 spin_unlock_bh(&ecm_db_lock);
4582 return mi->host;
4583}
4584EXPORT_SYMBOL(ecm_db_mapping_host_get_and_ref);
4585
4586/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004587 * ecm_db_node_iface_get_and_ref()
4588 */
4589struct ecm_db_iface_instance *ecm_db_node_iface_get_and_ref(struct ecm_db_node_instance *ni)
4590{
4591 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
4592
4593 spin_lock_bh(&ecm_db_lock);
4594 _ecm_db_iface_ref(ni->iface);
4595 spin_unlock_bh(&ecm_db_lock);
4596 return ni->iface;
4597}
4598EXPORT_SYMBOL(ecm_db_node_iface_get_and_ref);
4599
4600/*
Ben Menchaca84f36632014-02-28 20:57:38 +00004601 * ecm_db_iface_node_count_get()
4602 * Return the number of nodes to this iface
4603 */
4604int ecm_db_iface_node_count_get(struct ecm_db_iface_instance *ii)
4605{
4606 int count;
4607
4608 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304609
Ben Menchaca84f36632014-02-28 20:57:38 +00004610 spin_lock_bh(&ecm_db_lock);
4611 count = ii->node_count;
4612 spin_unlock_bh(&ecm_db_lock);
4613 return count;
4614}
4615EXPORT_SYMBOL(ecm_db_iface_node_count_get);
4616
4617/*
4618 * ecm_db_host_mapping_count_get()
4619 * Return the number of mappings to this host
4620 */
4621int ecm_db_host_mapping_count_get(struct ecm_db_host_instance *hi)
4622{
4623 int count;
4624
4625 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304626
Ben Menchaca84f36632014-02-28 20:57:38 +00004627 spin_lock_bh(&ecm_db_lock);
4628 count = hi->mapping_count;
4629 spin_unlock_bh(&ecm_db_lock);
4630 return count;
4631}
4632EXPORT_SYMBOL(ecm_db_host_mapping_count_get);
4633
4634/*
4635 * ecm_db_mapping_connections_total_count_get()
4636 * Return the total number of connections (NAT and non-NAT) this mapping has
4637 */
4638int ecm_db_mapping_connections_total_count_get(struct ecm_db_mapping_instance *mi)
4639{
4640 int count;
4641
4642 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304643
Ben Menchaca84f36632014-02-28 20:57:38 +00004644 spin_lock_bh(&ecm_db_lock);
4645 count = mi->from + mi->to + mi->nat_from + mi->nat_to;
4646 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);
4647 spin_unlock_bh(&ecm_db_lock);
4648 return count;
4649}
4650EXPORT_SYMBOL(ecm_db_mapping_connections_total_count_get);
4651
4652/*
4653 * ecm_db_connection_mapping_from_get_and_ref()
4654 * Return a reference to the from mapping of the connection
4655 */
4656struct ecm_db_mapping_instance *ecm_db_connection_mapping_from_get_and_ref(struct ecm_db_connection_instance *ci)
4657{
4658 struct ecm_db_mapping_instance *mi;
4659
4660 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304661
Ben Menchaca84f36632014-02-28 20:57:38 +00004662 spin_lock_bh(&ecm_db_lock);
4663 mi = ci->mapping_from;
4664 _ecm_db_mapping_ref(mi);
4665 spin_unlock_bh(&ecm_db_lock);
4666 return mi;
4667}
4668EXPORT_SYMBOL(ecm_db_connection_mapping_from_get_and_ref);
4669
4670/*
4671 * ecm_db_connection_mapping_nat_from_get_and_ref()
4672 * Return a reference to the from NAT mapping of the connection
4673 */
4674struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_from_get_and_ref(struct ecm_db_connection_instance *ci)
4675{
4676 struct ecm_db_mapping_instance *mi;
4677
4678 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304679
Ben Menchaca84f36632014-02-28 20:57:38 +00004680 spin_lock_bh(&ecm_db_lock);
4681 mi = ci->mapping_nat_from;
4682 _ecm_db_mapping_ref(mi);
4683 spin_unlock_bh(&ecm_db_lock);
4684 return mi;
4685}
4686EXPORT_SYMBOL(ecm_db_connection_mapping_nat_from_get_and_ref);
4687
4688/*
4689 * ecm_db_connection_mapping_to_get_and_ref()
4690 * Return a reference to the from mapping of the connection
4691 */
4692struct ecm_db_mapping_instance *ecm_db_connection_mapping_to_get_and_ref(struct ecm_db_connection_instance *ci)
4693{
4694 struct ecm_db_mapping_instance *mi;
4695
4696 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304697
Ben Menchaca84f36632014-02-28 20:57:38 +00004698 spin_lock_bh(&ecm_db_lock);
4699 mi = ci->mapping_to;
4700 _ecm_db_mapping_ref(mi);
4701 spin_unlock_bh(&ecm_db_lock);
4702 return mi;
4703}
4704EXPORT_SYMBOL(ecm_db_connection_mapping_to_get_and_ref);
4705
4706/*
4707 * ecm_db_connection_mapping_to_nat_get_and_ref()
4708 * Return a reference to the from NAT mapping of the connection
4709 */
4710struct ecm_db_mapping_instance *ecm_db_connection_mapping_nat_to_get_and_ref(struct ecm_db_connection_instance *ci)
4711{
4712 struct ecm_db_mapping_instance *mi;
4713
4714 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304715
Ben Menchaca84f36632014-02-28 20:57:38 +00004716 spin_lock_bh(&ecm_db_lock);
4717 mi = ci->mapping_nat_to;
4718 _ecm_db_mapping_ref(mi);
4719 spin_unlock_bh(&ecm_db_lock);
4720 return mi;
4721}
4722EXPORT_SYMBOL(ecm_db_connection_mapping_nat_to_get_and_ref);
4723
4724/*
4725 * ecm_db_connection_node_from_get_and_ref()
4726 * Return node reference
4727 */
4728struct ecm_db_node_instance *ecm_db_connection_node_from_get_and_ref(struct ecm_db_connection_instance *ci)
4729{
4730 struct ecm_db_node_instance *ni;
4731
4732 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304733
Ben Menchaca84f36632014-02-28 20:57:38 +00004734 spin_lock_bh(&ecm_db_lock);
Gareth Williams90f2a282014-08-27 15:56:25 +01004735 ni = ci->from_node;
Ben Menchaca84f36632014-02-28 20:57:38 +00004736 _ecm_db_node_ref(ni);
4737 spin_unlock_bh(&ecm_db_lock);
4738 return ni;
4739}
4740EXPORT_SYMBOL(ecm_db_connection_node_from_get_and_ref);
4741
4742/*
4743 * ecm_db_timer_groups_check()
4744 * Check for expired group entries, returns the number that have expired
4745 */
4746static uint32_t ecm_db_timer_groups_check(uint32_t time_now)
4747{
4748 ecm_db_timer_group_t i;
4749 uint32_t expired = 0;
4750
4751 DEBUG_TRACE("Timer groups check start %u\n", time_now);
4752
4753 /*
4754 * Examine all timer groups for expired entries.
4755 */
4756 for (i = 0; i < ECM_DB_TIMER_GROUPS_MAX; ++i) {
4757 struct ecm_db_timer_group *timer_group;
4758
4759 /*
4760 * The group tail tracks the oldest entry so that is what we examine.
4761 */
4762 timer_group = &ecm_db_timer_groups[i];
4763 spin_lock_bh(&ecm_db_lock);
4764 while (timer_group->tail) {
4765 struct ecm_db_timer_group_entry *tge;
4766
4767 tge = timer_group->tail;
4768 if (tge->timeout > time_now) {
4769 /*
4770 * Not expired - and no further will be as they are in order
4771 */
4772 break;
4773 }
4774
4775 /*
4776 * Has expired - remove the entry from the list and invoke the callback
4777 * NOTE: We know the entry is at the tail of the group
4778 */
4779 if (tge->prev) {
4780 tge->prev->next = NULL;
4781 } else {
4782 /*
4783 * First in the group
4784 */
4785 DEBUG_ASSERT(timer_group->head == tge, "%p: bad head, expecting %p got %p\n", timer_group, tge, timer_group->head);
4786 timer_group->head = NULL;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05304787 }
Ben Menchaca84f36632014-02-28 20:57:38 +00004788 timer_group->tail = tge->prev;
4789 tge->group = ECM_DB_TIMER_GROUPS_MAX;
4790 spin_unlock_bh(&ecm_db_lock);
4791 expired++;
4792 DEBUG_TRACE("%p: Expired\n", tge);
4793 tge->fn(tge->arg);
4794 spin_lock_bh(&ecm_db_lock);
4795 }
4796 spin_unlock_bh(&ecm_db_lock);
4797 }
4798
4799 spin_lock_bh(&ecm_db_lock);
4800 time_now = ecm_db_time;
4801 spin_unlock_bh(&ecm_db_lock);
4802 DEBUG_TRACE("Timer groups check end %u, expired count %u\n", time_now, expired);
4803 return expired;
4804}
4805
4806/*
4807 * ecm_db_connection_classifier_assign()
4808 * Assign a classifier to the connection assigned classifier list.
4809 *
4810 * This adds the classifier in the ci->assignments list in priority order according to the classifier type.
4811 * Only assigned classifiers are in this list, allowing fast retrival of in-order current assignments, avoiding the need to skip over unassigned classifiers.
4812 * 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.
4813 * This allows fast lookup based on type too.
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004814 * 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 +00004815 */
4816void ecm_db_connection_classifier_assign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *new_ca)
4817{
4818 struct ecm_classifier_instance *ca;
4819 struct ecm_classifier_instance *ca_prev;
4820 ecm_classifier_type_t new_ca_type;
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004821 struct ecm_db_connection_classifier_type_assignment *ta;
4822 struct ecm_db_connection_classifier_type_assignment_list *tal;
4823
Ben Menchaca84f36632014-02-28 20:57:38 +00004824 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4825
4826 /*
4827 * Get the type (which is also used as the priority)
4828 */
4829 new_ca_type = new_ca->type_get(new_ca);
4830
4831 /*
4832 * Connection holds ref to the classifier
4833 */
4834 new_ca->ref(new_ca);
4835
4836 /*
4837 * Find place to insert the classifier
4838 */
4839 spin_lock_bh(&ecm_db_lock);
4840 ca = ci->assignments;
4841 ca_prev = NULL;
4842 while (ca) {
4843 ecm_classifier_type_t ca_type;
4844 ca_type = ca->type_get(ca);
4845
4846 /*
4847 * If new ca is less important that the current assigned classifier insert here
4848 */
4849 if (new_ca_type < ca_type) {
4850 break;
4851 }
4852 ca_prev = ca;
4853 ca = ca->ca_next;
4854 }
4855
4856 /*
4857 * Insert new_ca before ca and after ca_prev.
4858 */
4859 new_ca->ca_prev = ca_prev;
4860 if (ca_prev) {
4861 ca_prev->ca_next = new_ca;
4862 } else {
4863 DEBUG_ASSERT(ci->assignments == ca, "%p: Bad assigmnment list, expecting: %p, got: %p\n", ci, ca, ci->assignments);
4864 ci->assignments = new_ca;
4865 }
4866
4867 new_ca->ca_next = ca;
4868 if (ca) {
4869 ca->ca_prev = new_ca;
4870 }
4871
4872 /*
4873 * Insert based on type too
4874 */
4875 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",
4876 ci, new_ca_type, new_ca, ci->assignments_by_type[new_ca_type]);
4877 ci->assignments_by_type[new_ca_type] = new_ca;
4878
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004879 /*
4880 * Add the connection into the type assignment list too.
4881 */
4882 ta = &ci->type_assignment[new_ca_type];
4883 if (ta->pending_unassign) {
4884 /*
4885 * The connection is pending unassignment / removal from list, but since it has been
4886 * re-assigned to the same type of classifier we can just clear the flag and avoid the removal.
4887 * NOTE: pending_unassign is only ever true if the iteration count is non-zero i.e. iteration is in progress.
4888 */
4889 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
4890 DEBUG_ASSERT(ta->iteration_count != 0, "%p: Bad pending_unassign: type: %d, Iteration count zero\n", ci, new_ca_type);
4891 ta->pending_unassign = false;
4892 spin_unlock_bh(&ecm_db_lock);
4893 return;
4894 }
4895
4896 /*
4897 * iteration_count should be zero as there should not be a duplicate assignment of the same type.
4898 * This is because if iteration_count was non-zero then pending_unassign should have been true.
4899 */
4900 DEBUG_ASSERT(ta->iteration_count == 0, "%p: Type: %d, Iteration count not zero: %d\n", ci, new_ca_type, ta->iteration_count);
4901
4902 /*
4903 * Insert the connection into the classifier type assignment list, at the head
4904 */
4905 tal = &ecm_db_connection_classifier_type_assignments[new_ca_type];
4906 ta->next = tal->type_assignments_list;
4907 ta->prev = NULL;
4908
4909 /*
4910 * If there is an existing head, it is no longer the head
4911 */
4912 if (tal->type_assignments_list) {
4913 struct ecm_db_connection_classifier_type_assignment *talh;
4914 talh = &tal->type_assignments_list->type_assignment[new_ca_type];
4915 talh->prev = ci;
4916 }
4917
4918 /*
4919 * Set new head
4920 */
4921 tal->type_assignments_list = ci;
4922
4923 /*
4924 * Set magic
4925 */
4926 DEBUG_SET_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC);
4927
4928 /*
4929 * Increment assignment count
4930 */
4931 tal->type_assignment_count++;
4932 DEBUG_ASSERT(tal->type_assignment_count > 0, "Bad iteration count: %d\n", tal->type_assignment_count);
4933
Ben Menchaca84f36632014-02-28 20:57:38 +00004934 spin_unlock_bh(&ecm_db_lock);
4935}
4936EXPORT_SYMBOL(ecm_db_connection_classifier_assign);
4937
4938/*
4939 * ecm_db_connection_classifier_assignments_get_and_ref()
4940 * Populate the given array with references to the currently assigned classifiers.
4941 *
4942 * This function returns the number of assignments starting from [0].
4943 * [0] is the lowest priority classifier, [return_val - 1] is the highest priority.
4944 * Release each classifier when you are done, for convenience use ecm_db_connection_assignments_release().
4945 *
4946 * NOTE: The array also contains the default classifier too which of course will always be at [0]
4947 *
4948 * WARNING: The array MUST be of size ECM_CLASSIFIER_TYPES.
4949 */
4950int ecm_db_connection_classifier_assignments_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *assignments[])
4951{
4952 int aci_count;
4953 struct ecm_classifier_instance *aci;
4954 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4955
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004956 aci_count = 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00004957 spin_lock_bh(&ecm_db_lock);
4958 aci = ci->assignments;
4959 while (aci) {
4960 aci->ref(aci);
4961 assignments[aci_count++] = aci;
4962 aci = aci->ca_next;
4963 }
4964 spin_unlock_bh(&ecm_db_lock);
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01004965 DEBUG_ASSERT(aci_count >= 1, "%p: Must have at least default classifier!\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00004966 return aci_count;
4967}
4968EXPORT_SYMBOL(ecm_db_connection_classifier_assignments_get_and_ref);
4969
4970/*
4971 * ecm_db_connection_assignments_release()
4972 * Release references to classifiers in the assignments array
4973 */
4974void ecm_db_connection_assignments_release(int assignment_count, struct ecm_classifier_instance *assignments[])
4975{
4976 int i;
4977 for (i = 0; i < assignment_count; ++i) {
4978 struct ecm_classifier_instance *aci = assignments[i];
4979 if (aci) {
4980 aci->deref(aci);
4981 }
4982 }
4983}
4984EXPORT_SYMBOL(ecm_db_connection_assignments_release);
4985
4986/*
4987 * ecm_db_connection_assigned_classifier_find_and_ref()
4988 * Return a ref to classifier of the requested type, if found
4989 */
4990struct ecm_classifier_instance *ecm_db_connection_assigned_classifier_find_and_ref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t type)
4991{
4992 struct ecm_classifier_instance *ca;
4993 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
4994 spin_lock_bh(&ecm_db_lock);
4995 ca = ci->assignments_by_type[type];
4996 if (ca) {
4997 ca->ref(ca);
4998 }
4999 spin_unlock_bh(&ecm_db_lock);
5000 return ca;
5001}
5002EXPORT_SYMBOL(ecm_db_connection_assigned_classifier_find_and_ref);
5003
5004/*
5005 * ecm_db_connection_classifier_unassign()
5006 * Unassign a classifier
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005007 *
5008 * The default classifier cannot be unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005009 */
5010void ecm_db_connection_classifier_unassign(struct ecm_db_connection_instance *ci, struct ecm_classifier_instance *cci)
5011{
5012 ecm_classifier_type_t ca_type;
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005013 struct ecm_db_connection_classifier_type_assignment *ta;
5014
Ben Menchaca84f36632014-02-28 20:57:38 +00005015 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5016
5017 DEBUG_ASSERT(cci->type_get(cci) != ECM_CLASSIFIER_TYPE_DEFAULT, "%p: Cannot unassign default", ci);
5018
Ben Menchaca84f36632014-02-28 20:57:38 +00005019 /*
5020 * Get the type
5021 */
5022 ca_type = cci->type_get(cci);
5023
5024 DEBUG_TRACE("%p: Unassign type: %d, classifier: %p\n", ci, ca_type, cci);
5025
5026 spin_lock_bh(&ecm_db_lock);
5027
5028 /*
5029 * Remove from assignments_by_type
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005030 * NOTE: It is possible that in SMP this classifier has already been unassigned.
Ben Menchaca84f36632014-02-28 20:57:38 +00005031 */
Gareth Williamsee0a38a2014-06-05 15:41:20 +01005032 if (ci->assignments_by_type[ca_type] == NULL) {
5033 spin_unlock_bh(&ecm_db_lock);
5034 DEBUG_TRACE("%p: Classifier type: %d already unassigned\n", ci, ca_type);
5035 return;
5036 }
Ben Menchaca84f36632014-02-28 20:57:38 +00005037 ci->assignments_by_type[ca_type] = NULL;
5038
5039 /*
5040 * Link out of assignments list
5041 */
5042 if (cci->ca_prev) {
5043 cci->ca_prev->ca_next = cci->ca_next;
5044 } else {
5045 DEBUG_ASSERT(ci->assignments == cci, "%p: Bad assigmnment list, expecting: %p, got: %p", ci, cci, ci->assignments);
5046 ci->assignments = cci->ca_next;
5047 }
5048 if (cci->ca_next) {
5049 cci->ca_next->ca_prev = cci->ca_prev;
5050 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005051
5052 /*
5053 * Remove from the classifier type assignment list
5054 */
5055 ta = &ci->type_assignment[ca_type];
5056 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5057 if (ta->iteration_count > 0) {
5058 /*
5059 * The list entry is being iterated outside of db lock being held.
5060 * We cannot remove this entry since it would mess up iteration.
5061 * Set the pending flag to be actioned another time
5062 */
5063 ta->pending_unassign = true;
5064 spin_unlock_bh(&ecm_db_lock);
5065 cci->deref(cci);
5066 return;
5067 }
5068
5069 /*
5070 * Remove the list entry
5071 */
5072 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
5073 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
Ben Menchaca84f36632014-02-28 20:57:38 +00005074 spin_unlock_bh(&ecm_db_lock);
5075 cci->deref(cci);
5076}
5077EXPORT_SYMBOL(ecm_db_connection_classifier_unassign);
5078
5079/*
5080 * ecm_db_connection_classifier_default_get_and_ref()
5081 * Get a reference to default classifier associated with this connection
5082 */
5083struct ecm_classifier_default_instance *ecm_db_connection_classifier_default_get_and_ref(struct ecm_db_connection_instance *ci)
5084{
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005085 struct ecm_classifier_default_instance *dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005086 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5087
5088 /*
5089 * No need to lock this object - it cannot change
5090 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005091 dci = (struct ecm_classifier_default_instance *)ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT];
5092 DEBUG_ASSERT(dci, "%p: No default classifier!\n", ci);
5093 dci->base.ref((struct ecm_classifier_instance *)dci);
5094 return dci;
Ben Menchaca84f36632014-02-28 20:57:38 +00005095}
5096EXPORT_SYMBOL(ecm_db_connection_classifier_default_get_and_ref);
5097
5098/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005099 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_first()
5100 * Return a reference to the first connection for which a classifier of the given type is associated with
5101 *
5102 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5103 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5104 */
5105struct ecm_db_connection_instance *ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ecm_classifier_type_t ca_type)
5106{
5107 struct ecm_db_connection_classifier_type_assignment_list *tal;
5108 struct ecm_db_connection_instance *ci;
5109
5110 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5111
5112 DEBUG_TRACE("Get and ref first connection assigned with classifier type: %d\n", ca_type);
5113
5114 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
5115 spin_lock_bh(&ecm_db_lock);
5116 ci = tal->type_assignments_list;
5117 while (ci) {
5118 struct ecm_db_connection_classifier_type_assignment *ta;
5119 ta = &ci->type_assignment[ca_type];
5120 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5121
5122 if (ta->pending_unassign) {
5123 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", ci, ca_type);
5124 ci = ta->next;
5125 continue;
5126 }
5127
5128 /*
5129 * Take reference to this connection.
5130 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
5131 * and the type assignment list entry maintains integrity.
5132 */
5133 _ecm_db_connection_ref(ci);
5134 ta->iteration_count++;
5135 DEBUG_ASSERT(ta->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
5136 spin_unlock_bh(&ecm_db_lock);
5137 return ci;
5138 }
5139 spin_unlock_bh(&ecm_db_lock);
5140 return NULL;
5141}
5142EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_first);
5143
5144/*
5145 * ecm_db_connection_by_classifier_type_assignment_get_and_ref_next()
5146 * Return a reference to the next connection for which a classifier of the given type is associated with.
5147 *
5148 * WARNING: YOU MUST NOT USE ecm_db_connection_deref() to release the references taken using this API.
5149 * YOU MUST use ecm_db_connection_by_classifier_type_assignment_deref(), this ensures type assignment list integrity.
5150 */
5151struct 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)
5152{
5153 struct ecm_db_connection_classifier_type_assignment *ta;
5154 struct ecm_db_connection_instance *cin;
5155
5156 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5157 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5158
5159 DEBUG_TRACE("Get and ref next connection assigned with classifier type: %d and ci: %p\n", ca_type, ci);
5160
5161 spin_lock_bh(&ecm_db_lock);
5162 ta = &ci->type_assignment[ca_type];
5163 cin = ta->next;
5164 while (cin) {
5165 struct ecm_db_connection_classifier_type_assignment *tan;
5166
5167 tan = &cin->type_assignment[ca_type];
5168 DEBUG_CHECK_MAGIC(tan, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", tan, cin);
5169
5170 if (tan->pending_unassign) {
5171 DEBUG_TRACE("Skip %p, pending unassign for type: %d\n", cin, ca_type);
5172 cin = tan->next;
5173 continue;
5174 }
5175
5176 /*
5177 * Take reference to this connection.
5178 * NOTE: Hold both the connection and the assignment entry so that when we unlock both the connection
5179 * and the type assignment list entry maintains integrity.
5180 */
5181 _ecm_db_connection_ref(cin);
5182 tan->iteration_count++;
5183 DEBUG_ASSERT(tan->iteration_count > 0, "Bad Iteration count: %d for type: %d, connection: %p\n", tan->iteration_count, ca_type, cin);
5184 spin_unlock_bh(&ecm_db_lock);
5185 return cin;
5186 }
5187 spin_unlock_bh(&ecm_db_lock);
5188 return NULL;
5189}
5190EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_get_and_ref_next);
5191
5192/*
5193 * ecm_db_connection_by_classifier_type_assignment_deref()
5194 * Release a reference to a connection while iterating a classifier type assignment list
5195 */
5196void ecm_db_connection_by_classifier_type_assignment_deref(struct ecm_db_connection_instance *ci, ecm_classifier_type_t ca_type)
5197{
5198 struct ecm_db_connection_classifier_type_assignment_list *tal;
5199 struct ecm_db_connection_classifier_type_assignment *ta;
5200
5201 DEBUG_ASSERT(ca_type < ECM_CLASSIFIER_TYPES, "Bad type: %d\n", ca_type);
5202 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5203
5204 tal = &ecm_db_connection_classifier_type_assignments[ca_type];
5205
5206 /*
5207 * Drop the iteration count
5208 */
5209 spin_lock_bh(&ecm_db_lock);
5210 ta = &ci->type_assignment[ca_type];
5211 DEBUG_CHECK_MAGIC(ta, ECM_DB_CLASSIFIER_TYPE_ASSIGNMENT_MAGIC, "%p: magic failed, ci: %p", ta, ci);
5212 ta->iteration_count--;
5213 DEBUG_ASSERT(ta->iteration_count >= 0, "Bad Iteration count: %d for type: %d, connection: %p\n", ta->iteration_count, ca_type, ci);
5214
5215 /*
5216 * If there are no more iterations on-going and this is pending unassign then we can remove it from the assignments list
5217 */
5218 if (ta->pending_unassign && (ta->iteration_count == 0)) {
5219 DEBUG_INFO("%p: Remove type assignment: %d\n", ci, ca_type);
5220 _ecm_db_classifier_type_assignment_remove(ci, ca_type);
5221 }
5222 spin_unlock_bh(&ecm_db_lock);
5223 ecm_db_connection_deref(ci);
5224}
5225EXPORT_SYMBOL(ecm_db_connection_by_classifier_type_assignment_deref);
5226
5227/*
5228 * ecm_db_connection_make_defunct_by_assignment_type()
5229 * Make defunct all connections that are currently assigned to a classifier of the given type
5230 */
5231void ecm_db_connection_make_defunct_by_assignment_type(ecm_classifier_type_t ca_type)
5232{
5233 struct ecm_db_connection_instance *ci;
5234
5235 DEBUG_INFO("Make defunct all assigned to type: %d\n", ca_type);
5236
5237 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
5238 while (ci) {
5239 struct ecm_db_connection_instance *cin;
5240
5241 DEBUG_TRACE("%p: Make defunct: %d\n", ci, ca_type);
5242 ecm_db_connection_make_defunct(ci);
5243
5244 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
5245 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
5246 ci = cin;
5247 }
5248}
5249EXPORT_SYMBOL(ecm_db_connection_make_defunct_by_assignment_type);
5250
5251/*
5252 * ecm_db_connection_regenerate_by_assignment_type()
5253 * Cause regeneration all connections that are currently assigned to a classifier of the given type
5254 */
5255void ecm_db_connection_regenerate_by_assignment_type(ecm_classifier_type_t ca_type)
5256{
5257 struct ecm_db_connection_instance *ci;
5258
5259 DEBUG_INFO("Regenerate all assigned to type: %d\n", ca_type);
5260
5261 ci = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type);
5262 while (ci) {
5263 struct ecm_db_connection_instance *cin;
5264
5265 DEBUG_TRACE("%p: Re-generate: %d\n", ci, ca_type);
5266 ecm_db_connection_classifier_generation_change(ci);
5267
5268 cin = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type);
5269 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
5270 ci = cin;
5271 }
5272}
5273EXPORT_SYMBOL(ecm_db_connection_regenerate_by_assignment_type);
5274
5275/*
Ben Menchaca84f36632014-02-28 20:57:38 +00005276 * ecm_db_connection_from_interfaces_get_and_ref()
5277 * Return the interface heirarchy from which this connection is established.
5278 *
5279 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5280 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5281 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5282 *
5283 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5284 */
5285int32_t ecm_db_connection_from_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5286{
5287 int32_t n;
5288 int32_t i;
5289 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5290
5291 spin_lock_bh(&ecm_db_lock);
5292 n = ci->from_interface_first;
5293 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5294 interfaces[i] = ci->from_interfaces[i];
5295 _ecm_db_iface_ref(interfaces[i]);
5296 }
5297 spin_unlock_bh(&ecm_db_lock);
5298 return n;
5299}
5300EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_and_ref);
5301
5302/*
5303 * ecm_db_connection_to_interfaces_get_and_ref()
5304 * Return the interface heirarchy to which this connection is established.
5305 *
5306 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5307 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5308 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5309 *
5310 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5311 */
5312int32_t ecm_db_connection_to_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5313{
5314 int32_t n;
5315 int32_t i;
5316 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5317
5318 spin_lock_bh(&ecm_db_lock);
5319 n = ci->to_interface_first;
5320 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5321 interfaces[i] = ci->to_interfaces[i];
5322 _ecm_db_iface_ref(interfaces[i]);
5323 }
5324 spin_unlock_bh(&ecm_db_lock);
5325 return n;
5326}
5327EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_and_ref);
5328
5329/*
5330 * ecm_db_connection_from_nat_interfaces_get_and_ref()
5331 * Return the interface heirarchy from (nat) which this connection is established.
5332 *
5333 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5334 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5335 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5336 *
5337 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5338 */
5339int32_t ecm_db_connection_from_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5340{
5341 int32_t n;
5342 int32_t i;
5343 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5344
5345 spin_lock_bh(&ecm_db_lock);
5346 n = ci->from_nat_interface_first;
5347 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5348 interfaces[i] = ci->from_nat_interfaces[i];
5349 _ecm_db_iface_ref(interfaces[i]);
5350 }
5351 spin_unlock_bh(&ecm_db_lock);
5352 return n;
5353}
5354EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_and_ref);
5355
5356/*
5357 * ecm_db_connection_to_nat_interfaces_get_and_ref()
5358 * Return the interface heirarchy to (nat) which this connection is established.
5359 *
5360 * 'interfaces' MUST be an array as large as ECM_DB_IFACE_HEIRARCHY_MAX.
5361 * Returns either ECM_DB_IFACE_HEIRARCHY_MAX if there are no interfaces / error.
5362 * Returns the index into the interfaces[] of the first interface (so "for (i = <ret val>, i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i)" works)
5363 *
5364 * Each interface is referenced on return, be sure to release them individually or use ecm_db_connection_interfaces_deref() instead.
5365 */
5366int32_t ecm_db_connection_to_nat_interfaces_get_and_ref(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[])
5367{
5368 int32_t n;
5369 int32_t i;
5370 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5371
5372 spin_lock_bh(&ecm_db_lock);
5373 n = ci->to_nat_interface_first;
5374 for (i = n; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5375 interfaces[i] = ci->to_nat_interfaces[i];
5376 _ecm_db_iface_ref(interfaces[i]);
5377 }
5378 spin_unlock_bh(&ecm_db_lock);
5379 return n;
5380}
5381EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_and_ref);
5382
5383/*
5384 * ecm_db_connection_interfaces_deref()
5385 * Release all interfaces in the given interfaces heirarchy array.
5386 *
5387 * 'first' is the number returned by one of the ecm_db_connection_xx_interfaces_get_and_ref().
5388 * You should NOT have released any references to any of the interfaces in the array youself, this releases them all.
5389 */
5390void ecm_db_connection_interfaces_deref(struct ecm_db_iface_instance *interfaces[], int32_t first)
5391{
5392 int32_t i;
5393 DEBUG_ASSERT((first >= 0) && (first <= ECM_DB_IFACE_HEIRARCHY_MAX), "Bad first: %d\n", first);
5394
5395 for (i = first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5396 ecm_db_iface_deref(interfaces[i]);
5397 }
5398}
5399EXPORT_SYMBOL(ecm_db_connection_interfaces_deref);
5400
5401/*
5402 * ecm_db_connection_from_interfaces_reset()
5403 * Reset the from interfaces heirarchy with a new set of interfaces
5404 *
5405 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5406 * This is deliberate - it's stating that there is no list :-)
5407 */
5408void ecm_db_connection_from_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5409{
5410 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5411 int32_t old_first;
5412 int32_t i;
5413 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5414
5415 /*
5416 * Iterate the from interface list, removing the old and adding in the new
5417 */
5418 spin_lock_bh(&ecm_db_lock);
5419 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5420 /*
5421 * Put any previous interface into the old list
5422 */
5423 old[i] = ci->from_interfaces[i];
5424 ci->from_interfaces[i] = NULL;
5425 if (i < new_first) {
5426 continue;
5427 }
5428 ci->from_interfaces[i] = interfaces[i];
5429 _ecm_db_iface_ref(ci->from_interfaces[i]);
5430 }
5431
5432 /*
5433 * Get old first and update to new first
5434 */
5435 old_first = ci->from_interface_first;
5436 ci->from_interface_first = new_first;
5437 ci->from_interface_set = true;
5438 spin_unlock_bh(&ecm_db_lock);
5439
5440 /*
5441 * Release old
5442 */
5443 ecm_db_connection_interfaces_deref(old, old_first);
5444}
5445EXPORT_SYMBOL(ecm_db_connection_from_interfaces_reset);
5446
5447/*
5448 * ecm_db_connection_to_interfaces_reset()
5449 * Reset the to interfaces heirarchy with a new set of interfaces
5450 *
5451 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5452 * This is deliberate - it's stating that there is no list :-)
5453 */
5454void ecm_db_connection_to_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5455{
5456 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5457 int32_t old_first;
5458 int32_t i;
5459 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5460
5461 /*
5462 * Iterate the to interface list, removing the old and adding in the new
5463 */
5464 spin_lock_bh(&ecm_db_lock);
5465 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5466 /*
5467 * Put any previous interface into the old list
5468 */
5469 old[i] = ci->to_interfaces[i];
5470 ci->to_interfaces[i] = NULL;
5471 if (i < new_first) {
5472 continue;
5473 }
5474 ci->to_interfaces[i] = interfaces[i];
5475 _ecm_db_iface_ref(ci->to_interfaces[i]);
5476 }
5477
5478 /*
5479 * Get old first and update to new first
5480 */
5481 old_first = ci->to_interface_first;
5482 ci->to_interface_first = new_first;
5483 ci->to_interface_set = true;
5484 spin_unlock_bh(&ecm_db_lock);
5485
5486 /*
5487 * Release old
5488 */
5489 ecm_db_connection_interfaces_deref(old, old_first);
5490}
5491EXPORT_SYMBOL(ecm_db_connection_to_interfaces_reset);
5492
5493/*
5494 * ecm_db_connection_from_nat_interfaces_reset()
5495 * Reset the from NAT interfaces heirarchy with a new set of interfaces
5496 *
5497 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5498 * This is deliberate - it's stating that there is no list :-)
5499 */
5500void ecm_db_connection_from_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5501{
5502 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5503 int32_t old_first;
5504 int32_t i;
5505 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5506
5507 /*
5508 * Iterate the from nat interface list, removing the old and adding in the new
5509 */
5510 spin_lock_bh(&ecm_db_lock);
5511 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5512 /*
5513 * Put any previous interface into the old list
5514 */
5515 old[i] = ci->from_nat_interfaces[i];
5516 ci->from_nat_interfaces[i] = NULL;
5517 if (i < new_first) {
5518 continue;
5519 }
5520 ci->from_nat_interfaces[i] = interfaces[i];
5521 _ecm_db_iface_ref(ci->from_nat_interfaces[i]);
5522 }
5523
5524 /*
5525 * Get old first and update to new first
5526 */
5527 old_first = ci->from_nat_interface_first;
5528 ci->from_nat_interface_first = new_first;
5529 ci->from_nat_interface_set = true;
5530 spin_unlock_bh(&ecm_db_lock);
5531
5532 /*
5533 * Release old
5534 */
5535 ecm_db_connection_interfaces_deref(old, old_first);
5536}
5537EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_reset);
5538
5539/*
5540 * ecm_db_connection_to_nat_interfaces_reset()
5541 * Reset the to NAT interfaces heirarchy with a new set of interfaces.
5542 *
5543 * NOTE: This will mark the list as set even if you specify no list as a replacement.
5544 * This is deliberate - it's stating that there is no list :-)
5545 */
5546void ecm_db_connection_to_nat_interfaces_reset(struct ecm_db_connection_instance *ci, struct ecm_db_iface_instance *interfaces[], int32_t new_first)
5547{
5548 struct ecm_db_iface_instance *old[ECM_DB_IFACE_HEIRARCHY_MAX];
5549 int32_t old_first;
5550 int32_t i;
5551 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5552
5553 /*
5554 * Iterate the to nat interface list, removing the old and adding in the new
5555 */
5556 spin_lock_bh(&ecm_db_lock);
5557 for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5558 /*
5559 * Put any previous interface into the old list
5560 */
5561 old[i] = ci->to_nat_interfaces[i];
5562 ci->to_nat_interfaces[i] = NULL;
5563 if (i < new_first) {
5564 continue;
5565 }
5566 ci->to_nat_interfaces[i] = interfaces[i];
5567 _ecm_db_iface_ref(ci->to_nat_interfaces[i]);
5568 }
5569
5570 /*
5571 * Get old first and update to new first
5572 */
5573 old_first = ci->to_nat_interface_first;
5574 ci->to_nat_interface_first = new_first;
5575 ci->to_nat_interface_set = true;
5576 spin_unlock_bh(&ecm_db_lock);
5577
5578 /*
5579 * Release old
5580 */
5581 ecm_db_connection_interfaces_deref(old, old_first);
5582}
5583EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_reset);
5584
5585/*
5586 * ecm_db_connection_to_nat_interfaces_get_count()
5587 * Return the number of interfaces in the list
5588 */
5589int32_t ecm_db_connection_to_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
5590{
5591 int32_t first;
5592 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5593 spin_lock_bh(&ecm_db_lock);
5594 first = ci->to_nat_interface_first;
5595 spin_unlock_bh(&ecm_db_lock);
5596 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5597}
5598EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_get_count);
5599
5600/*
5601 * ecm_db_connection_from_nat_interfaces_get_count()
5602 * Return the number of interfaces in the list
5603 */
5604int32_t ecm_db_connection_from_nat_interfaces_get_count(struct ecm_db_connection_instance *ci)
5605{
5606 int32_t first;
5607 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5608 spin_lock_bh(&ecm_db_lock);
5609 first = ci->from_nat_interface_first;
5610 spin_unlock_bh(&ecm_db_lock);
5611 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5612}
5613EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_get_count);
5614
5615/*
5616 * ecm_db_connection_to_interfaces_get_count()
5617 * Return the number of interfaces in the list
5618 */
5619int32_t ecm_db_connection_to_interfaces_get_count(struct ecm_db_connection_instance *ci)
5620{
5621 int32_t first;
5622 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5623 spin_lock_bh(&ecm_db_lock);
5624 first = ci->to_interface_first;
5625 spin_unlock_bh(&ecm_db_lock);
5626 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5627}
5628EXPORT_SYMBOL(ecm_db_connection_to_interfaces_get_count);
5629
5630/*
5631 * ecm_db_connection_from_interfaces_get_count()
5632 * Return the number of interfaces in the list
5633 */
5634int32_t ecm_db_connection_from_interfaces_get_count(struct ecm_db_connection_instance *ci)
5635{
5636 int32_t first;
5637 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5638 spin_lock_bh(&ecm_db_lock);
5639 first = ci->from_interface_first;
5640 spin_unlock_bh(&ecm_db_lock);
5641 return ECM_DB_IFACE_HEIRARCHY_MAX - first;
5642}
5643EXPORT_SYMBOL(ecm_db_connection_from_interfaces_get_count);
5644
5645/*
5646 * ecm_db_connection_to_interfaces_set_check()
5647 * Returns true if the interface list has been set - even if set to an empty list!
5648 */
5649bool ecm_db_connection_to_interfaces_set_check(struct ecm_db_connection_instance *ci)
5650{
5651 bool set;
5652
5653 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5654 spin_lock_bh(&ecm_db_lock);
5655 set = ci->to_interface_set;
5656 spin_unlock_bh(&ecm_db_lock);
5657 return set;
5658}
5659EXPORT_SYMBOL(ecm_db_connection_to_interfaces_set_check);
5660
5661/*
5662 * ecm_db_connection_from_interfaces_set_check()
5663 * Returns true if the interface list has been set - even if set to an empty list!
5664 */
5665bool ecm_db_connection_from_interfaces_set_check(struct ecm_db_connection_instance *ci)
5666{
5667 bool set;
5668
5669 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5670 spin_lock_bh(&ecm_db_lock);
5671 set = ci->from_interface_set;
5672 spin_unlock_bh(&ecm_db_lock);
5673 return set;
5674}
5675EXPORT_SYMBOL(ecm_db_connection_from_interfaces_set_check);
5676
5677/*
5678 * ecm_db_connection_to_nat_interfaces_set_check()
5679 * Returns true if the interface list has been set - even if set to an empty list!
5680 */
5681bool ecm_db_connection_to_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
5682{
5683 bool set;
5684
5685 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5686 spin_lock_bh(&ecm_db_lock);
5687 set = ci->to_nat_interface_set;
5688 spin_unlock_bh(&ecm_db_lock);
5689 return set;
5690}
5691EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_set_check);
5692
5693/*
5694 * ecm_db_connection_from_nat_interfaces_set_check()
5695 * Returns true if the interface list has been set - even if set to an empty list!
5696 */
5697bool ecm_db_connection_from_nat_interfaces_set_check(struct ecm_db_connection_instance *ci)
5698{
5699 bool set;
5700
5701 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5702 spin_lock_bh(&ecm_db_lock);
5703 set = ci->from_nat_interface_set;
5704 spin_unlock_bh(&ecm_db_lock);
5705 return set;
5706}
5707EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_set_check);
5708
5709/*
5710 * ecm_db_connection_from_interfaces_clear()
5711 * Clear down the interfaces list, marking the list as not set
5712 */
5713void ecm_db_connection_from_interfaces_clear(struct ecm_db_connection_instance *ci)
5714{
5715 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5716 int32_t discard_first;
5717 int32_t i;
5718
5719 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5720
5721 spin_lock_bh(&ecm_db_lock);
5722 for (i = ci->from_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5723 discard[i] = ci->from_interfaces[i];
5724 }
5725
5726 discard_first = ci->from_interface_first;
5727 ci->from_interface_set = false;
5728 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5729 spin_unlock_bh(&ecm_db_lock);
5730
5731 /*
5732 * Release previous
5733 */
5734 ecm_db_connection_interfaces_deref(discard, discard_first);
5735}
5736EXPORT_SYMBOL(ecm_db_connection_from_interfaces_clear);
5737
5738/*
5739 * ecm_db_connection_from_nat_interfaces_clear()
5740 * Clear down the interfaces list, marking the list as not set
5741 */
5742void ecm_db_connection_from_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
5743{
5744 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5745 int32_t discard_first;
5746 int32_t i;
5747
5748 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5749
5750 spin_lock_bh(&ecm_db_lock);
5751 for (i = ci->from_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5752 discard[i] = ci->from_nat_interfaces[i];
5753 }
5754
5755 discard_first = ci->from_nat_interface_first;
5756 ci->from_nat_interface_set = false;
5757 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5758 spin_unlock_bh(&ecm_db_lock);
5759
5760 /*
5761 * Release previous
5762 */
5763 ecm_db_connection_interfaces_deref(discard, discard_first);
5764}
5765EXPORT_SYMBOL(ecm_db_connection_from_nat_interfaces_clear);
5766
5767/*
5768 * ecm_db_connection_to_interfaces_clear()
5769 * Clear down the interfaces list, marking the list as not set
5770 */
5771void ecm_db_connection_to_interfaces_clear(struct ecm_db_connection_instance *ci)
5772{
5773 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5774 int32_t discard_first;
5775 int32_t i;
5776
5777 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5778
5779 spin_lock_bh(&ecm_db_lock);
5780 for (i = ci->to_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5781 discard[i] = ci->to_interfaces[i];
5782 }
5783
5784 discard_first = ci->to_interface_first;
5785 ci->to_interface_set = false;
5786 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5787 spin_unlock_bh(&ecm_db_lock);
5788
5789 /*
5790 * Release previous
5791 */
5792 ecm_db_connection_interfaces_deref(discard, discard_first);
5793}
5794EXPORT_SYMBOL(ecm_db_connection_to_interfaces_clear);
5795
5796/*
5797 * ecm_db_connection_to_nat_interfaces_clear()
5798 * Clear down the interfaces list, marking the list as not set
5799 */
5800void ecm_db_connection_to_nat_interfaces_clear(struct ecm_db_connection_instance *ci)
5801{
5802 struct ecm_db_iface_instance *discard[ECM_DB_IFACE_HEIRARCHY_MAX];
5803 int32_t discard_first;
5804 int32_t i;
5805
5806 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5807
5808 spin_lock_bh(&ecm_db_lock);
5809 for (i = ci->to_nat_interface_first; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
5810 discard[i] = ci->to_nat_interfaces[i];
5811 }
5812
5813 discard_first = ci->to_nat_interface_first;
5814 ci->to_nat_interface_set = false;
5815 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
5816 spin_unlock_bh(&ecm_db_lock);
5817
5818 /*
5819 * Release previous
5820 */
5821 ecm_db_connection_interfaces_deref(discard, discard_first);
5822}
5823EXPORT_SYMBOL(ecm_db_connection_to_nat_interfaces_clear);
5824
5825/*
5826 * ecm_db_connection_add()
5827 * Add the connection into the database.
5828 *
5829 * NOTE: The parameters are DIRECTIONAL in terms of which mapping established the connection.
5830 * 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.
5831 */
5832void ecm_db_connection_add(struct ecm_db_connection_instance *ci,
5833 struct ecm_front_end_connection_instance *feci,
Ben Menchaca84f36632014-02-28 20:57:38 +00005834 struct ecm_db_mapping_instance *mapping_from, struct ecm_db_mapping_instance *mapping_to,
5835 struct ecm_db_mapping_instance *mapping_nat_from, struct ecm_db_mapping_instance *mapping_nat_to,
Gareth Williams90f2a282014-08-27 15:56:25 +01005836 struct ecm_db_node_instance *from_node, struct ecm_db_node_instance *to_node,
5837 struct ecm_db_node_instance *from_nat_node, struct ecm_db_node_instance *to_nat_node,
Ben Menchaca84f36632014-02-28 20:57:38 +00005838 int protocol, ecm_db_direction_t dir,
5839 ecm_db_connection_final_callback_t final,
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07005840 ecm_db_connection_defunct_callback_t defunct,
Ben Menchaca84f36632014-02-28 20:57:38 +00005841 ecm_db_timer_group_t tg, bool is_routed,
5842 void *arg)
5843{
5844 ecm_db_connection_hash_t hash_index;
5845 ecm_db_connection_serial_hash_t serial_hash_index;
5846 struct ecm_db_listener_instance *li;
5847 struct ecm_db_iface_instance *iface_from;
5848 struct ecm_db_iface_instance *iface_to;
5849 struct ecm_db_iface_instance *iface_nat_from;
5850 struct ecm_db_iface_instance *iface_nat_to;
5851
5852 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed\n", ci);
5853 DEBUG_CHECK_MAGIC(mapping_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_from);
5854 DEBUG_CHECK_MAGIC(mapping_to, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_to);
5855 DEBUG_CHECK_MAGIC(mapping_nat_from, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mapping_nat_from);
5856 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 +01005857 DEBUG_CHECK_MAGIC(from_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_node);
5858 DEBUG_CHECK_MAGIC(to_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", to_node);
5859 DEBUG_CHECK_MAGIC(from_nat_node, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", from_nat_node);
5860 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 +00005861 DEBUG_ASSERT((protocol >= 0) && (protocol <= 255), "%p: invalid protocol number %d\n", ci, protocol);
5862
5863 spin_lock_bh(&ecm_db_lock);
5864 DEBUG_ASSERT(!(ci->flags & ECM_DB_CONNECTION_FLAGS_INSERTED), "%p: inserted\n", ci);
5865 spin_unlock_bh(&ecm_db_lock);
5866
5867 /*
5868 * Record owner arg and callbacks
5869 */
5870 ci->final = final;
Murat Sezgin7f6cdf62014-09-11 13:41:06 -07005871 ci->defunct = defunct;
Ben Menchaca84f36632014-02-28 20:57:38 +00005872 ci->arg = arg;
5873
5874 /*
5875 * Take reference to the front end
5876 */
5877 feci->ref(feci);
5878 ci->feci = feci;
5879
5880 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005881 * Ensure default classifier has been assigned this is a must to ensure minimum level of classification
Ben Menchaca84f36632014-02-28 20:57:38 +00005882 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01005883 DEBUG_ASSERT(ci->assignments_by_type[ECM_CLASSIFIER_TYPE_DEFAULT], "%p: No default classifier assigned\n", ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00005884
5885 /*
5886 * Connection takes references to the mappings
5887 */
5888 ecm_db_mapping_ref(mapping_from);
5889 ecm_db_mapping_ref(mapping_to);
5890 ci->mapping_from = mapping_from;
5891 ci->mapping_to = mapping_to;
5892
5893 ecm_db_mapping_ref(mapping_nat_from);
5894 ecm_db_mapping_ref(mapping_nat_to);
5895 ci->mapping_nat_from = mapping_nat_from;
5896 ci->mapping_nat_to = mapping_nat_to;
5897
5898 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01005899 * Take references to the nodes
5900 */
5901 ci->from_node = from_node;
5902 ecm_db_node_ref(from_node);
5903 ci->to_node = to_node;
5904 ecm_db_node_ref(to_node);
5905
5906 ci->from_nat_node = from_nat_node;
5907 ecm_db_node_ref(from_nat_node);
5908 ci->to_nat_node = to_nat_node;
5909 ecm_db_node_ref(to_nat_node);
5910
5911 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00005912 * Set the protocol and routed flag
5913 */
5914 ci->protocol = protocol;
5915 ci->is_routed = is_routed;
5916
5917 /*
5918 * Set direction of connection
5919 */
5920 ci->direction = dir;
5921
5922 /*
5923 * Identify which hash chain this connection will go into
5924 */
5925 hash_index = ecm_db_connection_generate_hash_index(mapping_from->host->address, mapping_from->port, mapping_to->host->address, mapping_to->port, protocol);
5926 ci->hash_index = hash_index;
5927
5928 /*
5929 * Identify which serial hash chain this connection will go into
5930 */
5931 serial_hash_index = ecm_db_connection_generate_serial_hash_index(ci->serial);
5932 ci->serial_hash_index = serial_hash_index;
5933
5934 /*
5935 * Now we need to lock
5936 */
5937 spin_lock_bh(&ecm_db_lock);
5938
5939 /*
5940 * Increment protocol counter stats
5941 */
5942 ecm_db_connection_count_by_protocol[protocol]++;
5943 DEBUG_ASSERT(ecm_db_connection_count_by_protocol[protocol] > 0, "%p: Invalid protocol count %d\n", ci, ecm_db_connection_count_by_protocol[protocol]);
5944
5945 DEBUG_TRACE("c\n");
5946
5947 /*
5948 * Set time
5949 */
5950 ci->time_added = ecm_db_time;
5951
5952 /*
5953 * Add connection into the global list
5954 */
5955 ci->prev = NULL;
5956 ci->next = ecm_db_connections;
5957 if (ecm_db_connections) {
5958 ecm_db_connections->prev = ci;
5959 }
5960 ecm_db_connections = ci;
5961
5962 /*
5963 * Add this connection into the connections hash table
5964 */
5965 ci->flags |= ECM_DB_CONNECTION_FLAGS_INSERTED;
5966
5967 /*
5968 * Insert mapping into the connections hash table
5969 */
5970 ci->hash_next = ecm_db_connection_table[hash_index];
5971 if (ecm_db_connection_table[hash_index]) {
5972 ecm_db_connection_table[hash_index]->hash_prev = ci;
5973 }
5974 ecm_db_connection_table[hash_index] = ci;
5975 ecm_db_connection_table_lengths[hash_index]++;
5976 DEBUG_ASSERT(ecm_db_connection_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ci, ecm_db_connection_table_lengths[hash_index]);
5977
5978 /*
5979 * Insert connection into the connections serial hash table
5980 */
5981 ci->serial_hash_next = ecm_db_connection_serial_table[serial_hash_index];
5982 if (ecm_db_connection_serial_table[serial_hash_index]) {
5983 ecm_db_connection_serial_table[serial_hash_index]->serial_hash_prev = ci;
5984 }
5985 ecm_db_connection_serial_table[serial_hash_index] = ci;
5986 ecm_db_connection_serial_table_lengths[serial_hash_index]++;
5987 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]);
5988
5989 /*
Gareth Williams90f2a282014-08-27 15:56:25 +01005990 * Add this connection into the FROM node
5991 */
5992 ci->node_from_prev = NULL;
5993 ci->node_from_next = from_node->from_connections;
5994 if (from_node->from_connections) {
5995 from_node->from_connections->node_from_prev = ci;
5996 }
5997 from_node->from_connections = ci;
5998 from_node->from_connections_count++;
5999 DEBUG_ASSERT(from_node->from_connections_count > 0, "%p: invalid count\n", ci);
6000
6001 /*
6002 * Add this connection into the TO node
6003 */
6004 ci->node_to_prev = NULL;
6005 ci->node_to_next = to_node->to_connections;
6006 if (to_node->to_connections) {
6007 to_node->to_connections->node_to_prev = ci;
6008 }
6009 to_node->to_connections = ci;
6010 to_node->to_connections_count++;
6011 DEBUG_ASSERT(to_node->to_connections_count > 0, "%p: invalid count\n", ci);
6012
6013 /*
6014 * Add this connection into the FROM NAT node
6015 */
6016 ci->node_from_nat_prev = NULL;
6017 ci->node_from_nat_next = from_nat_node->from_nat_connections;
6018 if (from_nat_node->from_nat_connections) {
6019 from_nat_node->from_nat_connections->node_from_nat_prev = ci;
6020 }
6021 from_nat_node->from_nat_connections = ci;
6022 from_nat_node->from_nat_connections_count++;
6023 DEBUG_ASSERT(from_nat_node->from_nat_connections_count > 0, "%p: invalid count\n", ci);
6024
6025 /*
6026 * Add this connection into the TO NAT node
6027 */
6028 ci->node_to_nat_prev = NULL;
6029 ci->node_to_nat_next = to_nat_node->to_nat_connections;
6030 if (to_nat_node->to_nat_connections) {
6031 to_nat_node->to_nat_connections->node_to_nat_prev = ci;
6032 }
6033 to_nat_node->to_nat_connections = ci;
6034 to_nat_node->to_nat_connections_count++;
6035 DEBUG_ASSERT(to_nat_node->to_nat_connections_count > 0, "%p: invalid count\n", ci);
6036
6037 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00006038 * Add this connection into the FROM mapping
6039 */
6040 ci->from_prev = NULL;
6041 ci->from_next = mapping_from->from_connections;
6042 if (mapping_from->from_connections) {
6043 mapping_from->from_connections->from_prev = ci;
6044 }
6045 mapping_from->from_connections = ci;
6046
6047 /*
6048 * Add this connection into the TO mapping
6049 */
6050 ci->to_prev = NULL;
6051 ci->to_next = mapping_to->to_connections;
6052 if (mapping_to->to_connections) {
6053 mapping_to->to_connections->to_prev = ci;
6054 }
6055 mapping_to->to_connections = ci;
6056
6057 /*
6058 * Add this connection into the FROM NAT mapping
6059 */
6060 ci->from_nat_prev = NULL;
6061 ci->from_nat_next = mapping_nat_from->from_nat_connections;
6062 if (mapping_nat_from->from_nat_connections) {
6063 mapping_nat_from->from_nat_connections->from_nat_prev = ci;
6064 }
6065 mapping_nat_from->from_nat_connections = ci;
6066
6067 /*
6068 * Add this connection into the TO NAT mapping
6069 */
6070 ci->to_nat_prev = NULL;
6071 ci->to_nat_next = mapping_nat_to->to_nat_connections;
6072 if (mapping_nat_to->to_nat_connections) {
6073 mapping_nat_to->to_nat_connections->to_nat_prev = ci;
6074 }
6075 mapping_nat_to->to_nat_connections = ci;
6076
6077 /*
6078 * Add this connection into the FROM iface list of connections
6079 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6080 * due to the heirarchy of dependencies being kept by the database.
6081 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006082 iface_from = from_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006083 ci->iface_from_prev = NULL;
6084 ci->iface_from_next = iface_from->from_connections;
6085 if (iface_from->from_connections) {
6086 iface_from->from_connections->iface_from_prev = ci;
6087 }
6088 iface_from->from_connections = ci;
6089
6090 /*
6091 * Add this connection into the TO iface list of connections
6092 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6093 * due to the heirarchy of dependencies being kept by the database.
6094 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006095 iface_to = to_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006096 ci->iface_to_prev = NULL;
6097 ci->iface_to_next = iface_to->to_connections;
6098 if (iface_to->to_connections) {
6099 iface_to->to_connections->iface_to_prev = ci;
6100 }
6101 iface_to->to_connections = ci;
6102
6103 /*
6104 * Add this connection into the FROM NAT iface list of connections
6105 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6106 * due to the heirarchy of dependencies being kept by the database.
6107 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006108 iface_nat_from = from_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006109 ci->iface_from_nat_prev = NULL;
6110 ci->iface_from_nat_next = iface_nat_from->from_nat_connections;
6111 if (iface_nat_from->from_nat_connections) {
6112 iface_nat_from->from_nat_connections->iface_from_nat_prev = ci;
6113 }
6114 iface_nat_from->from_nat_connections = ci;
6115
6116 /*
6117 * Add this connection into the TO NAT iface list of connections
6118 * NOTE: There is no need to ref the iface because it will exist for as long as this connection exists
6119 * due to the heirarchy of dependencies being kept by the database.
6120 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006121 iface_nat_to = to_nat_node->iface;
Ben Menchaca84f36632014-02-28 20:57:38 +00006122 ci->iface_to_nat_prev = NULL;
6123 ci->iface_to_nat_next = iface_nat_to->to_nat_connections;
6124 if (iface_nat_to->to_nat_connections) {
6125 iface_nat_to->to_nat_connections->iface_to_nat_prev = ci;
6126 }
6127 iface_nat_to->to_nat_connections = ci;
6128
Gareth Williams90f2a282014-08-27 15:56:25 +01006129
Ben Menchaca84f36632014-02-28 20:57:38 +00006130 /*
6131 * NOTE: The interface heirarchy lists are deliberately left empty - these are completed
6132 * by the front end if it is appropriate to do so.
6133 */
6134
6135 /*
6136 * Update the counters in the mapping
6137 */
6138 if (protocol == IPPROTO_UDP) {
6139 mapping_from->udp_from++;
6140 mapping_to->udp_to++;
6141 mapping_nat_from->udp_nat_from++;
6142 mapping_nat_to->udp_nat_to++;
6143 } else if (protocol == IPPROTO_TCP) {
6144 mapping_from->tcp_from++;
6145 mapping_to->tcp_to++;
6146 mapping_nat_from->tcp_nat_from++;
6147 mapping_nat_to->tcp_nat_to++;
6148 }
6149
6150 mapping_from->from++;
6151 mapping_to->to++;
6152 mapping_nat_from->nat_from++;
6153 mapping_nat_to->nat_to++;
6154
6155 /*
6156 * Set the generation number
6157 */
6158 ci->classifier_generation = ecm_db_classifier_generation;
6159
6160 spin_unlock_bh(&ecm_db_lock);
6161
6162 /*
6163 * Throw add event to the listeners
6164 */
6165 DEBUG_TRACE("%p: Throw connection added event\n", ci);
6166 li = ecm_db_listeners_get_and_ref_first();
6167 while (li) {
6168 struct ecm_db_listener_instance *lin;
6169 if (li->connection_added) {
6170 li->connection_added(li->arg, ci);
6171 }
6172
6173 /*
6174 * Get next listener
6175 */
6176 lin = ecm_db_listener_get_and_ref_next(li);
6177 ecm_db_listener_deref(li);
6178 li = lin;
6179 }
6180
6181 /*
6182 * Set timer group. 'ref' the connection to ensure it persists for the timer.
6183 */
6184 ecm_db_connection_ref(ci);
6185 ecm_db_timer_group_entry_set(&ci->defunct_timer, tg);
6186}
6187EXPORT_SYMBOL(ecm_db_connection_add);
6188
6189/*
6190 * ecm_db_mapping_add()
6191 * Add a mapping instance into the database
6192 *
6193 * NOTE: The mapping will take a reference to the host instance.
6194 */
6195void ecm_db_mapping_add(struct ecm_db_mapping_instance *mi, struct ecm_db_host_instance *hi, int port,
6196 ecm_db_mapping_final_callback_t final, void *arg)
6197{
6198 ecm_db_mapping_hash_t hash_index;
6199 struct ecm_db_listener_instance *li;
6200
6201 spin_lock_bh(&ecm_db_lock);
6202 DEBUG_CHECK_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC, "%p: magic failed\n", mi);
6203 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
6204 DEBUG_ASSERT(mi->from_connections == NULL, "%p: connections not null\n", mi);
6205 DEBUG_ASSERT(mi->to_connections == NULL, "%p: connections not null\n", mi);
6206 DEBUG_ASSERT(!(mi->flags & ECM_DB_MAPPING_FLAGS_INSERTED), "%p: inserted\n", mi);
6207 DEBUG_ASSERT((hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: not inserted\n", hi);
6208 DEBUG_ASSERT(!mi->from && !mi->to && !mi->tcp_from && !mi->tcp_to && !mi->udp_from && !mi->udp_to, "%p: count errors\n", mi);
6209 spin_unlock_bh(&ecm_db_lock);
6210
6211 mi->arg = arg;
6212 mi->final = final;
6213
6214 /*
6215 * Compute hash table position for insertion
6216 */
6217 hash_index = ecm_db_mapping_generate_hash_index(hi->address, port);
6218 mi->hash_index = hash_index;
6219
6220 /*
6221 * Record port
6222 */
6223 mi->port = port;
6224
6225 /*
6226 * Mapping takes a ref to the host
6227 */
6228 ecm_db_host_ref(hi);
6229 mi->host = hi;
6230
6231 /*
6232 * Set time
6233 */
6234 spin_lock_bh(&ecm_db_lock);
6235 mi->time_added = ecm_db_time;
6236
6237 /*
6238 * Record the mapping is inserted
6239 */
6240 mi->flags |= ECM_DB_MAPPING_FLAGS_INSERTED;
6241
6242 /*
6243 * Add into the global list
6244 */
6245 mi->prev = NULL;
6246 mi->next = ecm_db_mappings;
6247 if (ecm_db_mappings) {
6248 ecm_db_mappings->prev = mi;
6249 }
6250 ecm_db_mappings = mi;
6251
6252 /*
6253 * Insert mapping into the mappings hash table
6254 */
6255 mi->hash_next = ecm_db_mapping_table[hash_index];
6256 if (ecm_db_mapping_table[hash_index]) {
6257 ecm_db_mapping_table[hash_index]->hash_prev = mi;
6258 }
6259 ecm_db_mapping_table[hash_index] = mi;
6260 ecm_db_mapping_table_lengths[hash_index]++;
6261 DEBUG_ASSERT(ecm_db_mapping_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_mapping_table_lengths[hash_index]);
6262
6263 /*
6264 * Insert mapping into the host mapping list
6265 */
6266 mi->mapping_prev = NULL;
6267 mi->mapping_next = hi->mappings;
6268 if (hi->mappings) {
6269 hi->mappings->mapping_prev = mi;
6270 }
6271 hi->mappings = mi;
6272 hi->mapping_count++;
6273 spin_unlock_bh(&ecm_db_lock);
6274
6275 /*
6276 * Throw add event to the listeners
6277 */
6278 DEBUG_TRACE("%p: Throw mapping added event\n", mi);
6279 li = ecm_db_listeners_get_and_ref_first();
6280 while (li) {
6281 struct ecm_db_listener_instance *lin;
6282 if (li->mapping_added) {
6283 li->mapping_added(li->arg, mi);
6284 }
6285
6286 /*
6287 * Get next listener
6288 */
6289 lin = ecm_db_listener_get_and_ref_next(li);
6290 ecm_db_listener_deref(li);
6291 li = lin;
6292 }
6293}
6294EXPORT_SYMBOL(ecm_db_mapping_add);
6295
6296/*
6297 * ecm_db_host_add()
6298 * Add a host instance into the database
6299 */
Gareth Williams90f2a282014-08-27 15:56:25 +01006300void 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 +00006301{
6302 ecm_db_host_hash_t hash_index;
6303 struct ecm_db_listener_instance *li;
6304
6305 spin_lock_bh(&ecm_db_lock);
6306 DEBUG_CHECK_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC, "%p: magic failed\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00006307 DEBUG_ASSERT((hi->mappings == NULL) && (hi->mapping_count == 0), "%p: mappings not null\n", hi);
Ben Menchaca84f36632014-02-28 20:57:38 +00006308 DEBUG_ASSERT(!(hi->flags & ECM_DB_HOST_FLAGS_INSERTED), "%p: inserted\n", hi);
6309 spin_unlock_bh(&ecm_db_lock);
6310
6311 hi->arg = arg;
6312 hi->final = final;
6313 ECM_IP_ADDR_COPY(hi->address, address);
6314 hi->on_link = on_link;
6315
6316 /*
6317 * Compute hash index into which host will be added
6318 */
6319 hash_index = ecm_db_host_generate_hash_index(address);
6320 hi->hash_index = hash_index;
6321
6322 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00006323 * Add into the global list
6324 */
6325 spin_lock_bh(&ecm_db_lock);
6326 hi->flags |= ECM_DB_HOST_FLAGS_INSERTED;
6327 hi->prev = NULL;
6328 hi->next = ecm_db_hosts;
6329 if (ecm_db_hosts) {
6330 ecm_db_hosts->prev = hi;
6331 }
6332 ecm_db_hosts = hi;
6333
6334 /*
6335 * Add host into the hash table
6336 */
6337 hi->hash_next = ecm_db_host_table[hash_index];
6338 if (ecm_db_host_table[hash_index]) {
6339 ecm_db_host_table[hash_index]->hash_prev = hi;
6340 }
6341 ecm_db_host_table[hash_index] = hi;
6342 ecm_db_host_table_lengths[hash_index]++;
6343 DEBUG_ASSERT(ecm_db_host_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", hi, ecm_db_host_table_lengths[hash_index]);
6344
6345 /*
6346 * Set time of add
6347 */
6348 hi->time_added = ecm_db_time;
Ben Menchaca84f36632014-02-28 20:57:38 +00006349 spin_unlock_bh(&ecm_db_lock);
6350
6351 /*
6352 * Throw add event to the listeners
6353 */
6354 DEBUG_TRACE("%p: Throw host added event\n", hi);
6355 li = ecm_db_listeners_get_and_ref_first();
6356 while (li) {
6357 struct ecm_db_listener_instance *lin;
6358 if (li->host_added) {
6359 li->host_added(li->arg, hi);
6360 }
6361
6362 /*
6363 * Get next listener
6364 */
6365 lin = ecm_db_listener_get_and_ref_next(li);
6366 ecm_db_listener_deref(li);
6367 li = lin;
6368 }
6369}
6370EXPORT_SYMBOL(ecm_db_host_add);
6371
6372/*
6373 * ecm_db_node_add()
6374 * Add a node instance into the database
6375 */
6376void ecm_db_node_add(struct ecm_db_node_instance *ni, struct ecm_db_iface_instance *ii, uint8_t *address,
6377 ecm_db_node_final_callback_t final, void *arg)
6378{
6379 ecm_db_node_hash_t hash_index;
6380 struct ecm_db_listener_instance *li;
6381
6382 spin_lock_bh(&ecm_db_lock);
6383 DEBUG_CHECK_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC, "%p: magic failed\n", ni);
6384 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6385 DEBUG_ASSERT(address, "%p: address null\n", ni);
Gareth Williams90f2a282014-08-27 15:56:25 +01006386 DEBUG_ASSERT((ni->from_connections == NULL) && (ni->from_connections_count == 0), "%p: from_connections not null\n", ni);
6387 DEBUG_ASSERT((ni->to_connections == NULL) && (ni->to_connections_count == 0), "%p: to_connections not null\n", ni);
6388 DEBUG_ASSERT((ni->from_nat_connections == NULL) && (ni->from_nat_connections_count == 0), "%p: from_nat_connections not null\n", ni);
6389 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 +00006390 DEBUG_ASSERT((ni->iface == NULL), "%p: iface not null\n", ni);
6391 DEBUG_ASSERT(!(ni->flags & ECM_DB_NODE_FLAGS_INSERTED), "%p: inserted\n", ni);
6392 spin_unlock_bh(&ecm_db_lock);
6393
6394 memcpy(ni->address, address, ETH_ALEN);
6395 ni->arg = arg;
6396 ni->final = final;
6397
6398 /*
6399 * Compute hash chain for insertion
6400 */
6401 hash_index = ecm_db_node_generate_hash_index(address);
6402 ni->hash_index = hash_index;
6403
6404 /*
6405 * Node takes a ref to the iface
6406 */
6407 ecm_db_iface_ref(ii);
6408 ni->iface = ii;
6409
6410 /*
6411 * Add into the global list
6412 */
6413 spin_lock_bh(&ecm_db_lock);
6414 ni->flags |= ECM_DB_NODE_FLAGS_INSERTED;
6415 ni->prev = NULL;
6416 ni->next = ecm_db_nodes;
6417 if (ecm_db_nodes) {
6418 ecm_db_nodes->prev = ni;
6419 }
6420 ecm_db_nodes = ni;
6421
6422 /*
6423 * Insert into the hash chain
6424 */
6425 ni->hash_next = ecm_db_node_table[hash_index];
6426 if (ecm_db_node_table[hash_index]) {
6427 ecm_db_node_table[hash_index]->hash_prev = ni;
6428 }
6429 ecm_db_node_table[hash_index] = ni;
6430 ecm_db_node_table_lengths[hash_index]++;
6431 DEBUG_ASSERT(ecm_db_node_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ni, ecm_db_node_table_lengths[hash_index]);
6432
6433 /*
6434 * Set time of add
6435 */
6436 ni->time_added = ecm_db_time;
6437
6438 /*
6439 * Insert node into the iface nodes list
6440 */
6441 ni->node_prev = NULL;
6442 ni->node_next = ii->nodes;
6443 if (ii->nodes) {
6444 ii->nodes->node_prev = ni;
6445 }
6446 ii->nodes = ni;
6447 ii->node_count++;
6448 spin_unlock_bh(&ecm_db_lock);
6449
6450 /*
6451 * Throw add event to the listeners
6452 */
6453 DEBUG_TRACE("%p: Throw node added event\n", ni);
6454 li = ecm_db_listeners_get_and_ref_first();
6455 while (li) {
6456 struct ecm_db_listener_instance *lin;
6457 if (li->node_added) {
6458 li->node_added(li->arg, ni);
6459 }
6460
6461 /*
6462 * Get next listener
6463 */
6464 lin = ecm_db_listener_get_and_ref_next(li);
6465 ecm_db_listener_deref(li);
6466 li = lin;
6467 }
6468}
6469EXPORT_SYMBOL(ecm_db_node_add);
6470
6471/*
6472 * ecm_db_iface_xml_state_get_open()
6473 * Get the start of XML state for an interface object
6474 */
6475static int ecm_db_iface_xml_state_get_open(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6476{
6477 int count;
6478 int node_count;
6479 uint32_t time_added;
6480 uint64_t from_data_total;
6481 uint64_t to_data_total;
6482 uint64_t from_packet_total;
6483 uint64_t to_packet_total;
6484 uint64_t from_data_total_dropped;
6485 uint64_t to_data_total_dropped;
6486 uint64_t from_packet_total_dropped;
6487 uint64_t to_packet_total_dropped;
6488 int32_t interface_identifier;
6489 int32_t nss_interface_identifier;
6490 char name[IFNAMSIZ];
6491 int32_t mtu;
6492 ecm_db_iface_type_t type;
6493
6494 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6495 DEBUG_TRACE("%p: Open iface msg\n", ii);
6496
6497 /*
6498 * Create a small xml stats block, like:
6499 * <iface blah="" ... >
6500 * Extract general information from the iface for inclusion into the message
6501 */
6502 node_count = ecm_db_iface_node_count_get(ii);
6503 time_added = ii->time_added;
6504 ecm_db_iface_data_stats_get(ii, &from_data_total, &to_data_total,
6505 &from_packet_total, &to_packet_total,
6506 &from_data_total_dropped, &to_data_total_dropped,
6507 &from_packet_total_dropped, &to_packet_total_dropped);
6508 type = ii->type;
6509 spin_lock_bh(&ecm_db_lock);
6510 strcpy(name, ii->name);
6511 mtu = ii->mtu;
6512 interface_identifier = ii->interface_identifier;
6513 nss_interface_identifier = ii->nss_interface_identifier;
6514 spin_unlock_bh(&ecm_db_lock);
6515
6516 /*
6517 * Prep the message
6518 */
6519 count = snprintf(buf, buf_sz,
6520 "<iface type=\"%d\" name=\"%s\" nodes=\"%d\" time_added=\"%u\""
6521 " mtu=\"%d\" interface_identifier=\"%d\" nss_interface_identifier=\"%d\""
6522 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
6523 " from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\">\n",
6524 type,
6525 name,
6526 node_count,
6527 time_added,
6528 mtu,
6529 interface_identifier,
6530 nss_interface_identifier,
6531 from_data_total,
6532 to_data_total,
6533 from_packet_total,
6534 to_packet_total,
6535 from_data_total_dropped,
6536 to_data_total_dropped,
6537 from_packet_total_dropped,
6538 to_packet_total_dropped);
6539
6540 if ((count <= 0) || (count >= buf_sz)) {
6541 return -1;
6542 }
6543
6544 return count;
6545}
6546
6547/*
6548 * ecm_db_iface_xml_state_get_close()
6549 * Get the end of XML state for an interface object
6550 */
6551static int ecm_db_iface_xml_state_get_close(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6552{
6553 int count;
6554
6555 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6556 DEBUG_TRACE("%p: Close iface msg\n", ii);
6557
6558 /*
6559 * Create a small xml stats block, like:
6560 * </iface>
6561 */
6562
6563 /*
6564 * Prep the message
6565 */
6566 count = snprintf(buf, buf_sz, "</iface>\n");
6567
6568 if ((count <= 0) || (count >= buf_sz)) {
6569 return -1;
6570 }
6571
6572 return count;
6573}
6574
6575/*
6576 * ecm_db_iface_ethernet_xml_state_get()
6577 * Return interface type specific state
6578 */
6579static int ecm_db_iface_ethernet_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6580{
6581 int count;
6582 int total;
6583 uint8_t address[ETH_ALEN];
6584
6585 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6586 spin_lock_bh(&ecm_db_lock);
6587 memcpy(address, ii->type_info.ethernet.address, ETH_ALEN);
6588 spin_unlock_bh(&ecm_db_lock);
6589
6590 /*
6591 * Write out opening element
6592 */
6593 total = 0;
6594 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
6595 if ((count <= 0) || (count >= (buf_sz - total))) {
6596 return -1;
6597 }
6598 total += count;
6599
6600 /*
6601 * Write out type specific data
6602 */
6603 count = snprintf(buf + total, buf_sz - total, "<ethernet address=\"%pM\"/>\n", address);
6604 if ((count <= 0) || (count >= (buf_sz - total))) {
6605 return -1;
6606 }
6607 total += count;
6608
6609 /*
6610 * Write out closing element
6611 */
6612 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
6613 if ((count <= 0) || (count >= (buf_sz - total))) {
6614 return -1;
6615 }
6616 total += count;
6617 return total;
6618}
6619
6620/*
6621 * ecm_db_iface_add_ethernet()
6622 * Add a iface instance into the database
6623 */
6624void ecm_db_iface_add_ethernet(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
6625 int32_t interface_identifier, int32_t nss_interface_identifier,
6626 ecm_db_iface_final_callback_t final, void *arg)
6627{
6628 ecm_db_iface_hash_t hash_index;
6629 struct ecm_db_listener_instance *li;
6630 struct ecm_db_interface_info_ethernet *type_info;
6631
6632 spin_lock_bh(&ecm_db_lock);
6633 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6634 DEBUG_ASSERT(address, "%p: address null\n", ii);
6635 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
6636 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
6637 DEBUG_ASSERT(name, "%p: no name given\n", ii);
6638 spin_unlock_bh(&ecm_db_lock);
6639
6640 /*
6641 * Record general info
6642 */
6643 ii->type = ECM_DB_IFACE_TYPE_ETHERNET;
6644 ii->xml_state_get = ecm_db_iface_ethernet_xml_state_get;
6645 ii->arg = arg;
6646 ii->final = final;
6647 strcpy(ii->name, name);
6648 ii->mtu = mtu;
6649 ii->interface_identifier = interface_identifier;
6650 ii->nss_interface_identifier = nss_interface_identifier;
6651
6652 /*
6653 * Type specific info
6654 */
6655 type_info = &ii->type_info.ethernet;
6656 memcpy(type_info->address, address, ETH_ALEN);
6657
6658 /*
6659 * Compute hash chain for insertion
6660 */
6661 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
6662 ii->hash_index = hash_index;
6663
6664 /*
6665 * Add into the global list
6666 */
6667 spin_lock_bh(&ecm_db_lock);
6668 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
6669 ii->prev = NULL;
6670 ii->next = ecm_db_interfaces;
6671 if (ecm_db_interfaces) {
6672 ecm_db_interfaces->prev = ii;
6673 }
6674 ecm_db_interfaces = ii;
6675
6676 /*
6677 * Insert into chain
6678 */
6679 ii->hash_next = ecm_db_iface_table[hash_index];
6680 if (ecm_db_iface_table[hash_index]) {
6681 ecm_db_iface_table[hash_index]->hash_prev = ii;
6682 }
6683 ecm_db_iface_table[hash_index] = ii;
6684 ecm_db_iface_table_lengths[hash_index]++;
6685 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
6686
6687 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);
6688
6689 /*
6690 * Set time of addition
6691 */
6692 ii->time_added = ecm_db_time;
6693 spin_unlock_bh(&ecm_db_lock);
6694
6695 /*
6696 * Throw add event to the listeners
6697 */
6698 DEBUG_TRACE("%p: Throw iface added event\n", ii);
6699 li = ecm_db_listeners_get_and_ref_first();
6700 while (li) {
6701 struct ecm_db_listener_instance *lin;
6702 if (li->iface_added) {
6703 li->iface_added(li->arg, ii);
6704 }
6705
6706 /*
6707 * Get next listener
6708 */
6709 lin = ecm_db_listener_get_and_ref_next(li);
6710 ecm_db_listener_deref(li);
6711 li = lin;
6712 }
6713}
6714EXPORT_SYMBOL(ecm_db_iface_add_ethernet);
6715
6716/*
6717 * ecm_db_iface_lag_xml_state_get()
6718 * Return interface type specific state
6719 */
6720static int ecm_db_iface_lag_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6721{
6722 int count;
6723 int total;
6724 uint8_t address[ETH_ALEN];
6725
6726 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6727 spin_lock_bh(&ecm_db_lock);
6728 memcpy(address, ii->type_info.lag.address, ETH_ALEN);
6729 spin_unlock_bh(&ecm_db_lock);
6730
6731 /*
6732 * Write out opening element
6733 */
6734 total = 0;
6735 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
6736 if ((count <= 0) || (count >= (buf_sz - total))) {
6737 return -1;
6738 }
6739 total += count;
6740
6741 /*
6742 * Write out type specific data
6743 */
6744 count = snprintf(buf + total, buf_sz - total, "<lag address=\"%pM\"/>\n", address);
6745 if ((count <= 0) || (count >= (buf_sz - total))) {
6746 return -1;
6747 }
6748 total += count;
6749
6750 /*
6751 * Write out closing element
6752 */
6753 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
6754 if ((count <= 0) || (count == (buf_sz - total))) {
6755 return -1;
6756 }
6757 total += count;
6758 return total;
6759}
6760
6761/*
6762 * ecm_db_iface_add_lag()
6763 * Add a iface instance into the database
6764 */
6765void ecm_db_iface_add_lag(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
6766 int32_t interface_identifier, int32_t nss_interface_identifier,
6767 ecm_db_iface_final_callback_t final, void *arg)
6768{
6769 ecm_db_iface_hash_t hash_index;
6770 struct ecm_db_listener_instance *li;
6771 struct ecm_db_interface_info_lag *type_info;
6772
6773 spin_lock_bh(&ecm_db_lock);
6774 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6775 DEBUG_ASSERT(address, "%p: address null\n", ii);
6776 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
6777 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
6778 DEBUG_ASSERT(name, "%p: no name given\n", ii);
6779 spin_unlock_bh(&ecm_db_lock);
6780
6781 /*
6782 * Record general info
6783 */
6784 ii->type = ECM_DB_IFACE_TYPE_LAG;
6785 ii->xml_state_get = ecm_db_iface_lag_xml_state_get;
6786 ii->arg = arg;
6787 ii->final = final;
6788 strcpy(ii->name, name);
6789 ii->mtu = mtu;
6790 ii->interface_identifier = interface_identifier;
6791 ii->nss_interface_identifier = nss_interface_identifier;
6792
6793 /*
6794 * Type specific info
6795 */
6796 type_info = &ii->type_info.lag;
6797 memcpy(type_info->address, address, ETH_ALEN);
6798
6799 /*
6800 * Compute hash chain for insertion
6801 */
6802 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
6803 ii->hash_index = hash_index;
6804
6805 /*
6806 * Add into the global list
6807 */
6808 spin_lock_bh(&ecm_db_lock);
6809 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
6810 ii->prev = NULL;
6811 ii->next = ecm_db_interfaces;
6812 if (ecm_db_interfaces) {
6813 ecm_db_interfaces->prev = ii;
6814 }
6815 ecm_db_interfaces = ii;
6816
6817 /*
6818 * Insert into chain
6819 */
6820 ii->hash_next = ecm_db_iface_table[hash_index];
6821 if (ecm_db_iface_table[hash_index]) {
6822 ecm_db_iface_table[hash_index]->hash_prev = ii;
6823 }
6824 ecm_db_iface_table[hash_index] = ii;
6825 ecm_db_iface_table_lengths[hash_index]++;
6826 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
6827
6828 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);
6829
6830 /*
6831 * Set time of addition
6832 */
6833 ii->time_added = ecm_db_time;
6834 spin_unlock_bh(&ecm_db_lock);
6835
6836 /*
6837 * Throw add event to the listeners
6838 */
6839 DEBUG_TRACE("%p: Throw iface added event\n", ii);
6840 li = ecm_db_listeners_get_and_ref_first();
6841 while (li) {
6842 struct ecm_db_listener_instance *lin;
6843 if (li->iface_added) {
6844 li->iface_added(li->arg, ii);
6845 }
6846
6847 /*
6848 * Get next listener
6849 */
6850 lin = ecm_db_listener_get_and_ref_next(li);
6851 ecm_db_listener_deref(li);
6852 li = lin;
6853 }
6854}
6855EXPORT_SYMBOL(ecm_db_iface_add_lag);
6856
6857/*
6858 * ecm_db_iface_bridge_xml_state_get()
6859 * Return interface type specific state
6860 */
6861static int ecm_db_iface_bridge_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
6862{
6863 int count;
6864 int total;
6865 uint8_t address[ETH_ALEN];
6866
6867 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6868 spin_lock_bh(&ecm_db_lock);
6869 memcpy(address, ii->type_info.bridge.address, ETH_ALEN);
6870 spin_unlock_bh(&ecm_db_lock);
6871
6872 /*
6873 * Write out opening element
6874 */
6875 total = 0;
6876 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
6877 if ((count <= 0) || (count >= (buf_sz - total))) {
6878 return -1;
6879 }
6880 total += count;
6881
6882 /*
6883 * Write out type specific data
6884 */
6885 count = snprintf(buf + total, buf_sz - total, "<bridge address=\"%pM\"/>\n", address);
6886 if ((count <= 0) || (count >= (buf_sz - total))) {
6887 return -1;
6888 }
6889 total += count;
6890
6891 /*
6892 * Write out closing element
6893 */
6894 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
6895 if ((count <= 0) || (count >= (buf_sz - total))) {
6896 return -1;
6897 }
6898 total += count;
6899 return total;
6900}
6901
6902/*
6903 * ecm_db_iface_add_bridge()
6904 * Add a iface instance into the database
6905 */
6906void ecm_db_iface_add_bridge(struct ecm_db_iface_instance *ii, uint8_t *address, char *name, int32_t mtu,
6907 int32_t interface_identifier, int32_t nss_interface_identifier,
6908 ecm_db_iface_final_callback_t final, void *arg)
6909{
6910 ecm_db_iface_hash_t hash_index;
6911 struct ecm_db_listener_instance *li;
6912 struct ecm_db_interface_info_bridge *type_info;
6913
6914 spin_lock_bh(&ecm_db_lock);
6915 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
6916 DEBUG_ASSERT(address, "%p: address null\n", ii);
6917 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
6918 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
6919 DEBUG_ASSERT(name, "%p: no name given\n", ii);
6920 spin_unlock_bh(&ecm_db_lock);
6921
6922 /*
6923 * Record general info
6924 */
6925 ii->type = ECM_DB_IFACE_TYPE_BRIDGE;
6926 ii->xml_state_get = ecm_db_iface_bridge_xml_state_get;
6927 ii->arg = arg;
6928 ii->final = final;
6929 strcpy(ii->name, name);
6930 ii->mtu = mtu;
6931 ii->interface_identifier = interface_identifier;
6932 ii->nss_interface_identifier = nss_interface_identifier;
6933
6934 /*
6935 * Type specific info
6936 */
6937 type_info = &ii->type_info.bridge;
6938 memcpy(type_info->address, address, ETH_ALEN);
6939
6940 /*
6941 * Compute hash chain for insertion
6942 */
6943 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
6944 ii->hash_index = hash_index;
6945
6946 /*
6947 * Add into the global list
6948 */
6949 spin_lock_bh(&ecm_db_lock);
6950 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
6951 ii->prev = NULL;
6952 ii->next = ecm_db_interfaces;
6953 if (ecm_db_interfaces) {
6954 ecm_db_interfaces->prev = ii;
6955 }
6956 ecm_db_interfaces = ii;
6957
6958 /*
6959 * Insert into chain
6960 */
6961 ii->hash_next = ecm_db_iface_table[hash_index];
6962 if (ecm_db_iface_table[hash_index]) {
6963 ecm_db_iface_table[hash_index]->hash_prev = ii;
6964 }
6965 ecm_db_iface_table[hash_index] = ii;
6966 ecm_db_iface_table_lengths[hash_index]++;
6967 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
6968
6969 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);
6970
6971 /*
6972 * Set time of addition
6973 */
6974 ii->time_added = ecm_db_time;
6975 spin_unlock_bh(&ecm_db_lock);
6976
6977 /*
6978 * Throw add event to the listeners
6979 */
6980 DEBUG_TRACE("%p: Throw iface added event\n", ii);
6981 li = ecm_db_listeners_get_and_ref_first();
6982 while (li) {
6983 struct ecm_db_listener_instance *lin;
6984 if (li->iface_added) {
6985 li->iface_added(li->arg, ii);
6986 }
6987
6988 /*
6989 * Get next listener
6990 */
6991 lin = ecm_db_listener_get_and_ref_next(li);
6992 ecm_db_listener_deref(li);
6993 li = lin;
6994 }
6995}
6996EXPORT_SYMBOL(ecm_db_iface_add_bridge);
6997
6998/*
6999 * ecm_db_iface_vlan_xml_state_get()
7000 * Return interface type specific state
7001 */
7002static int ecm_db_iface_vlan_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7003{
7004 int count;
7005 int total;
7006 uint8_t address[ETH_ALEN];
7007 uint16_t vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307008 uint16_t vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007009
7010 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7011 spin_lock_bh(&ecm_db_lock);
7012 memcpy(address, ii->type_info.vlan.address, ETH_ALEN);
7013 vlan_tag = ii->type_info.vlan.vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307014 vlan_tpid = ii->type_info.vlan.vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007015 spin_unlock_bh(&ecm_db_lock);
7016
7017 /*
7018 * Write out opening element
7019 */
7020 total = 0;
7021 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7022 if ((count <= 0) || (count >= (buf_sz - total))) {
7023 return -1;
7024 }
7025 total += count;
7026
7027 /*
7028 * Write out type specific data
7029 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307030 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 +00007031 if ((count <= 0) || (count >= (buf_sz - total))) {
7032 return -1;
7033 }
7034 total += count;
7035
7036 /*
7037 * Write out closing element
7038 */
7039 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7040 if ((count <= 0) || (count >= (buf_sz - total))) {
7041 return -1;
7042 }
7043 total += count;
7044 return total;
7045}
7046
7047/*
7048 * ecm_db_iface_add_vlan()
7049 * Add a iface instance into the database
7050 */
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307051void 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 +00007052 int32_t interface_identifier, int32_t nss_interface_identifier,
7053 ecm_db_iface_final_callback_t final, void *arg)
7054{
7055 ecm_db_iface_hash_t hash_index;
7056 struct ecm_db_listener_instance *li;
7057 struct ecm_db_interface_info_vlan *type_info;
7058
7059 spin_lock_bh(&ecm_db_lock);
7060 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7061 DEBUG_ASSERT(address, "%p: address null\n", ii);
7062 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7063 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7064 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7065 spin_unlock_bh(&ecm_db_lock);
7066
7067 /*
7068 * Record general info
7069 */
7070 ii->type = ECM_DB_IFACE_TYPE_VLAN;
7071 ii->xml_state_get = ecm_db_iface_vlan_xml_state_get;
7072 ii->arg = arg;
7073 ii->final = final;
7074 strcpy(ii->name, name);
7075 ii->mtu = mtu;
7076 ii->interface_identifier = interface_identifier;
7077 ii->nss_interface_identifier = nss_interface_identifier;
7078
7079 /*
7080 * Type specific info
7081 */
7082 type_info = &ii->type_info.vlan;
7083 type_info->vlan_tag = vlan_tag;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05307084 type_info->vlan_tpid = vlan_tpid;
Ben Menchaca84f36632014-02-28 20:57:38 +00007085 memcpy(type_info->address, address, ETH_ALEN);
7086
7087 /*
7088 * Compute hash chain for insertion
7089 */
7090 hash_index = ecm_db_iface_generate_hash_index_ethernet(address);
7091 ii->hash_index = hash_index;
7092
7093 /*
7094 * Add into the global list
7095 */
7096 spin_lock_bh(&ecm_db_lock);
7097 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7098 ii->prev = NULL;
7099 ii->next = ecm_db_interfaces;
7100 if (ecm_db_interfaces) {
7101 ecm_db_interfaces->prev = ii;
7102 }
7103 ecm_db_interfaces = ii;
7104
7105 /*
7106 * Insert into chain
7107 */
7108 ii->hash_next = ecm_db_iface_table[hash_index];
7109 if (ecm_db_iface_table[hash_index]) {
7110 ecm_db_iface_table[hash_index]->hash_prev = ii;
7111 }
7112 ecm_db_iface_table[hash_index] = ii;
7113 ecm_db_iface_table_lengths[hash_index]++;
7114 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7115
7116 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);
7117
7118 /*
7119 * Set time of addition
7120 */
7121 ii->time_added = ecm_db_time;
7122 spin_unlock_bh(&ecm_db_lock);
7123
7124 /*
7125 * Throw add event to the listeners
7126 */
7127 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7128 li = ecm_db_listeners_get_and_ref_first();
7129 while (li) {
7130 struct ecm_db_listener_instance *lin;
7131 if (li->iface_added) {
7132 li->iface_added(li->arg, ii);
7133 }
7134
7135 /*
7136 * Get next listener
7137 */
7138 lin = ecm_db_listener_get_and_ref_next(li);
7139 ecm_db_listener_deref(li);
7140 li = lin;
7141 }
7142}
7143EXPORT_SYMBOL(ecm_db_iface_add_vlan);
7144
7145/*
7146 * ecm_db_iface_pppoe_xml_state_get()
7147 * Return interface type specific state
7148 */
7149static int ecm_db_iface_pppoe_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7150{
7151 int count;
7152 int total;
7153 uint16_t pppoe_session_id;
7154 uint8_t remote_mac[ETH_ALEN];
7155
7156 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7157 spin_lock_bh(&ecm_db_lock);
7158 pppoe_session_id = ii->type_info.pppoe.pppoe_session_id;
7159 memcpy(remote_mac, ii->type_info.pppoe.remote_mac, ETH_ALEN);
7160 spin_unlock_bh(&ecm_db_lock);
7161
7162 /*
7163 * Write out opening element
7164 */
7165 total = 0;
7166 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7167 if ((count <= 0) || (count >= (buf_sz - total))) {
7168 return -1;
7169 }
7170 total += count;
7171
7172 /*
7173 * Write out type specific data
7174 */
7175 count = snprintf(buf + total, buf_sz - total, "<pppoe pppoe_session_id=\"%u\" remote_mac=\"%pM\"/>\n",
7176 pppoe_session_id, remote_mac);
7177 if ((count <= 0) || (count >= (buf_sz - total))) {
7178 return -1;
7179 }
7180 total += count;
7181
7182 /*
7183 * Write out closing element
7184 */
7185 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7186 if ((count <= 0) || (count >= (buf_sz - total))) {
7187 return -1;
7188 }
7189 total += count;
7190 return total;
7191}
7192
7193/*
7194 * ecm_db_iface_add_pppoe()
7195 * Add a iface instance into the database
7196 */
7197void ecm_db_iface_add_pppoe(struct ecm_db_iface_instance *ii, uint16_t pppoe_session_id, uint8_t *remote_mac,
7198 char *name, int32_t mtu, int32_t interface_identifier,
7199 int32_t nss_interface_identifier, ecm_db_iface_final_callback_t final,
7200 void *arg)
7201{
7202 ecm_db_iface_hash_t hash_index;
7203 struct ecm_db_listener_instance *li;
7204 struct ecm_db_interface_info_pppoe *type_info;
7205
7206 spin_lock_bh(&ecm_db_lock);
7207 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7208 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7209 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7210 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7211 spin_unlock_bh(&ecm_db_lock);
7212
7213 /*
7214 * Record general info
7215 */
7216 ii->type = ECM_DB_IFACE_TYPE_PPPOE;
7217 ii->xml_state_get = ecm_db_iface_pppoe_xml_state_get;
7218 ii->arg = arg;
7219 ii->final = final;
7220 strcpy(ii->name, name);
7221 ii->mtu = mtu;
7222 ii->interface_identifier = interface_identifier;
7223 ii->nss_interface_identifier = nss_interface_identifier;
7224
7225 /*
7226 * Type specific info
7227 */
7228 type_info = &ii->type_info.pppoe;
7229 type_info->pppoe_session_id = pppoe_session_id;
7230 memcpy(type_info->remote_mac, remote_mac, ETH_ALEN);
7231
7232 /*
7233 * Compute hash chain for insertion
7234 */
7235 hash_index = ecm_db_iface_generate_hash_index_pppoe(pppoe_session_id);
7236 ii->hash_index = hash_index;
7237
7238 /*
7239 * Add into the global list
7240 */
7241 spin_lock_bh(&ecm_db_lock);
7242 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7243 ii->prev = NULL;
7244 ii->next = ecm_db_interfaces;
7245 if (ecm_db_interfaces) {
7246 ecm_db_interfaces->prev = ii;
7247 }
7248 ecm_db_interfaces = ii;
7249
7250 /*
7251 * Insert into chain
7252 */
7253 ii->hash_next = ecm_db_iface_table[hash_index];
7254 if (ecm_db_iface_table[hash_index]) {
7255 ecm_db_iface_table[hash_index]->hash_prev = ii;
7256 }
7257 ecm_db_iface_table[hash_index] = ii;
7258 ecm_db_iface_table_lengths[hash_index]++;
7259 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7260
7261 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);
7262
7263 /*
7264 * Set time of addition
7265 */
7266 ii->time_added = ecm_db_time;
7267 spin_unlock_bh(&ecm_db_lock);
7268
7269 /*
7270 * Throw add event to the listeners
7271 */
7272 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7273 li = ecm_db_listeners_get_and_ref_first();
7274 while (li) {
7275 struct ecm_db_listener_instance *lin;
7276 if (li->iface_added) {
7277 li->iface_added(li->arg, ii);
7278 }
7279
7280 /*
7281 * Get next listener
7282 */
7283 lin = ecm_db_listener_get_and_ref_next(li);
7284 ecm_db_listener_deref(li);
7285 li = lin;
7286 }
7287}
7288EXPORT_SYMBOL(ecm_db_iface_add_pppoe);
7289
7290/*
7291 * ecm_db_iface_unknown_xml_state_get()
7292 * Return interface type specific state
7293 */
7294static int ecm_db_iface_unknown_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7295{
7296 int count;
7297 int total;
7298 uint32_t os_specific_ident;
7299
7300 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7301 spin_lock_bh(&ecm_db_lock);
7302 os_specific_ident = ii->type_info.unknown.os_specific_ident;
7303 spin_unlock_bh(&ecm_db_lock);
7304
7305 /*
7306 * Write out opening element
7307 */
7308 total = 0;
7309 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7310 if ((count <= 0) || (count >= (buf_sz - total))) {
7311 return -1;
7312 }
7313 total += count;
7314
7315 /*
7316 * Write out type specific data
7317 */
7318 count = snprintf(buf + total, buf_sz - total, "<unknown os_specific_ident=\"%u\"/>\n", os_specific_ident);
7319 if ((count <= 0) || (count >= (buf_sz - total))) {
7320 return -1;
7321 }
7322 total += count;
7323
7324 /*
7325 * Write out closing element
7326 */
7327 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7328 if ((count <= 0) || (count >= (buf_sz - total))) {
7329 return -1;
7330 }
7331 total += count;
7332 return total;
7333}
7334
7335/*
7336 * ecm_db_iface_loopback_xml_state_get()
7337 * Return interface type specific state
7338 */
7339static int ecm_db_iface_loopback_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7340{
7341 int count;
7342 int total;
7343 uint32_t os_specific_ident;
7344
7345 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7346 spin_lock_bh(&ecm_db_lock);
7347 os_specific_ident = ii->type_info.loopback.os_specific_ident;
7348 spin_unlock_bh(&ecm_db_lock);
7349
7350 /*
7351 * Write out opening element
7352 */
7353 total = 0;
7354 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7355 if ((count <= 0) || (count >= (buf_sz - total))) {
7356 return -1;
7357 }
7358 total += count;
7359
7360 /*
7361 * Write out type specific data
7362 */
7363 count = snprintf(buf + total, buf_sz - total, "<loopback os_specific_ident=\"%u\"/>\n", os_specific_ident);
7364 if ((count <= 0) || (count >= (buf_sz - total))) {
7365 return -1;
7366 }
7367 total += count;
7368
7369 /*
7370 * Write out closing element
7371 */
7372 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7373 if ((count <= 0) || (count >= (buf_sz - total))) {
7374 return -1;
7375 }
7376 total += count;
7377 return total;
7378}
7379
7380/*
7381 * ecm_db_iface_ipsec_tunnel_xml_state_get()
7382 * Return interface type specific state
7383 *
7384 * GGG TODO Output state on ipsec tunnel specific data
7385 */
7386static int ecm_db_iface_ipsec_tunnel_xml_state_get(struct ecm_db_iface_instance *ii, char *buf, int buf_sz)
7387{
7388 int count;
7389 int total;
7390 uint32_t os_specific_ident;
7391
7392 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7393 spin_lock_bh(&ecm_db_lock);
7394 os_specific_ident = ii->type_info.ipsec_tunnel.os_specific_ident;
7395 spin_unlock_bh(&ecm_db_lock);
7396
7397 /*
7398 * Write out opening element
7399 */
7400 total = 0;
7401 count = ecm_db_iface_xml_state_get_open(ii, buf + total, buf_sz - total);
7402 if ((count <= 0) || (count >= (buf_sz - total))) {
7403 return -1;
7404 }
7405 total += count;
7406
7407 /*
7408 * Write out type specific data
7409 */
7410 count = snprintf(buf + total, buf_sz - total, "<ipsec_tunnel os_specific_ident=\"%u\"/>\n", os_specific_ident);
7411 if ((count <= 0) || (count >= (buf_sz - total))) {
7412 return -1;
7413 }
7414 total += count;
7415
7416 /*
7417 * Write out closing element
7418 */
7419 count = ecm_db_iface_xml_state_get_close(ii, buf + total, buf_sz - total);
7420 if ((count <= 0) || (count >= (buf_sz - total))) {
7421 return -1;
7422 }
7423 total += count;
7424 return total;
7425}
7426
7427/*
7428 * ecm_db_iface_add_unknown()
7429 * Add a iface instance into the database
7430 */
7431void ecm_db_iface_add_unknown(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
7432 int32_t interface_identifier, int32_t nss_interface_identifier,
7433 ecm_db_iface_final_callback_t final, void *arg)
7434{
7435 ecm_db_iface_hash_t hash_index;
7436 struct ecm_db_listener_instance *li;
7437 struct ecm_db_interface_info_unknown *type_info;
7438
7439 spin_lock_bh(&ecm_db_lock);
7440 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7441 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7442 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7443 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7444 spin_unlock_bh(&ecm_db_lock);
7445
7446 /*
7447 * Record general info
7448 */
7449 ii->type = ECM_DB_IFACE_TYPE_UNKNOWN;
7450 ii->xml_state_get = ecm_db_iface_unknown_xml_state_get;
7451 ii->arg = arg;
7452 ii->final = final;
7453 strcpy(ii->name, name);
7454 ii->mtu = mtu;
7455 ii->interface_identifier = interface_identifier;
7456 ii->nss_interface_identifier = nss_interface_identifier;
7457
7458 /*
7459 * Type specific info
7460 */
7461 type_info = &ii->type_info.unknown;
7462 type_info->os_specific_ident = os_specific_ident;
7463
7464 /*
7465 * Compute hash chain for insertion
7466 */
7467 hash_index = ecm_db_iface_generate_hash_index_unknown(os_specific_ident);
7468 ii->hash_index = hash_index;
7469
7470 /*
7471 * Add into the global list
7472 */
7473 spin_lock_bh(&ecm_db_lock);
7474 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7475 ii->prev = NULL;
7476 ii->next = ecm_db_interfaces;
7477 if (ecm_db_interfaces) {
7478 ecm_db_interfaces->prev = ii;
7479 }
7480 ecm_db_interfaces = ii;
7481
7482 /*
7483 * Insert into chain
7484 */
7485 ii->hash_next = ecm_db_iface_table[hash_index];
7486 if (ecm_db_iface_table[hash_index]) {
7487 ecm_db_iface_table[hash_index]->hash_prev = ii;
7488 }
7489 ecm_db_iface_table[hash_index] = ii;
7490 ecm_db_iface_table_lengths[hash_index]++;
7491 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7492
7493 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);
7494
7495 /*
7496 * Set time of addition
7497 */
7498 ii->time_added = ecm_db_time;
7499 spin_unlock_bh(&ecm_db_lock);
7500
7501 /*
7502 * Throw add event to the listeners
7503 */
7504 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7505 li = ecm_db_listeners_get_and_ref_first();
7506 while (li) {
7507 struct ecm_db_listener_instance *lin;
7508 if (li->iface_added) {
7509 li->iface_added(li->arg, ii);
7510 }
7511
7512 /*
7513 * Get next listener
7514 */
7515 lin = ecm_db_listener_get_and_ref_next(li);
7516 ecm_db_listener_deref(li);
7517 li = lin;
7518 }
7519}
7520EXPORT_SYMBOL(ecm_db_iface_add_unknown);
7521
7522/*
7523 * ecm_db_iface_add_loopback()
7524 * Add a iface instance into the database
7525 */
7526void ecm_db_iface_add_loopback(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
7527 int32_t interface_identifier, int32_t nss_interface_identifier,
7528 ecm_db_iface_final_callback_t final, void *arg)
7529{
7530 ecm_db_iface_hash_t hash_index;
7531 struct ecm_db_listener_instance *li;
7532 struct ecm_db_interface_info_loopback *type_info;
7533
7534 spin_lock_bh(&ecm_db_lock);
7535 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7536 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7537 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7538 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7539 spin_unlock_bh(&ecm_db_lock);
7540
7541 /*
7542 * Record general info
7543 */
7544 ii->type = ECM_DB_IFACE_TYPE_LOOPBACK;
7545 ii->xml_state_get = ecm_db_iface_loopback_xml_state_get;
7546 ii->arg = arg;
7547 ii->final = final;
7548 strcpy(ii->name, name);
7549 ii->mtu = mtu;
7550 ii->interface_identifier = interface_identifier;
7551 ii->nss_interface_identifier = nss_interface_identifier;
7552
7553 /*
7554 * Type specific info
7555 */
7556 type_info = &ii->type_info.loopback;
7557 type_info->os_specific_ident = os_specific_ident;
7558
7559 /*
7560 * Compute hash chain for insertion
7561 */
7562 hash_index = ecm_db_iface_generate_hash_index_loopback(os_specific_ident);
7563 ii->hash_index = hash_index;
7564
7565 /*
7566 * Add into the global list
7567 */
7568 spin_lock_bh(&ecm_db_lock);
7569 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7570 ii->prev = NULL;
7571 ii->next = ecm_db_interfaces;
7572 if (ecm_db_interfaces) {
7573 ecm_db_interfaces->prev = ii;
7574 }
7575 ecm_db_interfaces = ii;
7576
7577 /*
7578 * Insert into chain
7579 */
7580 ii->hash_next = ecm_db_iface_table[hash_index];
7581 if (ecm_db_iface_table[hash_index]) {
7582 ecm_db_iface_table[hash_index]->hash_prev = ii;
7583 }
7584 ecm_db_iface_table[hash_index] = ii;
7585 ecm_db_iface_table_lengths[hash_index]++;
7586 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7587
7588 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);
7589
7590 /*
7591 * Set time of addition
7592 */
7593 ii->time_added = ecm_db_time;
7594 spin_unlock_bh(&ecm_db_lock);
7595
7596 /*
7597 * Throw add event to the listeners
7598 */
7599 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7600 li = ecm_db_listeners_get_and_ref_first();
7601 while (li) {
7602 struct ecm_db_listener_instance *lin;
7603 if (li->iface_added) {
7604 li->iface_added(li->arg, ii);
7605 }
7606
7607 /*
7608 * Get next listener
7609 */
7610 lin = ecm_db_listener_get_and_ref_next(li);
7611 ecm_db_listener_deref(li);
7612 li = lin;
7613 }
7614}
7615EXPORT_SYMBOL(ecm_db_iface_add_loopback);
7616
7617/*
Zhu Ken56477be2014-08-05 17:50:28 +08007618 * ecm_db_iface_sit_daddr_is_null()
7619 * The sit addr is null or not
7620 */
7621bool ecm_db_iface_sit_daddr_is_null(struct ecm_db_iface_instance *ii)
7622{
7623 return ii->type_info.sit.daddr[0] == 0;
7624}
7625EXPORT_SYMBOL(ecm_db_iface_sit_daddr_is_null);
7626
7627/*
Ben Menchaca84f36632014-02-28 20:57:38 +00007628 * ecm_db_iface_add_sit()
7629 * Add a iface instance into the database
7630 */
7631void ecm_db_iface_add_sit(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_sit *type_info, char *name, int32_t mtu,
7632 int32_t interface_identifier, int32_t nss_interface_identifier,
7633 ecm_db_iface_final_callback_t final, void *arg)
7634{
7635 ecm_db_iface_hash_t hash_index;
7636 struct ecm_db_listener_instance *li;
7637
7638 spin_lock_bh(&ecm_db_lock);
7639 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7640 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7641 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7642 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7643 spin_unlock_bh(&ecm_db_lock);
7644
7645 /*
7646 * Record general info
7647 */
7648 ii->type = ECM_DB_IFACE_TYPE_SIT;
7649 ii->xml_state_get = ecm_db_iface_loopback_xml_state_get;
7650 ii->arg = arg;
7651 ii->final = final;
7652 strcpy(ii->name, name);
7653 ii->mtu = mtu;
7654 ii->interface_identifier = interface_identifier;
7655 ii->nss_interface_identifier = nss_interface_identifier;
7656
7657 /*
7658 * Type specific info to be copied
7659 */
7660 ii->type_info.sit = *type_info;
7661
7662 /*
7663 * Compute hash chain for insertion
7664 */
7665 hash_index = ecm_db_iface_generate_hash_index_sit(type_info->saddr, type_info->daddr);
7666 ii->hash_index = hash_index;
7667
7668 /*
7669 * Add into the global list
7670 */
7671 spin_lock_bh(&ecm_db_lock);
7672 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7673 ii->prev = NULL;
7674 ii->next = ecm_db_interfaces;
7675 if (ecm_db_interfaces) {
7676 ecm_db_interfaces->prev = ii;
7677 }
7678 ecm_db_interfaces = ii;
7679
7680 /*
7681 * Insert into chain
7682 */
7683 ii->hash_next = ecm_db_iface_table[hash_index];
7684 if (ecm_db_iface_table[hash_index]) {
7685 ecm_db_iface_table[hash_index]->hash_prev = ii;
7686 }
7687 ecm_db_iface_table[hash_index] = ii;
7688 ecm_db_iface_table_lengths[hash_index]++;
7689 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7690
7691 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);
7692
7693 /*
7694 * Set time of addition
7695 */
7696 ii->time_added = ecm_db_time;
7697 spin_unlock_bh(&ecm_db_lock);
7698
7699 /*
7700 * Throw add event to the listeners
7701 */
7702 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7703 li = ecm_db_listeners_get_and_ref_first();
7704 while (li) {
7705 struct ecm_db_listener_instance *lin;
7706 if (li->iface_added) {
7707 li->iface_added(li->arg, ii);
7708 }
7709
7710 /*
7711 * Get next listener
7712 */
7713 lin = ecm_db_listener_get_and_ref_next(li);
7714 ecm_db_listener_deref(li);
7715 li = lin;
7716 }
7717}
7718EXPORT_SYMBOL(ecm_db_iface_add_sit);
7719
7720/*
7721 * ecm_db_iface_add_tunipip6()
7722 * Add a iface instance into the database
7723 */
7724void ecm_db_iface_add_tunipip6(struct ecm_db_iface_instance *ii, struct ecm_db_interface_info_tunipip6 *type_info, char *name, int32_t mtu,
7725 int32_t interface_identifier, int32_t nss_interface_identifier,
7726 ecm_db_iface_final_callback_t final, void *arg)
7727{
7728 ecm_db_iface_hash_t hash_index;
7729 struct ecm_db_listener_instance *li;
7730
7731 spin_lock_bh(&ecm_db_lock);
7732 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7733 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7734 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7735 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7736 spin_unlock_bh(&ecm_db_lock);
7737
7738 /*
7739 * Record general info
7740 */
7741 ii->type = ECM_DB_IFACE_TYPE_TUNIPIP6;
7742 ii->xml_state_get = ecm_db_iface_loopback_xml_state_get;
7743 ii->arg = arg;
7744 ii->final = final;
7745 strcpy(ii->name, name);
7746 ii->mtu = mtu;
7747 ii->interface_identifier = interface_identifier;
7748 ii->nss_interface_identifier = nss_interface_identifier;
7749
7750 /*
7751 * Type specific info to be copied
7752 */
7753 ii->type_info.tunipip6 = *type_info;
7754
7755 /*
7756 * Compute hash chain for insertion
7757 */
7758 hash_index = ecm_db_iface_generate_hash_index_tunipip6(type_info->saddr, type_info->daddr);
7759 ii->hash_index = hash_index;
7760
7761 /*
7762 * Add into the global list
7763 */
7764 spin_lock_bh(&ecm_db_lock);
7765 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7766 ii->prev = NULL;
7767 ii->next = ecm_db_interfaces;
7768 if (ecm_db_interfaces) {
7769 ecm_db_interfaces->prev = ii;
7770 }
7771 ecm_db_interfaces = ii;
7772
7773 /*
7774 * Insert into chain
7775 */
7776 ii->hash_next = ecm_db_iface_table[hash_index];
7777 if (ecm_db_iface_table[hash_index]) {
7778 ecm_db_iface_table[hash_index]->hash_prev = ii;
7779 }
7780 ecm_db_iface_table[hash_index] = ii;
7781 ecm_db_iface_table_lengths[hash_index]++;
7782 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7783
7784 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);
7785
7786 /*
7787 * Set time of addition
7788 */
7789 ii->time_added = ecm_db_time;
7790 spin_unlock_bh(&ecm_db_lock);
7791
7792 /*
7793 * Throw add event to the listeners
7794 */
7795 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7796 li = ecm_db_listeners_get_and_ref_first();
7797 while (li) {
7798 struct ecm_db_listener_instance *lin;
7799 if (li->iface_added) {
7800 li->iface_added(li->arg, ii);
7801 }
7802
7803 /*
7804 * Get next listener
7805 */
7806 lin = ecm_db_listener_get_and_ref_next(li);
7807 ecm_db_listener_deref(li);
7808 li = lin;
7809 }
7810}
7811EXPORT_SYMBOL(ecm_db_iface_add_tunipip6);
7812
7813/*
7814 * ecm_db_iface_add_ipsec_tunnel()
7815 * Add a iface instance into the database
7816 *
7817 * GGG TODO This needs to take ipsec tunnel endpoint information etc. something very appropriate for ipsec tunnels, anyhow.
7818 */
7819void ecm_db_iface_add_ipsec_tunnel(struct ecm_db_iface_instance *ii, uint32_t os_specific_ident, char *name, int32_t mtu,
7820 int32_t interface_identifier, int32_t nss_interface_identifier,
7821 ecm_db_iface_final_callback_t final, void *arg)
7822{
7823 ecm_db_iface_hash_t hash_index;
7824 struct ecm_db_listener_instance *li;
7825 struct ecm_db_interface_info_ipsec_tunnel *type_info;
7826
7827 spin_lock_bh(&ecm_db_lock);
7828 DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
7829 DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
7830 DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
7831 DEBUG_ASSERT(name, "%p: no name given\n", ii);
7832 spin_unlock_bh(&ecm_db_lock);
7833
7834 /*
7835 * Record general info
7836 */
Ankit Dhanuka60683c52014-06-09 17:43:38 +05307837 ii->type = ECM_DB_IFACE_TYPE_IPSEC_TUNNEL;
Ben Menchaca84f36632014-02-28 20:57:38 +00007838 ii->xml_state_get = ecm_db_iface_ipsec_tunnel_xml_state_get;
7839 ii->arg = arg;
7840 ii->final = final;
7841 strcpy(ii->name, name);
7842 ii->mtu = mtu;
7843 ii->interface_identifier = interface_identifier;
7844 ii->nss_interface_identifier = nss_interface_identifier;
7845
7846 /*
7847 * Type specific info
7848 */
7849 type_info = &ii->type_info.ipsec_tunnel;
7850 type_info->os_specific_ident = os_specific_ident;
7851
7852 /*
7853 * Compute hash chain for insertion
7854 */
7855 hash_index = ecm_db_iface_generate_hash_index_ipsec_tunnel(os_specific_ident);
7856 ii->hash_index = hash_index;
7857
7858 /*
7859 * Add into the global list
7860 */
7861 spin_lock_bh(&ecm_db_lock);
7862 ii->flags |= ECM_DB_IFACE_FLAGS_INSERTED;
7863 ii->prev = NULL;
7864 ii->next = ecm_db_interfaces;
7865 if (ecm_db_interfaces) {
7866 ecm_db_interfaces->prev = ii;
7867 }
7868 ecm_db_interfaces = ii;
7869
7870 /*
7871 * Insert into chain
7872 */
7873 ii->hash_next = ecm_db_iface_table[hash_index];
7874 if (ecm_db_iface_table[hash_index]) {
7875 ecm_db_iface_table[hash_index]->hash_prev = ii;
7876 }
7877 ecm_db_iface_table[hash_index] = ii;
7878 ecm_db_iface_table_lengths[hash_index]++;
7879 DEBUG_ASSERT(ecm_db_iface_table_lengths[hash_index] > 0, "%p: invalid table len %d\n", ii, ecm_db_iface_table_lengths[hash_index]);
7880
7881 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);
7882
7883 /*
7884 * Set time of addition
7885 */
7886 ii->time_added = ecm_db_time;
7887 spin_unlock_bh(&ecm_db_lock);
7888
7889 /*
7890 * Throw add event to the listeners
7891 */
7892 DEBUG_TRACE("%p: Throw iface added event\n", ii);
7893 li = ecm_db_listeners_get_and_ref_first();
7894 while (li) {
7895 struct ecm_db_listener_instance *lin;
7896 if (li->iface_added) {
7897 li->iface_added(li->arg, ii);
7898 }
7899
7900 /*
7901 * Get next listener
7902 */
7903 lin = ecm_db_listener_get_and_ref_next(li);
7904 ecm_db_listener_deref(li);
7905 li = lin;
7906 }
7907}
7908EXPORT_SYMBOL(ecm_db_iface_add_ipsec_tunnel);
7909
7910/*
7911 * ecm_db_listener_add()
7912 * Add a listener instance into the database.
7913 */
7914void ecm_db_listener_add(struct ecm_db_listener_instance *li,
7915 ecm_db_iface_listener_added_callback_t iface_added,
7916 ecm_db_iface_listener_removed_callback_t iface_removed,
7917 ecm_db_node_listener_added_callback_t node_added,
7918 ecm_db_node_listener_removed_callback_t node_removed,
7919 ecm_db_host_listener_added_callback_t host_added,
7920 ecm_db_host_listener_removed_callback_t host_removed,
7921 ecm_db_mapping_listener_added_callback_t mapping_added,
7922 ecm_db_mapping_listener_removed_callback_t mapping_removed,
7923 ecm_db_connection_listener_added_callback_t connection_added,
7924 ecm_db_connection_listener_removed_callback_t connection_removed,
7925 ecm_db_listener_final_callback_t final,
7926 void *arg)
7927{
7928 spin_lock_bh(&ecm_db_lock);
7929 DEBUG_CHECK_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC, "%p: magic failed\n", li);
7930 DEBUG_ASSERT(!(li->flags & ECM_DB_LISTENER_FLAGS_INSERTED), "%p: inserted\n", li);
7931 spin_unlock_bh(&ecm_db_lock);
7932
7933 li->arg = arg;
7934 li->final = final;
7935 li->iface_added = iface_added;
7936 li->iface_removed = iface_removed;
7937 li->node_added = node_added;
7938 li->node_removed = node_removed;
7939 li->host_added = host_added;
7940 li->host_removed = host_removed;
7941 li->mapping_added = mapping_added;
7942 li->mapping_removed = mapping_removed;
7943 li->connection_added = connection_added;
7944 li->connection_removed = connection_removed;
7945
7946 /*
7947 * Add instance into listener list
7948 */
7949 spin_lock_bh(&ecm_db_lock);
7950 li->flags |= ECM_DB_LISTENER_FLAGS_INSERTED;
7951 li->next = ecm_db_listeners;
7952 ecm_db_listeners = li;
7953 spin_unlock_bh(&ecm_db_lock);
7954}
7955EXPORT_SYMBOL(ecm_db_listener_add);
7956
7957/*
7958 * ecm_db_connection_alloc()
7959 * Allocate a connection instance
7960 */
7961struct ecm_db_connection_instance *ecm_db_connection_alloc(void)
7962{
7963 struct ecm_db_connection_instance *ci;
7964
7965 /*
7966 * Allocate the connection
7967 */
7968 ci = (struct ecm_db_connection_instance *)kzalloc(sizeof(struct ecm_db_connection_instance), GFP_ATOMIC | __GFP_NOWARN);
7969 if (!ci) {
7970 DEBUG_WARN("Connection alloc failed\n");
7971 return NULL;
7972 }
7973
7974 /*
7975 * Initialise the defunct timer entry
7976 */
7977 ecm_db_timer_group_entry_init(&ci->defunct_timer, ecm_db_connection_defunct_callback, ci);
7978
7979 /*
7980 * Refs is 1 for the creator of the connection
7981 */
7982 ci->refs = 1;
7983 DEBUG_SET_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC);
7984
7985 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05007986 * Initialise the interfaces from/to lists.
7987 * Interfaces are added from end of array.
7988 */
7989 ci->from_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7990 ci->to_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7991 ci->from_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7992 ci->to_nat_interface_first = ECM_DB_IFACE_HEIRARCHY_MAX;
7993
7994 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00007995 * If the master thread is terminating then we cannot create new instances
7996 */
7997 spin_lock_bh(&ecm_db_lock);
7998 if (ecm_db_terminate_pending) {
7999 spin_unlock_bh(&ecm_db_lock);
8000 DEBUG_WARN("Thread terminating\n");
8001 kfree(ci);
8002 return NULL;
8003 }
8004
8005 /*
8006 * Assign runtime unique serial
8007 */
8008 ci->serial = ecm_db_connection_serial++;
8009
Ben Menchaca84f36632014-02-28 20:57:38 +00008010 ecm_db_connection_count++;
8011 DEBUG_ASSERT(ecm_db_connection_count > 0, "%p: connection count wrap\n", ci);
8012 spin_unlock_bh(&ecm_db_lock);
8013
8014 DEBUG_TRACE("Connection created %p\n", ci);
8015 return ci;
8016}
8017EXPORT_SYMBOL(ecm_db_connection_alloc);
8018
8019/*
8020 * ecm_db_mapping_alloc()
8021 * Allocate a mapping instance
8022 */
8023struct ecm_db_mapping_instance *ecm_db_mapping_alloc(void)
8024{
8025 struct ecm_db_mapping_instance *mi;
8026
8027 mi = (struct ecm_db_mapping_instance *)kzalloc(sizeof(struct ecm_db_mapping_instance), GFP_ATOMIC | __GFP_NOWARN);
8028 if (!mi) {
8029 DEBUG_WARN("Alloc failed\n");
8030 return NULL;
8031 }
8032
8033 mi->refs = 1;
8034 DEBUG_SET_MAGIC(mi, ECM_DB_MAPPING_INSTANCE_MAGIC);
8035
8036 /*
8037 * Alloc operation must be atomic to ensure thread and module can be held
8038 */
8039 spin_lock_bh(&ecm_db_lock);
8040
8041 /*
8042 * If the event processing thread is terminating then we cannot create new instances
8043 */
8044 if (ecm_db_terminate_pending) {
8045 spin_unlock_bh(&ecm_db_lock);
8046 DEBUG_WARN("Thread terminating\n");
8047 kfree(mi);
8048 return NULL;
8049 }
8050
Ben Menchaca84f36632014-02-28 20:57:38 +00008051 ecm_db_mapping_count++;
8052 spin_unlock_bh(&ecm_db_lock);
8053
8054 DEBUG_TRACE("Mapping created %p\n", mi);
8055 return mi;
8056}
8057EXPORT_SYMBOL(ecm_db_mapping_alloc);
8058
8059
8060/*
8061 * ecm_db_host_alloc()
8062 * Allocate a host instance
8063 */
8064struct ecm_db_host_instance *ecm_db_host_alloc(void)
8065{
8066 struct ecm_db_host_instance *hi;
8067 hi = (struct ecm_db_host_instance *)kzalloc(sizeof(struct ecm_db_host_instance), GFP_ATOMIC | __GFP_NOWARN);
8068 if (!hi) {
8069 DEBUG_WARN("Alloc failed\n");
8070 return NULL;
8071 }
8072
8073 hi->refs = 1;
8074 DEBUG_SET_MAGIC(hi, ECM_DB_HOST_INSTANCE_MAGIC);
8075
8076 /*
8077 * Alloc operation must be atomic to ensure thread and module can be held
8078 */
8079 spin_lock_bh(&ecm_db_lock);
8080
8081 /*
8082 * If the event processing thread is terminating then we cannot create new instances
8083 */
8084 if (ecm_db_terminate_pending) {
8085 spin_unlock_bh(&ecm_db_lock);
8086 DEBUG_WARN("Thread terminating\n");
8087 kfree(hi);
8088 return NULL;
8089 }
8090
Ben Menchaca84f36632014-02-28 20:57:38 +00008091 ecm_db_host_count++;
8092 spin_unlock_bh(&ecm_db_lock);
8093
8094 DEBUG_TRACE("Host created %p\n", hi);
8095 return hi;
8096}
8097EXPORT_SYMBOL(ecm_db_host_alloc);
8098
8099/*
8100 * ecm_db_node_alloc()
8101 * Allocate a node instance
8102 */
8103struct ecm_db_node_instance *ecm_db_node_alloc(void)
8104{
8105 struct ecm_db_node_instance *ni;
8106
8107 ni = (struct ecm_db_node_instance *)kzalloc(sizeof(struct ecm_db_node_instance), GFP_ATOMIC | __GFP_NOWARN);
8108 if (!ni) {
8109 DEBUG_WARN("Alloc failed\n");
8110 return NULL;
8111 }
8112
8113 ni->refs = 1;
8114 DEBUG_SET_MAGIC(ni, ECM_DB_NODE_INSTANCE_MAGIC);
8115
8116 /*
8117 * Alloc operation must be atomic to ensure thread and module can be held
8118 */
8119 spin_lock_bh(&ecm_db_lock);
8120
8121 /*
8122 * If the event processing thread is terminating then we cannot create new instances
8123 */
8124 if (ecm_db_terminate_pending) {
8125 spin_unlock_bh(&ecm_db_lock);
8126 DEBUG_WARN("Thread terminating\n");
8127 kfree(ni);
8128 return NULL;
8129 }
8130
Ben Menchaca84f36632014-02-28 20:57:38 +00008131 ecm_db_node_count++;
8132 spin_unlock_bh(&ecm_db_lock);
8133
8134 DEBUG_TRACE("Node created %p\n", ni);
8135 return ni;
8136}
8137EXPORT_SYMBOL(ecm_db_node_alloc);
8138
8139/*
8140 * ecm_db_iface_alloc()
8141 * Allocate a iface instance
8142 */
8143struct ecm_db_iface_instance *ecm_db_iface_alloc(void)
8144{
8145 struct ecm_db_iface_instance *ii;
8146
8147 ii = (struct ecm_db_iface_instance *)kzalloc(sizeof(struct ecm_db_iface_instance), GFP_ATOMIC | __GFP_NOWARN);
8148 if (!ii) {
8149 DEBUG_WARN("Alloc failed\n");
8150 return NULL;
8151 }
8152
8153 ii->refs = 1;
8154 DEBUG_SET_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC);
8155
8156 /*
8157 * Alloc operation must be atomic to ensure thread and module can be held
8158 */
8159 spin_lock_bh(&ecm_db_lock);
8160
8161 /*
8162 * If the event processing thread is terminating then we cannot create new instances
8163 */
8164 if (ecm_db_terminate_pending) {
8165 spin_unlock_bh(&ecm_db_lock);
8166 DEBUG_WARN("Thread terminating\n");
8167 kfree(ii);
8168 return NULL;
8169 }
8170
Ben Menchaca84f36632014-02-28 20:57:38 +00008171 ecm_db_iface_count++;
8172 spin_unlock_bh(&ecm_db_lock);
8173
8174 DEBUG_TRACE("iface created %p\n", ii);
8175 return ii;
8176}
8177EXPORT_SYMBOL(ecm_db_iface_alloc);
8178
8179/*
8180 * ecm_db_listener_alloc()
8181 * Allocate a listener instance
8182 */
8183struct ecm_db_listener_instance *ecm_db_listener_alloc(void)
8184{
8185 struct ecm_db_listener_instance *li;
8186
8187 li = (struct ecm_db_listener_instance *)kzalloc(sizeof(struct ecm_db_listener_instance), GFP_ATOMIC | __GFP_NOWARN);
8188 if (!li) {
8189 DEBUG_WARN("Alloc failed\n");
8190 return NULL;
8191 }
8192
8193 li->refs = 1;
8194 DEBUG_SET_MAGIC(li, ECM_DB_LISTENER_INSTANCE_MAGIC);
8195
8196 /*
8197 * Alloc operation must be atomic to ensure thread and module can be held
8198 */
8199 spin_lock_bh(&ecm_db_lock);
8200
8201 /*
8202 * If the event processing thread is terminating then we cannot create new instances
8203 */
8204 if (ecm_db_terminate_pending) {
8205 spin_unlock_bh(&ecm_db_lock);
8206 DEBUG_WARN("Thread terminating\n");
8207 kfree(li);
8208 return NULL;
8209 }
8210
Ben Menchaca84f36632014-02-28 20:57:38 +00008211 ecm_db_listeners_count++;
8212 DEBUG_ASSERT(ecm_db_listeners_count > 0, "%p: listener count wrap\n", li);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05008213 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00008214
8215 DEBUG_TRACE("Listener created %p\n", li);
Ben Menchaca84f36632014-02-28 20:57:38 +00008216 return li;
8217}
8218EXPORT_SYMBOL(ecm_db_listener_alloc);
8219
8220/*
8221 * ecm_db_time_get()
8222 * Return database time, in seconds since the database started.
8223 */
8224uint32_t ecm_db_time_get(void)
8225{
8226 uint32_t time_now;
8227 spin_lock_bh(&ecm_db_lock);
8228 time_now = ecm_db_time;
8229 spin_unlock_bh(&ecm_db_lock);
8230 return time_now;
8231}
8232EXPORT_SYMBOL(ecm_db_time_get);
8233
8234/*
Ben Menchaca84f36632014-02-28 20:57:38 +00008235 * ecm_db_get_state_dev_major()
8236 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008237static ssize_t ecm_db_get_state_dev_major(struct device *dev,
8238 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008239 char *buf)
8240{
8241 ssize_t count;
8242 int major;
8243
8244 spin_lock_bh(&ecm_db_lock);
8245 major = ecm_db_dev_major_id;
8246 spin_unlock_bh(&ecm_db_lock);
8247
8248 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", major);
8249
8250 return count;
8251}
8252
8253/*
8254 * ecm_db_get_connection_count()
8255 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008256static ssize_t ecm_db_get_connection_count(struct device *dev,
8257 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008258 char *buf)
8259{
8260 ssize_t count;
8261 int num;
8262
8263 /*
8264 * Operate under our locks
8265 */
8266 spin_lock_bh(&ecm_db_lock);
8267 num = ecm_db_connection_count;
8268 spin_unlock_bh(&ecm_db_lock);
8269
8270 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8271 return count;
8272}
8273
8274/*
8275 * ecm_db_get_host_count()
8276 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008277static ssize_t ecm_db_get_host_count(struct device *dev,
8278 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008279 char *buf)
8280{
8281 ssize_t count;
8282 int num;
8283
8284 /*
8285 * Operate under our locks
8286 */
8287 spin_lock_bh(&ecm_db_lock);
8288 num = ecm_db_host_count;
8289 spin_unlock_bh(&ecm_db_lock);
8290
8291 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8292 return count;
8293}
8294
8295/*
8296 * ecm_db_get_mapping_count()
8297 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008298static ssize_t ecm_db_get_mapping_count(struct device *dev,
8299 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008300 char *buf)
8301{
8302 ssize_t count;
8303 int num;
8304
8305 /*
8306 * Operate under our locks
8307 */
8308 spin_lock_bh(&ecm_db_lock);
8309 num = ecm_db_mapping_count;
8310 spin_unlock_bh(&ecm_db_lock);
8311
8312 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8313 return count;
8314}
8315
8316/*
8317 * ecm_db_get_node_count()
8318 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008319static ssize_t ecm_db_get_node_count(struct device *dev,
8320 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008321 char *buf)
8322{
8323 ssize_t count;
8324 int num;
8325
8326 /*
8327 * Operate under our locks
8328 */
8329 spin_lock_bh(&ecm_db_lock);
8330 num = ecm_db_node_count;
8331 spin_unlock_bh(&ecm_db_lock);
8332
8333 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8334 return count;
8335}
8336
8337/*
8338 * ecm_db_get_iface_count()
8339 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008340static ssize_t ecm_db_get_iface_count(struct device *dev,
8341 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008342 char *buf)
8343{
8344 ssize_t count;
8345 int num;
8346
8347 /*
8348 * Operate under our locks
8349 */
8350 spin_lock_bh(&ecm_db_lock);
8351 num = ecm_db_iface_count;
8352 spin_unlock_bh(&ecm_db_lock);
8353
8354 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8355 return count;
8356}
8357
8358/*
8359 * ecm_db_get_defunct_all()
8360 * Reading this file returns the accumulated total of all objects
8361 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008362static ssize_t ecm_db_get_defunct_all(struct device *dev,
8363 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008364 char *buf)
8365{
8366 ssize_t count;
8367 int num;
8368
8369 /*
8370 * Operate under our locks
8371 */
8372 spin_lock_bh(&ecm_db_lock);
8373 num = ecm_db_connection_count + ecm_db_mapping_count + ecm_db_host_count
8374 + ecm_db_node_count + ecm_db_iface_count;
8375 spin_unlock_bh(&ecm_db_lock);
8376
8377 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8378 return count;
8379}
8380
8381/*
8382 * ecm_db_set_defunct_all()
8383 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008384static ssize_t ecm_db_set_defunct_all(struct device *dev,
8385 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008386 const char *buf, size_t count)
8387{
8388 ecm_db_connection_defunct_all();
8389 return count;
8390}
8391
8392/*
8393 * ecm_db_get_connection_counts_simple()
8394 * Return total of connections for each simple protocol (tcp, udp, other). Primarily for use by the luci-bwc service.
8395 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008396static ssize_t ecm_db_get_connection_counts_simple(struct device *dev,
8397 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008398 char *buf)
8399{
8400 int tcp_count;
8401 int udp_count;
8402 int other_count;
8403 int total_count;
8404 ssize_t count;
8405
8406 /*
8407 * Get snapshot of the protocol counts
8408 */
8409 spin_lock_bh(&ecm_db_lock);
8410 tcp_count = ecm_db_connection_count_by_protocol[IPPROTO_TCP];
8411 udp_count = ecm_db_connection_count_by_protocol[IPPROTO_UDP];
8412 total_count = ecm_db_connection_count;
8413 other_count = total_count - (tcp_count + udp_count);
8414 spin_unlock_bh(&ecm_db_lock);
8415
8416 count = snprintf(buf, (ssize_t)PAGE_SIZE, "tcp %d udp %d other %d total %d\n", tcp_count, udp_count, other_count, total_count);
8417 return count;
8418}
8419
8420/*
8421 * ecm_db_get_state_file_output_mask()
8422 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008423static ssize_t ecm_db_get_state_file_output_mask(struct device *dev,
8424 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008425 char *buf)
8426{
8427 ssize_t count;
8428 int num;
8429
8430 /*
8431 * Operate under our locks
8432 */
8433 spin_lock_bh(&ecm_db_lock);
8434 num = ecm_db_state_file_output_mask;
8435 spin_unlock_bh(&ecm_db_lock);
8436
8437 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
8438 return count;
8439}
8440
8441/*
8442 * ecm_db_set_state_file_output_mask()
8443 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008444static ssize_t ecm_db_set_state_file_output_mask(struct device *dev,
8445 struct device_attribute *attr,
Ben Menchaca84f36632014-02-28 20:57:38 +00008446 const char *buf, size_t count)
8447{
8448 char num_buf[12];
8449 int num;
8450
8451 /*
8452 * Get the number from buf into a properly z-termed number buffer
8453 */
8454 if (count > 11) return 0;
8455 memcpy(num_buf, buf, count);
8456 num_buf[count] = '\0';
8457 sscanf(num_buf, "%d", &num);
8458 DEBUG_TRACE("ecm_db_state_file_output_mask = %x\n", num);
8459
8460 /*
8461 * Operate under our locks
8462 */
8463 spin_lock_bh(&ecm_db_lock);
8464 ecm_db_state_file_output_mask = num;
8465 spin_unlock_bh(&ecm_db_lock);
8466
8467 return count;
8468}
8469
8470/*
8471 * SysFS attributes for the default classifier itself.
8472 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008473static DEVICE_ATTR(state_dev_major, 0444, ecm_db_get_state_dev_major, NULL);
8474static DEVICE_ATTR(connection_count, 0444, ecm_db_get_connection_count, NULL);
8475static DEVICE_ATTR(host_count, 0444, ecm_db_get_host_count, NULL);
8476static DEVICE_ATTR(mapping_count, 0444, ecm_db_get_mapping_count, NULL);
8477static DEVICE_ATTR(node_count, 0444, ecm_db_get_node_count, NULL);
8478static DEVICE_ATTR(iface_count, 0444, ecm_db_get_iface_count, NULL);
8479static DEVICE_ATTR(defunct_all, 0644, ecm_db_get_defunct_all, ecm_db_set_defunct_all);
8480static DEVICE_ATTR(connection_counts_simple, 0444, ecm_db_get_connection_counts_simple, NULL);
8481static 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 +00008482
8483/*
Murat Sezgin1f381852014-11-20 09:51:07 -08008484 * System device attribute array.
Ben Menchaca84f36632014-02-28 20:57:38 +00008485 */
Murat Sezgin1f381852014-11-20 09:51:07 -08008486static struct device_attribute *ecm_db_attrs[] = {
8487 &dev_attr_state_dev_major,
8488 &dev_attr_connection_count,
8489 &dev_attr_host_count,
8490 &dev_attr_mapping_count,
8491 &dev_attr_node_count,
8492 &dev_attr_iface_count,
8493 &dev_attr_defunct_all,
8494 &dev_attr_connection_counts_simple,
8495 &dev_attr_state_file_output_mask,
Ben Menchaca84f36632014-02-28 20:57:38 +00008496};
8497
8498/*
Murat Sezgin1f381852014-11-20 09:51:07 -08008499 * Sub system node of the ECM default classifier
8500 * Sys device control points can be found at /sys/devices/system/ecm_db/ecm_dbX/
8501 */
8502static struct bus_type ecm_db_subsys = {
8503 .name = "ecm_db",
8504 .dev_name = "ecm_db",
8505};
8506
8507/*
8508 * ecm_db_dev_release()
8509 * This is a dummy release function for device.
8510 */
8511static void ecm_db_dev_release(struct device *dev)
8512{
8513
8514}
8515
8516/*
Ben Menchaca84f36632014-02-28 20:57:38 +00008517 * ecm_db_connection_heirarchy_xml_state_get()
8518 * Output XML state for an interface heirarchy list.
8519 *
8520 * Return value is comptible with snprintf()
8521 */
8522static int ecm_db_connection_heirarchy_xml_state_get(char *element, struct ecm_db_iface_instance *interfaces[], int32_t first_interface,
8523 char *buf, int buf_sz)
8524{
8525 int count;
8526 int total;
8527 int i;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308528
Ben Menchaca84f36632014-02-28 20:57:38 +00008529 /*
8530 * Output the opening element
8531 */
8532 total = 0;
8533 count = snprintf(buf + total,
8534 buf_sz - total,
8535 "<%s count=\"%d\">\n",
8536 element,
8537 ECM_DB_IFACE_HEIRARCHY_MAX - first_interface);
8538 if ((count <= 0) || (count >= (buf_sz - total))) {
8539 return -1;
8540 }
8541 total += count;
8542
8543 /*
8544 * Iterate the interface heirarchy list and output the information
8545 */
8546 for (i = first_interface; i < ECM_DB_IFACE_HEIRARCHY_MAX; ++i) {
8547 struct ecm_db_iface_instance *ii = interfaces[i];
8548 DEBUG_TRACE("Element: %s, Output interface @ %d: %p\n", element, i, ii);
8549 count = ii->xml_state_get(ii, buf + total, buf_sz - total);
8550 if ((count <= 0) || (count >= (buf_sz - total))) {
8551 return -1;
8552 }
8553 total += count;
8554 }
8555
8556 /*
8557 * Output closing element
8558 */
8559 count = snprintf(buf + total,
8560 buf_sz - total,
8561 "</%s>\n",
8562 element);
8563 if ((count <= 0) || (count >= (buf_sz - total))) {
8564 return -1;
8565 }
8566 total += count;
8567 return total;
8568}
8569
8570/*
8571 * ecm_db_char_dev_conn_msg_prep()
8572 * Prepare a connection message
8573 */
8574static bool ecm_db_char_dev_conn_msg_prep(struct ecm_db_state_file_instance *sfi)
8575{
8576 int msg_len;
8577 int extra_msg_len;
8578 long int expires_in;
8579 int sport;
8580 int sport_nat;
8581 char snode_address[25];
Gareth Williams2b87acb2014-05-26 19:12:58 +01008582 char snode_address_nat[25];
Ben Menchaca84f36632014-02-28 20:57:38 +00008583 char sip_address[50];
8584 char sip_address_nat[50];
8585 char dnode_address[25];
Gareth Williams2b87acb2014-05-26 19:12:58 +01008586 char dnode_address_nat[25];
Ben Menchaca84f36632014-02-28 20:57:38 +00008587 int dport;
8588 int dport_nat;
8589 char dip_address[50];
8590 char dip_address_nat[50];
8591 ecm_db_direction_t direction;
8592 int protocol;
8593 bool is_routed;
Gareth Williamsda721272014-11-13 17:48:12 -08008594 uint32_t generations;
Ben Menchaca84f36632014-02-28 20:57:38 +00008595 uint32_t time_added;
8596 uint32_t serial;
8597 uint64_t from_data_total;
8598 uint64_t to_data_total;
8599 uint64_t from_packet_total;
8600 uint64_t to_packet_total;
8601 uint64_t from_data_total_dropped;
8602 uint64_t to_data_total_dropped;
8603 uint64_t from_packet_total_dropped;
8604 uint64_t to_packet_total_dropped;
8605 struct ecm_db_host_instance *hi;
Gareth Williams90f2a282014-08-27 15:56:25 +01008606 struct ecm_db_node_instance *ni;
Ben Menchaca84f36632014-02-28 20:57:38 +00008607 int aci_index;
8608 int aci_count;
8609 struct ecm_front_end_connection_instance *feci;
8610 struct ecm_classifier_instance *assignments[ECM_CLASSIFIER_TYPES];
8611 int32_t first_interface;
8612 struct ecm_db_iface_instance *interfaces[ECM_DB_IFACE_HEIRARCHY_MAX];
8613
Gareth Williams72b43ed2014-05-14 18:23:43 +01008614 DEBUG_TRACE("%p: Prep conn msg for %p\n", sfi, sfi->ci);
Ben Menchaca84f36632014-02-28 20:57:38 +00008615
8616 /*
8617 * Identify expiration
8618 */
8619 spin_lock_bh(&ecm_db_lock);
8620 if (sfi->ci->defunct_timer.group == ECM_DB_TIMER_GROUPS_MAX) {
8621 expires_in = -1;
8622 } else {
8623 expires_in = (long int)(sfi->ci->defunct_timer.timeout - ecm_db_time);
8624 if (expires_in <= 0) {
8625 expires_in = 0;
8626 }
8627 }
8628 spin_unlock_bh(&ecm_db_lock);
8629
8630 /*
8631 * Extract information from the connection for inclusion into the message
8632 */
8633 sport = sfi->ci->mapping_from->port;
8634 sport_nat = sfi->ci->mapping_nat_from->port;
8635 dport = sfi->ci->mapping_to->port;
8636 dport_nat = sfi->ci->mapping_nat_to->port;
8637
8638 hi = sfi->ci->mapping_to->host;
8639 ecm_ip_addr_to_string(dip_address, hi->address);
Gareth Williams90f2a282014-08-27 15:56:25 +01008640 ni = sfi->ci->to_node;
8641 sprintf(dnode_address, "%pM", ni->address);
Ben Menchaca84f36632014-02-28 20:57:38 +00008642 hi = sfi->ci->mapping_nat_to->host;
8643 ecm_ip_addr_to_string(dip_address_nat, hi->address);
8644
8645 hi = sfi->ci->mapping_from->host;
8646 ecm_ip_addr_to_string(sip_address, hi->address);
Gareth Williams90f2a282014-08-27 15:56:25 +01008647 ni = sfi->ci->from_node;
8648 sprintf(snode_address, "%pM", ni->address);
Ben Menchaca84f36632014-02-28 20:57:38 +00008649 hi = sfi->ci->mapping_nat_from->host;
8650 ecm_ip_addr_to_string(sip_address_nat, hi->address);
8651
Gareth Williams90f2a282014-08-27 15:56:25 +01008652 ni = sfi->ci->to_nat_node;
8653 sprintf(dnode_address_nat, "%pM", ni->address);
Gareth Williams2b87acb2014-05-26 19:12:58 +01008654
Gareth Williams90f2a282014-08-27 15:56:25 +01008655 ni = sfi->ci->from_nat_node;
8656 sprintf(snode_address_nat, "%pM", ni->address);
Gareth Williams2b87acb2014-05-26 19:12:58 +01008657
Ben Menchaca84f36632014-02-28 20:57:38 +00008658 direction = sfi->ci->direction;
8659 protocol = sfi->ci->protocol;
8660 is_routed = sfi->ci->is_routed;
Gareth Williamsda721272014-11-13 17:48:12 -08008661 generations = sfi->ci->generations;
Ben Menchaca84f36632014-02-28 20:57:38 +00008662 time_added = sfi->ci->time_added;
8663 serial = sfi->ci->serial;
8664 ecm_db_connection_data_stats_get(sfi->ci, &from_data_total, &to_data_total,
8665 &from_packet_total, &to_packet_total,
8666 &from_data_total_dropped, &to_data_total_dropped,
8667 &from_packet_total_dropped, &to_packet_total_dropped);
8668
8669 /*
8670 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308671 */
Ben Menchaca84f36632014-02-28 20:57:38 +00008672 sfi->msgp = sfi->msg_buffer;
8673
8674 /*
8675 * Prep the message
8676 */
8677 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
Gareth Williams2b87acb2014-05-26 19:12:58 +01008678 "<conn serial=\"%u\" sip_address=\"%s\" sip_address_nat=\"%s\" sport=\"%d\" sport_nat=\"%d\" snode_address=\"%s\" snode_address_nat=\"%s\""
8679 " 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 -08008680 " protocol=\"%d\" is_routed=\"%d\" expires=\"%ld\" direction=\"%d\" time_added=\"%u\" generations=\"%u\""
Ben Menchaca84f36632014-02-28 20:57:38 +00008681 " 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",
8682 serial,
8683 sip_address,
8684 sip_address_nat,
8685 sport,
8686 sport_nat,
8687 snode_address,
Gareth Williams2b87acb2014-05-26 19:12:58 +01008688 snode_address_nat,
Ben Menchaca84f36632014-02-28 20:57:38 +00008689 dip_address,
8690 dip_address_nat,
8691 dport,
8692 dport_nat,
8693 dnode_address,
Gareth Williams2b87acb2014-05-26 19:12:58 +01008694 dnode_address_nat,
Ben Menchaca84f36632014-02-28 20:57:38 +00008695 protocol,
8696 is_routed,
8697 expires_in,
8698 direction,
8699 time_added,
Gareth Williamsda721272014-11-13 17:48:12 -08008700 generations,
Ben Menchaca84f36632014-02-28 20:57:38 +00008701 from_data_total,
8702 to_data_total,
8703 from_packet_total,
8704 to_packet_total,
8705 from_data_total_dropped,
8706 to_data_total_dropped,
8707 from_packet_total_dropped,
8708 to_packet_total_dropped);
8709
8710 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
8711 return false;
8712 }
8713
8714 /*
8715 * Output interface heirarchy information for this connection
8716 */
8717 first_interface = ecm_db_connection_from_interfaces_get_and_ref(sfi->ci, interfaces);
8718 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);
8719 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8720 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8721 return false;
8722 }
8723 msg_len += extra_msg_len;
8724
8725 first_interface = ecm_db_connection_to_interfaces_get_and_ref(sfi->ci, interfaces);
8726 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);
8727 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8728 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8729 return false;
8730 }
8731 msg_len += extra_msg_len;
8732
8733 first_interface = ecm_db_connection_from_nat_interfaces_get_and_ref(sfi->ci, interfaces);
8734 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);
8735 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8736 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8737 return false;
8738 }
8739 msg_len += extra_msg_len;
8740
8741 first_interface = ecm_db_connection_to_nat_interfaces_get_and_ref(sfi->ci, interfaces);
8742 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);
8743 ecm_db_connection_interfaces_deref(interfaces, first_interface);
8744 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8745 return false;
8746 }
8747 msg_len += extra_msg_len;
8748
8749 /*
8750 * Output front end state
8751 */
8752 feci = ecm_db_connection_front_end_get_and_ref(sfi->ci);
8753 extra_msg_len = feci->xml_state_get(feci, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8754 feci->deref(feci);
8755 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8756 return false;
8757 }
8758 msg_len += extra_msg_len;
8759
8760 /*
8761 * Grab references to the assigned classifiers so we can produce state for them
8762 */
8763 aci_count = ecm_db_connection_classifier_assignments_get_and_ref(sfi->ci, assignments);
8764
8765 /*
8766 * Iterate the assigned classifiers and provide a state record for each
8767 */
8768 for (aci_index = 0; aci_index < aci_count; ++aci_index) {
8769 struct ecm_classifier_instance *aci;
8770
8771 aci = assignments[aci_index];
8772 extra_msg_len = aci->xml_state_get(aci, sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len);
8773
8774 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8775 ecm_db_connection_assignments_release(aci_count, assignments);
8776 return false;
8777 }
8778
8779 msg_len += extra_msg_len;
8780 }
8781 ecm_db_connection_assignments_release(aci_count, assignments);
8782
8783 /*
8784 * Write out end element
8785 */
8786 extra_msg_len = snprintf(sfi->msgp + msg_len, ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len, "</conn>\n");
8787 if ((extra_msg_len <= 0) || (extra_msg_len >= (ECM_DB_STATE_FILE_BUFFER_SIZE - msg_len))) {
8788 return false;
8789 }
8790 msg_len += extra_msg_len;
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308791
Ben Menchaca84f36632014-02-28 20:57:38 +00008792 /*
8793 * Record the message length
8794 */
8795 sfi->msg_len = msg_len;
8796 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
8797 return true;
8798}
8799
8800/*
8801 * ecm_db_char_dev_mapping_msg_prep()
8802 * Prepare a mapping message
8803 */
8804static bool ecm_db_char_dev_mapping_msg_prep(struct ecm_db_state_file_instance *sfi)
8805{
8806 int msg_len;
8807 int port;
8808 char address[25];
8809 int tcp_from;
8810 int tcp_to;
8811 int udp_from;
8812 int udp_to;
8813 int from;
8814 int to;
8815 int tcp_nat_from;
8816 int tcp_nat_to;
8817 int udp_nat_from;
8818 int udp_nat_to;
8819 int nat_from;
8820 int nat_to;
8821 uint32_t time_added;
8822 uint64_t from_data_total;
8823 uint64_t to_data_total;
8824 uint64_t from_packet_total;
8825 uint64_t to_packet_total;
8826 uint64_t from_data_total_dropped;
8827 uint64_t to_data_total_dropped;
8828 uint64_t from_packet_total_dropped;
8829 uint64_t to_packet_total_dropped;
Ben Menchaca84f36632014-02-28 20:57:38 +00008830 struct ecm_db_host_instance *hi;
8831
8832 DEBUG_TRACE("%p: Prep mapping msg for %p\n", sfi, sfi->mi);
8833
8834 /*
8835 * Create a small xml stats element for our mapping.
8836 * Extract information from the mapping for inclusion into the message
8837 */
8838 ecm_db_mapping_port_count_get(sfi->mi, &tcp_from, &tcp_to, &udp_from, &udp_to, &from, &to,
8839 &tcp_nat_from, &tcp_nat_to, &udp_nat_from, &udp_nat_to, &nat_from, &nat_to);
8840 port = sfi->mi->port;
8841 time_added = sfi->mi->time_added;
8842 ecm_db_mapping_data_stats_get(sfi->mi, &from_data_total, &to_data_total,
8843 &from_packet_total, &to_packet_total,
8844 &from_data_total_dropped, &to_data_total_dropped,
8845 &from_packet_total_dropped, &to_packet_total_dropped);
8846 hi = sfi->mi->host;
8847 ecm_ip_addr_to_string(address, hi->address);
Ben Menchaca84f36632014-02-28 20:57:38 +00008848
8849 /*
8850 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308851 */
Ben Menchaca84f36632014-02-28 20:57:38 +00008852 sfi->msgp = sfi->msg_buffer;
8853
8854 /*
8855 * Prep the message
8856 */
8857 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
8858 "<mapping address=\"%s\" port=\"%d\" from=\"%d\" to=\"%d\" tcp_from=\"%d\" tcp_to=\"%d\" udp_from=\"%d\" udp_to=\"%d\""
8859 " nat_from=\"%d\" nat_to=\"%d\" tcp_nat_from=\"%d\" tcp_nat_to=\"%d\" udp_nat_from=\"%d\" udp_nat_to=\"%d\""
8860 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
8861 " 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 +01008862 " time_added=\"%u\"/>\n",
Ben Menchaca84f36632014-02-28 20:57:38 +00008863 address,
8864 port,
8865 from,
8866 to,
8867 tcp_from,
8868 tcp_to,
8869 udp_from,
8870 udp_to,
8871 nat_from,
8872 nat_to,
8873 tcp_nat_from,
8874 tcp_nat_to,
8875 udp_nat_from,
8876 udp_nat_to,
8877 from_data_total,
8878 to_data_total,
8879 from_packet_total,
8880 to_packet_total,
8881 from_data_total_dropped,
8882 to_data_total_dropped,
8883 from_packet_total_dropped,
8884 to_packet_total_dropped,
Gareth Williams90f2a282014-08-27 15:56:25 +01008885 time_added);
Ben Menchaca84f36632014-02-28 20:57:38 +00008886
8887 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
8888 return false;
8889 }
8890
8891 sfi->msg_len = msg_len;
8892 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
8893 return true;
8894}
8895
8896/*
8897 * ecm_db_char_dev_host_msg_prep()
8898 * Prepare a host message
8899 */
8900static bool ecm_db_char_dev_host_msg_prep(struct ecm_db_state_file_instance *sfi)
8901{
8902 int msg_len;
8903 char address[50];
8904 int mapping_count;
8905 uint32_t time_added;
8906 uint64_t from_data_total;
8907 uint64_t to_data_total;
8908 uint64_t from_packet_total;
8909 uint64_t to_packet_total;
8910 uint64_t from_data_total_dropped;
8911 uint64_t to_data_total_dropped;
8912 uint64_t from_packet_total_dropped;
8913 uint64_t to_packet_total_dropped;
Ben Menchaca84f36632014-02-28 20:57:38 +00008914 bool on_link;
8915
8916 DEBUG_TRACE("%p: Prep host msg for %p\n", sfi, sfi->hi);
8917
8918 /*
8919 * Create a small xml stats element for our host.
8920 * Extract information from the host for inclusion into the message
8921 */
8922 mapping_count = ecm_db_host_mapping_count_get(sfi->hi);
8923 ecm_ip_addr_to_string(address, sfi->hi->address);
8924 time_added = sfi->hi->time_added;
8925 ecm_db_host_data_stats_get(sfi->hi, &from_data_total, &to_data_total,
8926 &from_packet_total, &to_packet_total,
8927 &from_data_total_dropped, &to_data_total_dropped,
8928 &from_packet_total_dropped, &to_packet_total_dropped);
Ben Menchaca84f36632014-02-28 20:57:38 +00008929 on_link = sfi->hi->on_link;
8930
8931 /*
8932 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05308933 */
Ben Menchaca84f36632014-02-28 20:57:38 +00008934 sfi->msgp = sfi->msg_buffer;
8935
8936 /*
8937 * Prep the message
8938 */
8939 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
Gareth Williams90f2a282014-08-27 15:56:25 +01008940 "<host address=\"%s\" mappings=\"%d\" time_added=\"%u\" on_link=\"%d\""
Ben Menchaca84f36632014-02-28 20:57:38 +00008941 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
8942 " from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\"/>\n",
8943 address,
8944 mapping_count,
8945 time_added,
Ben Menchaca84f36632014-02-28 20:57:38 +00008946 on_link,
8947 from_data_total,
8948 to_data_total,
8949 from_packet_total,
8950 to_packet_total,
8951 from_data_total_dropped,
8952 to_data_total_dropped,
8953 from_packet_total_dropped,
8954 to_packet_total_dropped);
8955
8956 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
8957 return false;
8958 }
8959
8960 sfi->msg_len = msg_len;
8961 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
8962 return true;
8963}
8964
8965/*
8966 * ecm_db_char_dev_nod__msg_prep()
8967 * Prepare a node message
8968 */
8969static bool ecm_db_char_dev_node_msg_prep(struct ecm_db_state_file_instance *sfi)
8970{
8971 int msg_len;
8972 char address[25];
Gareth Williams90f2a282014-08-27 15:56:25 +01008973 int from_connections_count;
8974 int to_connections_count;
8975 int from_nat_connections_count;
8976 int to_nat_connections_count;
Ben Menchaca84f36632014-02-28 20:57:38 +00008977 uint32_t time_added;
8978 uint64_t from_data_total;
8979 uint64_t to_data_total;
8980 uint64_t from_packet_total;
8981 uint64_t to_packet_total;
8982 uint64_t from_data_total_dropped;
8983 uint64_t to_data_total_dropped;
8984 uint64_t from_packet_total_dropped;
8985 uint64_t to_packet_total_dropped;
8986
8987 DEBUG_TRACE("%p: Prep node msg for %p\n", sfi, sfi->ni);
8988
8989 /*
8990 * Create a small xml stats block for our managed node, like:
8991 * <node address="" hosts="" time_added="" from_data_total="" to_data_total="" />
8992 *
8993 * Extract information from the node for inclusion into the message
8994 */
Gareth Williams90f2a282014-08-27 15:56:25 +01008995 spin_lock_bh(&ecm_db_lock);
8996 from_connections_count = sfi->ni->from_connections_count;
8997 to_connections_count = sfi->ni->to_connections_count;
8998 from_nat_connections_count = sfi->ni->from_nat_connections_count;
8999 to_nat_connections_count = sfi->ni->to_nat_connections_count;
9000 spin_unlock_bh(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00009001 time_added = sfi->ni->time_added;
9002 ecm_db_node_data_stats_get(sfi->ni, &from_data_total, &to_data_total,
9003 &from_packet_total, &to_packet_total,
9004 &from_data_total_dropped, &to_data_total_dropped,
9005 &from_packet_total_dropped, &to_packet_total_dropped);
9006 sprintf(address, "%pM", sfi->ni->address);
9007
9008 /*
9009 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309010 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009011 sfi->msgp = sfi->msg_buffer;
9012
9013 /*
9014 * Prep the message
9015 */
9016 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
Gareth Williams90f2a282014-08-27 15:56:25 +01009017 "<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 +00009018 " from_data_total=\"%llu\" to_data_total=\"%llu\" from_packet_total=\"%llu\" to_packet_total=\"%llu\""
9019 " from_data_total_dropped=\"%llu\" to_data_total_dropped=\"%llu\" from_packet_total_dropped=\"%llu\" to_packet_total_dropped=\"%llu\" />\n",
9020 address,
Gareth Williams90f2a282014-08-27 15:56:25 +01009021 from_connections_count,
9022 to_connections_count,
9023 from_nat_connections_count,
9024 to_nat_connections_count,
Ben Menchaca84f36632014-02-28 20:57:38 +00009025 time_added,
9026 from_data_total,
9027 to_data_total,
9028 from_packet_total,
9029 to_packet_total,
9030 from_data_total_dropped,
9031 to_data_total_dropped,
9032 from_packet_total_dropped,
9033 to_packet_total_dropped);
9034
9035 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9036 return false;
9037 }
9038
9039 sfi->msg_len = msg_len;
9040 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9041 return true;
9042}
9043
9044/*
9045 * ecm_db_char_dev_iface_msg_prep()
9046 * Prepare an interface message
9047 */
9048static bool ecm_db_char_dev_iface_msg_prep(struct ecm_db_state_file_instance *sfi)
9049{
9050 int msg_len;
9051
9052 DEBUG_TRACE("%p: Prep iface msg for %p\n", sfi, sfi->ii);
9053
9054 /*
9055 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309056 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009057 sfi->msgp = sfi->msg_buffer;
9058
9059 /*
9060 * Prep the message
9061 */
9062 msg_len = sfi->ii->xml_state_get(sfi->ii, sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE);
9063
9064 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9065 return false;
9066 }
9067
9068 /*
9069 * Record the message length
9070 */
9071 sfi->msg_len = msg_len;
9072 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9073 return true;
9074}
9075
9076/*
9077 * ecm_db_char_dev_conn_chain_msg_prep()
9078 * Generate an conn hash table chain message
9079 */
9080static bool ecm_db_char_dev_conn_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9081{
9082 int chain_len;
9083 int msg_len;
9084 DEBUG_TRACE("%p: Prep conn chain msg\n", sfi);
9085
9086 /*
9087 * Get hash table chain length
9088 */
9089 spin_lock_bh(&ecm_db_lock);
9090 chain_len = ecm_db_connection_table_lengths[sfi->connection_hash_index];
9091 spin_unlock_bh(&ecm_db_lock);
9092
9093 /*
9094 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309095 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009096 sfi->msgp = sfi->msg_buffer;
9097
9098 /*
9099 * Create a small xml stats block like:
9100 * <conn_chain hash_index="" chain_length=""/>
9101 */
9102 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9103 "<conn_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9104 sfi->connection_hash_index,
9105 chain_len);
9106 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9107 return false;
9108 }
9109
9110 sfi->msg_len = msg_len;
9111 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9112 return true;
9113}
9114
9115/*
9116 * ecm_db_char_dev_mapping_chain_msg_prep()
9117 * Generate an mapping hash table chain message
9118 */
9119static bool ecm_db_char_dev_mapping_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9120{
9121 int chain_len;
9122 int msg_len;
9123 DEBUG_TRACE("%p: Prep mapping chain msg\n", sfi);
9124
9125 /*
9126 * Get hash table chain length
9127 */
9128 spin_lock_bh(&ecm_db_lock);
9129 chain_len = ecm_db_mapping_table_lengths[sfi->mapping_hash_index];
9130 spin_unlock_bh(&ecm_db_lock);
9131
9132 /*
9133 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309134 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009135 sfi->msgp = sfi->msg_buffer;
9136
9137 /*
9138 * Create a small xml stats block like:
9139 * <mapping_chain hash_index="" chain_length=""/>
9140 */
9141 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9142 "<mapping_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9143 sfi->mapping_hash_index,
9144 chain_len);
9145 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9146 return false;
9147 }
9148
9149 sfi->msg_len = msg_len;
9150 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9151 return true;
9152}
9153
9154/*
9155 * ecm_db_char_dev_host_chain_msg_prep()
9156 * Generate an host hash table chain message
9157 */
9158static bool ecm_db_char_dev_host_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9159{
9160 int chain_len;
9161 int msg_len;
9162 DEBUG_TRACE("%p: Prep host chain msg\n", sfi);
9163
9164 /*
9165 * Get hash table chain length
9166 */
9167 spin_lock_bh(&ecm_db_lock);
9168 chain_len = ecm_db_host_table_lengths[sfi->host_hash_index];
9169 spin_unlock_bh(&ecm_db_lock);
9170
9171 /*
9172 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309173 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009174 sfi->msgp = sfi->msg_buffer;
9175
9176 /*
9177 * Create a small xml stats block like:
9178 * <host_chain hash_index="" chain_length=""/>
9179 */
9180 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9181 "<host_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9182 sfi->host_hash_index,
9183 chain_len);
9184 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9185 return false;
9186 }
9187
9188 sfi->msg_len = msg_len;
9189 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9190 return true;
9191}
9192
9193/*
9194 * ecm_db_char_dev_node_chain_msg_prep()
9195 * Generate an node hash table chain message
9196 */
9197static bool ecm_db_char_dev_node_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9198{
9199 int chain_len;
9200 int msg_len;
9201 DEBUG_TRACE("%p: Prep node chain msg\n", sfi);
9202
9203 /*
9204 * Get hash table chain length
9205 */
9206 spin_lock_bh(&ecm_db_lock);
9207 chain_len = ecm_db_node_table_lengths[sfi->node_hash_index];
9208 spin_unlock_bh(&ecm_db_lock);
9209
9210 /*
9211 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309212 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009213 sfi->msgp = sfi->msg_buffer;
9214
9215 /*
9216 * Create a small xml stats block like:
9217 * <node_chain hash_index="" chain_length=""/>
9218 */
9219 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9220 "<node_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9221 sfi->node_hash_index,
9222 chain_len);
9223 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9224 return false;
9225 }
9226
9227 sfi->msg_len = msg_len;
9228 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9229 return true;
9230}
9231
9232/*
9233 * ecm_db_char_dev_iface_chain_msg_prep()
9234 * Generate an interface hash table chain message
9235 */
9236static bool ecm_db_char_dev_iface_chain_msg_prep(struct ecm_db_state_file_instance *sfi)
9237{
9238 int chain_len;
9239 int msg_len;
9240 DEBUG_TRACE("%p: Prep iface chain msg\n", sfi);
9241
9242 /*
9243 * Get hash table chain length
9244 */
9245 spin_lock_bh(&ecm_db_lock);
9246 chain_len = ecm_db_iface_table_lengths[sfi->iface_hash_index];
9247 spin_unlock_bh(&ecm_db_lock);
9248
9249 /*
9250 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309251 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009252 sfi->msgp = sfi->msg_buffer;
9253
9254 /*
9255 * Create a small xml stats block like:
9256 * <iface_chain hash_index="" chain_length=""/>
9257 */
9258 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9259 "<iface_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
9260 sfi->iface_hash_index,
9261 chain_len);
9262 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9263 return false;
9264 }
9265
9266 sfi->msg_len = msg_len;
9267 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9268 return true;
9269}
9270
9271/*
9272 * ecm_db_char_dev_protocol_count_msg_prep()
9273 * Generate a protocol usage message
9274 */
9275static bool ecm_db_char_dev_protocol_count_msg_prep(struct ecm_db_state_file_instance *sfi)
9276{
9277 int count;
9278 int msg_len;
9279 DEBUG_TRACE("%p: Prep protocol msg\n", sfi);
9280
9281 /*
9282 * Get protocol connection total count
9283 */
9284 spin_lock_bh(&ecm_db_lock);
9285 count = ecm_db_connection_count_by_protocol[sfi->protocol];
9286 spin_unlock_bh(&ecm_db_lock);
9287
9288 /*
9289 * Use fresh buffer
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309290 */
Ben Menchaca84f36632014-02-28 20:57:38 +00009291 sfi->msgp = sfi->msg_buffer;
9292
9293 /*
9294 * Create a small xml stats block like:
9295 * <conn_proto_count protocol="" count=""/>
9296 */
9297 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9298 "<conn_proto_count protocol=\"%d\" count=\"%d\"/>\n",
9299 sfi->protocol,
9300 count);
9301 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9302 return false;
9303 }
9304 sfi->msg_len = msg_len;
9305 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9306 return true;
9307}
9308
9309/*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009310 * ecm_db_char_dev_cta_msg_prep()
9311 * Generate a classifier type assignment message
9312 */
9313static bool ecm_db_char_dev_cta_msg_prep(struct ecm_db_state_file_instance *sfi, ecm_classifier_type_t ca_type)
9314{
9315 int msg_len;
9316 struct ecm_db_connection_instance *ci;
9317 int flags;
9318
9319 DEBUG_TRACE("%p: Prep classifier type assignment msg: %d\n", sfi, ca_type);
9320
9321 /*
9322 * Use fresh buffer
9323 */
9324 sfi->msgp = sfi->msg_buffer;
9325
9326 /*
9327 * Output message according to where we are with iteration.
9328 * Output element start?
9329 * We are producing an element like:
9330 * <classifier_conn_type_assignment ca_type="2">
9331 * <connection serial="1625"/>
9332 * ...
9333 * </classifier_conn_type_assignment>
9334 */
9335 flags = sfi->classifier_type_assignments_flags[ca_type];
9336 if (flags & ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN) {
9337 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9338 "<classifier_conn_type_assignment ca_type=\"%d\">\n",
9339 ca_type);
9340 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9341 return false;
9342 }
9343 sfi->msg_len = msg_len;
9344 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9345
9346 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN;
9347 return true;
9348 }
9349
9350 /*
9351 * Output connection detail, if any further to output for this type.
9352 */
9353 ci = sfi->classifier_type_assignments[ca_type];
9354 if (ci) {
9355 DEBUG_CHECK_MAGIC(ci, ECM_DB_CONNECTION_INSTANCE_MAGIC, "%p: magic failed", ci);
9356 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9357 "<connection serial=\"%u\"/>\n",
9358 ci->serial);
9359 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9360 return false;
9361 }
9362 sfi->msg_len = msg_len;
9363 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9364
9365 /*
9366 * Prep next connection for when we are called again, releasing this one.
9367 */
9368 if (!(sfi->classifier_type_assignments[ca_type] = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type))) {
9369 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_DB_STATE_FILE_CTA_FLAG_CONTENT_UNWRITTEN;
9370 }
9371 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
9372 return true;
9373 }
9374
9375 /*
9376 * Output closing element?
9377 */
9378 if (flags & ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN) {
9379 msg_len = snprintf(sfi->msgp, ECM_DB_STATE_FILE_BUFFER_SIZE,
9380 "</classifier_conn_type_assignment>\n");
9381 if ((msg_len <= 0) || (msg_len >= ECM_DB_STATE_FILE_BUFFER_SIZE)) {
9382 return false;
9383 }
9384 sfi->msg_len = msg_len;
9385 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
9386
9387 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_DB_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN;
9388 return true;
9389 }
9390
9391 return true;
9392}
9393
9394/*
9395 * ecm_db_state_file_classifier_type_assignments_release()
9396 * Releases any uniterated classifier assignments
9397 */
9398static void ecm_db_state_file_classifier_type_assignments_release(struct ecm_db_state_file_instance *sfi)
9399{
9400 ecm_classifier_type_t ca_type;
9401
9402 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
9403 struct ecm_db_connection_instance *ci;
9404
9405 ci = sfi->classifier_type_assignments[ca_type];
9406 if (!ci) {
9407 continue;
9408 }
9409
9410 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
9411 }
9412}
9413
9414/*
Ben Menchaca84f36632014-02-28 20:57:38 +00009415 * ecm_db_char_device_open()
9416 * Opens the special char device file which we use to dump our state.
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309417 *
Ben Menchaca84f36632014-02-28 20:57:38 +00009418 */
9419static int ecm_db_char_device_open(struct inode *inode, struct file *file)
9420{
9421 struct ecm_db_state_file_instance *sfi;
9422
9423 DEBUG_INFO("State open\n");
9424
9425 /*
9426 * Allocate state information for the reading
9427 */
9428 DEBUG_ASSERT(file->private_data == NULL, "unexpected double open: %p?\n", file->private_data);
9429
9430 sfi = (struct ecm_db_state_file_instance *)kzalloc(sizeof(struct ecm_db_state_file_instance), GFP_ATOMIC | __GFP_NOWARN);
9431 if (!sfi) {
9432 return -ENOMEM;
9433 }
9434 DEBUG_SET_MAGIC(sfi, ECM_DB_STATE_FILE_INSTANCE_MAGIC);
9435 file->private_data = sfi;
9436
9437 /*
9438 * Snapshot output mask for this file
9439 */
9440 spin_lock_bh(&ecm_db_lock);
9441 sfi->output_mask = ecm_db_state_file_output_mask;
9442 spin_unlock_bh(&ecm_db_lock);
9443
9444 /*
9445 * Take references to each object list that we are going to generate state for.
9446 */
9447 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_CONNECTIONS) {
9448 sfi->ci = ecm_db_connections_get_and_ref_first();
9449 }
9450 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_MAPPINGS) {
9451 sfi->mi = ecm_db_mappings_get_and_ref_first();
9452 }
9453 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_HOSTS) {
9454 sfi->hi = ecm_db_hosts_get_and_ref_first();
9455 }
9456 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_NODES) {
9457 sfi->ni = ecm_db_nodes_get_and_ref_first();
9458 }
9459 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_INTERFACES) {
9460 sfi->ii = ecm_db_interfaces_get_and_ref_first();
9461 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009462 if (sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_CLASSIFIER_TYPE_ASSIGNMENTS) {
9463 ecm_classifier_type_t ca_type;
9464
9465 /*
9466 * Iterate all classifier type assignments.
9467 * Hold the head of each list to start us off on our iterating process.
9468 */
9469 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
9470 if ((sfi->classifier_type_assignments[ca_type] = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type))) {
9471 /*
9472 * There is some content to write for this ca_type
9473 */
9474 sfi->classifier_type_assignments_flags[ca_type] =
9475 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;
9476
9477 }
9478 }
9479 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009480
9481 /*
9482 * Cannot do this if the event processing thread is exiting
9483 */
9484 spin_lock_bh(&ecm_db_lock);
9485 if (ecm_db_terminate_pending) {
9486 spin_unlock_bh(&ecm_db_lock);
9487
9488 if (sfi->ci) {
9489 ecm_db_connection_deref(sfi->ci);
9490 }
9491 if (sfi->mi) {
9492 ecm_db_mapping_deref(sfi->mi);
9493 }
9494 if (sfi->hi) {
9495 ecm_db_host_deref(sfi->hi);
9496 }
9497 if (sfi->ni) {
9498 ecm_db_node_deref(sfi->ni);
9499 }
9500 if (sfi->ii) {
9501 ecm_db_iface_deref(sfi->ii);
9502 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009503 ecm_db_state_file_classifier_type_assignments_release(sfi);
Ben Menchaca84f36632014-02-28 20:57:38 +00009504
9505 kfree(sfi);
9506 DEBUG_WARN("Terminating\n");
9507 return -EBUSY;
9508 }
9509 spin_unlock_bh(&ecm_db_lock);
9510
9511 DEBUG_INFO("State opened %p\n", sfi);
9512
9513 return 0;
9514}
9515
9516/*
9517 * ecm_db_char_device_release()
9518 * Called when a process closes the device file.
9519 */
9520static int ecm_db_char_device_release(struct inode *inode, struct file *file)
9521{
9522 struct ecm_db_state_file_instance *sfi;
9523
9524 sfi = (struct ecm_db_state_file_instance *)file->private_data;
9525 DEBUG_CHECK_MAGIC(sfi, ECM_DB_STATE_FILE_INSTANCE_MAGIC, "%p: magic failed", sfi);
9526 DEBUG_INFO("%p: State close\n", sfi);
9527
9528 /*
9529 * Release any references held
9530 */
9531 if (sfi->ci) {
9532 ecm_db_connection_deref(sfi->ci);
9533 }
9534 if (sfi->mi) {
9535 ecm_db_mapping_deref(sfi->mi);
9536 }
9537 if (sfi->hi) {
9538 ecm_db_host_deref(sfi->hi);
9539 }
9540 if (sfi->ni) {
9541 ecm_db_node_deref(sfi->ni);
9542 }
9543 if (sfi->ii) {
9544 ecm_db_iface_deref(sfi->ii);
9545 }
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009546 ecm_db_state_file_classifier_type_assignments_release(sfi);
9547
Ben Menchaca84f36632014-02-28 20:57:38 +00009548 DEBUG_CLEAR_MAGIC(sfi);
9549 kfree(sfi);
9550
9551 return 0;
9552}
9553
9554/*
9555 * ecm_db_char_device_read()
9556 * Called to read the state
9557 */
9558static ssize_t ecm_db_char_device_read(struct file *file, /* see include/linux/fs.h */
9559 char *buffer, /* buffer to fill with data */
9560 size_t length, /* length of the buffer */
9561 loff_t *offset) /* Doesn't apply - this is a char file */
9562{
9563 struct ecm_db_state_file_instance *sfi;
9564 int bytes_read = 0; /* Number of bytes actually written to the buffer */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009565 ecm_classifier_type_t ca_type;
Ben Menchaca84f36632014-02-28 20:57:38 +00009566
9567 sfi = (struct ecm_db_state_file_instance *)file->private_data;
9568 DEBUG_CHECK_MAGIC(sfi, ECM_DB_STATE_FILE_INSTANCE_MAGIC, "%p: magic failed", sfi);
9569 DEBUG_TRACE("%p: State read up to length %d bytes\n", sfi, length);
9570
Ben Menchaca84f36632014-02-28 20:57:38 +00009571
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009572 /*
9573 * If there is still some message remaining to be output then complete that first
9574 */
9575 if (sfi->msg_len) {
9576 goto char_device_read_output;
9577 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009578
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009579 if (!sfi->doc_start_written) {
9580 sfi->msgp = sfi->msg_buffer;
9581 sfi->msg_len = sprintf(sfi->msgp, "<ecm_db>\n");
9582 sfi->doc_start_written = true;
9583 goto char_device_read_output;
9584 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009585
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009586 if (sfi->ci) {
9587 struct ecm_db_connection_instance *cin;
9588 if (!ecm_db_char_dev_conn_msg_prep(sfi)) {
9589 return -EIO;
Ben Menchaca84f36632014-02-28 20:57:38 +00009590 }
9591
9592 /*
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009593 * Next connection for when we return
Ben Menchaca84f36632014-02-28 20:57:38 +00009594 */
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009595 cin = ecm_db_connection_get_and_ref_next(sfi->ci);
9596 ecm_db_connection_deref(sfi->ci);
9597 sfi->ci = cin;
9598
9599 goto char_device_read_output;
9600 }
9601
9602 if (sfi->mi) {
9603 struct ecm_db_mapping_instance *min;
9604 if (!ecm_db_char_dev_mapping_msg_prep(sfi)) {
9605 return -EIO;
9606 }
9607
9608 /*
9609 * Next mapping for when we return
9610 */
9611 min = ecm_db_mapping_get_and_ref_next(sfi->mi);
9612 ecm_db_mapping_deref(sfi->mi);
9613 sfi->mi = min;
9614
9615 goto char_device_read_output;
9616 }
9617
9618 if (sfi->hi) {
9619 struct ecm_db_host_instance *hin;
9620 if (!ecm_db_char_dev_host_msg_prep(sfi)) {
9621 return -EIO;
9622 }
9623
9624 /*
9625 * Next host for when we return
9626 */
9627 hin = ecm_db_host_get_and_ref_next(sfi->hi);
9628 ecm_db_host_deref(sfi->hi);
9629 sfi->hi = hin;
9630
9631 goto char_device_read_output;
9632 }
9633
9634 if (sfi->ni) {
9635 struct ecm_db_node_instance *nin;
9636 if (!ecm_db_char_dev_node_msg_prep(sfi)) {
9637 return -EIO;
9638 }
9639
9640 /*
9641 * Next node for when we return
9642 */
9643 nin = ecm_db_node_get_and_ref_next(sfi->ni);
9644 ecm_db_node_deref(sfi->ni);
9645 sfi->ni = nin;
9646
9647 goto char_device_read_output;
9648 }
9649
9650 if (sfi->ii) {
9651 struct ecm_db_iface_instance *iin;
9652 if (!ecm_db_char_dev_iface_msg_prep(sfi)) {
9653 return -EIO;
9654 }
9655
9656 /*
9657 * Next iface for when we return
9658 */
9659 iin = ecm_db_interface_get_and_ref_next(sfi->ii);
9660 ecm_db_iface_deref(sfi->ii);
9661 sfi->ii = iin;
9662
9663 goto char_device_read_output;
9664 }
9665
9666 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_CONNECTIONS_CHAIN) && (sfi->connection_hash_index < ECM_DB_CONNECTION_HASH_SLOTS)) {
9667 if (!ecm_db_char_dev_conn_chain_msg_prep(sfi)) {
9668 return -EIO;
9669 }
9670 sfi->connection_hash_index++;
9671 goto char_device_read_output;
9672 }
9673
9674 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_MAPPINGS_CHAIN) && (sfi->mapping_hash_index < ECM_DB_MAPPING_HASH_SLOTS)) {
9675 if (!ecm_db_char_dev_mapping_chain_msg_prep(sfi)) {
9676 return -EIO;
9677 }
9678 sfi->mapping_hash_index++;
9679 goto char_device_read_output;
9680 }
9681
9682 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_HOSTS_CHAIN) && (sfi->host_hash_index < ECM_DB_HOST_HASH_SLOTS)) {
9683 if (!ecm_db_char_dev_host_chain_msg_prep(sfi)) {
9684 return -EIO;
9685 }
9686 sfi->host_hash_index++;
9687 goto char_device_read_output;
9688 }
9689
9690 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_NODES_CHAIN) && (sfi->node_hash_index < ECM_DB_NODE_HASH_SLOTS)) {
9691 if (!ecm_db_char_dev_node_chain_msg_prep(sfi)) {
9692 return -EIO;
9693 }
9694 sfi->node_hash_index++;
9695 goto char_device_read_output;
9696 }
9697
9698 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_INTERFACES_CHAIN) && (sfi->iface_hash_index < ECM_DB_IFACE_HASH_SLOTS)) {
9699 if (!ecm_db_char_dev_iface_chain_msg_prep(sfi)) {
9700 return -EIO;
9701 }
9702 sfi->iface_hash_index++;
9703 goto char_device_read_output;
9704 }
9705
9706 if ((sfi->output_mask & ECM_DB_STATE_FILE_OUTPUT_PROTOCOL_COUNTS) && (sfi->protocol < 256)) {
9707 if (!ecm_db_char_dev_protocol_count_msg_prep(sfi)) {
9708 return -EIO;
9709 }
9710 sfi->protocol++;
9711 goto char_device_read_output;
9712 }
9713
9714 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
9715 int flags;
9716
9717 flags = sfi->classifier_type_assignments_flags[ca_type];
9718
9719 if (!flags) {
9720 /*
9721 * Nothing further to write out for this ca_type
9722 */
9723 continue;
9724 }
9725 if (!ecm_db_char_dev_cta_msg_prep(sfi, ca_type)) {
9726 return -EIO;
9727 }
9728 goto char_device_read_output;
9729 }
9730
9731 if (!sfi->doc_end_written) {
9732 sfi->msgp = sfi->msg_buffer;
9733 sfi->msg_len = sprintf(sfi->msgp, "</ecm_db>\n");
9734 sfi->doc_end_written = true;
9735 goto char_device_read_output;
9736 }
9737
9738 /*
9739 * EOF
9740 */
9741 return 0;
9742
9743char_device_read_output:
Ben Menchaca84f36632014-02-28 20:57:38 +00009744
9745 /*
9746 * If supplied buffer is small we limit what we output
9747 */
9748 bytes_read = sfi->msg_len;
9749 if (bytes_read > length) {
9750 bytes_read = length;
9751 }
9752 if (copy_to_user(buffer, sfi->msgp, bytes_read)) {
9753 return -EIO;
9754 }
9755 sfi->msg_len -= bytes_read;
9756 sfi->msgp += bytes_read;
9757
9758 DEBUG_TRACE("State read done, bytes_read %d bytes\n", bytes_read);
9759
Radha krishna Simha Jiguruf7dc34c2014-05-12 18:59:07 +05309760 /*
Ben Menchaca84f36632014-02-28 20:57:38 +00009761 * Most read functions return the number of bytes put into the buffer
9762 */
9763 return bytes_read;
9764}
9765
9766/*
9767 * ecm_db_char_device_write()
9768 */
9769static ssize_t ecm_db_char_device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
9770{
9771 return -EINVAL;
9772}
9773
9774/*
9775 * File operations used in the char device
9776 * NOTE: The char device is a simple file that allows us to dump our connection tracking state
9777 */
9778static struct file_operations ecm_db_fops = {
9779 .read = ecm_db_char_device_read,
9780 .write = ecm_db_char_device_write,
9781 .open = ecm_db_char_device_open,
9782 .release = ecm_db_char_device_release
9783};
9784
9785/*
9786 * ecm_db_timer_callback()
9787 * Manage expiration of connections
9788 * NOTE: This is softirq context
9789 */
9790static void ecm_db_timer_callback(unsigned long data)
9791{
9792 uint32_t timer;
9793
9794 /*
9795 * Increment timer.
9796 */
9797 spin_lock_bh(&ecm_db_lock);
9798 timer = ++ecm_db_time;
9799 spin_unlock_bh(&ecm_db_lock);
9800 DEBUG_TRACE("Garbage timer tick %d\n", timer);
9801
9802 /*
9803 * Check timer groups
9804 */
9805 ecm_db_timer_groups_check(timer);
9806
9807 /*
9808 * Set the timer for the next second
9809 */
9810 ecm_db_timer.expires += HZ;
9811 if (ecm_db_timer.expires <= jiffies) {
9812 DEBUG_WARN("losing time %lu, jiffies = %lu\n", ecm_db_timer.expires, jiffies);
9813 ecm_db_timer.expires = jiffies + HZ;
9814 }
9815 add_timer(&ecm_db_timer);
9816}
9817
9818/*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009819 * ecm_db_init()
Ben Menchaca84f36632014-02-28 20:57:38 +00009820 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009821int ecm_db_init(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00009822{
9823 int result;
Murat Sezgin1f381852014-11-20 09:51:07 -08009824 int i;
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009825 DEBUG_INFO("ECM Module init\n");
Ben Menchaca84f36632014-02-28 20:57:38 +00009826
9827 /*
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009828 * Initialise our global database lock
Ben Menchaca84f36632014-02-28 20:57:38 +00009829 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009830 spin_lock_init(&ecm_db_lock);
Ben Menchaca84f36632014-02-28 20:57:38 +00009831
9832 /*
Murat Sezgin1f381852014-11-20 09:51:07 -08009833 * Register System device control
Ben Menchaca84f36632014-02-28 20:57:38 +00009834 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009835 result = subsys_system_register(&ecm_db_subsys, NULL);
Ben Menchaca84f36632014-02-28 20:57:38 +00009836 if (result) {
9837 DEBUG_ERROR("Failed to register SysFS class %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009838 return result;
Ben Menchaca84f36632014-02-28 20:57:38 +00009839 }
9840
9841 /*
9842 * Register SYSFS device control
9843 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009844 memset(&ecm_db_dev, 0, sizeof(ecm_db_dev));
9845 ecm_db_dev.id = 0;
9846 ecm_db_dev.bus = &ecm_db_subsys;
9847 ecm_db_dev.release = ecm_db_dev_release;
9848 result = device_register(&ecm_db_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00009849 if (result) {
Murat Sezgin1f381852014-11-20 09:51:07 -08009850 DEBUG_ERROR("Failed to register System device %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009851 goto task_cleanup_1;
Ben Menchaca84f36632014-02-28 20:57:38 +00009852 }
9853
9854 /*
9855 * Create files, one for each parameter supported by this module
9856 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009857 for (i = 0; i < ARRAY_SIZE(ecm_db_attrs); i++) {
9858 result = device_create_file(&ecm_db_dev, ecm_db_attrs[i]);
9859 if (result) {
9860 DEBUG_ERROR("Failed to create attribute file %d\n", result);
9861 goto task_cleanup_2;
9862 }
Ben Menchaca84f36632014-02-28 20:57:38 +00009863 }
9864
9865 /*
9866 * Register a char device that we will use to provide a dump of our state
9867 */
Murat Sezgin1f381852014-11-20 09:51:07 -08009868 result = register_chrdev(0, ecm_db_subsys.name, &ecm_db_fops);
Ben Menchaca84f36632014-02-28 20:57:38 +00009869 if (result < 0) {
9870 DEBUG_ERROR("Failed to register chrdev %d\n", result);
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009871 goto task_cleanup_2;
Ben Menchaca84f36632014-02-28 20:57:38 +00009872 }
9873 ecm_db_dev_major_id = result;
9874 DEBUG_TRACE("registered chr dev major id assigned %d\n", ecm_db_dev_major_id);
9875
Ben Menchaca84f36632014-02-28 20:57:38 +00009876 /*
9877 * Set a timer to manage cleanup of expired connections
9878 */
9879 init_timer(&ecm_db_timer);
9880 ecm_db_timer.function = ecm_db_timer_callback;
9881 ecm_db_timer.data = 0;
9882 ecm_db_timer.expires = jiffies + HZ;
9883 add_timer(&ecm_db_timer);
9884
9885 /*
9886 * Initialise timer groups with time values
9887 */
9888 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].time = ECM_DB_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
9889 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT;
9890 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_GENERIC_TIMEOUT;
9891 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT;
9892 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].time = ECM_DB_CONNECTION_IGMP_TIMEOUT;
9893 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT;
9894 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
9895 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT;
9896 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].time = ECM_DB_CONNECTION_UDP_TIMEOUT;
9897 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT;
9898 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].time = ECM_DB_CONNECTION_ICMP_TIMEOUT;
9899 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT;
9900 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].time = ECM_DB_CONNECTION_TCP_SHORT_TIMEOUT;
9901 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT;
9902 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].time = ECM_DB_CONNECTION_TCP_RST_TIMEOUT;
9903 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT;
9904 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
9905 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT;
9906 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].time = ECM_DB_CONNECTION_PPTP_DATA_TIMEOUT;
9907 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT;
9908 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].time = ECM_DB_CONNECTION_RTCP_TIMEOUT;
9909 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT;
9910 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].time = ECM_DB_CONNECTION_TCP_LONG_TIMEOUT;
9911 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT;
9912 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_FAST_TIMEOUT;
9913 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT;
9914 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].time = ECM_DB_CONNECTION_RTSP_SLOW_TIMEOUT;
9915 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT;
9916 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].time = ECM_DB_CONNECTION_DNS_TIMEOUT;
9917 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT;
9918 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].time = ECM_DB_CONNECTION_FTP_TIMEOUT;
9919 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT;
9920 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].time = ECM_DB_CONNECTION_BITTORRENT_TIMEOUT;
9921 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT;
9922
9923 /*
9924 * H323 timeout value is 8 hours (8h * 60m * 60s == 28800 seconds).
9925 */
9926 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].time = ECM_DB_CONNECTION_H323_TIMEOUT;
9927 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT;
9928
9929 /*
9930 * IKE Timeout (seconds) = 15 hours
9931 */
9932 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].time = ECM_DB_CONNECTION_IKE_TIMEOUT;
9933 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT;
9934
9935 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].time = ECM_DB_CONNECTION_ESP_TIMEOUT;
9936 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT;
9937 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].time = ECM_DB_CONNECTION_ESP_PENDING_TIMEOUT;
9938 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT;
9939
9940 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].time = ECM_DB_CONNECTION_SDP_TIMEOUT;
9941 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT;
9942 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].time = ECM_DB_CONNECTION_SIP_TIMEOUT;
9943 ecm_db_timer_groups[ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT].tg = ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT;
9944
9945 /*
9946 * Reset connection by protocol counters
9947 */
9948 memset(ecm_db_connection_count_by_protocol, 0, sizeof(ecm_db_connection_count_by_protocol));
9949
Gareth Williamsdd6dfce2014-10-14 15:51:31 +01009950 /*
9951 * Reset classifier type assignment lists
9952 */
9953 memset(ecm_db_connection_classifier_type_assignments, 0, sizeof(ecm_db_connection_classifier_type_assignments));
9954
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009955 return 0;
Ben Menchaca84f36632014-02-28 20:57:38 +00009956
Ben Menchaca84f36632014-02-28 20:57:38 +00009957task_cleanup_2:
Murat Sezgin1f381852014-11-20 09:51:07 -08009958 while (--i >= 0) {
9959 device_remove_file(&ecm_db_dev, ecm_db_attrs[i]);
9960 }
9961 device_unregister(&ecm_db_dev);
Ben Menchaca84f36632014-02-28 20:57:38 +00009962task_cleanup_1:
Murat Sezgin1f381852014-11-20 09:51:07 -08009963 bus_unregister(&ecm_db_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00009964
Ben Menchaca84f36632014-02-28 20:57:38 +00009965 return result;
9966}
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009967EXPORT_SYMBOL(ecm_db_init);
Ben Menchaca84f36632014-02-28 20:57:38 +00009968
9969/*
9970 * ecm_db_exit()
9971 */
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009972void ecm_db_exit(void)
Ben Menchaca84f36632014-02-28 20:57:38 +00009973{
Murat Sezgin1f381852014-11-20 09:51:07 -08009974 int i;
Ben Menchaca84f36632014-02-28 20:57:38 +00009975 DEBUG_INFO("ECM DB Module exit\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -05009976
9977 spin_lock_bh(&ecm_db_lock);
9978 ecm_db_terminate_pending = true;
9979 spin_unlock_bh(&ecm_db_lock);
9980
9981 ecm_db_connection_defunct_all();
9982
9983 /*
9984 * Destroy garbage timer
9985 * Timer must be cancelled outside of holding db lock - if the
9986 * timer callback runs on another CPU we would deadlock
9987 * as we would wait for the callback to finish and it would wait
9988 * indefinately for the lock to be released!
9989 */
9990 del_timer_sync(&ecm_db_timer);
Murat Sezgin1f381852014-11-20 09:51:07 -08009991 unregister_chrdev(ecm_db_dev_major_id, ecm_db_subsys.name);
9992
9993 for (i = 0; i < ARRAY_SIZE(ecm_db_attrs); i++) {
9994 device_remove_file(&ecm_db_dev, ecm_db_attrs[i]);
9995 }
9996
9997 device_unregister(&ecm_db_dev);
9998 bus_unregister(&ecm_db_subsys);
Ben Menchaca84f36632014-02-28 20:57:38 +00009999}
Nicolas Costaf46c33b2014-05-15 10:02:00 -050010000EXPORT_SYMBOL(ecm_db_exit);