1/*
2 **************************************************************************
3 * Copyright (c) 2014-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/tcp.h>
21#include <linux/module.h>
22#include <linux/skbuff.h>
23#include <linux/icmp.h>
24#include <linux/debugfs.h>
25#include <linux/kthread.h>
26#include <linux/pkt_sched.h>
27#include <linux/string.h>
28#include <net/route.h>
29#include <net/ip.h>
30#include <net/tcp.h>
31#include <asm/unaligned.h>
32#include <asm/uaccess.h>	/* for put_user */
33#include <net/ipv6.h>
34#include <linux/inet.h>
35#include <linux/in.h>
36#include <linux/udp.h>
37#include <linux/tcp.h>
38
39#include <linux/netfilter_ipv4.h>
40#include <linux/netfilter_bridge.h>
41#include <net/netfilter/nf_conntrack.h>
42#include <net/netfilter/nf_conntrack_helper.h>
43#include <net/netfilter/nf_conntrack_l4proto.h>
44#include <net/netfilter/nf_conntrack_l3proto.h>
45#include <net/netfilter/nf_conntrack_core.h>
46#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
47#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
48#include <linux/netfilter/xt_dscp.h>
49#include <net/netfilter/nf_conntrack_dscpremark_ext.h>
50
51/*
52 * Debug output levels
53 * 0 = OFF
54 * 1 = ASSERTS / ERRORS
55 * 2 = 1 + WARN
56 * 3 = 2 + INFO
57 * 4 = 3 + TRACE
58 */
59#define DEBUG_LEVEL ECM_CLASSIFIER_DSCP_DEBUG_LEVEL
60
61#include "ecm_types.h"
62#include "ecm_db_types.h"
63#include "ecm_state.h"
64#include "ecm_tracker.h"
65#include "ecm_classifier.h"
66#include "ecm_front_end_types.h"
67#include "ecm_tracker_udp.h"
68#include "ecm_tracker_tcp.h"
69#include "ecm_db.h"
70#include "ecm_classifier_dscp.h"
71
72/*
73 * Magic numbers
74 */
75#define ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC 0xFA43
76
77/*
78 * struct ecm_classifier_dscp_instance
79 * 	State to allow tracking of dynamic qos for a connection
80 */
81struct ecm_classifier_dscp_instance {
82	struct ecm_classifier_instance base;			/* Base type */
83
84	struct ecm_classifier_dscp_instance *next;		/* Next classifier state instance (for accouting and reporting purposes) */
85	struct ecm_classifier_dscp_instance *prev;		/* Next classifier state instance (for accouting and reporting purposes) */
86
87	uint32_t ci_serial;					/* RO: Serial of the connection */
88	struct ecm_classifier_process_response process_response;/* Last process response computed */
89
90	int refs;						/* Integer to trap we never go negative */
91#if (DEBUG_LEVEL > 0)
92	uint16_t magic;
93#endif
94};
95
96/*
97 * Operational control
98 */
99static bool ecm_classifier_dscp_enabled = true;			/* Operational behaviour */
100
101/*
102 * Management thread control
103 */
104static bool ecm_classifier_dscp_terminate_pending = false;	/* True when the user wants us to terminate */
105
106/*
107 * Debugfs dentry object.
108 */
109static struct dentry *ecm_classifier_dscp_dentry;
110
111/*
112 * Locking of the classifier structures
113 */
114static DEFINE_SPINLOCK(ecm_classifier_dscp_lock);			/* Protect SMP access. */
115
116/*
117 * List of our classifier instances
118 */
119static struct ecm_classifier_dscp_instance *ecm_classifier_dscp_instances = NULL;
120								/* list of all active instances */
121static int ecm_classifier_dscp_count = 0;			/* Tracks number of instances allocated */
122
123/*
124 * ecm_classifier_dscp_ref()
125 *	Ref
126 */
127static void ecm_classifier_dscp_ref(struct ecm_classifier_instance *ci)
128{
129	struct ecm_classifier_dscp_instance *cdscpi;
130	cdscpi = (struct ecm_classifier_dscp_instance *)ci;
131
132	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi);
133	spin_lock_bh(&ecm_classifier_dscp_lock);
134	cdscpi->refs++;
135	DEBUG_TRACE("%p: cdscpi ref %d\n", cdscpi, cdscpi->refs);
136	DEBUG_ASSERT(cdscpi->refs > 0, "%p: ref wrap\n", cdscpi);
137	spin_unlock_bh(&ecm_classifier_dscp_lock);
138}
139
140/*
141 * ecm_classifier_dscp_deref()
142 *	Deref
143 */
144static int ecm_classifier_dscp_deref(struct ecm_classifier_instance *ci)
145{
146	struct ecm_classifier_dscp_instance *cdscpi;
147	cdscpi = (struct ecm_classifier_dscp_instance *)ci;
148
149	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi);
150	spin_lock_bh(&ecm_classifier_dscp_lock);
151	cdscpi->refs--;
152	DEBUG_ASSERT(cdscpi->refs >= 0, "%p: refs wrapped\n", cdscpi);
153	DEBUG_TRACE("%p: DSCP classifier deref %d\n", cdscpi, cdscpi->refs);
154	if (cdscpi->refs) {
155		int refs = cdscpi->refs;
156		spin_unlock_bh(&ecm_classifier_dscp_lock);
157		return refs;
158	}
159
160	/*
161	 * Object to be destroyed
162	 */
163	ecm_classifier_dscp_count--;
164	DEBUG_ASSERT(ecm_classifier_dscp_count >= 0, "%p: ecm_classifier_dscp_count wrap\n", cdscpi);
165
166	/*
167	 * UnLink the instance from our list
168	 */
169	if (cdscpi->next) {
170		cdscpi->next->prev = cdscpi->prev;
171	}
172	if (cdscpi->prev) {
173		cdscpi->prev->next = cdscpi->next;
174	} else {
175		DEBUG_ASSERT(ecm_classifier_dscp_instances == cdscpi, "%p: list bad %p\n", cdscpi, ecm_classifier_dscp_instances);
176		ecm_classifier_dscp_instances = cdscpi->next;
177	}
178
179	spin_unlock_bh(&ecm_classifier_dscp_lock);
180
181	/*
182	 * Final
183	 */
184	DEBUG_INFO("%p: Final DSCP classifier instance\n", cdscpi);
185	kfree(cdscpi);
186
187	return 0;
188}
189
190/*
191 * ecm_classifier_dscp_process()
192 *	Process new data for connection
193 */
194static void ecm_classifier_dscp_process(struct ecm_classifier_instance *aci, ecm_tracker_sender_type_t sender,
195						struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb,
196						struct ecm_classifier_process_response *process_response)
197{
198	struct ecm_classifier_dscp_instance *cdscpi;
199	ecm_classifier_relevence_t relevance;
200	struct ecm_db_connection_instance *ci = NULL;
201	struct ecm_front_end_connection_instance *feci;
202	ecm_front_end_acceleration_mode_t accel_mode;
203	int protocol;
204	uint32_t became_relevant = 0;
205	struct nf_conn *ct;
206	enum ip_conntrack_info ctinfo;
207	struct nf_ct_dscpremark_ext *dscpcte;
208	uint32_t flow_qos_tag;
209	uint32_t return_qos_tag;
210	uint8_t flow_dscp;
211	uint8_t return_dscp;
212	bool dscp_marked = false;
213
214	cdscpi = (struct ecm_classifier_dscp_instance *)aci;
215	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi);
216
217	/*
218	 * Are we yet to decide if this instance is relevant to the connection?
219	 */
220	spin_lock_bh(&ecm_classifier_dscp_lock);
221	relevance = cdscpi->process_response.relevance;
222
223	/*
224	 * Are we relevant?
225	 */
226	if (relevance == ECM_CLASSIFIER_RELEVANCE_NO) {
227		/*
228		 * Lock still held
229		 */
230		goto dscp_classifier_out;
231	}
232
233	/*
234	 * Yes or maybe relevant.
235	 *
236	 * Need to decide our relevance to this connection.
237	 * We are only relevent to a connection iff:
238	 * 1. We are enabled.
239	 * 2. Connection can be accelerated.
240	 * 3. Connection has a ct, ct has a dscp remark extension and the rule is validated.
241	 * Any other condition and we are not and will stop analysing this connection.
242	 */
243	if (!ecm_classifier_dscp_enabled) {
244		/*
245		 * Lock still held
246		 */
247		cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO;
248		goto dscp_classifier_out;
249	}
250	spin_unlock_bh(&ecm_classifier_dscp_lock);
251
252	/*
253	 * Can we accelerate?
254	 */
255	ci = ecm_db_connection_serial_find_and_ref(cdscpi->ci_serial);
256	if (!ci) {
257		DEBUG_TRACE("%p: No ci found for %u\n", cdscpi, cdscpi->ci_serial);
258		spin_lock_bh(&ecm_classifier_dscp_lock);
259		cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO;
260		goto dscp_classifier_out;
261	}
262	feci = ecm_db_connection_front_end_get_and_ref(ci);
263	accel_mode = feci->accel_state_get(feci);
264	feci->deref(feci);
265	protocol = ecm_db_connection_protocol_get(ci);
266	ecm_db_connection_deref(ci);
267	if (ECM_FRONT_END_ACCELERATION_NOT_POSSIBLE(accel_mode)) {
268		spin_lock_bh(&ecm_classifier_dscp_lock);
269		cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO;
270		goto dscp_classifier_out;
271	}
272
273	/*
274	 * Is there a valid conntrack?
275	 */
276	ct = nf_ct_get(skb, &ctinfo);
277	if (!ct) {
278		spin_lock_bh(&ecm_classifier_dscp_lock);
279		cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO;
280		goto dscp_classifier_out;
281	}
282
283	/*
284	 * Is there a DSCPREMARK extension?
285	 */
286	spin_lock_bh(&ct->lock);
287	dscpcte = nf_ct_dscpremark_ext_find(ct);
288	if (!dscpcte) {
289		spin_unlock_bh(&ct->lock);
290		spin_lock_bh(&ecm_classifier_dscp_lock);
291		cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO;
292		goto dscp_classifier_out;
293	}
294
295	/*
296	 * Was a DSCP rule enabled for the flow using the iptables 'DSCP'
297	 * target?
298	 */
299	if (nf_conntrack_dscpremark_ext_get_dscp_rule_validity(ct)
300				== NF_CT_DSCPREMARK_EXT_RULE_VALID) {
301		dscp_marked = true;
302	}
303
304	/*
305	 * Extract the priority and DSCP from skb and store into ct extension
306	 * for each direction.
307	 *
308	 * For TCP flows, we would have the values for both the directions by
309	 * the time the connection is established. For UDP flows, we copy
310	 * over the values from one direction to another if we find the
311	 * values for the other direction not set, which would be due to one
312	 * of the following.
313	 * a. We might not have seen a packet in the opposite direction
314	 * b. There were no explicitly configured priority/DSCP for the opposite
315	 *    direction.
316	 *
317	 */
318	if (sender == ECM_TRACKER_SENDER_TYPE_SRC) {
319		/*
320		 * Record latest flow
321		 */
322		flow_qos_tag = skb->priority;
323		dscpcte->flow_priority = flow_qos_tag;
324		flow_dscp = ip_hdr->ds >> XT_DSCP_SHIFT;	/* NOTE: XT_DSCP_SHIFT is okay for V4 and V6 */
325		dscpcte->flow_dscp = flow_dscp;
326
327		/*
328		 * Get the other side ready to return our PR
329		 */
330		if (protocol == IPPROTO_TCP) {
331			return_qos_tag = dscpcte->reply_priority;
332			return_dscp = dscpcte->reply_dscp;
333		} else {
334			/*
335			 * Copy over the flow direction QoS
336			 * and DSCP if the reply direction
337			 * values are not set.
338			 */
339			if (dscpcte->reply_priority == 0) {
340				return_qos_tag = flow_qos_tag;
341			} else {
342				return_qos_tag = dscpcte->reply_priority;
343			}
344
345			if (dscpcte->reply_dscp == 0) {
346				return_dscp = flow_dscp;
347			} else {
348				return_dscp = dscpcte->reply_dscp;
349			}
350		}
351		DEBUG_TRACE("Flow DSCP: %x Flow priority: %d, Return DSCP: %x Return priority: %d\n",
352				dscpcte->flow_dscp, dscpcte->flow_priority, return_dscp, return_qos_tag);
353	} else {
354		/*
355		 * Record latest return
356		 */
357		return_qos_tag = skb->priority;
358		dscpcte->reply_priority = return_qos_tag;
359		return_dscp = ip_hdr->ds >> XT_DSCP_SHIFT;	/* NOTE: XT_DSCP_SHIFT is okay for V4 and V6 */
360		dscpcte->reply_dscp = return_dscp;
361
362		/*
363		 * Get the other side ready to return our PR
364		 */
365		if (protocol == IPPROTO_TCP) {
366			flow_qos_tag = dscpcte->flow_priority;
367			flow_dscp = dscpcte->flow_dscp;
368		} else {
369			/*
370			 * Copy over the return direction QoS
371			 * and DSCP if the flow direction
372			 * values are not set.
373			 */
374			if (dscpcte->flow_priority == 0) {
375				flow_qos_tag = return_qos_tag;
376			} else {
377				flow_qos_tag = dscpcte->flow_priority;
378			}
379
380			if (dscpcte->flow_dscp == 0) {
381				flow_dscp = return_dscp;
382			} else {
383				flow_dscp = dscpcte->flow_dscp;
384			}
385		}
386		DEBUG_TRACE("Return DSCP: %x Return priority: %d, Flow DSCP: %x Flow priority: %d\n",
387				dscpcte->reply_dscp, dscpcte->reply_priority, flow_dscp, flow_qos_tag);
388	}
389	spin_unlock_bh(&ct->lock);
390
391	/*
392	 * We are relevant to the connection
393	 */
394	became_relevant = ecm_db_time_get();
395
396	spin_lock_bh(&ecm_classifier_dscp_lock);
397	cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
398	cdscpi->process_response.became_relevant = became_relevant;
399
400	cdscpi->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_QOS_TAG;
401	cdscpi->process_response.flow_qos_tag = flow_qos_tag;
402	cdscpi->process_response.return_qos_tag = return_qos_tag;
403
404	/*
405	 * Check if we need to set DSCP
406	 */
407	if (dscp_marked) {
408		cdscpi->process_response.flow_dscp = flow_dscp;
409		cdscpi->process_response.return_dscp = return_dscp;
410		cdscpi->process_response.process_actions |= ECM_CLASSIFIER_PROCESS_ACTION_DSCP;
411	}
412
413dscp_classifier_out:
414
415	/*
416	 * Return our process response
417	 */
418	*process_response = cdscpi->process_response;
419	spin_unlock_bh(&ecm_classifier_dscp_lock);
420}
421
422/*
423 * ecm_classifier_dscp_sync_to_v4()
424 *	Front end is pushing accel engine state to us
425 */
426static void ecm_classifier_dscp_sync_to_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
427{
428	struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused));
429
430	cdscpi = (struct ecm_classifier_dscp_instance *)aci;
431	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi);
432}
433
434/*
435 * ecm_classifier_dscp_sync_from_v4()
436 *	Front end is retrieving accel engine state from us
437 */
438static void ecm_classifier_dscp_sync_from_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc)
439{
440	struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused));
441
442	cdscpi = (struct ecm_classifier_dscp_instance *)aci;
443	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi);
444}
445
446/*
447 * ecm_classifier_dscp_sync_to_v6()
448 *	Front end is pushing accel engine state to us
449 */
450static void ecm_classifier_dscp_sync_to_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
451{
452	struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused));
453
454	cdscpi = (struct ecm_classifier_dscp_instance *)aci;
455	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi);
456}
457
458/*
459 * ecm_classifier_dscp_sync_from_v6()
460 *	Front end is retrieving accel engine state from us
461 */
462static void ecm_classifier_dscp_sync_from_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc)
463{
464	struct ecm_classifier_dscp_instance *cdscpi __attribute__((unused));
465
466	cdscpi = (struct ecm_classifier_dscp_instance *)aci;
467	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi);
468}
469
470/*
471 * ecm_classifier_dscp_type_get()
472 *	Get type of classifier this is
473 */
474static ecm_classifier_type_t ecm_classifier_dscp_type_get(struct ecm_classifier_instance *ci)
475{
476	struct ecm_classifier_dscp_instance *cdscpi;
477	cdscpi = (struct ecm_classifier_dscp_instance *)ci;
478
479	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi);
480	return ECM_CLASSIFIER_TYPE_DSCP;
481}
482
483/*
484 * ecm_classifier_dscp_last_process_response_get()
485 *	Get result code returned by the last process call
486 */
487static void ecm_classifier_dscp_last_process_response_get(struct ecm_classifier_instance *ci,
488							struct ecm_classifier_process_response *process_response)
489{
490	struct ecm_classifier_dscp_instance *cdscpi;
491
492	cdscpi = (struct ecm_classifier_dscp_instance *)ci;
493	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi);
494
495	spin_lock_bh(&ecm_classifier_dscp_lock);
496	*process_response = cdscpi->process_response;
497	spin_unlock_bh(&ecm_classifier_dscp_lock);
498}
499
500/*
501 * ecm_classifier_dscp_reclassify_allowed()
502 *	Indicate if reclassify is allowed
503 */
504static bool ecm_classifier_dscp_reclassify_allowed(struct ecm_classifier_instance *ci)
505{
506	struct ecm_classifier_dscp_instance *cdscpi;
507	cdscpi = (struct ecm_classifier_dscp_instance *)ci;
508	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi);
509
510	return true;
511}
512
513/*
514 * ecm_classifier_dscp_reclassify()
515 *	Reclassify
516 */
517static void ecm_classifier_dscp_reclassify(struct ecm_classifier_instance *ci)
518{
519	struct ecm_classifier_dscp_instance *cdscpi;
520	cdscpi = (struct ecm_classifier_dscp_instance *)ci;
521	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed\n", cdscpi);
522
523	/*
524	 * Revert back to MAYBE relevant - we will evaluate when we get the next process() call.
525	 */
526	spin_lock_bh(&ecm_classifier_dscp_lock);
527	cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_MAYBE;
528	spin_unlock_bh(&ecm_classifier_dscp_lock);
529}
530
531#ifdef ECM_STATE_OUTPUT_ENABLE
532/*
533 * ecm_classifier_dscp_state_get()
534 *	Return state
535 */
536static int ecm_classifier_dscp_state_get(struct ecm_classifier_instance *ci, struct ecm_state_file_instance *sfi)
537{
538	int result;
539	struct ecm_classifier_dscp_instance *cdscpi;
540	struct ecm_classifier_process_response process_response;
541
542	cdscpi = (struct ecm_classifier_dscp_instance *)ci;
543	DEBUG_CHECK_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC, "%p: magic failed", cdscpi);
544
545	if ((result = ecm_state_prefix_add(sfi, "dscp"))) {
546		return result;
547	}
548
549	spin_lock_bh(&ecm_classifier_dscp_lock);
550	process_response = cdscpi->process_response;
551	spin_unlock_bh(&ecm_classifier_dscp_lock);
552
553	/*
554	 * Output our last process response
555	 */
556	if ((result = ecm_classifier_process_response_state_get(sfi, &process_response))) {
557		return result;
558	}
559
560	return ecm_state_prefix_remove(sfi);
561}
562#endif
563
564/*
565 * ecm_classifier_dscp_instance_alloc()
566 *	Allocate an instance of the DSCP classifier
567 */
568struct ecm_classifier_dscp_instance *ecm_classifier_dscp_instance_alloc(struct ecm_db_connection_instance *ci)
569{
570	struct ecm_classifier_dscp_instance *cdscpi;
571
572	/*
573	 * Allocate the instance
574	 */
575	cdscpi = (struct ecm_classifier_dscp_instance *)kzalloc(sizeof(struct ecm_classifier_dscp_instance), GFP_ATOMIC | __GFP_NOWARN);
576	if (!cdscpi) {
577		DEBUG_WARN("Failed to allocate DSCP instance\n");
578		return NULL;
579	}
580
581	DEBUG_SET_MAGIC(cdscpi, ECM_CLASSIFIER_DSCP_INSTANCE_MAGIC);
582	cdscpi->refs = 1;
583	cdscpi->base.process = ecm_classifier_dscp_process;
584	cdscpi->base.sync_from_v4 = ecm_classifier_dscp_sync_from_v4;
585	cdscpi->base.sync_to_v4 = ecm_classifier_dscp_sync_to_v4;
586	cdscpi->base.sync_from_v6 = ecm_classifier_dscp_sync_from_v6;
587	cdscpi->base.sync_to_v6 = ecm_classifier_dscp_sync_to_v6;
588	cdscpi->base.type_get = ecm_classifier_dscp_type_get;
589	cdscpi->base.last_process_response_get = ecm_classifier_dscp_last_process_response_get;
590	cdscpi->base.reclassify_allowed = ecm_classifier_dscp_reclassify_allowed;
591	cdscpi->base.reclassify = ecm_classifier_dscp_reclassify;
592#ifdef ECM_STATE_OUTPUT_ENABLE
593	cdscpi->base.state_get = ecm_classifier_dscp_state_get;
594#endif
595	cdscpi->base.ref = ecm_classifier_dscp_ref;
596	cdscpi->base.deref = ecm_classifier_dscp_deref;
597	cdscpi->ci_serial = ecm_db_connection_serial_get(ci);
598	cdscpi->process_response.process_actions = 0;
599	cdscpi->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_MAYBE;
600
601	spin_lock_bh(&ecm_classifier_dscp_lock);
602
603	/*
604	 * Final check if we are pending termination
605	 */
606	if (ecm_classifier_dscp_terminate_pending) {
607		spin_unlock_bh(&ecm_classifier_dscp_lock);
608		DEBUG_INFO("%p: Terminating\n", ci);
609		kfree(cdscpi);
610		return NULL;
611	}
612
613	/*
614	 * Link the new instance into our list at the head
615	 */
616	cdscpi->next = ecm_classifier_dscp_instances;
617	if (ecm_classifier_dscp_instances) {
618		ecm_classifier_dscp_instances->prev = cdscpi;
619	}
620	ecm_classifier_dscp_instances = cdscpi;
621
622	/*
623	 * Increment stats
624	 */
625	ecm_classifier_dscp_count++;
626	DEBUG_ASSERT(ecm_classifier_dscp_count > 0, "%p: ecm_classifier_dscp_count wrap\n", cdscpi);
627	spin_unlock_bh(&ecm_classifier_dscp_lock);
628
629	DEBUG_INFO("DSCP instance alloc: %p\n", cdscpi);
630	return cdscpi;
631}
632EXPORT_SYMBOL(ecm_classifier_dscp_instance_alloc);
633
634/*
635 * ecm_classifier_dscp_init()
636 */
637int ecm_classifier_dscp_init(struct dentry *dentry)
638{
639	DEBUG_INFO("DSCP classifier Module init\n");
640
641	ecm_classifier_dscp_dentry = debugfs_create_dir("ecm_classifier_dscp", dentry);
642	if (!ecm_classifier_dscp_dentry) {
643		DEBUG_ERROR("Failed to create ecm dscp directory in debugfs\n");
644		return -1;
645	}
646
647	if (!debugfs_create_bool("enabled", S_IRUGO | S_IWUSR, ecm_classifier_dscp_dentry,
648					(u32 *)&ecm_classifier_dscp_enabled)) {
649		DEBUG_ERROR("Failed to create dscp enabled file in debugfs\n");
650		debugfs_remove_recursive(ecm_classifier_dscp_dentry);
651		return -1;
652	}
653
654	return 0;
655}
656EXPORT_SYMBOL(ecm_classifier_dscp_init);
657
658/*
659 * ecm_classifier_dscp_exit()
660 */
661void ecm_classifier_dscp_exit(void)
662{
663	DEBUG_INFO("DSCP classifier Module exit\n");
664
665	spin_lock_bh(&ecm_classifier_dscp_lock);
666	ecm_classifier_dscp_terminate_pending = true;
667	spin_unlock_bh(&ecm_classifier_dscp_lock);
668
669	/*
670	 * Remove the debugfs files recursively.
671	 */
672	if (ecm_classifier_dscp_dentry) {
673		debugfs_remove_recursive(ecm_classifier_dscp_dentry);
674	}
675}
676EXPORT_SYMBOL(ecm_classifier_dscp_exit);
677