root/net/netfilter/xt_IDLETIMER.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __idletimer_tg_find_by_label
  2. idletimer_tg_show
  3. idletimer_tg_work
  4. idletimer_tg_expired
  5. idletimer_check_sysfs_name
  6. idletimer_tg_create
  7. idletimer_tg_target
  8. idletimer_tg_checkentry
  9. idletimer_tg_destroy
  10. idletimer_tg_init
  11. idletimer_tg_exit

   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/list.h>
  22 #include <linux/mutex.h>
  23 #include <linux/netfilter.h>
  24 #include <linux/netfilter/x_tables.h>
  25 #include <linux/netfilter/xt_IDLETIMER.h>
  26 #include <linux/kdev_t.h>
  27 #include <linux/kobject.h>
  28 #include <linux/workqueue.h>
  29 #include <linux/sysfs.h>
  30 
  31 struct idletimer_tg {
  32         struct list_head entry;
  33         struct timer_list timer;
  34         struct work_struct work;
  35 
  36         struct kobject *kobj;
  37         struct device_attribute attr;
  38 
  39         unsigned int refcnt;
  40 };
  41 
  42 static LIST_HEAD(idletimer_tg_list);
  43 static DEFINE_MUTEX(list_mutex);
  44 
  45 static struct kobject *idletimer_tg_kobj;
  46 
  47 static
  48 struct idletimer_tg *__idletimer_tg_find_by_label(const char *label)
  49 {
  50         struct idletimer_tg *entry;
  51 
  52         list_for_each_entry(entry, &idletimer_tg_list, entry) {
  53                 if (!strcmp(label, entry->attr.attr.name))
  54                         return entry;
  55         }
  56 
  57         return NULL;
  58 }
  59 
  60 static ssize_t idletimer_tg_show(struct device *dev,
  61                                  struct device_attribute *attr, char *buf)
  62 {
  63         struct idletimer_tg *timer;
  64         unsigned long expires = 0;
  65 
  66         mutex_lock(&list_mutex);
  67 
  68         timer = __idletimer_tg_find_by_label(attr->attr.name);
  69         if (timer)
  70                 expires = timer->timer.expires;
  71 
  72         mutex_unlock(&list_mutex);
  73 
  74         if (time_after(expires, jiffies))
  75                 return sprintf(buf, "%u\n",
  76                                jiffies_to_msecs(expires - jiffies) / 1000);
  77 
  78         return sprintf(buf, "0\n");
  79 }
  80 
  81 static void idletimer_tg_work(struct work_struct *work)
  82 {
  83         struct idletimer_tg *timer = container_of(work, struct idletimer_tg,
  84                                                   work);
  85 
  86         sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name);
  87 }
  88 
  89 static void idletimer_tg_expired(struct timer_list *t)
  90 {
  91         struct idletimer_tg *timer = from_timer(timer, t, timer);
  92 
  93         pr_debug("timer %s expired\n", timer->attr.attr.name);
  94 
  95         schedule_work(&timer->work);
  96 }
  97 
  98 static int idletimer_check_sysfs_name(const char *name, unsigned int size)
  99 {
 100         int ret;
 101 
 102         ret = xt_check_proc_name(name, size);
 103         if (ret < 0)
 104                 return ret;
 105 
 106         if (!strcmp(name, "power") ||
 107             !strcmp(name, "subsystem") ||
 108             !strcmp(name, "uevent"))
 109                 return -EINVAL;
 110 
 111         return 0;
 112 }
 113 
 114 static int idletimer_tg_create(struct idletimer_tg_info *info)
 115 {
 116         int ret;
 117 
 118         info->timer = kmalloc(sizeof(*info->timer), GFP_KERNEL);
 119         if (!info->timer) {
 120                 ret = -ENOMEM;
 121                 goto out;
 122         }
 123 
 124         ret = idletimer_check_sysfs_name(info->label, sizeof(info->label));
 125         if (ret < 0)
 126                 goto out_free_timer;
 127 
 128         sysfs_attr_init(&info->timer->attr.attr);
 129         info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
 130         if (!info->timer->attr.attr.name) {
 131                 ret = -ENOMEM;
 132                 goto out_free_timer;
 133         }
 134         info->timer->attr.attr.mode = 0444;
 135         info->timer->attr.show = idletimer_tg_show;
 136 
 137         ret = sysfs_create_file(idletimer_tg_kobj, &info->timer->attr.attr);
 138         if (ret < 0) {
 139                 pr_debug("couldn't add file to sysfs");
 140                 goto out_free_attr;
 141         }
 142 
 143         list_add(&info->timer->entry, &idletimer_tg_list);
 144 
 145         timer_setup(&info->timer->timer, idletimer_tg_expired, 0);
 146         info->timer->refcnt = 1;
 147 
 148         INIT_WORK(&info->timer->work, idletimer_tg_work);
 149 
 150         mod_timer(&info->timer->timer,
 151                   msecs_to_jiffies(info->timeout * 1000) + jiffies);
 152 
 153         return 0;
 154 
 155 out_free_attr:
 156         kfree(info->timer->attr.attr.name);
 157 out_free_timer:
 158         kfree(info->timer);
 159 out:
 160         return ret;
 161 }
 162 
 163 /*
 164  * The actual xt_tables plugin.
 165  */
 166 static unsigned int idletimer_tg_target(struct sk_buff *skb,
 167                                          const struct xt_action_param *par)
 168 {
 169         const struct idletimer_tg_info *info = par->targinfo;
 170 
 171         pr_debug("resetting timer %s, timeout period %u\n",
 172                  info->label, info->timeout);
 173 
 174         mod_timer(&info->timer->timer,
 175                   msecs_to_jiffies(info->timeout * 1000) + jiffies);
 176 
 177         return XT_CONTINUE;
 178 }
 179 
 180 static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
 181 {
 182         struct idletimer_tg_info *info = par->targinfo;
 183         int ret;
 184 
 185         pr_debug("checkentry targinfo%s\n", info->label);
 186 
 187         if (info->timeout == 0) {
 188                 pr_debug("timeout value is zero\n");
 189                 return -EINVAL;
 190         }
 191         if (info->timeout >= INT_MAX / 1000) {
 192                 pr_debug("timeout value is too big\n");
 193                 return -EINVAL;
 194         }
 195         if (info->label[0] == '\0' ||
 196             strnlen(info->label,
 197                     MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) {
 198                 pr_debug("label is empty or not nul-terminated\n");
 199                 return -EINVAL;
 200         }
 201 
 202         mutex_lock(&list_mutex);
 203 
 204         info->timer = __idletimer_tg_find_by_label(info->label);
 205         if (info->timer) {
 206                 info->timer->refcnt++;
 207                 mod_timer(&info->timer->timer,
 208                           msecs_to_jiffies(info->timeout * 1000) + jiffies);
 209 
 210                 pr_debug("increased refcnt of timer %s to %u\n",
 211                          info->label, info->timer->refcnt);
 212         } else {
 213                 ret = idletimer_tg_create(info);
 214                 if (ret < 0) {
 215                         pr_debug("failed to create timer\n");
 216                         mutex_unlock(&list_mutex);
 217                         return ret;
 218                 }
 219         }
 220 
 221         mutex_unlock(&list_mutex);
 222         return 0;
 223 }
 224 
 225 static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
 226 {
 227         const struct idletimer_tg_info *info = par->targinfo;
 228 
 229         pr_debug("destroy targinfo %s\n", info->label);
 230 
 231         mutex_lock(&list_mutex);
 232 
 233         if (--info->timer->refcnt == 0) {
 234                 pr_debug("deleting timer %s\n", info->label);
 235 
 236                 list_del(&info->timer->entry);
 237                 del_timer_sync(&info->timer->timer);
 238                 cancel_work_sync(&info->timer->work);
 239                 sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
 240                 kfree(info->timer->attr.attr.name);
 241                 kfree(info->timer);
 242         } else {
 243                 pr_debug("decreased refcnt of timer %s to %u\n",
 244                          info->label, info->timer->refcnt);
 245         }
 246 
 247         mutex_unlock(&list_mutex);
 248 }
 249 
 250 static struct xt_target idletimer_tg __read_mostly = {
 251         .name           = "IDLETIMER",
 252         .family         = NFPROTO_UNSPEC,
 253         .target         = idletimer_tg_target,
 254         .targetsize     = sizeof(struct idletimer_tg_info),
 255         .usersize       = offsetof(struct idletimer_tg_info, timer),
 256         .checkentry     = idletimer_tg_checkentry,
 257         .destroy        = idletimer_tg_destroy,
 258         .me             = THIS_MODULE,
 259 };
 260 
 261 static struct class *idletimer_tg_class;
 262 
 263 static struct device *idletimer_tg_device;
 264 
 265 static int __init idletimer_tg_init(void)
 266 {
 267         int err;
 268 
 269         idletimer_tg_class = class_create(THIS_MODULE, "xt_idletimer");
 270         err = PTR_ERR(idletimer_tg_class);
 271         if (IS_ERR(idletimer_tg_class)) {
 272                 pr_debug("couldn't register device class\n");
 273                 goto out;
 274         }
 275 
 276         idletimer_tg_device = device_create(idletimer_tg_class, NULL,
 277                                             MKDEV(0, 0), NULL, "timers");
 278         err = PTR_ERR(idletimer_tg_device);
 279         if (IS_ERR(idletimer_tg_device)) {
 280                 pr_debug("couldn't register system device\n");
 281                 goto out_class;
 282         }
 283 
 284         idletimer_tg_kobj = &idletimer_tg_device->kobj;
 285 
 286         err = xt_register_target(&idletimer_tg);
 287         if (err < 0) {
 288                 pr_debug("couldn't register xt target\n");
 289                 goto out_dev;
 290         }
 291 
 292         return 0;
 293 out_dev:
 294         device_destroy(idletimer_tg_class, MKDEV(0, 0));
 295 out_class:
 296         class_destroy(idletimer_tg_class);
 297 out:
 298         return err;
 299 }
 300 
 301 static void __exit idletimer_tg_exit(void)
 302 {
 303         xt_unregister_target(&idletimer_tg);
 304 
 305         device_destroy(idletimer_tg_class, MKDEV(0, 0));
 306         class_destroy(idletimer_tg_class);
 307 }
 308 
 309 module_init(idletimer_tg_init);
 310 module_exit(idletimer_tg_exit);
 311 
 312 MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
 313 MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
 314 MODULE_DESCRIPTION("Xtables: idle time monitor");
 315 MODULE_LICENSE("GPL v2");
 316 MODULE_ALIAS("ipt_IDLETIMER");
 317 MODULE_ALIAS("ip6t_IDLETIMER");

/* [<][>][^][v][top][bottom][index][help] */