1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * linux/net/netfilter/xt_IDLETIMER.c
4 *
5 * Netfilter module to trigger a timer when packet matches.
6 * After timer expires a kevent will be sent.
7 *
8 * Copyright (C) 2004, 2010 Nokia Corporation
9 * Written by Timo Teras <ext-timo.teras@nokia.com>
10 *
11 * Converted to x_tables and reworked for upstream inclusion
12 * by Luciano Coelho <luciano.coelho@nokia.com>
13 *
14 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
15 */
16
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/module.h>
20 #include <linux/timer.h>
21 #include <linux/alarmtimer.h>
22 #include <linux/list.h>
23 #include <linux/mutex.h>
24 #include <linux/netfilter.h>
25 #include <linux/netfilter/x_tables.h>
26 #include <linux/netfilter/xt_IDLETIMER.h>
27 #include <linux/kdev_t.h>
28 #include <linux/kobject.h>
29 #include <linux/workqueue.h>
30 #include <linux/sysfs.h>
31 #include <linux/suspend.h>
32 #include <net/sock.h>
33 #include <net/inet_sock.h>
34
35 #define NLMSG_MAX_SIZE 64
36
37 struct idletimer_tg {
38 struct list_head entry;
39 struct alarm alarm;
40 struct timer_list timer;
41 struct work_struct work;
42
43 struct kobject *kobj;
44 struct device_attribute attr;
45
46 struct timespec64 delayed_timer_trigger;
47 struct timespec64 last_modified_timer;
48 struct timespec64 last_suspend_time;
49 struct notifier_block pm_nb;
50
51 int timeout;
52 unsigned int refcnt;
53 u8 timer_type;
54
55 bool work_pending;
56 bool send_nl_msg;
57 bool active;
58 uid_t uid;
59 bool suspend_time_valid;
60 };
61
62 static LIST_HEAD(idletimer_tg_list);
63 static DEFINE_MUTEX(list_mutex);
64 static DEFINE_SPINLOCK(timestamp_lock);
65
66 static struct kobject *idletimer_tg_kobj;
67
check_for_delayed_trigger(struct idletimer_tg * timer,struct timespec64 * ts)68 static bool check_for_delayed_trigger(struct idletimer_tg *timer,
69 struct timespec64 *ts)
70 {
71 bool state;
72 struct timespec64 temp;
73 spin_lock_bh(×tamp_lock);
74 timer->work_pending = false;
75 if ((ts->tv_sec - timer->last_modified_timer.tv_sec) > timer->timeout ||
76 timer->delayed_timer_trigger.tv_sec != 0) {
77 state = false;
78 temp.tv_sec = timer->timeout;
79 temp.tv_nsec = 0;
80 if (timer->delayed_timer_trigger.tv_sec != 0) {
81 temp = timespec64_add(timer->delayed_timer_trigger,
82 temp);
83 ts->tv_sec = temp.tv_sec;
84 ts->tv_nsec = temp.tv_nsec;
85 timer->delayed_timer_trigger.tv_sec = 0;
86 timer->work_pending = true;
87 schedule_work(&timer->work);
88 } else {
89 temp = timespec64_add(timer->last_modified_timer, temp);
90 ts->tv_sec = temp.tv_sec;
91 ts->tv_nsec = temp.tv_nsec;
92 }
93 } else {
94 state = timer->active;
95 }
96 spin_unlock_bh(×tamp_lock);
97 return state;
98 }
99
notify_netlink_uevent(const char * iface,struct idletimer_tg * timer)100 static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer)
101 {
102 char iface_msg[NLMSG_MAX_SIZE];
103 char state_msg[NLMSG_MAX_SIZE];
104 char timestamp_msg[NLMSG_MAX_SIZE];
105 char uid_msg[NLMSG_MAX_SIZE];
106 char *envp[] = { iface_msg, state_msg, timestamp_msg, uid_msg, NULL };
107 int res;
108 struct timespec64 ts;
109 u64 time_ns;
110 bool state;
111
112 res = snprintf(iface_msg, NLMSG_MAX_SIZE, "INTERFACE=%s",
113 iface);
114 if (NLMSG_MAX_SIZE <= res) {
115 pr_err("message too long (%d)\n", res);
116 return;
117 }
118
119 ts = ktime_to_timespec64(ktime_get_boottime());
120 state = check_for_delayed_trigger(timer, &ts);
121 res = snprintf(state_msg, NLMSG_MAX_SIZE, "STATE=%s",
122 state ? "active" : "inactive");
123
124 if (NLMSG_MAX_SIZE <= res) {
125 pr_err("message too long (%d)\n", res);
126 return;
127 }
128
129 if (state) {
130 res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID=%u", timer->uid);
131 if (NLMSG_MAX_SIZE <= res)
132 pr_err("message too long (%d)\n", res);
133 } else {
134 res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID=");
135 if (NLMSG_MAX_SIZE <= res)
136 pr_err("message too long (%d)\n", res);
137 }
138
139 time_ns = timespec64_to_ns(&ts);
140 res = snprintf(timestamp_msg, NLMSG_MAX_SIZE, "TIME_NS=%llu", time_ns);
141 if (NLMSG_MAX_SIZE <= res) {
142 timestamp_msg[0] = '\0';
143 pr_err("message too long (%d)\n", res);
144 }
145
146 pr_debug("putting nlmsg: <%s> <%s> <%s> <%s>\n", iface_msg, state_msg,
147 timestamp_msg, uid_msg);
148 kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp);
149 return;
150 }
151
152 static
__idletimer_tg_find_by_label(const char * label)153 struct idletimer_tg *__idletimer_tg_find_by_label(const char *label)
154 {
155 struct idletimer_tg *entry;
156
157 list_for_each_entry(entry, &idletimer_tg_list, entry) {
158 if (!strcmp(label, entry->attr.attr.name))
159 return entry;
160 }
161
162 return NULL;
163 }
164
idletimer_tg_show(struct device * dev,struct device_attribute * attr,char * buf)165 static ssize_t idletimer_tg_show(struct device *dev,
166 struct device_attribute *attr, char *buf)
167 {
168 struct idletimer_tg *timer;
169 unsigned long expires = 0;
170 struct timespec64 ktimespec = {};
171 long time_diff = 0;
172 unsigned long now = jiffies;
173
174 mutex_lock(&list_mutex);
175
176 timer = __idletimer_tg_find_by_label(attr->attr.name);
177 if (timer) {
178 if (timer->timer_type & XT_IDLETIMER_ALARM) {
179 ktime_t expires_alarm = alarm_expires_remaining(&timer->alarm);
180 ktimespec = ktime_to_timespec64(expires_alarm);
181 time_diff = ktimespec.tv_sec;
182 } else {
183 expires = timer->timer.expires;
184 time_diff = jiffies_to_msecs(expires - now) / 1000;
185 }
186 }
187
188 mutex_unlock(&list_mutex);
189
190 if (time_after(expires, now) || ktimespec.tv_sec > 0)
191 return scnprintf(buf, PAGE_SIZE, "%ld\n", time_diff);
192
193 if (timer->send_nl_msg)
194 return scnprintf(buf, PAGE_SIZE, "0 %d\n",
195 jiffies_to_msecs(now - expires) / 1000);
196
197 return scnprintf(buf, PAGE_SIZE, "0\n");
198 }
199
idletimer_tg_work(struct work_struct * work)200 static void idletimer_tg_work(struct work_struct *work)
201 {
202 struct idletimer_tg *timer = container_of(work, struct idletimer_tg,
203 work);
204
205 sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name);
206
207 if (timer->send_nl_msg)
208 notify_netlink_uevent(timer->attr.attr.name, timer);
209 }
210
idletimer_tg_expired(struct timer_list * t)211 static void idletimer_tg_expired(struct timer_list *t)
212 {
213 struct idletimer_tg *timer = from_timer(timer, t, timer);
214
215 pr_debug("timer %s expired\n", timer->attr.attr.name);
216
217 spin_lock_bh(×tamp_lock);
218 timer->active = false;
219 timer->work_pending = true;
220 schedule_work(&timer->work);
221 spin_unlock_bh(×tamp_lock);
222 }
223
idletimer_resume(struct notifier_block * notifier,unsigned long pm_event,void * unused)224 static int idletimer_resume(struct notifier_block *notifier,
225 unsigned long pm_event, void *unused)
226 {
227 struct timespec64 ts;
228 unsigned long time_diff, now = jiffies;
229 struct idletimer_tg *timer = container_of(notifier,
230 struct idletimer_tg, pm_nb);
231 if (!timer)
232 return NOTIFY_DONE;
233
234 switch (pm_event) {
235 case PM_SUSPEND_PREPARE:
236 timer->last_suspend_time =
237 ktime_to_timespec64(ktime_get_boottime());
238 timer->suspend_time_valid = true;
239 break;
240 case PM_POST_SUSPEND:
241 if (!timer->suspend_time_valid)
242 break;
243 timer->suspend_time_valid = false;
244
245 spin_lock_bh(×tamp_lock);
246 if (!timer->active) {
247 spin_unlock_bh(×tamp_lock);
248 break;
249 }
250 /* since jiffies are not updated when suspended now represents
251 * the time it would have suspended */
252 if (time_after(timer->timer.expires, now)) {
253 ts = ktime_to_timespec64(ktime_get_boottime());
254 ts = timespec64_sub(ts, timer->last_suspend_time);
255 time_diff = timespec64_to_jiffies(&ts);
256 if (timer->timer.expires > (time_diff + now)) {
257 mod_timer_pending(&timer->timer,
258 (timer->timer.expires - time_diff));
259 } else {
260 del_timer(&timer->timer);
261 timer->timer.expires = 0;
262 timer->active = false;
263 timer->work_pending = true;
264 schedule_work(&timer->work);
265 }
266 }
267 spin_unlock_bh(×tamp_lock);
268 break;
269 default:
270 break;
271 }
272 return NOTIFY_DONE;
273 }
274
idletimer_tg_alarmproc(struct alarm * alarm,ktime_t now)275 static enum alarmtimer_restart idletimer_tg_alarmproc(struct alarm *alarm,
276 ktime_t now)
277 {
278 struct idletimer_tg *timer = alarm->data;
279
280 pr_debug("alarm %s expired\n", timer->attr.attr.name);
281 schedule_work(&timer->work);
282 return ALARMTIMER_NORESTART;
283 }
284
idletimer_check_sysfs_name(const char * name,unsigned int size)285 static int idletimer_check_sysfs_name(const char *name, unsigned int size)
286 {
287 int ret;
288
289 ret = xt_check_proc_name(name, size);
290 if (ret < 0)
291 return ret;
292
293 if (!strcmp(name, "power") ||
294 !strcmp(name, "subsystem") ||
295 !strcmp(name, "uevent"))
296 return -EINVAL;
297
298 return 0;
299 }
300
idletimer_tg_create(struct idletimer_tg_info * info)301 static int idletimer_tg_create(struct idletimer_tg_info *info)
302 {
303 int ret;
304
305 info->timer = kzalloc(sizeof(*info->timer), GFP_KERNEL);
306 if (!info->timer) {
307 ret = -ENOMEM;
308 goto out;
309 }
310
311 ret = idletimer_check_sysfs_name(info->label, sizeof(info->label));
312 if (ret < 0)
313 goto out_free_timer;
314
315 sysfs_attr_init(&info->timer->attr.attr);
316 info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
317 if (!info->timer->attr.attr.name) {
318 ret = -ENOMEM;
319 goto out_free_timer;
320 }
321 info->timer->attr.attr.mode = 0444;
322 info->timer->attr.show = idletimer_tg_show;
323
324 ret = sysfs_create_file(idletimer_tg_kobj, &info->timer->attr.attr);
325 if (ret < 0) {
326 pr_debug("couldn't add file to sysfs\n");
327 goto out_free_attr;
328 }
329
330 list_add(&info->timer->entry, &idletimer_tg_list);
331 pr_debug("timer type value is 0.\n");
332 info->timer->timer_type = 0;
333 info->timer->refcnt = 1;
334 info->timer->send_nl_msg = false;
335 info->timer->active = true;
336 info->timer->timeout = info->timeout;
337
338 info->timer->delayed_timer_trigger.tv_sec = 0;
339 info->timer->delayed_timer_trigger.tv_nsec = 0;
340 info->timer->work_pending = false;
341 info->timer->uid = 0;
342 info->timer->last_modified_timer =
343 ktime_to_timespec64(ktime_get_boottime());
344
345 info->timer->pm_nb.notifier_call = idletimer_resume;
346 ret = register_pm_notifier(&info->timer->pm_nb);
347 if (ret)
348 printk(KERN_WARNING "[%s] Failed to register pm notifier %d\n",
349 __func__, ret);
350
351 INIT_WORK(&info->timer->work, idletimer_tg_work);
352
353 timer_setup(&info->timer->timer, idletimer_tg_expired, 0);
354 mod_timer(&info->timer->timer,
355 msecs_to_jiffies(info->timeout * 1000) + jiffies);
356
357 return 0;
358
359 out_free_attr:
360 kfree(info->timer->attr.attr.name);
361 out_free_timer:
362 kfree(info->timer);
363 out:
364 return ret;
365 }
366
idletimer_tg_create_v1(struct idletimer_tg_info_v1 * info)367 static int idletimer_tg_create_v1(struct idletimer_tg_info_v1 *info)
368 {
369 int ret;
370
371 info->timer = kzalloc(sizeof(*info->timer), GFP_KERNEL);
372 if (!info->timer) {
373 ret = -ENOMEM;
374 goto out;
375 }
376
377 ret = idletimer_check_sysfs_name(info->label, sizeof(info->label));
378 if (ret < 0)
379 goto out_free_timer;
380
381 sysfs_attr_init(&info->timer->attr.attr);
382 info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
383 if (!info->timer->attr.attr.name) {
384 ret = -ENOMEM;
385 goto out_free_timer;
386 }
387 info->timer->attr.attr.mode = 0444;
388 info->timer->attr.show = idletimer_tg_show;
389
390 ret = sysfs_create_file(idletimer_tg_kobj, &info->timer->attr.attr);
391 if (ret < 0) {
392 pr_debug("couldn't add file to sysfs\n");
393 goto out_free_attr;
394 }
395
396 /* notify userspace */
397 kobject_uevent(idletimer_tg_kobj,KOBJ_ADD);
398
399 list_add(&info->timer->entry, &idletimer_tg_list);
400 pr_debug("timer type value is %u\n", info->timer_type);
401 info->timer->timer_type = info->timer_type;
402 info->timer->refcnt = 1;
403 info->timer->send_nl_msg = (info->send_nl_msg != 0);
404 info->timer->active = true;
405 info->timer->timeout = info->timeout;
406
407 info->timer->delayed_timer_trigger.tv_sec = 0;
408 info->timer->delayed_timer_trigger.tv_nsec = 0;
409 info->timer->work_pending = false;
410 info->timer->uid = 0;
411 info->timer->last_modified_timer =
412 ktime_to_timespec64(ktime_get_boottime());
413
414 info->timer->pm_nb.notifier_call = idletimer_resume;
415 ret = register_pm_notifier(&info->timer->pm_nb);
416 if (ret)
417 printk(KERN_WARNING "[%s] Failed to register pm notifier %d\n",
418 __func__, ret);
419
420 INIT_WORK(&info->timer->work, idletimer_tg_work);
421
422 if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
423 ktime_t tout;
424 alarm_init(&info->timer->alarm, ALARM_BOOTTIME,
425 idletimer_tg_alarmproc);
426 info->timer->alarm.data = info->timer;
427 tout = ktime_set(info->timeout, 0);
428 alarm_start_relative(&info->timer->alarm, tout);
429 } else {
430 timer_setup(&info->timer->timer, idletimer_tg_expired, 0);
431 mod_timer(&info->timer->timer,
432 msecs_to_jiffies(info->timeout * 1000) + jiffies);
433 }
434
435 return 0;
436
437 out_free_attr:
438 kfree(info->timer->attr.attr.name);
439 out_free_timer:
440 kfree(info->timer);
441 out:
442 return ret;
443 }
444
reset_timer(struct idletimer_tg * const info_timer,const __u32 info_timeout,struct sk_buff * skb)445 static void reset_timer(struct idletimer_tg * const info_timer,
446 const __u32 info_timeout,
447 struct sk_buff *skb)
448 {
449 unsigned long now = jiffies;
450 bool timer_prev;
451
452 spin_lock_bh(×tamp_lock);
453 timer_prev = info_timer->active;
454 info_timer->active = true;
455 /* timer_prev is used to guard overflow problem in time_before*/
456 if (!timer_prev || time_before(info_timer->timer.expires, now)) {
457 pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n",
458 info_timer->timer.expires, now);
459
460 /* Stores the uid resposible for waking up the radio */
461 if (skb && (skb->sk)) {
462 info_timer->uid = from_kuid_munged(current_user_ns(),
463 sock_i_uid(skb_to_full_sk(skb)));
464 }
465
466 /* checks if there is a pending inactive notification*/
467 if (info_timer->work_pending)
468 info_timer->delayed_timer_trigger = info_timer->last_modified_timer;
469 else {
470 info_timer->work_pending = true;
471 schedule_work(&info_timer->work);
472 }
473 }
474
475 info_timer->last_modified_timer = ktime_to_timespec64(ktime_get_boottime());
476 mod_timer(&info_timer->timer, msecs_to_jiffies(info_timeout * 1000) + now);
477 spin_unlock_bh(×tamp_lock);
478 }
479
480 /*
481 * The actual xt_tables plugin.
482 */
idletimer_tg_target(struct sk_buff * skb,const struct xt_action_param * par)483 static unsigned int idletimer_tg_target(struct sk_buff *skb,
484 const struct xt_action_param *par)
485 {
486 const struct idletimer_tg_info *info = par->targinfo;
487 unsigned long now = jiffies;
488
489 pr_debug("resetting timer %s, timeout period %u\n",
490 info->label, info->timeout);
491
492 info->timer->active = true;
493
494 if (time_before(info->timer->timer.expires, now)) {
495 schedule_work(&info->timer->work);
496 pr_debug("Starting timer %s (Expired, Jiffies): %lu, %lu\n",
497 info->label, info->timer->timer.expires, now);
498 }
499
500 /* TODO: Avoid modifying timers on each packet */
501 reset_timer(info->timer, info->timeout, skb);
502
503 return XT_CONTINUE;
504 }
505
506 /*
507 * The actual xt_tables plugin.
508 */
idletimer_tg_target_v1(struct sk_buff * skb,const struct xt_action_param * par)509 static unsigned int idletimer_tg_target_v1(struct sk_buff *skb,
510 const struct xt_action_param *par)
511 {
512 const struct idletimer_tg_info_v1 *info = par->targinfo;
513 unsigned long now = jiffies;
514
515 pr_debug("resetting timer %s, timeout period %u\n",
516 info->label, info->timeout);
517
518 if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
519 ktime_t tout = ktime_set(info->timeout, 0);
520 alarm_start_relative(&info->timer->alarm, tout);
521 } else {
522 info->timer->active = true;
523
524 if (time_before(info->timer->timer.expires, now)) {
525 schedule_work(&info->timer->work);
526 pr_debug("Starting timer %s (Expired, Jiffies): %lu, %lu\n",
527 info->label, info->timer->timer.expires, now);
528 }
529
530 /* TODO: Avoid modifying timers on each packet */
531 reset_timer(info->timer, info->timeout, skb);
532 }
533
534 return XT_CONTINUE;
535 }
536
idletimer_tg_helper(struct idletimer_tg_info * info)537 static int idletimer_tg_helper(struct idletimer_tg_info *info)
538 {
539 if (info->timeout == 0) {
540 pr_debug("timeout value is zero\n");
541 return -EINVAL;
542 }
543 if (info->timeout >= INT_MAX / 1000) {
544 pr_debug("timeout value is too big\n");
545 return -EINVAL;
546 }
547 if (info->label[0] == '\0' ||
548 strnlen(info->label,
549 MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) {
550 pr_debug("label is empty or not nul-terminated\n");
551 return -EINVAL;
552 }
553 return 0;
554 }
555
556
idletimer_tg_checkentry(const struct xt_tgchk_param * par)557 static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
558 {
559 struct idletimer_tg_info *info = par->targinfo;
560 int ret;
561
562 pr_debug("checkentry targinfo%s\n", info->label);
563
564 ret = idletimer_tg_helper(info);
565 if(ret < 0)
566 {
567 pr_debug("checkentry helper return invalid\n");
568 return -EINVAL;
569 }
570 mutex_lock(&list_mutex);
571
572 info->timer = __idletimer_tg_find_by_label(info->label);
573 if (info->timer) {
574 info->timer->refcnt++;
575 reset_timer(info->timer, info->timeout, NULL);
576 pr_debug("increased refcnt of timer %s to %u\n",
577 info->label, info->timer->refcnt);
578 } else {
579 ret = idletimer_tg_create(info);
580 if (ret < 0) {
581 pr_debug("failed to create timer\n");
582 mutex_unlock(&list_mutex);
583 return ret;
584 }
585 }
586
587 mutex_unlock(&list_mutex);
588 return 0;
589 }
590
idletimer_tg_checkentry_v1(const struct xt_tgchk_param * par)591 static int idletimer_tg_checkentry_v1(const struct xt_tgchk_param *par)
592 {
593 struct idletimer_tg_info_v1 *info = par->targinfo;
594 int ret;
595
596 pr_debug("checkentry targinfo%s\n", info->label);
597
598 ret = idletimer_tg_helper((struct idletimer_tg_info *)info);
599 if(ret < 0)
600 {
601 pr_debug("checkentry helper return invalid\n");
602 return -EINVAL;
603 }
604
605 if (info->timer_type > XT_IDLETIMER_ALARM) {
606 pr_debug("invalid value for timer type\n");
607 return -EINVAL;
608 }
609
610 if (info->send_nl_msg > 1) {
611 pr_debug("invalid value for send_nl_msg\n");
612 return -EINVAL;
613 }
614
615 mutex_lock(&list_mutex);
616
617 info->timer = __idletimer_tg_find_by_label(info->label);
618 if (info->timer) {
619 if (info->timer->timer_type != info->timer_type) {
620 pr_debug("Adding/Replacing rule with same label and different timer type is not allowed\n");
621 mutex_unlock(&list_mutex);
622 return -EINVAL;
623 }
624
625 info->timer->refcnt++;
626 if (info->timer_type & XT_IDLETIMER_ALARM) {
627 /* calculate remaining expiry time */
628 ktime_t tout = alarm_expires_remaining(&info->timer->alarm);
629 struct timespec64 ktimespec = ktime_to_timespec64(tout);
630
631 if (ktimespec.tv_sec > 0) {
632 pr_debug("time_expiry_remaining %lld\n",
633 ktimespec.tv_sec);
634 alarm_start_relative(&info->timer->alarm, tout);
635 }
636 } else {
637 reset_timer(info->timer, info->timeout, NULL);
638 }
639 pr_debug("increased refcnt of timer %s to %u\n",
640 info->label, info->timer->refcnt);
641 } else {
642 ret = idletimer_tg_create_v1(info);
643 if (ret < 0) {
644 pr_debug("failed to create timer\n");
645 mutex_unlock(&list_mutex);
646 return ret;
647 }
648 }
649
650 mutex_unlock(&list_mutex);
651 return 0;
652 }
653
idletimer_tg_destroy(const struct xt_tgdtor_param * par)654 static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
655 {
656 const struct idletimer_tg_info *info = par->targinfo;
657
658 pr_debug("destroy targinfo %s\n", info->label);
659
660 mutex_lock(&list_mutex);
661
662 if (--info->timer->refcnt == 0) {
663 pr_debug("deleting timer %s\n", info->label);
664
665 list_del(&info->timer->entry);
666 del_timer_sync(&info->timer->timer);
667 sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
668 unregister_pm_notifier(&info->timer->pm_nb);
669 cancel_work_sync(&info->timer->work);
670 kfree(info->timer->attr.attr.name);
671 kfree(info->timer);
672 } else {
673 pr_debug("decreased refcnt of timer %s to %u\n",
674 info->label, info->timer->refcnt);
675 }
676
677 mutex_unlock(&list_mutex);
678 }
679
idletimer_tg_destroy_v1(const struct xt_tgdtor_param * par)680 static void idletimer_tg_destroy_v1(const struct xt_tgdtor_param *par)
681 {
682 const struct idletimer_tg_info_v1 *info = par->targinfo;
683
684 pr_debug("destroy targinfo %s\n", info->label);
685
686 mutex_lock(&list_mutex);
687
688 if (--info->timer->refcnt == 0) {
689 pr_debug("deleting timer %s\n", info->label);
690
691 list_del(&info->timer->entry);
692 if (info->timer->timer_type & XT_IDLETIMER_ALARM) {
693 alarm_cancel(&info->timer->alarm);
694 } else {
695 del_timer_sync(&info->timer->timer);
696 }
697 sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
698 unregister_pm_notifier(&info->timer->pm_nb);
699 cancel_work_sync(&info->timer->work);
700 kfree(info->timer->attr.attr.name);
701 kfree(info->timer);
702 } else {
703 pr_debug("decreased refcnt of timer %s to %u\n",
704 info->label, info->timer->refcnt);
705 }
706
707 mutex_unlock(&list_mutex);
708 }
709
710
711 static struct xt_target idletimer_tg[] __read_mostly = {
712 {
713 .name = "IDLETIMER",
714 .family = NFPROTO_UNSPEC,
715 .target = idletimer_tg_target,
716 .targetsize = sizeof(struct idletimer_tg_info),
717 .usersize = offsetof(struct idletimer_tg_info, timer),
718 .checkentry = idletimer_tg_checkentry,
719 .destroy = idletimer_tg_destroy,
720 .me = THIS_MODULE,
721 },
722 {
723 .name = "IDLETIMER",
724 .family = NFPROTO_UNSPEC,
725 .revision = 1,
726 .target = idletimer_tg_target_v1,
727 .targetsize = sizeof(struct idletimer_tg_info_v1),
728 .usersize = offsetof(struct idletimer_tg_info_v1, timer),
729 .checkentry = idletimer_tg_checkentry_v1,
730 .destroy = idletimer_tg_destroy_v1,
731 .me = THIS_MODULE,
732 },
733
734
735 };
736
737 static struct class *idletimer_tg_class;
738
739 static struct device *idletimer_tg_device;
740
idletimer_tg_init(void)741 static int __init idletimer_tg_init(void)
742 {
743 int err;
744
745 idletimer_tg_class = class_create(THIS_MODULE, "xt_idletimer");
746 err = PTR_ERR(idletimer_tg_class);
747 if (IS_ERR(idletimer_tg_class)) {
748 pr_debug("couldn't register device class\n");
749 goto out;
750 }
751
752 idletimer_tg_device = device_create(idletimer_tg_class, NULL,
753 MKDEV(0, 0), NULL, "timers");
754 err = PTR_ERR(idletimer_tg_device);
755 if (IS_ERR(idletimer_tg_device)) {
756 pr_debug("couldn't register system device\n");
757 goto out_class;
758 }
759
760 idletimer_tg_kobj = &idletimer_tg_device->kobj;
761
762 err = xt_register_targets(idletimer_tg, ARRAY_SIZE(idletimer_tg));
763
764 if (err < 0) {
765 pr_debug("couldn't register xt target\n");
766 goto out_dev;
767 }
768
769 return 0;
770 out_dev:
771 device_destroy(idletimer_tg_class, MKDEV(0, 0));
772 out_class:
773 class_destroy(idletimer_tg_class);
774 out:
775 return err;
776 }
777
idletimer_tg_exit(void)778 static void __exit idletimer_tg_exit(void)
779 {
780 xt_unregister_targets(idletimer_tg, ARRAY_SIZE(idletimer_tg));
781
782 device_destroy(idletimer_tg_class, MKDEV(0, 0));
783 class_destroy(idletimer_tg_class);
784 }
785
786 module_init(idletimer_tg_init);
787 module_exit(idletimer_tg_exit);
788
789 MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
790 MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
791 MODULE_DESCRIPTION("Xtables: idle time monitor");
792 MODULE_LICENSE("GPL v2");
793 MODULE_ALIAS("ipt_IDLETIMER");
794 MODULE_ALIAS("ip6t_IDLETIMER");
795 MODULE_ALIAS("arpt_IDLETIMER");
796