blob: 004a8e5f9d9e50e3a80f5692ec7c9d4b38d5273d [file] [log] [blame]
Nicolas Costaf46c33b2014-05-15 10:02:00 -05001/*
2 **************************************************************************
Gareth Williamsd5618a82015-05-20 11:13:32 +01003 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
Nicolas Costaf46c33b2014-05-15 10:02:00 -05004 * 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 */
Murat Sezgin3ab259d2015-06-11 14:15:35 -070016#include <linux/version.h>
Nicolas Costaf46c33b2014-05-15 10:02:00 -050017#include <linux/module.h>
Murat Sezginf2b94532014-12-05 14:53:53 -080018#include <linux/of.h>
Murat Sezgin908ecb32015-05-10 20:54:36 -070019#include <linux/debugfs.h>
Murat Sezgin3ab259d2015-06-11 14:15:35 -070020#include <linux/inet.h>
21#include <linux/etherdevice.h>
22#include <net/netfilter/nf_conntrack.h>
23#include <net/ip.h>
24#include <net/ipv6.h>
25/*
26 * Debug output levels
27 * 0 = OFF
28 * 1 = ASSERTS / ERRORS
29 * 2 = 1 + WARN
30 * 3 = 2 + INFO
31 * 4 = 3 + TRACE
32 */
33#define DEBUG_LEVEL ECM_INIT_DEBUG_LEVEL
Nicolas Costaf46c33b2014-05-15 10:02:00 -050034
Murat Sezgin3ab259d2015-06-11 14:15:35 -070035#include "ecm_types.h"
36#include "ecm_db_types.h"
37#include "ecm_state.h"
38#include "ecm_tracker.h"
39#include "ecm_classifier.h"
40#include "ecm_front_end_types.h"
Tushar Mathurd38cacd2015-07-28 12:19:10 +053041#include "ecm_db.h"
Murat Sezgin8d916a12015-03-18 15:56:50 -070042#include "ecm_front_end_ipv4.h"
Murat Sezgin3ab259d2015-06-11 14:15:35 -070043#ifdef ECM_IPV6_ENABLE
44#include "ecm_front_end_ipv6.h"
45#endif
Murat Sezgin5f138492015-06-11 15:18:27 -070046#include "ecm_front_end_common.h"
Murat Sezgin8d916a12015-03-18 15:56:50 -070047
Murat Sezgin908ecb32015-05-10 20:54:36 -070048struct dentry *ecm_dentry; /* Dentry object for top level ecm debugfs directory */
Nicolas Costaf46c33b2014-05-15 10:02:00 -050049
Murat Sezgin908ecb32015-05-10 20:54:36 -070050extern int ecm_db_init(struct dentry *dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050051extern void ecm_db_connection_defunct_all(void);
52extern void ecm_db_exit(void);
53
Murat Sezgin908ecb32015-05-10 20:54:36 -070054extern int ecm_classifier_default_init(struct dentry *dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050055extern void ecm_classifier_default_exit(void);
56
Murat Sezginaaaafb42014-11-24 17:02:05 -080057#ifdef ECM_CLASSIFIER_NL_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -070058extern int ecm_classifier_nl_rules_init(struct dentry *dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050059extern void ecm_classifier_nl_rules_exit(void);
Murat Sezginaaaafb42014-11-24 17:02:05 -080060#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -050061
Hai Shalom81f4e202014-06-04 09:30:27 -070062#ifdef ECM_CLASSIFIER_HYFI_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -070063extern int ecm_classifier_hyfi_rules_init(struct dentry *dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050064extern void ecm_classifier_hyfi_rules_exit(void);
Hai Shalom81f4e202014-06-04 09:30:27 -070065#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -050066
67extern int ecm_interface_init(void);
Nicolas Costaf46c33b2014-05-15 10:02:00 -050068extern void ecm_interface_exit(void);
69
Murat Sezginb3731e82014-11-26 12:20:59 -080070#ifdef ECM_CLASSIFIER_DSCP_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -070071extern int ecm_classifier_dscp_init(struct dentry *dentry);
Gareth Williams4a02c9b2014-10-10 14:50:33 +010072extern void ecm_classifier_dscp_exit(void);
Murat Sezginb3731e82014-11-26 12:20:59 -080073#endif
Gareth Williams4a02c9b2014-10-10 14:50:33 +010074
Gareth Williamsf98d4192015-03-11 16:55:41 +000075#ifdef ECM_STATE_OUTPUT_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -070076extern int ecm_state_init(struct dentry *dentry);
Gareth Williamsf98d4192015-03-11 16:55:41 +000077extern void ecm_state_exit(void);
78#endif
79
Gareth Williamsdcda9b92015-05-13 10:08:15 +010080#ifdef ECM_CLASSIFIER_PCC_ENABLE
81extern int ecm_classifier_pcc_init(struct dentry *dentry);
82extern void ecm_classifier_pcc_exit(void);
83#endif
84
Nicolas Costaf46c33b2014-05-15 10:02:00 -050085/*
86 * ecm_init()
87 */
88static int __init ecm_init(void)
89{
90 int ret;
Murat Sezginf2b94532014-12-05 14:53:53 -080091
92 /*
93 * Run only for IPQ8064 platform, if the device tree is used.
94 */
95#ifdef CONFIG_OF
96 if (!of_machine_is_compatible("qcom,ipq8064")) {
Murat Sezgin3ab259d2015-06-11 14:15:35 -070097 DEBUG_WARN("Not compatible platform for ECM\n");
Murat Sezginf2b94532014-12-05 14:53:53 -080098 return 0;
99 }
100#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500101 printk(KERN_INFO "ECM init\n");
102
Murat Sezgin908ecb32015-05-10 20:54:36 -0700103 ecm_dentry = debugfs_create_dir("ecm", NULL);
104 if (!ecm_dentry) {
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700105 DEBUG_ERROR("Failed to create ecm directory in debugfs\n");
Murat Sezgin908ecb32015-05-10 20:54:36 -0700106 return -1;
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500107 }
108
Murat Sezgin908ecb32015-05-10 20:54:36 -0700109 ret = ecm_db_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500110 if (0 != ret) {
111 goto err_db;
112 }
113
Murat Sezgin908ecb32015-05-10 20:54:36 -0700114 ret = ecm_classifier_default_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500115 if (0 != ret) {
116 goto err_cls_default;
117 }
118
Murat Sezginaaaafb42014-11-24 17:02:05 -0800119#ifdef ECM_CLASSIFIER_NL_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -0700120 ret = ecm_classifier_nl_rules_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500121 if (0 != ret) {
122 goto err_cls_nl;
123 }
Murat Sezginaaaafb42014-11-24 17:02:05 -0800124#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500125
Hai Shalom81f4e202014-06-04 09:30:27 -0700126#ifdef ECM_CLASSIFIER_HYFI_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -0700127 ret = ecm_classifier_hyfi_rules_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500128 if (0 != ret) {
129 goto err_cls_hyfi;
130 }
Hai Shalom81f4e202014-06-04 09:30:27 -0700131#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500132
Murat Sezginb3731e82014-11-26 12:20:59 -0800133#ifdef ECM_CLASSIFIER_DSCP_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -0700134 ret = ecm_classifier_dscp_init(ecm_dentry);
Gareth Williams4a02c9b2014-10-10 14:50:33 +0100135 if (0 != ret) {
136 goto err_cls_dscp;
137 }
Murat Sezginb3731e82014-11-26 12:20:59 -0800138#endif
Gareth Williams4a02c9b2014-10-10 14:50:33 +0100139
Gareth Williamsdcda9b92015-05-13 10:08:15 +0100140#ifdef ECM_CLASSIFIER_PCC_ENABLE
141 ret = ecm_classifier_pcc_init(ecm_dentry);
142 if (0 != ret) {
143 goto err_cls_pcc;
144 }
145#endif
146
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500147 ret = ecm_interface_init();
148 if (0 != ret) {
149 goto err_iface;
150 }
151
Murat Sezginb3731e82014-11-26 12:20:59 -0800152#ifdef ECM_INTERFACE_BOND_ENABLE
Murat Sezgin8e10a7c2015-06-11 15:49:24 -0700153 ret = ecm_front_end_bond_notifier_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500154 if (0 != ret) {
155 goto err_bond;
156 }
Murat Sezginb3731e82014-11-26 12:20:59 -0800157#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500158
Murat Sezgin908ecb32015-05-10 20:54:36 -0700159 ret = ecm_front_end_ipv4_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500160 if (0 != ret) {
161 goto err_fe_ipv4;
162 }
163
Gareth Williams8ac34292015-03-17 14:06:58 +0000164#ifdef ECM_IPV6_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -0700165 ret = ecm_front_end_ipv6_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500166 if (0 != ret) {
167 goto err_fe_ipv6;
168 }
Murat Sezgin49465a42014-11-24 15:37:48 -0800169#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500170
Murat Sezgin5f138492015-06-11 15:18:27 -0700171 ret = ecm_front_end_conntrack_notifier_init(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500172 if (0 != ret) {
173 goto err_ct;
174 }
175
Gareth Williamsf98d4192015-03-11 16:55:41 +0000176#ifdef ECM_STATE_OUTPUT_ENABLE
Murat Sezgin908ecb32015-05-10 20:54:36 -0700177 ret = ecm_state_init(ecm_dentry);
Gareth Williamsf98d4192015-03-11 16:55:41 +0000178 if (0 != ret) {
179 goto err_state;
180 }
181#endif
182
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500183 printk(KERN_INFO "ECM init complete\n");
184 return 0;
185
Gareth Williamsf98d4192015-03-11 16:55:41 +0000186#ifdef ECM_STATE_OUTPUT_ENABLE
187err_state:
Murat Sezgin5f138492015-06-11 15:18:27 -0700188 ecm_front_end_conntrack_notifier_exit();
Gareth Williamsf98d4192015-03-11 16:55:41 +0000189#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500190err_ct:
Gareth Williams8ac34292015-03-17 14:06:58 +0000191#ifdef ECM_IPV6_ENABLE
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500192 ecm_front_end_ipv6_exit();
193err_fe_ipv6:
Murat Sezgin49465a42014-11-24 15:37:48 -0800194#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500195 ecm_front_end_ipv4_exit();
196err_fe_ipv4:
Murat Sezginb3731e82014-11-26 12:20:59 -0800197#ifdef ECM_INTERFACE_BOND_ENABLE
Murat Sezgin8e10a7c2015-06-11 15:49:24 -0700198 ecm_front_end_bond_notifier_exit();
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500199err_bond:
Murat Sezginb3731e82014-11-26 12:20:59 -0800200#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500201 ecm_interface_exit();
202err_iface:
Gareth Williamsdcda9b92015-05-13 10:08:15 +0100203#ifdef ECM_CLASSIFIER_PCC_ENABLE
204 ecm_classifier_pcc_exit();
205err_cls_pcc:
206#endif
Murat Sezginb3731e82014-11-26 12:20:59 -0800207#ifdef ECM_CLASSIFIER_DSCP_ENABLE
Gareth Williams4a02c9b2014-10-10 14:50:33 +0100208 ecm_classifier_dscp_exit();
209err_cls_dscp:
Murat Sezginb3731e82014-11-26 12:20:59 -0800210#endif
Hai Shalom81f4e202014-06-04 09:30:27 -0700211#ifdef ECM_CLASSIFIER_HYFI_ENABLE
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500212 ecm_classifier_hyfi_rules_exit();
213err_cls_hyfi:
Hai Shalom81f4e202014-06-04 09:30:27 -0700214#endif
Murat Sezginaaaafb42014-11-24 17:02:05 -0800215#ifdef ECM_CLASSIFIER_NL_ENABLE
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500216 ecm_classifier_nl_rules_exit();
217err_cls_nl:
Murat Sezginaaaafb42014-11-24 17:02:05 -0800218#endif
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500219 ecm_classifier_default_exit();
220err_cls_default:
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500221 ecm_db_exit();
222err_db:
Murat Sezgin908ecb32015-05-10 20:54:36 -0700223 debugfs_remove_recursive(ecm_dentry);
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500224
225 printk(KERN_INFO "ECM init failed: %d\n", ret);
226 return ret;
227}
228
229/*
230 * ecm_exit()
231 */
232static void __exit ecm_exit(void)
233{
234 printk(KERN_INFO "ECM exit\n");
235
Murat Sezginf2b94532014-12-05 14:53:53 -0800236 /*
237 * If the platform is not IPQ8064 and device tree is enabled,
238 * this means ECM started but none of the features are used.
239 * So, just return here.
240 */
241#ifdef CONFIG_OF
242 if (!of_machine_is_compatible("qcom,ipq8064")) {
243 return;
244 }
245#endif
246
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500247 /* call stop on anything that requires a prepare-to-exit signal */
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700248 DEBUG_INFO("stop conntrack notifier\n");
Murat Sezgin5f138492015-06-11 15:18:27 -0700249 ecm_front_end_conntrack_notifier_stop(1);
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700250 DEBUG_INFO("stop front_end_ipv4\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500251 ecm_front_end_ipv4_stop(1);
Gareth Williams8ac34292015-03-17 14:06:58 +0000252#ifdef ECM_IPV6_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700253 DEBUG_INFO("stop front_end_ipv6\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500254 ecm_front_end_ipv6_stop(1);
Murat Sezgin49465a42014-11-24 15:37:48 -0800255#endif
Murat Sezginb3731e82014-11-26 12:20:59 -0800256#ifdef ECM_INTERFACE_BOND_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700257 DEBUG_INFO("stop bond notifier\n");
Murat Sezgin8e10a7c2015-06-11 15:49:24 -0700258 ecm_front_end_bond_notifier_stop(1);
Murat Sezginb3731e82014-11-26 12:20:59 -0800259#endif
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700260 DEBUG_INFO("defunct all db connections\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500261 ecm_db_connection_defunct_all();
262
263 /* now call exit on each module */
Gareth Williamsf98d4192015-03-11 16:55:41 +0000264#ifdef ECM_STATE_OUTPUT_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700265 DEBUG_INFO("stop state\n");
Gareth Williamsf98d4192015-03-11 16:55:41 +0000266 ecm_state_exit();
267#endif
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700268 DEBUG_INFO("exit conntrack notifier\n");
Murat Sezgin5f138492015-06-11 15:18:27 -0700269 ecm_front_end_conntrack_notifier_exit();
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700270 DEBUG_INFO("exit front_end_ipv4\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500271 ecm_front_end_ipv4_exit();
Gareth Williams8ac34292015-03-17 14:06:58 +0000272#ifdef ECM_IPV6_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700273 DEBUG_INFO("exit front_end_ipv6\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500274 ecm_front_end_ipv6_exit();
Murat Sezgin49465a42014-11-24 15:37:48 -0800275#endif
Murat Sezginb3731e82014-11-26 12:20:59 -0800276#ifdef ECM_INTERFACE_BOND_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700277 DEBUG_INFO("exit bond notifier\n");
Murat Sezgin8e10a7c2015-06-11 15:49:24 -0700278 ecm_front_end_bond_notifier_exit();
Murat Sezginb3731e82014-11-26 12:20:59 -0800279#endif
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700280 DEBUG_INFO("exit interface\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500281 ecm_interface_exit();
Gareth Williamsdcda9b92015-05-13 10:08:15 +0100282
283#ifdef ECM_CLASSIFIER_PCC_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700284 DEBUG_INFO("exit pcc classifier\n");
Gareth Williamsdcda9b92015-05-13 10:08:15 +0100285 ecm_classifier_pcc_exit();
286#endif
Murat Sezginb3731e82014-11-26 12:20:59 -0800287#ifdef ECM_CLASSIFIER_DSCP_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700288 DEBUG_INFO("exit dscp classifier\n");
Gareth Williams4a02c9b2014-10-10 14:50:33 +0100289 ecm_classifier_dscp_exit();
Murat Sezginb3731e82014-11-26 12:20:59 -0800290#endif
Hai Shalom81f4e202014-06-04 09:30:27 -0700291#ifdef ECM_CLASSIFIER_HYFI_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700292 DEBUG_INFO("exit hyfi classifier\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500293 ecm_classifier_hyfi_rules_exit();
Hai Shalom81f4e202014-06-04 09:30:27 -0700294#endif
Murat Sezginaaaafb42014-11-24 17:02:05 -0800295#ifdef ECM_CLASSIFIER_NL_ENABLE
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700296 DEBUG_INFO("exit nl classifier\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500297 ecm_classifier_nl_rules_exit();
Murat Sezginaaaafb42014-11-24 17:02:05 -0800298#endif
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700299 DEBUG_INFO("exit default classifier\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500300 ecm_classifier_default_exit();
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700301 DEBUG_INFO("exit db\n");
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500302 ecm_db_exit();
Murat Sezgin908ecb32015-05-10 20:54:36 -0700303
304 if (ecm_dentry != NULL) {
Murat Sezgin3ab259d2015-06-11 14:15:35 -0700305 DEBUG_INFO("remove ecm debugfs\n");
Murat Sezgin908ecb32015-05-10 20:54:36 -0700306 debugfs_remove_recursive(ecm_dentry);
307 }
Nicolas Costaf46c33b2014-05-15 10:02:00 -0500308
309 printk(KERN_INFO "ECM exit complete\n");
310}
311
312module_init(ecm_init)
313module_exit(ecm_exit)
314
315MODULE_AUTHOR("Qualcomm Atheros, Inc.");
316MODULE_DESCRIPTION("ECM Core");
317#ifdef MODULE_LICENSE
318MODULE_LICENSE("Dual BSD/GPL");
319#endif
320