2 * linux/net/ipv4/netfilter/ipt_IDLETIMER.c
4 * Netfilter module to trigger a timer when packet matches.
5 * After timer expires a kevent will be sent.
7 * Copyright (C) 2004 Nokia Corporation. All rights reserved.
8 * Written by Timo Teras <ext-timo.teras@nokia.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25 #include <linux/module.h>
26 #include <linux/skbuff.h>
27 #include <linux/timer.h>
28 #include <linux/list.h>
29 #include <linux/spinlock.h>
30 #include <linux/notifier.h>
31 #include <linux/netfilter.h>
32 #include <linux/rtnetlink.h>
33 #include <linux/netfilter/x_tables.h>
34 #include <linux/netfilter_ipv4/ipt_IDLETIMER.h>
35 #include <linux/kobject.h>
36 #include <linux/workqueue.h>
39 #define DEBUGP(format, args...) printk("%s:%s:" format, \
40 __FILE__, __FUNCTION__ , ## args)
42 #define DEBUGP(format, args...)
46 * Internal timer management.
48 static ssize_t utimer_attr_show(struct device *, struct device_attribute *attr, char *buf);
49 static ssize_t utimer_attr_store(struct device *, struct device_attribute *attr,
50 const char *buf, size_t count);
54 struct list_head entry;
55 struct timer_list timer;
56 struct work_struct work;
59 static LIST_HEAD(active_utimer_head);
60 static DEFINE_SPINLOCK(list_lock);
61 static DEVICE_ATTR(idletimer, 0644, utimer_attr_show, utimer_attr_store);
63 static void utimer_delete(struct utimer_t *timer)
65 DEBUGP("Deleting timer '%s'\n", timer->name);
67 list_del(&timer->entry);
68 del_timer_sync(&timer->timer);
72 static void utimer_work(struct work_struct *work)
74 struct utimer_t *timer = container_of(work, struct utimer_t, work);
75 struct net_device *netdev;
77 netdev = dev_get_by_name(timer->name);
80 sysfs_notify(&netdev->dev.kobj, NULL,
86 static void utimer_expired(unsigned long data)
88 struct utimer_t *timer = (struct utimer_t *) data;
90 DEBUGP("Timer '%s' expired\n", timer->name);
92 spin_lock_bh(&list_lock);
94 spin_unlock_bh(&list_lock);
96 schedule_work(&timer->work);
99 static struct utimer_t *utimer_create(const char *name)
101 struct utimer_t *timer;
103 timer = kmalloc(sizeof(struct utimer_t), GFP_ATOMIC);
107 list_add(&timer->entry, &active_utimer_head);
108 strlcpy(timer->name, name, sizeof(timer->name));
110 init_timer(&timer->timer);
111 timer->timer.function = utimer_expired;
112 timer->timer.data = (unsigned long) timer;
114 INIT_WORK(&timer->work, utimer_work);
116 DEBUGP("Created timer '%s'\n", timer->name);
121 static struct utimer_t *__utimer_find(const char *name)
123 struct utimer_t *entry;
125 list_for_each_entry(entry, &active_utimer_head, entry) {
126 if (strcmp(name, entry->name) == 0) {
134 static void utimer_modify(const char *name,
135 unsigned long expires)
137 struct utimer_t *timer;
139 DEBUGP("Modifying timer '%s'\n", name);
140 spin_lock_bh(&list_lock);
141 timer = __utimer_find(name);
143 timer = utimer_create(name);
144 mod_timer(&timer->timer, expires);
145 spin_unlock_bh(&list_lock);
148 static ssize_t utimer_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
150 struct utimer_t *timer;
151 unsigned long expires = 0;
152 struct net_device *netdev = container_of(dev, struct net_device, dev);
154 spin_lock_bh(&list_lock);
155 timer = __utimer_find(netdev->name);
157 expires = timer->timer.expires;
158 spin_unlock_bh(&list_lock);
161 return sprintf(buf, "%lu\n", (expires-jiffies) / HZ);
163 return sprintf(buf, "0\n");
166 static ssize_t utimer_attr_store(struct device *dev, struct device_attribute *attr,
167 const char *buf, size_t count)
170 struct net_device *netdev = container_of(dev, struct net_device, dev);
172 if (sscanf(buf, "%d", &expires) == 1) {
174 utimer_modify(netdev->name,
175 jiffies+HZ*(unsigned long)expires);
181 static int utimer_notifier_call(struct notifier_block *this,
182 unsigned long event, void *ptr)
184 struct net_device *dev = ptr;
188 DEBUGP("NETDEV_UP: %s\n", dev->name);
189 device_create_file(&dev->dev,
190 &dev_attr_idletimer);
193 DEBUGP("NETDEV_DOWN: %s\n", dev->name);
194 device_remove_file(&dev->dev,
195 &dev_attr_idletimer);
202 static struct notifier_block utimer_notifier_block = {
203 .notifier_call = utimer_notifier_call,
207 static int utimer_init(void)
209 return register_netdevice_notifier(&utimer_notifier_block);
212 static void utimer_fini(void)
214 struct utimer_t *entry, *next;
215 struct net_device *dev;
217 list_for_each_entry_safe(entry, next, &active_utimer_head, entry)
218 utimer_delete(entry);
221 unregister_netdevice_notifier(&utimer_notifier_block);
223 utimer_notifier_call(&utimer_notifier_block,
229 * The actual iptables plugin.
231 static unsigned int ipt_idletimer_target(struct sk_buff **pskb,
232 const struct net_device *in,
233 const struct net_device *out,
234 unsigned int hooknum,
235 const struct xt_target *xttarget,
236 const void *targinfo)
238 struct ipt_idletimer_info *target = (struct ipt_idletimer_info*) targinfo;
239 unsigned long expires;
241 expires = jiffies + HZ*target->timeout;
244 utimer_modify(in->name, expires);
247 utimer_modify(out->name, expires);
252 static int ipt_idletimer_checkentry(const char *tablename,
254 const struct xt_target *target,
256 unsigned int hookmask)
258 struct ipt_idletimer_info *info =
259 (struct ipt_idletimer_info *) targinfo;
261 if (info->timeout == 0) {
262 DEBUGP("timeout value is zero\n");
269 static struct xt_target ipt_idletimer = {
271 .target = ipt_idletimer_target,
272 .checkentry = ipt_idletimer_checkentry,
274 .targetsize = sizeof(struct ipt_idletimer_info),
277 static int __init init(void)
285 if (xt_register_target(&ipt_idletimer)) {
293 static void __exit fini(void)
295 xt_unregister_target(&ipt_idletimer);
302 MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
303 MODULE_DESCRIPTION("iptables idletimer target module");
304 MODULE_LICENSE("GPL");