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