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