aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorAdam Nielsen <a.nielsen@shikadi.net>2010-04-09 10:51:40 -0400
committerPatrick McHardy <kaber@trash.net>2010-04-09 10:51:40 -0400
commitb660d0485efeff743c72f1be2185832de8477a24 (patch)
tree8ea3c2babf7f42d991c35370ec3a349eb4d72a31 /net/netfilter
parented86308f6179d8fa6151c2d0f652aad0091548e2 (diff)
netfilter: xt_LED: add refcounts to LED target
Add reference counting to the netfilter LED target, to fix errors when multiple rules point to the same target ("LED trigger already exists"). Signed-off-by: Adam Nielsen <a.nielsen@shikadi.net> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/xt_LED.c69
1 files changed, 63 insertions, 6 deletions
diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c
index efcf56db23e8..bd102c77d1f0 100644
--- a/net/netfilter/xt_LED.c
+++ b/net/netfilter/xt_LED.c
@@ -31,12 +31,18 @@ MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>"); 31MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
32MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match"); 32MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
33 33
34static LIST_HEAD(xt_led_triggers);
35static DEFINE_MUTEX(xt_led_mutex);
36
34/* 37/*
35 * This is declared in here (the kernel module) only, to avoid having these 38 * This is declared in here (the kernel module) only, to avoid having these
36 * dependencies in userspace code. This is what xt_led_info.internal_data 39 * dependencies in userspace code. This is what xt_led_info.internal_data
37 * points to. 40 * points to.
38 */ 41 */
39struct xt_led_info_internal { 42struct xt_led_info_internal {
43 struct list_head list;
44 int refcnt;
45 char *trigger_id;
40 struct led_trigger netfilter_led_trigger; 46 struct led_trigger netfilter_led_trigger;
41 struct timer_list timer; 47 struct timer_list timer;
42}; 48};
@@ -53,7 +59,7 @@ led_tg(struct sk_buff *skb, const struct xt_target_param *par)
53 */ 59 */
54 if ((ledinfo->delay > 0) && ledinfo->always_blink && 60 if ((ledinfo->delay > 0) && ledinfo->always_blink &&
55 timer_pending(&ledinternal->timer)) 61 timer_pending(&ledinternal->timer))
56 led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF); 62 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
57 63
58 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); 64 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
59 65
@@ -74,12 +80,23 @@ led_tg(struct sk_buff *skb, const struct xt_target_param *par)
74 80
75static void led_timeout_callback(unsigned long data) 81static void led_timeout_callback(unsigned long data)
76{ 82{
77 struct xt_led_info *ledinfo = (struct xt_led_info *)data; 83 struct xt_led_info_internal *ledinternal = (struct xt_led_info_internal *)data;
78 struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
79 84
80 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); 85 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
81} 86}
82 87
88static struct xt_led_info_internal *led_trigger_lookup(const char *name)
89{
90 struct xt_led_info_internal *ledinternal;
91
92 list_for_each_entry(ledinternal, &xt_led_triggers, list) {
93 if (!strcmp(name, ledinternal->netfilter_led_trigger.name)) {
94 return ledinternal;
95 }
96 }
97 return NULL;
98}
99
83static int led_tg_check(const struct xt_tgchk_param *par) 100static int led_tg_check(const struct xt_tgchk_param *par)
84{ 101{
85 struct xt_led_info *ledinfo = par->targinfo; 102 struct xt_led_info *ledinfo = par->targinfo;
@@ -91,11 +108,25 @@ static int led_tg_check(const struct xt_tgchk_param *par)
91 return -EINVAL; 108 return -EINVAL;
92 } 109 }
93 110
111 mutex_lock(&xt_led_mutex);
112
113 ledinternal = led_trigger_lookup(ledinfo->id);
114 if (ledinternal) {
115 ledinternal->refcnt++;
116 goto out;
117 }
118
119 err = -ENOMEM;
94 ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL); 120 ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
95 if (!ledinternal) 121 if (!ledinternal)
96 return -ENOMEM; 122 goto exit_mutex_only;
123
124 ledinternal->trigger_id = kstrdup(ledinfo->id, GFP_KERNEL);
125 if (!ledinternal->trigger_id)
126 goto exit_internal_alloc;
97 127
98 ledinternal->netfilter_led_trigger.name = ledinfo->id; 128 ledinternal->refcnt = 1;
129 ledinternal->netfilter_led_trigger.name = ledinternal->trigger_id;
99 130
100 err = led_trigger_register(&ledinternal->netfilter_led_trigger); 131 err = led_trigger_register(&ledinternal->netfilter_led_trigger);
101 if (err) { 132 if (err) {
@@ -108,13 +139,26 @@ static int led_tg_check(const struct xt_tgchk_param *par)
108 /* See if we need to set up a timer */ 139 /* See if we need to set up a timer */
109 if (ledinfo->delay > 0) 140 if (ledinfo->delay > 0)
110 setup_timer(&ledinternal->timer, led_timeout_callback, 141 setup_timer(&ledinternal->timer, led_timeout_callback,
111 (unsigned long)ledinfo); 142 (unsigned long)ledinternal);
143
144 list_add_tail(&ledinternal->list, &xt_led_triggers);
145
146out:
147 mutex_unlock(&xt_led_mutex);
112 148
113 ledinfo->internal_data = ledinternal; 149 ledinfo->internal_data = ledinternal;
150
114 return 0; 151 return 0;
115 152
116exit_alloc: 153exit_alloc:
154 kfree(ledinternal->trigger_id);
155
156exit_internal_alloc:
117 kfree(ledinternal); 157 kfree(ledinternal);
158
159exit_mutex_only:
160 mutex_unlock(&xt_led_mutex);
161
118 return err; 162 return err;
119} 163}
120 164
@@ -123,10 +167,23 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par)
123 const struct xt_led_info *ledinfo = par->targinfo; 167 const struct xt_led_info *ledinfo = par->targinfo;
124 struct xt_led_info_internal *ledinternal = ledinfo->internal_data; 168 struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
125 169
170 mutex_lock(&xt_led_mutex);
171
172 if (--ledinternal->refcnt) {
173 mutex_unlock(&xt_led_mutex);
174 return;
175 }
176
177 list_del(&ledinternal->list);
178
126 if (ledinfo->delay > 0) 179 if (ledinfo->delay > 0)
127 del_timer_sync(&ledinternal->timer); 180 del_timer_sync(&ledinternal->timer);
128 181
129 led_trigger_unregister(&ledinternal->netfilter_led_trigger); 182 led_trigger_unregister(&ledinternal->netfilter_led_trigger);
183
184 mutex_unlock(&xt_led_mutex);
185
186 kfree(ledinternal->trigger_id);
130 kfree(ledinternal); 187 kfree(ledinternal);
131} 188}
132 189