0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0008 #include <linux/module.h>
0009 #include <linux/skbuff.h>
0010 #include <linux/netfilter/x_tables.h>
0011 #include <linux/slab.h>
0012 #include <linux/leds.h>
0013 #include <linux/mutex.h>
0014
0015 #include <linux/netfilter/xt_LED.h>
0016
0017 MODULE_LICENSE("GPL");
0018 MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
0019 MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
0020 MODULE_ALIAS("ipt_LED");
0021 MODULE_ALIAS("ip6t_LED");
0022
0023 static LIST_HEAD(xt_led_triggers);
0024 static DEFINE_MUTEX(xt_led_mutex);
0025
0026
0027
0028
0029
0030
0031 struct xt_led_info_internal {
0032 struct list_head list;
0033 int refcnt;
0034 char *trigger_id;
0035 struct led_trigger netfilter_led_trigger;
0036 struct timer_list timer;
0037 };
0038
0039 #define XT_LED_BLINK_DELAY 50
0040
0041 static unsigned int
0042 led_tg(struct sk_buff *skb, const struct xt_action_param *par)
0043 {
0044 const struct xt_led_info *ledinfo = par->targinfo;
0045 struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
0046 unsigned long led_delay = XT_LED_BLINK_DELAY;
0047
0048
0049
0050
0051
0052 if ((ledinfo->delay > 0) && ledinfo->always_blink &&
0053 timer_pending(&ledinternal->timer))
0054 led_trigger_blink_oneshot(&ledinternal->netfilter_led_trigger,
0055 &led_delay, &led_delay, 1);
0056 else
0057 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
0058
0059
0060 if (ledinfo->delay > 0) {
0061 mod_timer(&ledinternal->timer,
0062 jiffies + msecs_to_jiffies(ledinfo->delay));
0063
0064
0065 } else if (ledinfo->delay == 0) {
0066 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
0067 }
0068
0069
0070
0071 return XT_CONTINUE;
0072 }
0073
0074 static void led_timeout_callback(struct timer_list *t)
0075 {
0076 struct xt_led_info_internal *ledinternal = from_timer(ledinternal, t,
0077 timer);
0078
0079 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
0080 }
0081
0082 static struct xt_led_info_internal *led_trigger_lookup(const char *name)
0083 {
0084 struct xt_led_info_internal *ledinternal;
0085
0086 list_for_each_entry(ledinternal, &xt_led_triggers, list) {
0087 if (!strcmp(name, ledinternal->netfilter_led_trigger.name)) {
0088 return ledinternal;
0089 }
0090 }
0091 return NULL;
0092 }
0093
0094 static int led_tg_check(const struct xt_tgchk_param *par)
0095 {
0096 struct xt_led_info *ledinfo = par->targinfo;
0097 struct xt_led_info_internal *ledinternal;
0098 int err;
0099
0100 if (ledinfo->id[0] == '\0')
0101 return -EINVAL;
0102
0103 mutex_lock(&xt_led_mutex);
0104
0105 ledinternal = led_trigger_lookup(ledinfo->id);
0106 if (ledinternal) {
0107 ledinternal->refcnt++;
0108 goto out;
0109 }
0110
0111 err = -ENOMEM;
0112 ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
0113 if (!ledinternal)
0114 goto exit_mutex_only;
0115
0116 ledinternal->trigger_id = kstrdup(ledinfo->id, GFP_KERNEL);
0117 if (!ledinternal->trigger_id)
0118 goto exit_internal_alloc;
0119
0120 ledinternal->refcnt = 1;
0121 ledinternal->netfilter_led_trigger.name = ledinternal->trigger_id;
0122
0123 err = led_trigger_register(&ledinternal->netfilter_led_trigger);
0124 if (err) {
0125 pr_info_ratelimited("Trigger name is already in use.\n");
0126 goto exit_alloc;
0127 }
0128
0129
0130
0131
0132 timer_setup(&ledinternal->timer, led_timeout_callback, 0);
0133
0134 list_add_tail(&ledinternal->list, &xt_led_triggers);
0135
0136 out:
0137 mutex_unlock(&xt_led_mutex);
0138
0139 ledinfo->internal_data = ledinternal;
0140
0141 return 0;
0142
0143 exit_alloc:
0144 kfree(ledinternal->trigger_id);
0145
0146 exit_internal_alloc:
0147 kfree(ledinternal);
0148
0149 exit_mutex_only:
0150 mutex_unlock(&xt_led_mutex);
0151
0152 return err;
0153 }
0154
0155 static void led_tg_destroy(const struct xt_tgdtor_param *par)
0156 {
0157 const struct xt_led_info *ledinfo = par->targinfo;
0158 struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
0159
0160 mutex_lock(&xt_led_mutex);
0161
0162 if (--ledinternal->refcnt) {
0163 mutex_unlock(&xt_led_mutex);
0164 return;
0165 }
0166
0167 list_del(&ledinternal->list);
0168
0169 del_timer_sync(&ledinternal->timer);
0170
0171 led_trigger_unregister(&ledinternal->netfilter_led_trigger);
0172
0173 mutex_unlock(&xt_led_mutex);
0174
0175 kfree(ledinternal->trigger_id);
0176 kfree(ledinternal);
0177 }
0178
0179 static struct xt_target led_tg_reg __read_mostly = {
0180 .name = "LED",
0181 .revision = 0,
0182 .family = NFPROTO_UNSPEC,
0183 .target = led_tg,
0184 .targetsize = sizeof(struct xt_led_info),
0185 .usersize = offsetof(struct xt_led_info, internal_data),
0186 .checkentry = led_tg_check,
0187 .destroy = led_tg_destroy,
0188 .me = THIS_MODULE,
0189 };
0190
0191 static int __init led_tg_init(void)
0192 {
0193 return xt_register_target(&led_tg_reg);
0194 }
0195
0196 static void __exit led_tg_exit(void)
0197 {
0198 xt_unregister_target(&led_tg_reg);
0199 }
0200
0201 module_init(led_tg_init);
0202 module_exit(led_tg_exit);