18
18
19
19
#include <linux/module.h>
20
20
#include <linux/timer.h>
21
+ #include <linux/alarmtimer.h>
21
22
#include <linux/list.h>
22
23
#include <linux/mutex.h>
23
24
#include <linux/netfilter.h>
30
31
31
32
struct idletimer_tg {
32
33
struct list_head entry ;
34
+ struct alarm alarm ;
33
35
struct timer_list timer ;
34
36
struct work_struct work ;
35
37
36
38
struct kobject * kobj ;
37
39
struct device_attribute attr ;
38
40
39
41
unsigned int refcnt ;
42
+ u8 timer_type ;
40
43
};
41
44
42
45
static LIST_HEAD (idletimer_tg_list );
@@ -62,20 +65,30 @@ static ssize_t idletimer_tg_show(struct device *dev,
62
65
{
63
66
struct idletimer_tg * timer ;
64
67
unsigned long expires = 0 ;
68
+ struct timespec64 ktimespec = {};
69
+ long time_diff = 0 ;
65
70
66
71
mutex_lock (& list_mutex );
67
72
68
73
timer = __idletimer_tg_find_by_label (attr -> attr .name );
69
- if (timer )
74
+ if (timer ) {
75
+ if (timer -> timer_type & XT_IDLETIMER_ALARM ) {
76
+ ktime_t expires_alarm = alarm_expires_remaining (& timer -> alarm );
77
+ ktimespec = ktime_to_timespec64 (expires_alarm );
78
+ time_diff = ktimespec .tv_sec ;
79
+ } else {
70
80
expires = timer -> timer .expires ;
81
+ time_diff = jiffies_to_msecs (
82
+ expires - jiffies ) / 1000 ;
83
+ }
84
+ }
71
85
72
86
mutex_unlock (& list_mutex );
73
87
74
- if (time_after (expires , jiffies ))
75
- return sprintf (buf , "%u\n" ,
76
- jiffies_to_msecs (expires - jiffies ) / 1000 );
88
+ if (time_after (expires , jiffies ) || ktimespec .tv_sec > 0 )
89
+ return snprintf (buf , PAGE_SIZE , "%ld\n" , time_diff );
77
90
78
- return sprintf (buf , "0\n" );
91
+ return snprintf (buf , PAGE_SIZE , "0\n" );
79
92
}
80
93
81
94
static void idletimer_tg_work (struct work_struct * work )
@@ -95,6 +108,16 @@ static void idletimer_tg_expired(struct timer_list *t)
95
108
schedule_work (& timer -> work );
96
109
}
97
110
111
+ static enum alarmtimer_restart idletimer_tg_alarmproc (struct alarm * alarm ,
112
+ ktime_t now )
113
+ {
114
+ struct idletimer_tg * timer = alarm -> data ;
115
+
116
+ pr_debug ("alarm %s expired\n" , timer -> attr .attr .name );
117
+ schedule_work (& timer -> work );
118
+ return ALARMTIMER_NORESTART ;
119
+ }
120
+
98
121
static int idletimer_check_sysfs_name (const char * name , unsigned int size )
99
122
{
100
123
int ret ;
@@ -160,6 +183,68 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
160
183
return ret ;
161
184
}
162
185
186
+ static int idletimer_tg_create_v1 (struct idletimer_tg_info_v1 * info )
187
+ {
188
+ int ret ;
189
+
190
+ info -> timer = kmalloc (sizeof (* info -> timer ), GFP_KERNEL );
191
+ if (!info -> timer ) {
192
+ ret = - ENOMEM ;
193
+ goto out ;
194
+ }
195
+
196
+ ret = idletimer_check_sysfs_name (info -> label , sizeof (info -> label ));
197
+ if (ret < 0 )
198
+ goto out_free_timer ;
199
+
200
+ sysfs_attr_init (& info -> timer -> attr .attr );
201
+ info -> timer -> attr .attr .name = kstrdup (info -> label , GFP_KERNEL );
202
+ if (!info -> timer -> attr .attr .name ) {
203
+ ret = - ENOMEM ;
204
+ goto out_free_timer ;
205
+ }
206
+ info -> timer -> attr .attr .mode = 0444 ;
207
+ info -> timer -> attr .show = idletimer_tg_show ;
208
+
209
+ ret = sysfs_create_file (idletimer_tg_kobj , & info -> timer -> attr .attr );
210
+ if (ret < 0 ) {
211
+ pr_debug ("couldn't add file to sysfs" );
212
+ goto out_free_attr ;
213
+ }
214
+
215
+ /* notify userspace */
216
+ kobject_uevent (idletimer_tg_kobj ,KOBJ_ADD );
217
+
218
+ list_add (& info -> timer -> entry , & idletimer_tg_list );
219
+ pr_debug ("timer type value is %u" , info -> timer_type );
220
+ info -> timer -> timer_type = info -> timer_type ;
221
+ info -> timer -> refcnt = 1 ;
222
+
223
+ INIT_WORK (& info -> timer -> work , idletimer_tg_work );
224
+
225
+ if (info -> timer -> timer_type & XT_IDLETIMER_ALARM ) {
226
+ ktime_t tout ;
227
+ alarm_init (& info -> timer -> alarm , ALARM_BOOTTIME ,
228
+ idletimer_tg_alarmproc );
229
+ info -> timer -> alarm .data = info -> timer ;
230
+ tout = ktime_set (info -> timeout , 0 );
231
+ alarm_start_relative (& info -> timer -> alarm , tout );
232
+ } else {
233
+ timer_setup (& info -> timer -> timer , idletimer_tg_expired , 0 );
234
+ mod_timer (& info -> timer -> timer ,
235
+ msecs_to_jiffies (info -> timeout * 1000 ) + jiffies );
236
+ }
237
+
238
+ return 0 ;
239
+
240
+ out_free_attr :
241
+ kfree (info -> timer -> attr .attr .name );
242
+ out_free_timer :
243
+ kfree (info -> timer );
244
+ out :
245
+ return ret ;
246
+ }
247
+
163
248
/*
164
249
* The actual xt_tables plugin.
165
250
*/
@@ -177,13 +262,30 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb,
177
262
return XT_CONTINUE ;
178
263
}
179
264
180
- static int idletimer_tg_checkentry (const struct xt_tgchk_param * par )
265
+ /*
266
+ * The actual xt_tables plugin.
267
+ */
268
+ static unsigned int idletimer_tg_target_v1 (struct sk_buff * skb ,
269
+ const struct xt_action_param * par )
181
270
{
182
- struct idletimer_tg_info * info = par -> targinfo ;
183
- int ret ;
271
+ const struct idletimer_tg_info_v1 * info = par -> targinfo ;
184
272
185
- pr_debug ("checkentry targinfo%s\n" , info -> label );
273
+ pr_debug ("resetting timer %s, timeout period %u\n" ,
274
+ info -> label , info -> timeout );
275
+
276
+ if (info -> timer -> timer_type & XT_IDLETIMER_ALARM ) {
277
+ ktime_t tout = ktime_set (info -> timeout , 0 );
278
+ alarm_start_relative (& info -> timer -> alarm , tout );
279
+ } else {
280
+ mod_timer (& info -> timer -> timer ,
281
+ msecs_to_jiffies (info -> timeout * 1000 ) + jiffies );
282
+ }
186
283
284
+ return XT_CONTINUE ;
285
+ }
286
+
287
+ static int idletimer_tg_helper (struct idletimer_tg_info * info )
288
+ {
187
289
if (info -> timeout == 0 ) {
188
290
pr_debug ("timeout value is zero\n" );
189
291
return - EINVAL ;
@@ -198,7 +300,23 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
198
300
pr_debug ("label is empty or not nul-terminated\n" );
199
301
return - EINVAL ;
200
302
}
303
+ return 0 ;
304
+ }
201
305
306
+
307
+ static int idletimer_tg_checkentry (const struct xt_tgchk_param * par )
308
+ {
309
+ struct idletimer_tg_info * info = par -> targinfo ;
310
+ int ret ;
311
+
312
+ pr_debug ("checkentry targinfo%s\n" , info -> label );
313
+
314
+ ret = idletimer_tg_helper (info );
315
+ if (ret < 0 )
316
+ {
317
+ pr_debug ("checkentry helper return invalid\n" );
318
+ return - EINVAL ;
319
+ }
202
320
mutex_lock (& list_mutex );
203
321
204
322
info -> timer = __idletimer_tg_find_by_label (info -> label );
@@ -222,6 +340,65 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
222
340
return 0 ;
223
341
}
224
342
343
+ static int idletimer_tg_checkentry_v1 (const struct xt_tgchk_param * par )
344
+ {
345
+ struct idletimer_tg_info_v1 * info = par -> targinfo ;
346
+ int ret ;
347
+
348
+ pr_debug ("checkentry targinfo%s\n" , info -> label );
349
+
350
+ ret = idletimer_tg_helper ((struct idletimer_tg_info * )info );
351
+ if (ret < 0 )
352
+ {
353
+ pr_debug ("checkentry helper return invalid\n" );
354
+ return - EINVAL ;
355
+ }
356
+
357
+ if (info -> timer_type > XT_IDLETIMER_ALARM ) {
358
+ pr_debug ("invalid value for timer type\n" );
359
+ return - EINVAL ;
360
+ }
361
+
362
+ mutex_lock (& list_mutex );
363
+
364
+ info -> timer = __idletimer_tg_find_by_label (info -> label );
365
+ if (info -> timer ) {
366
+ if (info -> timer -> timer_type != info -> timer_type ) {
367
+ pr_debug ("Adding/Replacing rule with same label and different timer type is not allowed\n" );
368
+ mutex_unlock (& list_mutex );
369
+ return - EINVAL ;
370
+ }
371
+
372
+ info -> timer -> refcnt ++ ;
373
+ if (info -> timer_type & XT_IDLETIMER_ALARM ) {
374
+ /* calculate remaining expiry time */
375
+ ktime_t tout = alarm_expires_remaining (& info -> timer -> alarm );
376
+ struct timespec64 ktimespec = ktime_to_timespec64 (tout );
377
+
378
+ if (ktimespec .tv_sec > 0 ) {
379
+ pr_debug ("time_expiry_remaining %lld\n" ,
380
+ ktimespec .tv_sec );
381
+ alarm_start_relative (& info -> timer -> alarm , tout );
382
+ }
383
+ } else {
384
+ mod_timer (& info -> timer -> timer ,
385
+ msecs_to_jiffies (info -> timeout * 1000 ) + jiffies );
386
+ }
387
+ pr_debug ("increased refcnt of timer %s to %u\n" ,
388
+ info -> label , info -> timer -> refcnt );
389
+ } else {
390
+ ret = idletimer_tg_create_v1 (info );
391
+ if (ret < 0 ) {
392
+ pr_debug ("failed to create timer\n" );
393
+ mutex_unlock (& list_mutex );
394
+ return ret ;
395
+ }
396
+ }
397
+
398
+ mutex_unlock (& list_mutex );
399
+ return 0 ;
400
+ }
401
+
225
402
static void idletimer_tg_destroy (const struct xt_tgdtor_param * par )
226
403
{
227
404
const struct idletimer_tg_info * info = par -> targinfo ;
@@ -247,7 +424,38 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
247
424
mutex_unlock (& list_mutex );
248
425
}
249
426
250
- static struct xt_target idletimer_tg __read_mostly = {
427
+ static void idletimer_tg_destroy_v1 (const struct xt_tgdtor_param * par )
428
+ {
429
+ const struct idletimer_tg_info_v1 * info = par -> targinfo ;
430
+
431
+ pr_debug ("destroy targinfo %s\n" , info -> label );
432
+
433
+ mutex_lock (& list_mutex );
434
+
435
+ if (-- info -> timer -> refcnt == 0 ) {
436
+ pr_debug ("deleting timer %s\n" , info -> label );
437
+
438
+ list_del (& info -> timer -> entry );
439
+ if (info -> timer -> timer_type & XT_IDLETIMER_ALARM ) {
440
+ alarm_cancel (& info -> timer -> alarm );
441
+ } else {
442
+ del_timer_sync (& info -> timer -> timer );
443
+ }
444
+ cancel_work_sync (& info -> timer -> work );
445
+ sysfs_remove_file (idletimer_tg_kobj , & info -> timer -> attr .attr );
446
+ kfree (info -> timer -> attr .attr .name );
447
+ kfree (info -> timer );
448
+ } else {
449
+ pr_debug ("decreased refcnt of timer %s to %u\n" ,
450
+ info -> label , info -> timer -> refcnt );
451
+ }
452
+
453
+ mutex_unlock (& list_mutex );
454
+ }
455
+
456
+
457
+ static struct xt_target idletimer_tg [] __read_mostly = {
458
+ {
251
459
.name = "IDLETIMER" ,
252
460
.family = NFPROTO_UNSPEC ,
253
461
.target = idletimer_tg_target ,
@@ -256,6 +464,20 @@ static struct xt_target idletimer_tg __read_mostly = {
256
464
.checkentry = idletimer_tg_checkentry ,
257
465
.destroy = idletimer_tg_destroy ,
258
466
.me = THIS_MODULE ,
467
+ },
468
+ {
469
+ .name = "IDLETIMER" ,
470
+ .family = NFPROTO_UNSPEC ,
471
+ .revision = 1 ,
472
+ .target = idletimer_tg_target_v1 ,
473
+ .targetsize = sizeof (struct idletimer_tg_info_v1 ),
474
+ .usersize = offsetof(struct idletimer_tg_info_v1 , timer ),
475
+ .checkentry = idletimer_tg_checkentry_v1 ,
476
+ .destroy = idletimer_tg_destroy_v1 ,
477
+ .me = THIS_MODULE ,
478
+ },
479
+
480
+
259
481
};
260
482
261
483
static struct class * idletimer_tg_class ;
@@ -283,7 +505,8 @@ static int __init idletimer_tg_init(void)
283
505
284
506
idletimer_tg_kobj = & idletimer_tg_device -> kobj ;
285
507
286
- err = xt_register_target (& idletimer_tg );
508
+ err = xt_register_targets (idletimer_tg , ARRAY_SIZE (idletimer_tg ));
509
+
287
510
if (err < 0 ) {
288
511
pr_debug ("couldn't register xt target\n" );
289
512
goto out_dev ;
@@ -300,7 +523,7 @@ static int __init idletimer_tg_init(void)
300
523
301
524
static void __exit idletimer_tg_exit (void )
302
525
{
303
- xt_unregister_target ( & idletimer_tg );
526
+ xt_unregister_targets ( idletimer_tg , ARRAY_SIZE ( idletimer_tg ) );
304
527
305
528
device_destroy (idletimer_tg_class , MKDEV (0 , 0 ));
306
529
class_destroy (idletimer_tg_class );
0 commit comments