blob: 6c6fcd4b8fdd660e39227242a9c1d41c113885ae [file] [log] [blame]
Googler298baf22022-08-01 19:58:45 -07001/*
2 **************************************************************************
3 * Copyright (c) 2015, 2020-2021, 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/*
18 * Parental Controls Classifier.
19 * While not implementing parental controls feature itself.
20 * This module provides an interface for customer parental controls systems to interract with the ECM.
21 * This ensures that acceleration will not interfere with parental controls logics, especially DPI.
22 */
23
24#include <linux/version.h>
25#include <linux/types.h>
26#include <linux/ip.h>
27#include <linux/tcp.h>
28#include <linux/module.h>
29#include <linux/skbuff.h>
30#include <linux/icmp.h>
31#include <linux/debugfs.h>
32#include <linux/kthread.h>
33#include <linux/pkt_sched.h>
34#include <linux/string.h>
35#include <linux/ctype.h>
36#include <net/route.h>
37#include <net/ip.h>
38#include <net/tcp.h>
39#include <asm/unaligned.h>
40#include <asm/uaccess.h> /* for put_user */
41#include <net/ipv6.h>
42#include <linux/inet.h>
43#include <linux/in.h>
44#include <linux/udp.h>
45#include <linux/tcp.h>
46
47#include <linux/netfilter_ipv4.h>
48#include <linux/netfilter_bridge.h>
49#include <net/netfilter/nf_conntrack.h>
50#include <net/netfilter/nf_conntrack_helper.h>
51#include <net/netfilter/nf_conntrack_l4proto.h>
52#include <net/netfilter/nf_conntrack_core.h>
53#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
54#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
55
56/*
57 * Debug output levels
58 * 0 = OFF
59 * 1 = ASSERTS / ERRORS
60 * 2 = 1 + WARN
61 * 3 = 2 + INFO
62 * 4 = 3 + TRACE
63 */
64#define DEBUG_LEVEL ECM_CLASSIFIER_PCC_DEBUG_LEVEL
65
66#include "ecm_types.h"
67#include "ecm_db_types.h"
68#include "ecm_state.h"
69#include "ecm_tracker.h"
70#include "ecm_classifier.h"
71#include "ecm_front_end_types.h"
72#include "ecm_tracker_datagram.h"
73#include "ecm_tracker_udp.h"
74#include "ecm_tracker_tcp.h"
75#include "ecm_db.h"
76#include "ecm_classifier_pcc.h"
77#include "ecm_classifier_pcc_public.h"
78
79/*
80 * Magic numbers
81 */
82#define ECM_CLASSIFIER_PCC_INSTANCE_MAGIC 0x2351
83
84/*
85 * struct ecm_classifier_pcc_instance
86 * State per connection for PCC classifier
87 */
88struct ecm_classifier_pcc_instance {
89 struct ecm_classifier_instance base; /* Base type */
90
91 ecm_classifier_pcc_result_t accel_permit_state; /* Permission state for acceleration */
92 uint32_t ci_serial; /* RO: Serial of the connection */
93 long process_jiffies_last; /* Rate limiting the calls to the registrant */
94 uint32_t reg_calls_to; /* #calls to registrant */
95 uint32_t reg_calls_from; /* #calls from registrant */
96 uint32_t feature_flags; /* Feature flags */
97
98 struct ecm_classifier_process_response process_response;
99 /* Last process response computed */
100 int refs; /* Integer to trap we never go negative */
101#if (DEBUG_LEVEL > 0)
102 uint16_t magic;
103#endif
104};
105
106static DEFINE_SPINLOCK(ecm_classifier_pcc_lock); /* Concurrency control SMP access */
107static int ecm_classifier_pcc_count = 0; /* Tracks number of instances allocated */
108static struct ecm_classifier_pcc_registrant *ecm_classifier_registrant = NULL;
109 /* Singleton Parent Controls code */
110
111/*
112 * Operational control
113 */
114static bool ecm_classifier_pcc_enabled = false; /* Enable / disable state of the classifier function */
115
116/*
117 * Debugfs dentry object.
118 */
119static struct dentry *ecm_classifier_pcc_dentry;
120
121/*
122 * ecm_classifier_pcc_register()
123 * Register a new PCC module.
124 *
125 */
126int ecm_classifier_pcc_register(struct ecm_classifier_pcc_registrant *r)
127{
128 /*
129 * Hold the module of the registrant
130 */
131 if (!try_module_get(r->this_module)) {
132 return -ESHUTDOWN;
133 }
134
135 /*
136 * Hold the registrant we have been given for our purposes.
137 */
138 r->ref(r);
139
140 spin_lock_bh(&ecm_classifier_pcc_lock);
141 if (ecm_classifier_registrant) {
142 spin_unlock_bh(&ecm_classifier_pcc_lock);
143 DEBUG_WARN("Registrant already\n");
144 module_put(r->this_module);
145 r->deref(r);
146 return -EALREADY;
147 }
148 ecm_classifier_registrant = r;
149 ecm_classifier_pcc_enabled = true;
150 spin_unlock_bh(&ecm_classifier_pcc_lock);
151
152 /*
153 * Destroy all the connections
154 */
155 ecm_db_connection_defunct_all();
156 return 0;
157}
158EXPORT_SYMBOL(ecm_classifier_pcc_register);
159
160/*
161 * ecm_classifier_pcc_unregister_begin()
162 * Begin unregistration process
163 */
164void ecm_classifier_pcc_unregister_begin(struct ecm_classifier_pcc_registrant *r)
165{
166 struct ecm_classifier_pcc_registrant *reg;
167
168 spin_lock_bh(&ecm_classifier_pcc_lock);
169 reg = ecm_classifier_registrant;
170 if (!reg) {
171 spin_unlock_bh(&ecm_classifier_pcc_lock);
172 DEBUG_WARN("No Registrant\n");
173 return;
174 }
175 if (reg != r) {
176 spin_unlock_bh(&ecm_classifier_pcc_lock);
177 DEBUG_WARN("Unexpected registrant, given: %px, expecting: %px\n", r, reg);
178 return;
179 }
180
181 ecm_classifier_registrant = NULL;
182 ecm_classifier_pcc_enabled = false;
183 spin_unlock_bh(&ecm_classifier_pcc_lock);
184
185 /*
186 * Release our ref upon the registrant that we took when it was registered
187 */
188 reg->deref(reg);
189 module_put(reg->this_module);
190
191 /*
192 * Destroy all the connections
193 */
194 ecm_db_connection_defunct_all();
195}
196EXPORT_SYMBOL(ecm_classifier_pcc_unregister_begin);
197
198/*
199 * ecm_classifier_pcc_decel_v4()
200 * Decelerate connection.
201 *
202 * Big endian parameters apart from protocol
203 */
204bool ecm_classifier_pcc_decel_v4(uint8_t *src_mac, __be32 src_ip, int src_port,
205 uint8_t *dest_mac, __be32 dest_ip, int dest_port, int protocol)
206{
207 /*
208 * MAC addresses are not used to decelerate the connection, but in the future
209 * MAC based deceleration can be added to this function.
210 */
211 return ecm_db_connection_decel_v4(src_ip, src_port, dest_ip, dest_port, protocol);
212}
213EXPORT_SYMBOL(ecm_classifier_pcc_decel_v4);
214
215/*
216 * ecm_classifier_pcc_decel_v6()
217 * Decelerate connection.
218 *
219 * Big endian parameters apart from protocol
220 */
221bool ecm_classifier_pcc_decel_v6(uint8_t *src_mac, struct in6_addr *src_ip,
222 int src_port, uint8_t *dest_mac, struct in6_addr *dest_ip,
223 int dest_port, int protocol)
224{
225 /*
226 * MAC addresses are not used to decelerate the connection, but in the future
227 * MAC based deceleration can be added to this function.
228 */
229 return ecm_db_connection_decel_v6(src_ip, src_port, dest_ip, dest_port, protocol);
230}
231EXPORT_SYMBOL(ecm_classifier_pcc_decel_v6);
232
233/*
234 * ecm_classifier_pcc_permit_accel_v4()
235 * Permit acceleration.
236 *
237 * Big endian parameters apart from protocol
238 */
239void ecm_classifier_pcc_permit_accel_v4(uint8_t *src_mac, __be32 src_ip, int src_port, uint8_t *dest_mac, __be32 dest_ip, int dest_port, int protocol)
240{
241 ip_addr_t ecm_src_ip;
242 ip_addr_t ecm_dest_ip;
243 struct ecm_db_connection_instance *ci;
244 struct ecm_classifier_instance *classi;
245 struct ecm_classifier_pcc_instance *pcci;
246
247 /*
248 * Look up ECM connection from the given tuple
249 */
250 src_port = ntohs(src_port);
251 dest_port = ntohs(dest_port);
252 ECM_NIN4_ADDR_TO_IP_ADDR(ecm_src_ip, src_ip);
253 ECM_NIN4_ADDR_TO_IP_ADDR(ecm_dest_ip, dest_ip);
254
255 DEBUG_INFO("Permit Accel v4, lookup connection using \n"
256 "Protocol: %d\n"
257 "src: " ECM_IP_ADDR_DOT_FMT ":%d\n"
258 "dest: " ECM_IP_ADDR_DOT_FMT ":%d\n",
259 protocol,
260 ECM_IP_ADDR_TO_DOT(ecm_src_ip), src_port,
261 ECM_IP_ADDR_TO_DOT(ecm_dest_ip), dest_port);
262
263 ci = ecm_db_connection_find_and_ref(ecm_src_ip, ecm_dest_ip, protocol, src_port, dest_port);
264 if (!ci) {
265 DEBUG_TRACE("Not found\n");
266 return;
267 }
268
269 /*
270 * Get the PCC classifier
271 */
272 classi = ecm_db_connection_assigned_classifier_find_and_ref(ci, ECM_CLASSIFIER_TYPE_PCC);
273 if (!classi) {
274 DEBUG_TRACE("No PCC classi\n");
275 ecm_db_connection_deref(ci);
276 return;
277 }
278 pcci = (struct ecm_classifier_pcc_instance *)classi;
279 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
280
281 /*
282 * Set the permitted accel state to PERMITTED
283 * NOTE: When we next see activity on this connection it shall be accelerated (save depending on other classifiers decisions too).
284 */
285 spin_lock_bh(&ecm_classifier_pcc_lock);
286 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_PERMITTED;
287 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
288 pcci->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
289 pcci->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_ACCEL;
290 pcci->reg_calls_from++;
291 spin_unlock_bh(&ecm_classifier_pcc_lock);
292
293 classi->deref(classi);
294 ecm_db_connection_deref(ci);
295}
296EXPORT_SYMBOL(ecm_classifier_pcc_permit_accel_v4);
297
298/*
299 * ecm_classifier_pcc_permit_accel_v6()
300 * Permit acceleration
301 *
302 * Big endian parameters apart from protocol.
303 *
304 * NOTE: If IPv6 is not supported in ECM this function must still exist as a stub to avoid compilation problems for registrants.
305 */
306void ecm_classifier_pcc_permit_accel_v6(uint8_t *src_mac, struct in6_addr *src_ip, int src_port, uint8_t *dest_mac, struct in6_addr *dest_ip, int dest_port, int protocol)
307{
308#ifdef ECM_IPV6_ENABLE
309 struct in6_addr in6;
310 ip_addr_t ecm_src_ip;
311 ip_addr_t ecm_dest_ip;
312 struct ecm_db_connection_instance *ci;
313 struct ecm_classifier_instance *classi;
314 struct ecm_classifier_pcc_instance *pcci;
315
316 /*
317 * Look up ECM connection from the given tuple
318 */
319 src_port = ntohs(src_port);
320 dest_port = ntohs(dest_port);
321 in6 = *src_ip;
322 ECM_NIN6_ADDR_TO_IP_ADDR(ecm_src_ip, in6);
323 in6 = *dest_ip;
324 ECM_NIN6_ADDR_TO_IP_ADDR(ecm_dest_ip, in6);
325
326 DEBUG_INFO("Permit Accel v6, lookup connection using \n"
327 "Protocol: %d\n"
328 "src: " ECM_IP_ADDR_OCTAL_FMT ":%d\n"
329 "dest: " ECM_IP_ADDR_OCTAL_FMT ":%d\n",
330 protocol,
331 ECM_IP_ADDR_TO_OCTAL(ecm_src_ip), src_port,
332 ECM_IP_ADDR_TO_OCTAL(ecm_dest_ip), dest_port);
333
334 ci = ecm_db_connection_find_and_ref(ecm_src_ip, ecm_dest_ip, protocol, src_port, dest_port);
335 if (!ci) {
336 DEBUG_TRACE("Not found\n");
337 return;
338 }
339
340 /*
341 * Get the PCC classifier
342 */
343 classi = ecm_db_connection_assigned_classifier_find_and_ref(ci, ECM_CLASSIFIER_TYPE_PCC);
344 if (!classi) {
345 DEBUG_TRACE("No PCC classi\n");
346 ecm_db_connection_deref(ci);
347 return;
348 }
349 pcci = (struct ecm_classifier_pcc_instance *)classi;
350 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
351
352 /*
353 * Set the permitted accel state to PERMITTED
354 * NOTE: When we next see activity on this connection it shall be accelerated (save depending on other classifiers decisions too).
355 */
356 spin_lock_bh(&ecm_classifier_pcc_lock);
357 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_PERMITTED;
358 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
359 pcci->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
360 pcci->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_ACCEL;
361 pcci->reg_calls_from++;
362 spin_unlock_bh(&ecm_classifier_pcc_lock);
363
364 classi->deref(classi);
365 ecm_db_connection_deref(ci);
366#endif
367}
368EXPORT_SYMBOL(ecm_classifier_pcc_permit_accel_v6);
369
370/*
371 * ecm_classifier_pcc_deny_accel_v4()
372 * Deny acceleration
373 */
374void ecm_classifier_pcc_deny_accel_v4(uint8_t *src_mac, __be32 src_ip, int src_port, uint8_t *dest_mac, __be32 dest_ip, int dest_port, int protocol)
375{
376 ip_addr_t ecm_src_ip;
377 ip_addr_t ecm_dest_ip;
378 struct ecm_db_connection_instance *ci;
379 struct ecm_classifier_instance *classi;
380 struct ecm_classifier_pcc_instance *pcci;
381 struct ecm_front_end_connection_instance *feci;
382
383 /*
384 * Look up ECM connection from the given tuple
385 */
386 src_port = ntohs(src_port);
387 dest_port = ntohs(dest_port);
388 ECM_NIN4_ADDR_TO_IP_ADDR(ecm_src_ip, src_ip);
389 ECM_NIN4_ADDR_TO_IP_ADDR(ecm_dest_ip, dest_ip);
390
391 DEBUG_INFO("Deny Accel v4, lookup connection using \n"
392 "Protocol: %d\n"
393 "src: " ECM_IP_ADDR_DOT_FMT ":%d\n"
394 "dest: " ECM_IP_ADDR_DOT_FMT ":%d\n",
395 protocol,
396 ECM_IP_ADDR_TO_DOT(ecm_src_ip), src_port,
397 ECM_IP_ADDR_TO_DOT(ecm_dest_ip), dest_port);
398
399 ci = ecm_db_connection_find_and_ref(ecm_src_ip, ecm_dest_ip, protocol, src_port, dest_port);
400 if (!ci) {
401 DEBUG_TRACE("Not found\n");
402 return;
403 }
404
405 /*
406 * Get the PCC classifier
407 */
408 classi = ecm_db_connection_assigned_classifier_find_and_ref(ci, ECM_CLASSIFIER_TYPE_PCC);
409 if (!classi) {
410 DEBUG_TRACE("No PCC classi\n");
411 ecm_db_connection_deref(ci);
412 return;
413 }
414 pcci = (struct ecm_classifier_pcc_instance *)classi;
415 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
416
417 /*
418 * Set the permitted accel state to DENIED
419 * NOTE: When we next see activity on this connection it shall be accelerated (save depending on other classifiers decisions too).
420 */
421 spin_lock_bh(&ecm_classifier_pcc_lock);
422 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_DENIED;
423 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
424 pcci->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
425 pcci->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_NO;
426 pcci->reg_calls_from++;
427 spin_unlock_bh(&ecm_classifier_pcc_lock);
428
429 /*
430 * Get the front end and issue a deceleration
431 * If the connection is not accelerated anyway this will have no effect
432 */
433 feci = ecm_db_connection_front_end_get_and_ref(ci);
434 feci->decelerate(feci);
435 feci->deref(feci);
436
437 classi->deref(classi);
438 ecm_db_connection_deref(ci);
439}
440EXPORT_SYMBOL(ecm_classifier_pcc_deny_accel_v4);
441
442/*
443 * ecm_classifier_pcc_deny_accel_v6()
444 * Deny acceleration
445 *
446 * NOTE: If IPv6 is not supported in ECM this function must still exist as a stub to avoid compilation problems for registrants.
447 */
448void ecm_classifier_pcc_deny_accel_v6(uint8_t *src_mac, struct in6_addr *src_ip, int src_port, uint8_t *dest_mac, struct in6_addr *dest_ip, int dest_port, int protocol)
449{
450#ifdef ECM_IPV6_ENABLE
451 struct in6_addr in6;
452 ip_addr_t ecm_src_ip;
453 ip_addr_t ecm_dest_ip;
454 struct ecm_db_connection_instance *ci;
455 struct ecm_classifier_instance *classi;
456 struct ecm_classifier_pcc_instance *pcci;
457 struct ecm_front_end_connection_instance *feci;
458
459 /*
460 * Look up ECM connection from the given tuple
461 */
462 src_port = ntohs(src_port);
463 dest_port = ntohs(dest_port);
464 in6 = *src_ip;
465 ECM_NIN6_ADDR_TO_IP_ADDR(ecm_src_ip, in6);
466 in6 = *dest_ip;
467 ECM_NIN6_ADDR_TO_IP_ADDR(ecm_dest_ip, in6);
468
469 DEBUG_INFO("Deny Accel v6, lookup connection using \n"
470 "Protocol: %d\n"
471 "src: " ECM_IP_ADDR_OCTAL_FMT ":%d\n"
472 "dest: " ECM_IP_ADDR_OCTAL_FMT ":%d\n",
473 protocol,
474 ECM_IP_ADDR_TO_OCTAL(ecm_src_ip), src_port,
475 ECM_IP_ADDR_TO_OCTAL(ecm_dest_ip), dest_port);
476
477 ci = ecm_db_connection_find_and_ref(ecm_src_ip, ecm_dest_ip, protocol, src_port, dest_port);
478 if (!ci) {
479 DEBUG_TRACE("Not found\n");
480 return;
481 }
482
483 /*
484 * Get the PCC classifier
485 */
486 classi = ecm_db_connection_assigned_classifier_find_and_ref(ci, ECM_CLASSIFIER_TYPE_PCC);
487 if (!classi) {
488 DEBUG_TRACE("No PCC classi\n");
489 ecm_db_connection_deref(ci);
490 return;
491 }
492 pcci = (struct ecm_classifier_pcc_instance *)classi;
493 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
494
495 /*
496 * Set the permitted accel state to DENIED
497 * NOTE: When we next see activity on this connection it shall be accelerated (save depending on other classifiers decisions too).
498 */
499 spin_lock_bh(&ecm_classifier_pcc_lock);
500 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_DENIED;
501 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
502 pcci->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
503 pcci->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_NO;
504 pcci->reg_calls_from++;
505 spin_unlock_bh(&ecm_classifier_pcc_lock);
506
507 /*
508 * Get the front end and issue a deceleration
509 * If the connection is not accelerated anyway this will have no effect
510 */
511 feci = ecm_db_connection_front_end_get_and_ref(ci);
512 feci->decelerate(feci);
513 feci->deref(feci);
514
515 classi->deref(classi);
516 ecm_db_connection_deref(ci);
517#endif
518}
519EXPORT_SYMBOL(ecm_classifier_pcc_deny_accel_v6);
520
521/*
522 * ecm_classifier_pcc_unregister_force()
523 * Unregister the registrant, if any
524 */
525static void ecm_classifier_pcc_unregister_force(struct ecm_classifier_pcc_instance *pcci)
526{
527 struct ecm_classifier_pcc_registrant *reg;
528
529 spin_lock_bh(&ecm_classifier_pcc_lock);
530 reg = ecm_classifier_registrant;
531 if (!reg) {
532 spin_unlock_bh(&ecm_classifier_pcc_lock);
533 return;
534 }
535 ecm_classifier_registrant = NULL;
536 ecm_classifier_pcc_enabled = false;
537 spin_unlock_bh(&ecm_classifier_pcc_lock);
538
539 /*
540 * Release our ref upon the registrant that we took when it was registered
541 */
542 DEBUG_INFO("Force unregistration of: %px\n", reg);
543 reg->deref(reg);
544
545 /*
546 * Release hold on registrant module
547 */
548 module_put(reg->this_module);
549
550 /*
551 * Destroy all the connections
552 */
553 ecm_db_connection_defunct_all();
554}
555
556/*
557 * _ecm_classifier_pcc_ref()
558 * Ref
559 */
560static void _ecm_classifier_pcc_ref(struct ecm_classifier_pcc_instance *pcci)
561{
562 pcci->refs++;
563 DEBUG_TRACE("%px: pcci ref %d\n", pcci, pcci->refs);
564 DEBUG_ASSERT(pcci->refs > 0, "%px: ref wrap\n", pcci);
565}
566
567/*
568 * ecm_classifier_pcc_ref()
569 * Ref
570 */
571static void ecm_classifier_pcc_ref(struct ecm_classifier_instance *ci)
572{
573 struct ecm_classifier_pcc_instance *pcci;
574 pcci = (struct ecm_classifier_pcc_instance *)ci;
575
576 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
577 spin_lock_bh(&ecm_classifier_pcc_lock);
578 _ecm_classifier_pcc_ref(pcci);
579 spin_unlock_bh(&ecm_classifier_pcc_lock);
580}
581
582/*
583 * ecm_classifier_pcc_deref()
584 * Deref
585 */
586static int ecm_classifier_pcc_deref(struct ecm_classifier_instance *ci)
587{
588 struct ecm_classifier_pcc_instance *pcci;
589 pcci = (struct ecm_classifier_pcc_instance *)ci;
590
591 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
592 spin_lock_bh(&ecm_classifier_pcc_lock);
593 pcci->refs--;
594 DEBUG_ASSERT(pcci->refs >= 0, "%px: refs wrapped\n", pcci);
595 DEBUG_TRACE("%px: Parental Controls classifier deref %d\n", pcci, pcci->refs);
596 if (pcci->refs) {
597 int refs = pcci->refs;
598 spin_unlock_bh(&ecm_classifier_pcc_lock);
599 return refs;
600 }
601
602 /*
603 * Object to be destroyed
604 */
605 ecm_classifier_pcc_count--;
606 DEBUG_ASSERT(ecm_classifier_pcc_count >= 0, "%px: ecm_classifier_pcc_count wrap\n", pcci);
607
608 spin_unlock_bh(&ecm_classifier_pcc_lock);
609
610 /*
611 * Final
612 */
613 DEBUG_INFO("%px: Final Parental Controls classifier instance\n", pcci);
614 kfree(pcci);
615
616 return 0;
617}
618
619/*
620 * ecm_classifier_pcc_get_mirror_info()
621 * Get mirroring related information.
622 */
623static int ecm_classifier_pcc_get_mirror_info(struct ecm_classifier_pcc_info cinfo,
624 int *flow_mirror_ifindex_ptr, int *return_mirror_ifindex_ptr)
625{
626 struct net_device *flow_dev = cinfo.mirror.tuple_mirror_dev;
627 struct net_device *return_dev = cinfo.mirror.tuple_ret_mirror_dev;
628
629 if (!flow_dev && !return_dev) {
630 DEBUG_ERROR("No mirror net devices are specified\n");
631 return -1;
632 }
633
634 /*
635 * Fetch mirror interface information.
636 */
637 if (flow_dev) {
638 dev_hold(flow_dev);
639 *flow_mirror_ifindex_ptr = flow_dev->ifindex;
640 dev_put(flow_dev);
641 }
642
643 if (return_dev) {
644 dev_hold(return_dev);
645 *return_mirror_ifindex_ptr = return_dev->ifindex;
646 dev_put(return_dev);
647 }
648
649 return 0;
650}
651
652/*
653 * ecm_classifier_pcc_process()
654 * Process new packet
655 *
656 * NOTE: This function would only ever be called if all other classifiers have failed.
657 */
658static void ecm_classifier_pcc_process(struct ecm_classifier_instance *aci, ecm_tracker_sender_type_t sender,
659 struct ecm_tracker_ip_header *ip_hdr, struct sk_buff *skb,
660 struct ecm_classifier_process_response *process_response)
661{
662 struct ecm_classifier_pcc_instance *pcci = (struct ecm_classifier_pcc_instance *)aci;
663 ecm_classifier_pcc_result_t accel_permit_state;
664 ecm_classifier_pcc_result_t reg_result;
665 struct ecm_db_connection_instance *ci;
666 long jiffies_now;
667 int ip_version;
668 uint8_t src_mac[ETH_ALEN];
669 uint8_t dest_mac[ETH_ALEN];
670 int protocol;
671 int src_port;
672 int dst_port;
673 ip_addr_t src_ip;
674 ip_addr_t dst_ip;
675 struct ecm_classifier_pcc_registrant *registrant;
676 struct ecm_classifier_pcc_info cinfo = {0};
677 int flow_mirror_ifindex = -1;
678 int return_mirror_ifindex = -1;
679
680 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: invalid state magic\n", pcci);
681
682 /*
683 * Get connection
684 */
685 ci = ecm_db_connection_serial_find_and_ref(pcci->ci_serial);
686 if (!ci) {
687 /*
688 * Connection has gone from under us
689 */
690 spin_lock_bh(&ecm_classifier_pcc_lock);
691 goto not_relevant;
692 }
693
694 /*
695 * Early detection of DNS server port
696 */
697 dst_port = ecm_db_connection_port_get(ci, ECM_DB_OBJ_DIR_TO);
698
699 spin_lock_bh(&ecm_classifier_pcc_lock);
700
701 /*
702 * Not relevant to the connection if not enabled.
703 */
704 if (unlikely(!ecm_classifier_pcc_enabled)) {
705 /*
706 * Not relevant.
707 */
708 goto not_relevant;
709 }
710
711 /*
712 * What is our acceleration permit state?
713 * If it is something other than ECM_CLASSIFIER_PCC_RESULT_NOT_YET then we have a definitive result already.
714 */
715 accel_permit_state = pcci->accel_permit_state;
716 if (accel_permit_state != ECM_CLASSIFIER_PCC_RESULT_NOT_YET) {
717 *process_response = pcci->process_response;
718 spin_unlock_bh(&ecm_classifier_pcc_lock);
719 ecm_db_connection_deref(ci);
720 return;
721 }
722
723 /*
724 * If the destination port is to DNS server then we implicitly deny acceleration
725 */
726 if (dst_port == 53) {
727 /*
728 * By setting the permit state to DENIED we will always deny from this point on
729 */
730 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_DENIED;
731 goto deny_accel;
732 }
733
734 /*
735 * We need to call to the registrant BUT we cannot do this at a rate that exceeds 1/sec
736 * NOTE: Not worried about wrap around, it's only one second.
737 */
738 jiffies_now = jiffies;
739 if ((jiffies_now - pcci->process_jiffies_last) < HZ) {
740 /*
741 * We cannot permit acceleration just yet
742 * Deny accel but don't change the permit state - we try again later
743 */
744 goto deny_accel;
745 }
746 pcci->process_jiffies_last = jiffies_now;
747
748 /*
749 * We have to call out to our registrant to see if we can get permission to accelerate.
750 * Get our registrant
751 */
752 registrant = ecm_classifier_registrant;
753 registrant->ref(registrant);
754
755 /*
756 * Bump reg calls made to the registrant.
757 */
758 pcci->reg_calls_to++;
759
760 spin_unlock_bh(&ecm_classifier_pcc_lock);
761
762 /*
763 * See if we can hold the registrant module - it may be unloading.
764 */
765 if (!try_module_get(registrant->this_module)) {
766 /*
767 * Module is unloading.
768 */
769 registrant->deref(registrant);
770
771 /*
772 * Force unregistration
773 */
774 ecm_classifier_pcc_unregister_force(pcci);
775
776 /*
777 * We are implicitly "not relevant".
778 */
779 spin_lock_bh(&ecm_classifier_pcc_lock);
780 goto not_relevant;
781 }
782
783 /*
784 * Ask the registrant if we may accelerate (big endian)
785 */
786 ip_version = ecm_db_connection_ip_version_get(ci);
787 protocol = ecm_db_connection_protocol_get(ci);
788 ecm_db_connection_address_get(ci, ECM_DB_OBJ_DIR_FROM, src_ip);
789 src_port = htons(ecm_db_connection_port_get(ci, ECM_DB_OBJ_DIR_FROM));
790 dst_port = htons(dst_port);
791 ecm_db_connection_address_get(ci, ECM_DB_OBJ_DIR_TO, dst_ip);
792 ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_FROM, src_mac);
793 ecm_db_connection_node_address_get(ci, ECM_DB_OBJ_DIR_TO, dest_mac);
794
795 /*
796 * Default is permitted in case ip_version is unsupported here
797 */
798 reg_result = ECM_CLASSIFIER_PCC_RESULT_PERMITTED;
799 if (ip_version == 4) {
800 __be32 src_ip4;
801 __be32 dest_ip4;
802
803 ECM_IP_ADDR_TO_NIN4_ADDR(src_ip4, src_ip);
804 ECM_IP_ADDR_TO_NIN4_ADDR(dest_ip4, dst_ip);
805
806 /*
807 * get_accel_info_v4 callback has higher priority over
808 * okay_to_accel_v4 callback.
809 * get_accel_info_v4 callback is the advance version of older
810 * okay_to_accel_v4 callback, from which the registrant can not
811 * only can tell the final acceleration decision about the flow but
812 * can also request for additional features like mirroring.
813 * get_accel_info_v4 callback is also backward compatible, means
814 * it can be used by the registrant for only specifying acceleration
815 * decisions.
816 */
817 if (registrant->get_accel_info_v4){
818 reg_result = registrant->get_accel_info_v4(registrant,
819 src_mac, src_ip4, src_port, dest_mac,
820 dest_ip4, dst_port, protocol, &cinfo);
821 pcci->feature_flags = cinfo.feature_flags;
822 } else {
823 reg_result = registrant->okay_to_accel_v4(registrant,
824 src_mac, src_ip4, src_port, dest_mac,
825 dest_ip4, dst_port, protocol);
826 pcci->feature_flags = ECM_CLASSIFIER_PCC_FEATURE_NONE;
827 }
828 }
829#ifdef ECM_IPV6_ENABLE
830 if (ip_version == 6) {
831 struct in6_addr src_ip6;
832 struct in6_addr dest_ip6;
833 ECM_IP_ADDR_TO_NIN6_ADDR(src_ip6, src_ip);
834 ECM_IP_ADDR_TO_NIN6_ADDR(dest_ip6, dst_ip);
835
836 /*
837 * get_accel_info_v6 callback has higher priority over
838 * okay_to_accel_v6 callback.
839 * get_accel_info_v6 callback is the advance version of older
840 * okay_to_accel_v6 callback, from which the registrant can not
841 * only can tell the final acceleration decision about the flow but
842 * can also request for additional features like mirroring.
843 * get_accel_info_v6 callback is also backward compatible, means
844 * it can be used by the registrant for only specifying acceleration
845 * decisions.
846 */
847 if (registrant->get_accel_info_v6){
848 reg_result = registrant->get_accel_info_v6(registrant,
849 src_mac, &src_ip6, src_port, dest_mac,
850 &dest_ip6, dst_port, protocol, &cinfo);
851 pcci->feature_flags = cinfo.feature_flags;
852 } else {
853 reg_result = registrant->okay_to_accel_v6(registrant,
854 src_mac, &src_ip6, src_port, dest_mac,
855 &dest_ip6, dst_port, protocol);
856 pcci->feature_flags = ECM_CLASSIFIER_PCC_FEATURE_NONE;
857 }
858 }
859#endif
860
861 /*
862 * Release the ref taken for this call
863 */
864 registrant->deref(registrant);
865
866 /*
867 * Release the module ref taken.
868 */
869 module_put(registrant->this_module);
870
871 /*
872 * Handle the features requested by registrants, if any.
873 */
874 if (cinfo.feature_flags & ECM_CLASSIFIER_PCC_FEATURE_MIRROR) {
875 if (ecm_classifier_pcc_get_mirror_info(cinfo, &flow_mirror_ifindex,
876 &return_mirror_ifindex) < 0) {
877 spin_lock_bh(&ecm_classifier_pcc_lock);
878 goto deny_accel;
879 }
880 }
881
882 /*
883 * Handle the result
884 */
885 switch (reg_result) {
886 case ECM_CLASSIFIER_PCC_RESULT_NOT_YET:
887 /*
888 * Deny accel but don't change the permit state - we try again later
889 */
890 spin_lock_bh(&ecm_classifier_pcc_lock);
891 goto deny_accel;
892 case ECM_CLASSIFIER_PCC_RESULT_DENIED:
893 /*
894 * Deny accel and set the permit state to denied - this connection is denied from this point on.
895 */
896 spin_lock_bh(&ecm_classifier_pcc_lock);
897 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_DENIED;
898 goto deny_accel;
899 case ECM_CLASSIFIER_PCC_RESULT_PERMITTED:
900 break;
901 default:
902 DEBUG_ASSERT(false, "Unhandled result: %d\n", reg_result);
903 }
904
905 /*
906 * Acceleration is permitted
907 */
908 spin_lock_bh(&ecm_classifier_pcc_lock);
909
910 /*
911 * Fill mirror information in the process response.
912 */
913 if (cinfo.feature_flags & ECM_CLASSIFIER_PCC_FEATURE_MIRROR) {
914 pcci->process_response.flow_mirror_ifindex = flow_mirror_ifindex;
915 pcci->process_response.return_mirror_ifindex = return_mirror_ifindex;
916 pcci->process_response.process_actions |=
917 ECM_CLASSIFIER_PROCESS_ACTION_MIRROR_ENABLED;
918 }
919
920 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_PERMITTED;
921 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
922 pcci->process_response.process_actions |= ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
923 pcci->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_ACCEL;
924 *process_response = pcci->process_response;
925 spin_unlock_bh(&ecm_classifier_pcc_lock);
926 ecm_db_connection_deref(ci);
927
928 return;
929
930not_relevant:
931
932 /*
933 * ecm_classifier_pcc_lock MUST be held
934 */
935 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_NO;
936 pcci->process_response.process_actions = 0;
937 *process_response = pcci->process_response;
938 spin_unlock_bh(&ecm_classifier_pcc_lock);
939 if (ci) {
940 ecm_db_connection_deref(ci);
941 }
942 return;
943
944deny_accel:
945
946 /*
947 * ecm_classifier_pcc_lock MUST be held
948 */
949 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
950 pcci->process_response.process_actions = ECM_CLASSIFIER_PROCESS_ACTION_ACCEL_MODE;
951 pcci->process_response.accel_mode = ECM_CLASSIFIER_ACCELERATION_MODE_NO;
952 *process_response = pcci->process_response;
953 spin_unlock_bh(&ecm_classifier_pcc_lock);
954 ecm_db_connection_deref(ci);
955 return;
956
957}
958
959/*
960 * ecm_classifier_pcc_type_get()
961 * Get type of classifier this is
962 */
963static ecm_classifier_type_t ecm_classifier_pcc_type_get(struct ecm_classifier_instance *aci)
964{
965 struct ecm_classifier_pcc_instance *pcci;
966 pcci = (struct ecm_classifier_pcc_instance *)aci;
967
968 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
969 return ECM_CLASSIFIER_TYPE_PCC;
970}
971
972/*
973 * ecm_classifier_pcc_reclassify_allowed()
974 * Get whether reclassification is allowed
975 */
976static bool ecm_classifier_pcc_reclassify_allowed(struct ecm_classifier_instance *aci)
977{
978 struct ecm_classifier_pcc_instance *pcci;
979 pcci = (struct ecm_classifier_pcc_instance *)aci;
980
981 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
982 return true;
983}
984
985/*
986 * ecm_classifier_pcc_reclassify()
987 * Reclassify
988 */
989static void ecm_classifier_pcc_reclassify(struct ecm_classifier_instance *aci)
990{
991 struct ecm_classifier_pcc_instance *pcci;
992 pcci = (struct ecm_classifier_pcc_instance *)aci;
993 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
994
995 /*
996 * Connection needs to be reset to 'as new'
997 * NOTE: Implicitly the connection would have been decelerated now so we don't need to worry about that.
998 */
999 spin_lock_bh(&ecm_classifier_pcc_lock);
1000 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_NOT_YET;
1001
1002 /*
1003 * Reset jiffies for rate limiting registrant calls
1004 */
1005 pcci->process_jiffies_last = jiffies;
1006
1007 spin_unlock_bh(&ecm_classifier_pcc_lock);
1008}
1009
1010/*
1011 * ecm_classifier_pcc_last_process_response_get()
1012 * Get result code returned by the last process call
1013 */
1014static void ecm_classifier_pcc_last_process_response_get(struct ecm_classifier_instance *aci,
1015 struct ecm_classifier_process_response *process_response)
1016{
1017 struct ecm_classifier_pcc_instance *pcci;
1018 pcci = (struct ecm_classifier_pcc_instance *)aci;
1019 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
1020
1021 spin_lock_bh(&ecm_classifier_pcc_lock);
1022 *process_response = pcci->process_response;
1023 spin_unlock_bh(&ecm_classifier_pcc_lock);
1024}
1025
1026/*
1027 * ecm_classifier_pcc_sync_to_v4()
1028 * Front end is pushing accel engine state to us
1029 */
1030static void ecm_classifier_pcc_sync_to_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
1031{
1032 struct ecm_classifier_pcc_instance *pcci __attribute__((unused));
1033
1034 pcci = (struct ecm_classifier_pcc_instance *)aci;
1035 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
1036}
1037
1038/*
1039 * ecm_classifier_pcc_sync_from_v4()
1040 * Front end is retrieving accel engine state from us
1041 */
1042static void ecm_classifier_pcc_sync_from_v4(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc)
1043{
1044 struct ecm_classifier_pcc_instance *pcci __attribute__((unused));
1045
1046 pcci = (struct ecm_classifier_pcc_instance *)aci;
1047 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
1048}
1049
1050/*
1051 * ecm_classifier_pcc_sync_to_v6()
1052 * Front end is pushing accel engine state to us
1053 */
1054static void ecm_classifier_pcc_sync_to_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_sync *sync)
1055{
1056 struct ecm_classifier_pcc_instance *pcci __attribute__((unused));
1057
1058 pcci = (struct ecm_classifier_pcc_instance *)aci;
1059 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
1060}
1061
1062/*
1063 * ecm_classifier_pcc_sync_from_v6()
1064 * Front end is retrieving accel engine state from us
1065 */
1066static void ecm_classifier_pcc_sync_from_v6(struct ecm_classifier_instance *aci, struct ecm_classifier_rule_create *ecrc)
1067{
1068 struct ecm_classifier_pcc_instance *pcci __attribute__((unused));
1069
1070 pcci = (struct ecm_classifier_pcc_instance *)aci;
1071 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
1072}
1073
1074#ifdef ECM_STATE_OUTPUT_ENABLE
1075/*
1076 * ecm_classifier_pcc_state_get()
1077 * Return state
1078 */
1079static int ecm_classifier_pcc_state_get(struct ecm_classifier_instance *ci, struct ecm_state_file_instance *sfi)
1080{
1081 int result;
1082 struct ecm_classifier_pcc_instance *pcci;
1083 struct ecm_classifier_process_response process_response;
1084 ecm_classifier_pcc_result_t accel_permit_state;
1085 uint32_t reg_calls_to;
1086 uint32_t reg_calls_from;
1087 uint32_t feature_flags;
1088
1089 pcci = (struct ecm_classifier_pcc_instance *)ci;
1090 DEBUG_CHECK_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC, "%px: magic failed", pcci);
1091
1092 if ((result = ecm_state_prefix_add(sfi, "pcc"))) {
1093 return result;
1094 }
1095
1096 spin_lock_bh(&ecm_classifier_pcc_lock);
1097 accel_permit_state = pcci->accel_permit_state;
1098 process_response = pcci->process_response;
1099 reg_calls_to = pcci->reg_calls_to;
1100 reg_calls_from = pcci->reg_calls_from;
1101 feature_flags = pcci->feature_flags;
1102 spin_unlock_bh(&ecm_classifier_pcc_lock);
1103
1104 if ((result = ecm_state_write(sfi, "accel_permit_state", "%d", accel_permit_state))) {
1105 return result;
1106 }
1107
1108 if ((result = ecm_state_write(sfi, "reg_calls_to", "%d", reg_calls_to))) {
1109 return result;
1110 }
1111
1112 if ((result = ecm_state_write(sfi, "reg_calls_from", "%d", reg_calls_from))) {
1113 return result;
1114 }
1115
1116 if ((result = ecm_state_write(sfi, "feature_flags", "0x%x", feature_flags))) {
1117 return result;
1118 }
1119
1120 if (process_response.process_actions & ECM_CLASSIFIER_PROCESS_ACTION_MIRROR_ENABLED) {
1121 struct net_device *dev;
1122
1123 if ((dev = dev_get_by_index(&init_net, process_response.flow_mirror_ifindex))) {
1124 if ((result = ecm_state_write(sfi, "flow_mirror", "%s",
1125 dev->name))) {
1126 dev_put(dev);
1127 return result;
1128 }
1129 dev_put(dev);
1130 }
1131
1132 if ((dev = dev_get_by_index(&init_net, process_response.return_mirror_ifindex))) {
1133 if ((result = ecm_state_write(sfi, "return_mirror", "%s",
1134 dev->name))) {
1135 dev_put(dev);
1136 return result;
1137 }
1138 dev_put(dev);
1139 }
1140 }
1141
1142 /*
1143 * Output our last process response
1144 */
1145 if ((result = ecm_classifier_process_response_state_get(sfi, &process_response))) {
1146 return result;
1147 }
1148
1149 return ecm_state_prefix_remove(sfi);
1150}
1151#endif
1152
1153/*
1154 * ecm_classifier_pcc_instance_alloc()
1155 * Allocate an instance of the Parental Controls classifier
1156 */
1157struct ecm_classifier_pcc_instance *ecm_classifier_pcc_instance_alloc(struct ecm_db_connection_instance *ci)
1158{
1159 struct ecm_classifier_pcc_instance *pcci;
1160 struct ecm_classifier_instance *cdi;
1161
1162 /*
1163 * Allocate the instance
1164 */
1165 pcci = (struct ecm_classifier_pcc_instance *)kzalloc(sizeof(struct ecm_classifier_pcc_instance), GFP_ATOMIC | __GFP_NOWARN);
1166 if (!pcci) {
1167 DEBUG_WARN("Failed to allocate Parental Controls Classifier instance\n");
1168 return NULL;
1169 }
1170
1171 DEBUG_SET_MAGIC(pcci, ECM_CLASSIFIER_PCC_INSTANCE_MAGIC);
1172 pcci->refs = 1;
1173 pcci->ci_serial = ecm_db_connection_serial_get(ci);
1174
1175 /*
1176 * We are relevant to the connection at this time
1177 */
1178 pcci->process_response.relevance = ECM_CLASSIFIER_RELEVANCE_YES;
1179
1180 /*
1181 * Don't know yet whether we are allowed to accelerate - need to query the registrant
1182 */
1183 pcci->accel_permit_state = ECM_CLASSIFIER_PCC_RESULT_NOT_YET;
1184
1185 /*
1186 * Reset jiffies for rate limiting registrant calls
1187 */
1188 pcci->process_jiffies_last = jiffies;
1189
1190 /*
1191 * Methods generic to all classifiers.
1192 */
1193 cdi = (struct ecm_classifier_instance *)pcci;
1194 cdi->process = ecm_classifier_pcc_process;
1195 cdi->sync_from_v4 = ecm_classifier_pcc_sync_from_v4;
1196 cdi->sync_to_v4 = ecm_classifier_pcc_sync_to_v4;
1197 cdi->sync_from_v6 = ecm_classifier_pcc_sync_from_v6;
1198 cdi->sync_to_v6 = ecm_classifier_pcc_sync_to_v6;
1199 cdi->type_get = ecm_classifier_pcc_type_get;
1200 cdi->reclassify_allowed = ecm_classifier_pcc_reclassify_allowed;
1201 cdi->reclassify = ecm_classifier_pcc_reclassify;
1202 cdi->last_process_response_get = ecm_classifier_pcc_last_process_response_get;
1203#ifdef ECM_STATE_OUTPUT_ENABLE
1204 cdi->state_get = ecm_classifier_pcc_state_get;
1205#endif
1206 cdi->ref = ecm_classifier_pcc_ref;
1207 cdi->deref = ecm_classifier_pcc_deref;
1208
1209 /*
1210 * Increment stats
1211 */
1212 spin_lock_bh(&ecm_classifier_pcc_lock);
1213 ecm_classifier_pcc_count++;
1214 DEBUG_ASSERT(ecm_classifier_pcc_count > 0, "%px: ecm_classifier_pcc_count wrap\n", pcci);
1215 spin_unlock_bh(&ecm_classifier_pcc_lock);
1216
1217 DEBUG_INFO("Parental Controls classifier instance alloc: %px\n", pcci);
1218 return pcci;
1219}
1220EXPORT_SYMBOL(ecm_classifier_pcc_instance_alloc);
1221
1222/*
1223 * ecm_classifier_pcc_init()
1224 */
1225int ecm_classifier_pcc_init(struct dentry *dentry)
1226{
1227 DEBUG_INFO("Parental Controls classifier Module init\n");
1228
1229 ecm_classifier_pcc_dentry = debugfs_create_dir("ecm_classifier_pcc", dentry);
1230 if (!ecm_classifier_pcc_dentry) {
1231 DEBUG_ERROR("Failed to create ecm pcc directory in debugfs\n");
1232 return -1;
1233 }
1234
1235 if (!debugfs_create_u32("enabled", S_IRUGO, ecm_classifier_pcc_dentry,
1236 (u32 *)&ecm_classifier_pcc_enabled)) {
1237 DEBUG_ERROR("Failed to create pcc enabled file in debugfs\n");
1238 debugfs_remove_recursive(ecm_classifier_pcc_dentry);
1239 return -1;
1240 }
1241
1242 return 0;
1243}
1244EXPORT_SYMBOL(ecm_classifier_pcc_init);
1245
1246/*
1247 * ecm_classifier_pcc_exit()
1248 */
1249void ecm_classifier_pcc_exit(void)
1250{
1251 DEBUG_INFO("Parental Controls classifier Module exit\n");
1252
1253 /*
1254 * Remove the debugfs files recursively.
1255 */
1256 if (ecm_classifier_pcc_dentry) {
1257 debugfs_remove_recursive(ecm_classifier_pcc_dentry);
1258 }
1259
1260}
1261EXPORT_SYMBOL(ecm_classifier_pcc_exit);