]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - net/ipv4/netfilter/ipt_IDLETIMER.c
6432192cdeb0d1db29e0068c31653e09c50dee17
[linux-2.6-omap-h63xx.git] / net / ipv4 / netfilter / ipt_IDLETIMER.c
1 /*
2  * linux/net/ipv4/netfilter/ipt_IDLETIMER.c
3  *
4  * Netfilter module to trigger a timer when packet matches.
5  * After timer expires a kevent will be sent.
6  *
7  * Copyright (C) 2004 Nokia Corporation. All rights reserved.
8  * Written by Timo Teras <ext-timo.teras@nokia.com>
9  *
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.
13  *
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.
18  *
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
22  * 02110-1301 USA
23  */
24
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>
37
38 #if 0
39 #define DEBUGP(format, args...) printk("%s:%s:" format, \
40                                        __FILE__, __FUNCTION__ , ## args)
41 #else
42 #define DEBUGP(format, args...)
43 #endif
44
45 /*
46  * Internal timer management.
47  */
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);
51
52 struct utimer_t {
53         char name[IFNAMSIZ];
54         struct list_head entry;
55         struct timer_list timer;
56         struct work_struct work;
57 };
58
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);
62
63 static void utimer_delete(struct utimer_t *timer)
64 {
65         DEBUGP("Deleting timer '%s'\n", timer->name);
66
67         list_del(&timer->entry);
68         del_timer_sync(&timer->timer);
69         kfree(timer);
70 }
71
72 static void utimer_work(struct work_struct *work)
73 {
74         struct utimer_t *timer = container_of(work, struct utimer_t, work);
75         struct net_device *netdev;
76
77         netdev = dev_get_by_name(&init_net, timer->name);
78
79         if (netdev != NULL) {
80                 sysfs_notify(&netdev->dev.kobj, NULL,
81                              "idletimer");
82                 dev_put(netdev);
83         }
84 }
85
86 static void utimer_expired(unsigned long data)
87 {
88         struct utimer_t *timer = (struct utimer_t *) data;
89
90         DEBUGP("Timer '%s' expired\n", timer->name);
91
92         spin_lock_bh(&list_lock);
93         utimer_delete(timer);
94         spin_unlock_bh(&list_lock);
95
96         schedule_work(&timer->work);
97 }
98
99 static struct utimer_t *utimer_create(const char *name)
100 {
101         struct utimer_t *timer;
102
103         timer = kmalloc(sizeof(struct utimer_t), GFP_ATOMIC);
104         if (timer == NULL)
105                 return NULL;
106
107         list_add(&timer->entry, &active_utimer_head);
108         strlcpy(timer->name, name, sizeof(timer->name));
109
110         init_timer(&timer->timer);
111         timer->timer.function = utimer_expired;
112         timer->timer.data = (unsigned long) timer;
113
114         INIT_WORK(&timer->work, utimer_work);
115
116         DEBUGP("Created timer '%s'\n", timer->name);
117
118         return timer;
119 }
120
121 static struct utimer_t *__utimer_find(const char *name)
122 {
123         struct utimer_t *entry;
124
125         list_for_each_entry(entry, &active_utimer_head, entry) {
126                 if (strcmp(name, entry->name) == 0) {
127                         return entry;
128                 }
129         }
130
131         return NULL;
132 }
133
134 static void utimer_modify(const char *name,
135                           unsigned long expires)
136 {
137         struct utimer_t *timer;
138
139         DEBUGP("Modifying timer '%s'\n", name);
140         spin_lock_bh(&list_lock);
141         timer = __utimer_find(name);
142         if (timer == NULL)
143                 timer = utimer_create(name);
144         mod_timer(&timer->timer, expires);
145         spin_unlock_bh(&list_lock);
146 }
147
148 static ssize_t utimer_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
149 {
150         struct utimer_t *timer;
151         unsigned long expires = 0;
152         struct net_device *netdev = container_of(dev, struct net_device, dev);
153
154         spin_lock_bh(&list_lock);
155         timer = __utimer_find(netdev->name);
156         if (timer)
157                 expires = timer->timer.expires;
158         spin_unlock_bh(&list_lock);
159
160         if (expires)
161                 return sprintf(buf, "%lu\n", (expires-jiffies) / HZ);
162
163         return sprintf(buf, "0\n");
164 }
165
166 static ssize_t utimer_attr_store(struct device *dev, struct device_attribute *attr,
167                                  const char *buf, size_t count)
168 {
169         int expires;
170         struct net_device *netdev = container_of(dev, struct net_device, dev);
171
172         if (sscanf(buf, "%d", &expires) == 1) {
173                 if (expires > 0)
174                         utimer_modify(netdev->name,
175                                       jiffies+HZ*(unsigned long)expires);
176         }
177
178         return count;
179 }
180
181 static int utimer_notifier_call(struct notifier_block *this,
182                                 unsigned long event, void *ptr)
183 {
184         struct net_device *dev = ptr;
185         int ret = NOTIFY_DONE;
186
187         switch (event) {
188         case NETDEV_UP:
189                 DEBUGP("NETDEV_UP: %s\n", dev->name);
190                 ret = device_create_file(&dev->dev,
191                                          &dev_attr_idletimer);
192                 break;
193         case NETDEV_DOWN:
194                 DEBUGP("NETDEV_DOWN: %s\n", dev->name);
195                 device_remove_file(&dev->dev,
196                                          &dev_attr_idletimer);
197                 break;
198         }
199
200         return ret;
201 }
202
203 static struct notifier_block utimer_notifier_block = {
204         .notifier_call  = utimer_notifier_call,
205 };
206
207
208 static int utimer_init(void)
209 {
210         return register_netdevice_notifier(&utimer_notifier_block);
211 }
212
213 static void utimer_fini(void)
214 {
215         struct utimer_t *entry, *next;
216         struct net_device *dev;
217
218         list_for_each_entry_safe(entry, next, &active_utimer_head, entry)
219                 utimer_delete(entry);
220
221         rtnl_lock();
222         unregister_netdevice_notifier(&utimer_notifier_block);
223         for_each_netdev(&init_net, dev)
224                 utimer_notifier_call(&utimer_notifier_block,
225                                      NETDEV_DOWN, dev);
226         rtnl_unlock();
227 }
228
229 /*
230  * The actual iptables plugin.
231  */
232 static unsigned int ipt_idletimer_target(struct sk_buff *pskb,
233                                          const struct net_device *in,
234                                          const struct net_device *out,
235                                          unsigned int hooknum,
236                                          const struct xt_target *xttarget,
237                                          const void *targinfo)
238 {
239         struct ipt_idletimer_info *target = (struct ipt_idletimer_info*) targinfo;
240         unsigned long expires;
241
242         expires = jiffies + HZ*target->timeout;
243
244         if (in != NULL)
245                 utimer_modify(in->name, expires);
246
247         if (out != NULL)
248                 utimer_modify(out->name, expires);
249
250         return XT_CONTINUE;
251 }
252
253 static bool ipt_idletimer_checkentry(const char *tablename,
254                                     const void *e,
255                                     const struct xt_target *target,
256                                     void *targinfo,
257                                     unsigned int hookmask)
258 {
259         struct ipt_idletimer_info *info =
260                 (struct ipt_idletimer_info *) targinfo;
261
262         if (info->timeout == 0) {
263                 DEBUGP("timeout value is zero\n");
264                 return 0;
265         }
266
267         return true;
268 }
269
270 static struct xt_target ipt_idletimer = {
271         .name           = "IDLETIMER",
272         .target         = ipt_idletimer_target,
273         .checkentry     = ipt_idletimer_checkentry,
274         .me             = THIS_MODULE,
275         .targetsize     = sizeof(struct ipt_idletimer_info),
276 };
277
278 static int __init init(void)
279 {
280         int ret;
281
282         ret = utimer_init();
283         if (ret)
284                 return ret;
285
286         if (xt_register_target(&ipt_idletimer)) {
287                 utimer_fini();
288                 return -EINVAL;
289         }
290
291         return 0;
292 }
293
294 static void __exit fini(void)
295 {
296         xt_unregister_target(&ipt_idletimer);
297         utimer_fini();
298 }
299
300 module_init(init);
301 module_exit(fini);
302
303 MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
304 MODULE_DESCRIPTION("iptables idletimer target module");
305 MODULE_LICENSE("GPL");