• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/net/netfilter/
1/*
2 * xt_LED.c - netfilter target to make LEDs blink upon packet matches
3 *
4 * Copyright (C) 2008 Adam Nielsen <a.nielsen@shikadi.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA.
19 *
20 */
21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22#include <linux/module.h>
23#include <linux/skbuff.h>
24#include <linux/netfilter/x_tables.h>
25#include <linux/slab.h>
26#include <linux/leds.h>
27#include <linux/mutex.h>
28
29#include <linux/netfilter/xt_LED.h>
30
31MODULE_LICENSE("GPL");
32MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
33MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
34
35static LIST_HEAD(xt_led_triggers);
36static DEFINE_MUTEX(xt_led_mutex);
37
38/*
39 * This is declared in here (the kernel module) only, to avoid having these
40 * dependencies in userspace code.  This is what xt_led_info.internal_data
41 * points to.
42 */
43struct xt_led_info_internal {
44	struct list_head list;
45	int refcnt;
46	char *trigger_id;
47	struct led_trigger netfilter_led_trigger;
48	struct timer_list timer;
49};
50
51static unsigned int
52led_tg(struct sk_buff *skb, const struct xt_action_param *par)
53{
54	const struct xt_led_info *ledinfo = par->targinfo;
55	struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
56
57	/*
58	 * If "always blink" is enabled, and there's still some time until the
59	 * LED will switch off, briefly switch it off now.
60	 */
61	if ((ledinfo->delay > 0) && ledinfo->always_blink &&
62	    timer_pending(&ledinternal->timer))
63		led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
64
65	led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
66
67	/* If there's a positive delay, start/update the timer */
68	if (ledinfo->delay > 0) {
69		mod_timer(&ledinternal->timer,
70			  jiffies + msecs_to_jiffies(ledinfo->delay));
71
72	/* Otherwise if there was no delay given, blink as fast as possible */
73	} else if (ledinfo->delay == 0) {
74		led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
75	}
76
77	/* else the delay is negative, which means switch on and stay on */
78
79	return XT_CONTINUE;
80}
81
82static void led_timeout_callback(unsigned long data)
83{
84	struct xt_led_info_internal *ledinternal = (struct xt_led_info_internal *)data;
85
86	led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
87}
88
89static struct xt_led_info_internal *led_trigger_lookup(const char *name)
90{
91	struct xt_led_info_internal *ledinternal;
92
93	list_for_each_entry(ledinternal, &xt_led_triggers, list) {
94		if (!strcmp(name, ledinternal->netfilter_led_trigger.name)) {
95			return ledinternal;
96		}
97	}
98	return NULL;
99}
100
101static int led_tg_check(const struct xt_tgchk_param *par)
102{
103	struct xt_led_info *ledinfo = par->targinfo;
104	struct xt_led_info_internal *ledinternal;
105	int err;
106
107	if (ledinfo->id[0] == '\0') {
108		pr_info("No 'id' parameter given.\n");
109		return -EINVAL;
110	}
111
112	mutex_lock(&xt_led_mutex);
113
114	ledinternal = led_trigger_lookup(ledinfo->id);
115	if (ledinternal) {
116		ledinternal->refcnt++;
117		goto out;
118	}
119
120	err = -ENOMEM;
121	ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
122	if (!ledinternal)
123		goto exit_mutex_only;
124
125	ledinternal->trigger_id = kstrdup(ledinfo->id, GFP_KERNEL);
126	if (!ledinternal->trigger_id)
127		goto exit_internal_alloc;
128
129	ledinternal->refcnt = 1;
130	ledinternal->netfilter_led_trigger.name = ledinternal->trigger_id;
131
132	err = led_trigger_register(&ledinternal->netfilter_led_trigger);
133	if (err) {
134		pr_warning("led_trigger_register() failed\n");
135		if (err == -EEXIST)
136			pr_warning("Trigger name is already in use.\n");
137		goto exit_alloc;
138	}
139
140	/* See if we need to set up a timer */
141	if (ledinfo->delay > 0)
142		setup_timer(&ledinternal->timer, led_timeout_callback,
143			    (unsigned long)ledinternal);
144
145	list_add_tail(&ledinternal->list, &xt_led_triggers);
146
147out:
148	mutex_unlock(&xt_led_mutex);
149
150	ledinfo->internal_data = ledinternal;
151
152	return 0;
153
154exit_alloc:
155	kfree(ledinternal->trigger_id);
156
157exit_internal_alloc:
158	kfree(ledinternal);
159
160exit_mutex_only:
161	mutex_unlock(&xt_led_mutex);
162
163	return err;
164}
165
166static void led_tg_destroy(const struct xt_tgdtor_param *par)
167{
168	const struct xt_led_info *ledinfo = par->targinfo;
169	struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
170
171	mutex_lock(&xt_led_mutex);
172
173	if (--ledinternal->refcnt) {
174		mutex_unlock(&xt_led_mutex);
175		return;
176	}
177
178	list_del(&ledinternal->list);
179
180	if (ledinfo->delay > 0)
181		del_timer_sync(&ledinternal->timer);
182
183	led_trigger_unregister(&ledinternal->netfilter_led_trigger);
184
185	mutex_unlock(&xt_led_mutex);
186
187	kfree(ledinternal->trigger_id);
188	kfree(ledinternal);
189}
190
191static struct xt_target led_tg_reg __read_mostly = {
192	.name		= "LED",
193	.revision	= 0,
194	.family		= NFPROTO_UNSPEC,
195	.target		= led_tg,
196	.targetsize	= sizeof(struct xt_led_info),
197	.checkentry	= led_tg_check,
198	.destroy	= led_tg_destroy,
199	.me		= THIS_MODULE,
200};
201
202static int __init led_tg_init(void)
203{
204	return xt_register_target(&led_tg_reg);
205}
206
207static void __exit led_tg_exit(void)
208{
209	xt_unregister_target(&led_tg_reg);
210}
211
212module_init(led_tg_init);
213module_exit(led_tg_exit);
214