blob: 902d5ae2317fe883b85f58466da84d110d152bf5 [file] [log] [blame]
Gareth Williamsf98d4192015-03-11 16:55:41 +00001/*
2 **************************************************************************
3 * Copyright (c) 2015, 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/version.h>
18#include <linux/types.h>
19#include <linux/ip.h>
20#include <linux/module.h>
21#include <linux/sysctl.h>
22#include <linux/kthread.h>
23#include <linux/device.h>
24#include <linux/fs.h>
25#include <linux/string.h>
26#include <asm/unaligned.h>
27#include <asm/uaccess.h> /* for put_user */
28#include <linux/inet.h>
29#include <linux/ipv6.h>
30#include <linux/netfilter_bridge.h>
31
32/*
33 * Debug output levels
34 * 0 = OFF
35 * 1 = ASSERTS / ERRORS
36 * 2 = 1 + WARN
37 * 3 = 2 + INFO
38 * 4 = 3 + TRACE
39 */
40#define DEBUG_LEVEL ECM_STATE_DEBUG_LEVEL
41
42#include <nss_api_if.h>
43
44#include "ecm_types.h"
45#include "ecm_db_types.h"
46#include "ecm_tracker.h"
47#include "ecm_classifier.h"
48#include "ecm_front_end_types.h"
49#include "ecm_classifier_default.h"
50#include "ecm_db.h"
51
52/*
53 * Magic numbers
54 */
55#define ECM_STATE_FILE_INSTANCE_MAGIC 0xB3FE
56
57/*
58 * System device linkage
59 */
60static struct device ecm_state_dev; /* System device linkage */
61
62/*
63 * Locking of the state - concurrency control
64 */
65static spinlock_t ecm_state_lock; /* Protect the table from SMP access. */
66
67/*
68 * Character device stuff - used to communicate status back to user space
69 */
70#define ECM_STATE_FILE_BUFFER_SIZE 8192
71static int ecm_state_dev_major_id = 0; /* Major ID of registered char dev from which we can dump out state to userspace */
72
73#define ECM_STATE_FILE_OUTPUT_CONNECTIONS 1
74#define ECM_STATE_FILE_OUTPUT_MAPPINGS 2
75#define ECM_STATE_FILE_OUTPUT_HOSTS 4
76#define ECM_STATE_FILE_OUTPUT_NODES 8
77#define ECM_STATE_FILE_OUTPUT_INTERFACES 16
78#define ECM_STATE_FILE_OUTPUT_CONNECTIONS_CHAIN 32
79#define ECM_STATE_FILE_OUTPUT_MAPPINGS_CHAIN 64
80#define ECM_STATE_FILE_OUTPUT_HOSTS_CHAIN 128
81#define ECM_STATE_FILE_OUTPUT_NODES_CHAIN 256
82#define ECM_STATE_FILE_OUTPUT_INTERFACES_CHAIN 512
83#define ECM_STATE_FILE_OUTPUT_PROTOCOL_COUNTS 1024
84#define ECM_STATE_FILE_OUTPUT_CLASSIFIER_TYPE_ASSIGNMENTS 2048
85
86/*
87 * Assistive flags for classifier connection type assignments
88 */
89#define ECM_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN 1
90#define ECM_STATE_FILE_CTA_FLAG_CONTENT_UNWRITTEN 2
91#define ECM_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN 4
92
93/*
94 * struct ecm_state_file_instance
95 * Structure used as state per open instance of our db state file
96 */
97struct ecm_state_file_instance {
98 int output_mask; /* The content types wanted by the user */
99 struct ecm_db_connection_instance *ci; /* All connections list iterator */
100 struct ecm_db_mapping_instance *mi; /* All mappings list iterator */
101 struct ecm_db_host_instance *hi; /* All hosts list iterator */
102 struct ecm_db_node_instance *ni; /* All nodes list iterator */
103 struct ecm_db_iface_instance *ii; /* All interfaces list iterator */
104 struct ecm_db_connection_instance *classifier_type_assignments[ECM_CLASSIFIER_TYPES];
105 /* Classifier type connection assignments iterator, one for each classifier type */
106 int classifier_type_assignments_flags[ECM_CLASSIFIER_TYPES];
107 /* Classifier type connection assignments flags to assist the iteration */
108 int connection_hash_index; /* Connection hash table lengths iterator */
109 int mapping_hash_index; /* Mapping hash table lengths iterator */
110 int host_hash_index; /* Host hash table lengths iterator */
111 int node_hash_index; /* Node hash table lengths iterator */
112 int iface_hash_index; /* Interface hash table lengths iterator */
113 int protocol; /* Protocol connection count iterator */
114 bool doc_start_written; /* Has xml doc opening element been written? */
115 bool doc_end_written; /* Has xml doc closing element been written? */
116 char msg_buffer[ECM_STATE_FILE_BUFFER_SIZE]; /* Used to hold the current state message being output */
117 char *msgp; /* Points into the msg buffer as we output it piece by piece */
118 int msg_len; /* Length of the buffer still to be written out */
119#if (DEBUG_LEVEL > 0)
120 uint16_t magic;
121#endif
122};
123static int ecm_state_file_output_mask = ECM_STATE_FILE_OUTPUT_CONNECTIONS;
124 /* Bit mask specifies which data to output in the state file */
125
126/*
127 * ecm_db_get_state_dev_major()
128 */
129static ssize_t ecm_db_get_state_dev_major(struct device *dev,
130 struct device_attribute *attr,
131 char *buf)
132{
133 ssize_t count;
134 int major;
135
136 spin_lock_bh(&ecm_state_lock);
137 major = ecm_state_dev_major_id;
138 spin_unlock_bh(&ecm_state_lock);
139
140 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", major);
141
142 return count;
143}
144
145/*
146 * ecm_db_get_state_file_output_mask()
147 */
148static ssize_t ecm_db_get_state_file_output_mask(struct device *dev,
149 struct device_attribute *attr,
150 char *buf)
151{
152 ssize_t count;
153 int num;
154
155 /*
156 * Operate under our locks
157 */
158 spin_lock_bh(&ecm_state_lock);
159 num = ecm_state_file_output_mask;
160 spin_unlock_bh(&ecm_state_lock);
161
162 count = snprintf(buf, (ssize_t)PAGE_SIZE, "%d\n", num);
163 return count;
164}
165
166/*
167 * ecm_db_set_state_file_output_mask()
168 */
169static ssize_t ecm_db_set_state_file_output_mask(struct device *dev,
170 struct device_attribute *attr,
171 const char *buf, size_t count)
172{
173 char num_buf[12];
174 int num;
175
176 /*
177 * Get the number from buf into a properly z-termed number buffer
178 */
179 if (count > 11) return 0;
180 memcpy(num_buf, buf, count);
181 num_buf[count] = '\0';
182 sscanf(num_buf, "%d", &num);
183 DEBUG_TRACE("ecm_state_file_output_mask = %x\n", num);
184
185 /*
186 * Operate under our locks
187 */
188 spin_lock_bh(&ecm_state_lock);
189 ecm_state_file_output_mask = num;
190 spin_unlock_bh(&ecm_state_lock);
191
192 return count;
193}
194
195/*
196 * SysFS attributes for the default classifier itself.
197 */
198static DEVICE_ATTR(state_dev_major, 0444, ecm_db_get_state_dev_major, NULL);
199static DEVICE_ATTR(state_file_output_mask, 0644, ecm_db_get_state_file_output_mask, ecm_db_set_state_file_output_mask);
200
201/*
202 * System device attribute array.
203 */
204static struct device_attribute *ecm_state_attrs[] = {
205 &dev_attr_state_dev_major,
206 &dev_attr_state_file_output_mask,
207};
208
209/*
210 * Sub system node of the ECM DB State
211 * Sys device control points can be found at /sys/devices/system/ecm_state/ecm_stateX/
212 */
213static struct bus_type ecm_state_subsys = {
214 .name = "ecm_state",
215 .dev_name = "ecm_state",
216};
217
218/*
219 * ecm_state_dev_release()
220 * This is a dummy release function for device.
221 */
222static void ecm_state_dev_release(struct device *dev)
223{
224
225}
226
227/*
228 * ecm_state_char_dev_conn_msg_prep()
229 * Prepare a connection message
230 */
231static bool ecm_state_char_dev_conn_msg_prep(struct ecm_state_file_instance *sfi)
232{
233 int msg_len;
234
235 DEBUG_TRACE("%p: Prep conn msg for %p\n", sfi, sfi->ci);
236
237 /*
238 * Use fresh buffer
239 */
240 sfi->msgp = sfi->msg_buffer;
241
242 /*
243 * Prep the message
244 */
245 msg_len = ecm_db_connection_xml_state_get(sfi->ci, sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE);
246
247 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
248 return false;
249 }
250
251 /*
252 * Record the message length
253 */
254 sfi->msg_len = msg_len;
255 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
256 return true;
257}
258
259/*
260 * ecm_state_char_dev_mapping_msg_prep()
261 * Prepare a mapping message
262 */
263static bool ecm_state_char_dev_mapping_msg_prep(struct ecm_state_file_instance *sfi)
264{
265 int msg_len;
266
267 DEBUG_TRACE("%p: Prep mapping msg for %p\n", sfi, sfi->mi);
268
269 /*
270 * Use fresh buffer
271 */
272 sfi->msgp = sfi->msg_buffer;
273
274 /*
275 * Prep the message
276 */
277 msg_len = ecm_db_mapping_xml_state_get(sfi->mi, sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE);
278
279 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
280 return false;
281 }
282
283 /*
284 * Record the message length
285 */
286 sfi->msg_len = msg_len;
287 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
288 return true;
289}
290
291/*
292 * ecm_state_char_dev_host_msg_prep()
293 * Prepare a host message
294 */
295static bool ecm_state_char_dev_host_msg_prep(struct ecm_state_file_instance *sfi)
296{
297 int msg_len;
298
299 DEBUG_TRACE("%p: Prep host msg for %p\n", sfi, sfi->hi);
300
301 /*
302 * Use fresh buffer
303 */
304 sfi->msgp = sfi->msg_buffer;
305
306 /*
307 * Prep the message
308 */
309 msg_len = ecm_db_host_xml_state_get(sfi->hi, sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE);
310
311 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
312 return false;
313 }
314
315 /*
316 * Record the message length
317 */
318 sfi->msg_len = msg_len;
319 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
320 return true;
321}
322
323/*
324 * ecm_state_char_dev_nod__msg_prep()
325 * Prepare a node message
326 */
327static bool ecm_state_char_dev_node_msg_prep(struct ecm_state_file_instance *sfi)
328{
329 int msg_len;
330
331 DEBUG_TRACE("%p: Prep node msg for %p\n", sfi, sfi->ni);
332
333 /*
334 * Use fresh buffer
335 */
336 sfi->msgp = sfi->msg_buffer;
337
338 /*
339 * Prep the message
340 */
341 msg_len = ecm_db_node_xml_state_get(sfi->ni, sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE);
342
343 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
344 return false;
345 }
346
347 /*
348 * Record the message length
349 */
350 sfi->msg_len = msg_len;
351 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
352 return true;
353}
354
355/*
356 * ecm_state_char_dev_iface_msg_prep()
357 * Prepare an interface message
358 */
359static bool ecm_state_char_dev_iface_msg_prep(struct ecm_state_file_instance *sfi)
360{
361 int msg_len;
362
363 DEBUG_TRACE("%p: Prep iface msg for %p\n", sfi, sfi->ii);
364
365 /*
366 * Use fresh buffer
367 */
368 sfi->msgp = sfi->msg_buffer;
369
370 /*
371 * Prep the message
372 */
373 msg_len = ecm_db_iface_xml_state_get(sfi->ii, sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE);
374
375 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
376 return false;
377 }
378
379 /*
380 * Record the message length
381 */
382 sfi->msg_len = msg_len;
383 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
384 return true;
385}
386
387/*
388 * ecm_state_char_dev_conn_chain_msg_prep()
389 * Generate an conn hash table chain message
390 */
391static bool ecm_state_char_dev_conn_chain_msg_prep(struct ecm_state_file_instance *sfi)
392{
393 int chain_len;
394 int msg_len;
395 DEBUG_TRACE("%p: Prep conn chain msg\n", sfi);
396
397 /*
398 * Get hash table chain length
399 */
400 chain_len = ecm_db_connection_hash_table_lengths_get(sfi->connection_hash_index);
401
402 /*
403 * Use fresh buffer
404 */
405 sfi->msgp = sfi->msg_buffer;
406
407 /*
408 * Create a small xml stats block like:
409 * <conn_chain hash_index="" chain_length=""/>
410 */
411 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
412 "<conn_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
413 sfi->connection_hash_index,
414 chain_len);
415
416 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
417 return false;
418 }
419
420 /*
421 * Record the message length
422 */
423 sfi->msg_len = msg_len;
424 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
425 return true;
426}
427
428/*
429 * ecm_state_char_dev_mapping_chain_msg_prep()
430 * Generate an mapping hash table chain message
431 */
432static bool ecm_state_char_dev_mapping_chain_msg_prep(struct ecm_state_file_instance *sfi)
433{
434 int chain_len;
435 int msg_len;
436 DEBUG_TRACE("%p: Prep mapping chain msg\n", sfi);
437
438 /*
439 * Get hash table chain length
440 */
441 chain_len = ecm_db_mapping_hash_table_lengths_get(sfi->mapping_hash_index);
442
443 /*
444 * Use fresh buffer
445 */
446 sfi->msgp = sfi->msg_buffer;
447
448 /*
449 * Create a small xml stats block like:
450 * <mapping_chain hash_index="" chain_length=""/>
451 */
452 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
453 "<mapping_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
454 sfi->mapping_hash_index,
455 chain_len);
456
457 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
458 return false;
459 }
460
461 /*
462 * Record the message length
463 */
464 sfi->msg_len = msg_len;
465 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
466 return true;
467}
468
469/*
470 * ecm_state_char_dev_host_chain_msg_prep()
471 * Generate an host hash table chain message
472 */
473static bool ecm_state_char_dev_host_chain_msg_prep(struct ecm_state_file_instance *sfi)
474{
475 int chain_len;
476 int msg_len;
477 DEBUG_TRACE("%p: Prep host chain msg\n", sfi);
478
479 /*
480 * Get hash table chain length
481 */
482 chain_len = ecm_db_host_hash_table_lengths_get(sfi->host_hash_index);
483
484 /*
485 * Use fresh buffer
486 */
487 sfi->msgp = sfi->msg_buffer;
488
489 /*
490 * Create a small xml stats block like:
491 * <host_chain hash_index="" chain_length=""/>
492 */
493 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
494 "<host_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
495 sfi->host_hash_index,
496 chain_len);
497
498 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
499 return false;
500 }
501
502 /*
503 * Record the message length
504 */
505 sfi->msg_len = msg_len;
506 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
507 return true;
508}
509
510/*
511 * ecm_state_char_dev_node_chain_msg_prep()
512 * Generate an node hash table chain message
513 */
514static bool ecm_state_char_dev_node_chain_msg_prep(struct ecm_state_file_instance *sfi)
515{
516 int chain_len;
517 int msg_len;
518 DEBUG_TRACE("%p: Prep node chain msg\n", sfi);
519
520 /*
521 * Get hash table chain length
522 */
523 chain_len = ecm_db_node_hash_table_lengths_get(sfi->node_hash_index);
524
525 /*
526 * Use fresh buffer
527 */
528 sfi->msgp = sfi->msg_buffer;
529
530 /*
531 * Create a small xml stats block like:
532 * <node_chain hash_index="" chain_length=""/>
533 */
534 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
535 "<node_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
536 sfi->node_hash_index,
537 chain_len);
538
539 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
540 return false;
541 }
542
543 /*
544 * Record the message length
545 */
546 sfi->msg_len = msg_len;
547 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
548 return true;
549}
550
551/*
552 * ecm_state_char_dev_iface_chain_msg_prep()
553 * Generate an interface hash table chain message
554 */
555static bool ecm_state_char_dev_iface_chain_msg_prep(struct ecm_state_file_instance *sfi)
556{
557 int chain_len;
558 int msg_len;
559 DEBUG_TRACE("%p: Prep iface chain msg\n", sfi);
560
561 /*
562 * Get hash table chain length
563 */
564 chain_len = ecm_db_iface_hash_table_lengths_get(sfi->iface_hash_index);
565
566 /*
567 * Use fresh buffer
568 */
569 sfi->msgp = sfi->msg_buffer;
570
571 /*
572 * Create a small xml stats block like:
573 * <iface_chain hash_index="" chain_length=""/>
574 */
575 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
576 "<iface_chain hash_index=\"%d\" chain_length=\"%d\"/>\n",
577 sfi->iface_hash_index,
578 chain_len);
579
580 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
581 return false;
582 }
583
584 /*
585 * Record the message length
586 */
587 sfi->msg_len = msg_len;
588 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
589 return true;
590}
591
592/*
593 * ecm_state_char_dev_protocol_count_msg_prep()
594 * Generate a protocol usage message
595 */
596static bool ecm_state_char_dev_protocol_count_msg_prep(struct ecm_state_file_instance *sfi)
597{
598 int count;
599 int msg_len;
600 DEBUG_TRACE("%p: Prep protocol msg\n", sfi);
601
602 /*
603 * Get protocol connection total count
604 */
605 count = ecm_db_connection_count_by_protocol_get(sfi->protocol);
606
607 /*
608 * Use fresh buffer
609 */
610 sfi->msgp = sfi->msg_buffer;
611
612 /*
613 * Create a small xml stats block like:
614 * <conn_proto_count protocol="" count=""/>
615 */
616 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
617 "<conn_proto_count protocol=\"%d\" count=\"%d\"/>\n",
618 sfi->protocol,
619 count);
620
621 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
622 return false;
623 }
624
625 /*
626 * Record the message length
627 */
628 sfi->msg_len = msg_len;
629 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
630 return true;
631}
632
633/*
634 * ecm_state_char_dev_cta_msg_prep()
635 * Generate a classifier type assignment message
636 */
637static bool ecm_state_char_dev_cta_msg_prep(struct ecm_state_file_instance *sfi, ecm_classifier_type_t ca_type)
638{
639 int msg_len;
640 struct ecm_db_connection_instance *ci;
641 int flags;
642
643 DEBUG_TRACE("%p: Prep classifier type assignment msg: %d\n", sfi, ca_type);
644
645 /*
646 * Use fresh buffer
647 */
648 sfi->msgp = sfi->msg_buffer;
649
650 /*
651 * Output message according to where we are with iteration.
652 * Output element start?
653 * We are producing an element like:
654 * <classifier_conn_type_assignment ca_type="2">
655 * <connection serial="1625"/>
656 * ...
657 * </classifier_conn_type_assignment>
658 */
659 flags = sfi->classifier_type_assignments_flags[ca_type];
660 if (flags & ECM_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN) {
661 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
662 "<classifier_conn_type_assignment ca_type=\"%d\">\n",
663 ca_type);
664 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
665 return false;
666 }
667 sfi->msg_len = msg_len;
668 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
669
670 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN;
671 return true;
672 }
673
674 /*
675 * Output connection detail, if any further to output for this type.
676 */
677 ci = sfi->classifier_type_assignments[ca_type];
678 if (ci) {
679 uint32_t serial;
680
681 serial = ecm_db_connection_serial_get(ci);
682 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
683 "<connection serial=\"%u\"/>\n",
684 serial);
685 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
686 return false;
687 }
688 sfi->msg_len = msg_len;
689 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
690
691 /*
692 * Prep next connection for when we are called again, releasing this one.
693 */
694 if (!(sfi->classifier_type_assignments[ca_type] = ecm_db_connection_by_classifier_type_assignment_get_and_ref_next(ci, ca_type))) {
695 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_STATE_FILE_CTA_FLAG_CONTENT_UNWRITTEN;
696 }
697 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
698 return true;
699 }
700
701 /*
702 * Output closing element?
703 */
704 if (flags & ECM_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN) {
705 msg_len = snprintf(sfi->msgp, ECM_STATE_FILE_BUFFER_SIZE,
706 "</classifier_conn_type_assignment>\n");
707 if ((msg_len <= 0) || (msg_len >= ECM_STATE_FILE_BUFFER_SIZE)) {
708 return false;
709 }
710 sfi->msg_len = msg_len;
711 DEBUG_TRACE("%p: Prepped msg %s\n", sfi, sfi->msgp);
712
713 sfi->classifier_type_assignments_flags[ca_type] &= ~ECM_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN;
714 return true;
715 }
716
717 return true;
718}
719
720/*
721 * ecm_state_file_classifier_type_assignments_release()
722 * Releases any uniterated classifier assignments
723 */
724static void ecm_state_file_classifier_type_assignments_release(struct ecm_state_file_instance *sfi)
725{
726 ecm_classifier_type_t ca_type;
727
728 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
729 struct ecm_db_connection_instance *ci;
730
731 ci = sfi->classifier_type_assignments[ca_type];
732 if (!ci) {
733 continue;
734 }
735
736 ecm_db_connection_by_classifier_type_assignment_deref(ci, ca_type);
737 }
738}
739
740/*
741 * ecm_state_char_device_open()
742 * Opens the special char device file which we use to dump our state.
743 */
744static int ecm_state_char_device_open(struct inode *inode, struct file *file)
745{
746 struct ecm_state_file_instance *sfi;
747
748 DEBUG_INFO("State open\n");
749
750 /*
751 * Allocate state information for the reading
752 */
753 DEBUG_ASSERT(file->private_data == NULL, "unexpected double open: %p?\n", file->private_data);
754
755 sfi = (struct ecm_state_file_instance *)kzalloc(sizeof(struct ecm_state_file_instance), GFP_ATOMIC | __GFP_NOWARN);
756 if (!sfi) {
757 return -ENOMEM;
758 }
759 DEBUG_SET_MAGIC(sfi, ECM_STATE_FILE_INSTANCE_MAGIC);
760 file->private_data = sfi;
761
762 /*
763 * Snapshot output mask for this file
764 */
765 spin_lock_bh(&ecm_state_lock);
766 sfi->output_mask = ecm_state_file_output_mask;
767 spin_unlock_bh(&ecm_state_lock);
768
769 /*
770 * Get the first indicies for hash and protocol stats should they be needed.
771 * NOTE: There are no references held here so it does not matter to get them all even if they are not wanted.
772 */
773 sfi->connection_hash_index = ecm_db_connection_hash_index_get_first();
774 sfi->mapping_hash_index = ecm_db_mapping_hash_index_get_first();
775 sfi->host_hash_index = ecm_db_host_hash_index_get_first();
776 sfi->node_hash_index = ecm_db_node_hash_index_get_first();
777 sfi->iface_hash_index = ecm_db_iface_hash_index_get_first();
778 sfi->protocol = ecm_db_protocol_get_first();
779
780 /*
781 * Take references to each object list that we are going to generate state for.
782 */
783 if (sfi->output_mask & ECM_STATE_FILE_OUTPUT_CONNECTIONS) {
784 sfi->ci = ecm_db_connections_get_and_ref_first();
785 }
786 if (sfi->output_mask & ECM_STATE_FILE_OUTPUT_MAPPINGS) {
787 sfi->mi = ecm_db_mappings_get_and_ref_first();
788 }
789 if (sfi->output_mask & ECM_STATE_FILE_OUTPUT_HOSTS) {
790 sfi->hi = ecm_db_hosts_get_and_ref_first();
791 }
792 if (sfi->output_mask & ECM_STATE_FILE_OUTPUT_NODES) {
793 sfi->ni = ecm_db_nodes_get_and_ref_first();
794 }
795 if (sfi->output_mask & ECM_STATE_FILE_OUTPUT_INTERFACES) {
796 sfi->ii = ecm_db_interfaces_get_and_ref_first();
797 }
798 if (sfi->output_mask & ECM_STATE_FILE_OUTPUT_CLASSIFIER_TYPE_ASSIGNMENTS) {
799 ecm_classifier_type_t ca_type;
800
801 /*
802 * Iterate all classifier type assignments.
803 * Hold the head of each list to start us off on our iterating process.
804 */
805 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
806 if ((sfi->classifier_type_assignments[ca_type] = ecm_db_connection_by_classifier_type_assignment_get_and_ref_first(ca_type))) {
807 /*
808 * There is some content to write for this ca_type
809 */
810 sfi->classifier_type_assignments_flags[ca_type] =
811 ECM_STATE_FILE_CTA_FLAG_ELEMENT_START_UNWRITTEN | ECM_STATE_FILE_CTA_FLAG_CONTENT_UNWRITTEN | ECM_STATE_FILE_CTA_FLAG_ELEMENT_END_UNWRITTEN;
812
813 }
814 }
815 }
816
817 DEBUG_INFO("State opened %p\n", sfi);
818
819 return 0;
820}
821
822/*
823 * ecm_state_char_device_release()
824 * Called when a process closes the device file.
825 */
826static int ecm_state_char_device_release(struct inode *inode, struct file *file)
827{
828 struct ecm_state_file_instance *sfi;
829
830 sfi = (struct ecm_state_file_instance *)file->private_data;
831 DEBUG_CHECK_MAGIC(sfi, ECM_STATE_FILE_INSTANCE_MAGIC, "%p: magic failed", sfi);
832 DEBUG_INFO("%p: State close\n", sfi);
833
834 /*
835 * Release any references held
836 */
837 if (sfi->ci) {
838 ecm_db_connection_deref(sfi->ci);
839 }
840 if (sfi->mi) {
841 ecm_db_mapping_deref(sfi->mi);
842 }
843 if (sfi->hi) {
844 ecm_db_host_deref(sfi->hi);
845 }
846 if (sfi->ni) {
847 ecm_db_node_deref(sfi->ni);
848 }
849 if (sfi->ii) {
850 ecm_db_iface_deref(sfi->ii);
851 }
852 ecm_state_file_classifier_type_assignments_release(sfi);
853
854 DEBUG_CLEAR_MAGIC(sfi);
855 kfree(sfi);
856
857 return 0;
858}
859
860/*
861 * ecm_state_char_device_read()
862 * Called to read the state
863 */
864static ssize_t ecm_state_char_device_read(struct file *file, /* see include/linux/fs.h */
865 char *buffer, /* buffer to fill with data */
866 size_t length, /* length of the buffer */
867 loff_t *offset) /* Doesn't apply - this is a char file */
868{
869 struct ecm_state_file_instance *sfi;
870 int bytes_read = 0; /* Number of bytes actually written to the buffer */
871 ecm_classifier_type_t ca_type;
872
873 sfi = (struct ecm_state_file_instance *)file->private_data;
874 DEBUG_CHECK_MAGIC(sfi, ECM_STATE_FILE_INSTANCE_MAGIC, "%p: magic failed", sfi);
875 DEBUG_TRACE("%p: State read up to length %d bytes\n", sfi, length);
876
877 /*
878 * If there is still some message remaining to be output then complete that first
879 */
880 if (sfi->msg_len) {
881 goto char_device_read_output;
882 }
883
884 if (!sfi->doc_start_written) {
885 sfi->msgp = sfi->msg_buffer;
886 sfi->msg_len = sprintf(sfi->msgp, "<ecm_state>\n");
887 sfi->doc_start_written = true;
888 goto char_device_read_output;
889 }
890
891 if (sfi->ci) {
892 struct ecm_db_connection_instance *cin;
893 if (!ecm_state_char_dev_conn_msg_prep(sfi)) {
894 return -EIO;
895 }
896
897 /*
898 * Next connection for when we return
899 */
900 cin = ecm_db_connection_get_and_ref_next(sfi->ci);
901 ecm_db_connection_deref(sfi->ci);
902 sfi->ci = cin;
903
904 goto char_device_read_output;
905 }
906
907 if (sfi->mi) {
908 struct ecm_db_mapping_instance *min;
909 if (!ecm_state_char_dev_mapping_msg_prep(sfi)) {
910 return -EIO;
911 }
912
913 /*
914 * Next mapping for when we return
915 */
916 min = ecm_db_mapping_get_and_ref_next(sfi->mi);
917 ecm_db_mapping_deref(sfi->mi);
918 sfi->mi = min;
919
920 goto char_device_read_output;
921 }
922
923 if (sfi->hi) {
924 struct ecm_db_host_instance *hin;
925 if (!ecm_state_char_dev_host_msg_prep(sfi)) {
926 return -EIO;
927 }
928
929 /*
930 * Next host for when we return
931 */
932 hin = ecm_db_host_get_and_ref_next(sfi->hi);
933 ecm_db_host_deref(sfi->hi);
934 sfi->hi = hin;
935
936 goto char_device_read_output;
937 }
938
939 if (sfi->ni) {
940 struct ecm_db_node_instance *nin;
941 if (!ecm_state_char_dev_node_msg_prep(sfi)) {
942 return -EIO;
943 }
944
945 /*
946 * Next node for when we return
947 */
948 nin = ecm_db_node_get_and_ref_next(sfi->ni);
949 ecm_db_node_deref(sfi->ni);
950 sfi->ni = nin;
951
952 goto char_device_read_output;
953 }
954
955 if (sfi->ii) {
956 struct ecm_db_iface_instance *iin;
957 if (!ecm_state_char_dev_iface_msg_prep(sfi)) {
958 return -EIO;
959 }
960
961 /*
962 * Next iface for when we return
963 */
964 iin = ecm_db_interface_get_and_ref_next(sfi->ii);
965 ecm_db_iface_deref(sfi->ii);
966 sfi->ii = iin;
967
968 goto char_device_read_output;
969 }
970
971 if ((sfi->output_mask & ECM_STATE_FILE_OUTPUT_CONNECTIONS_CHAIN) && (sfi->connection_hash_index >= 0)) {
972 if (!ecm_state_char_dev_conn_chain_msg_prep(sfi)) {
973 return -EIO;
974 }
975 sfi->connection_hash_index = ecm_db_connection_hash_index_get_next(sfi->connection_hash_index);
976 goto char_device_read_output;
977 }
978
979 if ((sfi->output_mask & ECM_STATE_FILE_OUTPUT_MAPPINGS_CHAIN) && (sfi->mapping_hash_index >= 0)) {
980 if (!ecm_state_char_dev_mapping_chain_msg_prep(sfi)) {
981 return -EIO;
982 }
983 sfi->mapping_hash_index = ecm_db_mapping_hash_index_get_next(sfi->mapping_hash_index);
984 goto char_device_read_output;
985 }
986
987 if ((sfi->output_mask & ECM_STATE_FILE_OUTPUT_HOSTS_CHAIN) && (sfi->host_hash_index >= 0)) {
988 if (!ecm_state_char_dev_host_chain_msg_prep(sfi)) {
989 return -EIO;
990 }
991 sfi->host_hash_index = ecm_db_host_hash_index_get_next(sfi->host_hash_index);
992 goto char_device_read_output;
993 }
994
995 if ((sfi->output_mask & ECM_STATE_FILE_OUTPUT_NODES_CHAIN) && (sfi->node_hash_index >= 0)) {
996 if (!ecm_state_char_dev_node_chain_msg_prep(sfi)) {
997 return -EIO;
998 }
999 sfi->node_hash_index = ecm_db_node_hash_index_get_next(sfi->node_hash_index);
1000 goto char_device_read_output;
1001 }
1002
1003 if ((sfi->output_mask & ECM_STATE_FILE_OUTPUT_INTERFACES_CHAIN) && (sfi->iface_hash_index >= 0)) {
1004 if (!ecm_state_char_dev_iface_chain_msg_prep(sfi)) {
1005 return -EIO;
1006 }
1007 sfi->iface_hash_index = ecm_db_iface_hash_index_get_next(sfi->iface_hash_index);
1008 goto char_device_read_output;
1009 }
1010
1011 if ((sfi->output_mask & ECM_STATE_FILE_OUTPUT_PROTOCOL_COUNTS) && (sfi->protocol >= 0)) {
1012 if (!ecm_state_char_dev_protocol_count_msg_prep(sfi)) {
1013 return -EIO;
1014 }
1015 sfi->protocol = ecm_db_protocol_get_next(sfi->protocol);
1016 goto char_device_read_output;
1017 }
1018
1019 for (ca_type = 0; ca_type < ECM_CLASSIFIER_TYPES; ++ca_type) {
1020 int flags;
1021
1022 flags = sfi->classifier_type_assignments_flags[ca_type];
1023
1024 if (!flags) {
1025 /*
1026 * Nothing further to write out for this ca_type
1027 */
1028 continue;
1029 }
1030 if (!ecm_state_char_dev_cta_msg_prep(sfi, ca_type)) {
1031 return -EIO;
1032 }
1033 goto char_device_read_output;
1034 }
1035
1036 if (!sfi->doc_end_written) {
1037 sfi->msgp = sfi->msg_buffer;
1038 sfi->msg_len = sprintf(sfi->msgp, "</ecm_state>\n");
1039 sfi->doc_end_written = true;
1040 goto char_device_read_output;
1041 }
1042
1043 /*
1044 * EOF
1045 */
1046 return 0;
1047
1048char_device_read_output:
1049
1050 /*
1051 * If supplied buffer is small we limit what we output
1052 */
1053 bytes_read = sfi->msg_len;
1054 if (bytes_read > length) {
1055 bytes_read = length;
1056 }
1057 if (copy_to_user(buffer, sfi->msgp, bytes_read)) {
1058 return -EIO;
1059 }
1060 sfi->msg_len -= bytes_read;
1061 sfi->msgp += bytes_read;
1062
1063 DEBUG_TRACE("State read done, bytes_read %d bytes\n", bytes_read);
1064
1065 /*
1066 * Most read functions return the number of bytes put into the buffer
1067 */
1068 return bytes_read;
1069}
1070
1071/*
1072 * ecm_state_char_device_write()
1073 */
1074static ssize_t ecm_state_char_device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
1075{
1076 return -EINVAL;
1077}
1078
1079/*
1080 * File operations used in the char device
1081 * NOTE: The char device is a simple file that allows us to dump our connection tracking state
1082 */
1083static struct file_operations ecm_state_fops = {
1084 .read = ecm_state_char_device_read,
1085 .write = ecm_state_char_device_write,
1086 .open = ecm_state_char_device_open,
1087 .release = ecm_state_char_device_release
1088};
1089
1090/*
1091 * ecm_state_init()
1092 */
1093int ecm_state_init(void)
1094{
1095 int result;
1096 int attr_index;
1097 DEBUG_INFO("ECM State init\n");
1098
1099 /*
1100 * Initialise our global lock
1101 */
1102 spin_lock_init(&ecm_state_lock);
1103
1104 /*
1105 * Register system device subsystem
1106 */
1107 result = subsys_system_register(&ecm_state_subsys, NULL);
1108 if (result) {
1109 DEBUG_ERROR("Failed to register subsystem %d\n", result);
1110 return result;
1111 }
1112
1113 /*
1114 * Register system device that represents us
1115 */
1116 memset(&ecm_state_dev, 0, sizeof(ecm_state_dev));
1117 ecm_state_dev.id = 0;
1118 ecm_state_dev.bus = &ecm_state_subsys;
1119 ecm_state_dev.release = ecm_state_dev_release;
1120 result = device_register(&ecm_state_dev);
1121 if (result) {
1122 DEBUG_ERROR("Failed to register system device %d\n", result);
1123 goto init_cleanup_1;
1124 }
1125
1126 /*
1127 * Create files, one for each parameter supported
1128 */
1129 for (attr_index = 0; attr_index < ARRAY_SIZE(ecm_state_attrs); attr_index++) {
1130 result = device_create_file(&ecm_state_dev, ecm_state_attrs[attr_index]);
1131 if (result) {
1132 DEBUG_ERROR("Failed to create attribute file %d\n", result);
1133 goto init_cleanup_2;
1134 }
1135 }
1136
1137 /*
1138 * Register a char device that we will use to provide a dump of our state
1139 */
1140 result = register_chrdev(0, ecm_state_subsys.name, &ecm_state_fops);
1141 if (result < 0) {
1142 DEBUG_ERROR("Failed to register chrdev %d\n", result);
1143 goto init_cleanup_2;
1144 }
1145 ecm_state_dev_major_id = result;
1146 DEBUG_TRACE("registered chr dev major id assigned %d\n", ecm_state_dev_major_id);
1147
1148 return 0;
1149
1150init_cleanup_2:
1151 /*
1152 * Unwind the attributes we have created so far
1153 */
1154 while (--attr_index >= 0) {
1155 device_remove_file(&ecm_state_dev, ecm_state_attrs[attr_index]);
1156 }
1157 device_unregister(&ecm_state_dev);
1158init_cleanup_1:
1159 bus_unregister(&ecm_state_subsys);
1160
1161 return result;
1162}
1163EXPORT_SYMBOL(ecm_state_init);
1164
1165/*
1166 * ecm_state_exit()
1167 */
1168void ecm_state_exit(void)
1169{
1170 int attr_index;
1171
1172 DEBUG_INFO("ECM State exit\n");
1173
1174 unregister_chrdev(ecm_state_dev_major_id, ecm_state_subsys.name);
1175
1176 for (attr_index = 0; attr_index < ARRAY_SIZE(ecm_state_attrs); attr_index++) {
1177 device_remove_file(&ecm_state_dev, ecm_state_attrs[attr_index]);
1178 }
1179
1180 device_unregister(&ecm_state_dev);
1181 bus_unregister(&ecm_state_subsys);
1182}
1183EXPORT_SYMBOL(ecm_state_exit);
1184