linux/net/netfilter/xt_LED.c
<<
>>
Prefs
   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
  22#include <linux/module.h>
  23#include <linux/skbuff.h>
  24#include <linux/netfilter/x_tables.h>
  25#include <linux/leds.h>
  26#include <linux/mutex.h>
  27
  28#include <linux/netfilter/xt_LED.h>
  29
  30MODULE_LICENSE("GPL");
  31MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
  32MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
  33
  34/*
  35 * 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
  37 * points to.
  38 */
  39struct xt_led_info_internal {
  40        struct led_trigger netfilter_led_trigger;
  41        struct timer_list timer;
  42};
  43
  44static unsigned int
  45led_tg(struct sk_buff *skb, const struct xt_target_param *par)
  46{
  47        const struct xt_led_info *ledinfo = par->targinfo;
  48        struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
  49
  50        /*
  51         * If "always blink" is enabled, and there's still some time until the
  52         * LED will switch off, briefly switch it off now.
  53         */
  54        if ((ledinfo->delay > 0) && ledinfo->always_blink &&
  55            timer_pending(&ledinternal->timer))
  56                led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF);
  57
  58        led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
  59
  60        /* If there's a positive delay, start/update the timer */
  61        if (ledinfo->delay > 0) {
  62                mod_timer(&ledinternal->timer,
  63                          jiffies + msecs_to_jiffies(ledinfo->delay));
  64
  65        /* Otherwise if there was no delay given, blink as fast as possible */
  66        } else if (ledinfo->delay == 0) {
  67                led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
  68        }
  69
  70        /* else the delay is negative, which means switch on and stay on */
  71
  72        return XT_CONTINUE;
  73}
  74
  75static void led_timeout_callback(unsigned long data)
  76{
  77        struct xt_led_info *ledinfo = (struct xt_led_info *)data;
  78        struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
  79
  80        led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
  81}
  82
  83static bool led_tg_check(const struct xt_tgchk_param *par)
  84{
  85        struct xt_led_info *ledinfo = par->targinfo;
  86        struct xt_led_info_internal *ledinternal;
  87        int err;
  88
  89        if (ledinfo->id[0] == '\0') {
  90                printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n");
  91                return false;
  92        }
  93
  94        ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
  95        if (!ledinternal) {
  96                printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n");
  97                return false;
  98        }
  99
 100        ledinternal->netfilter_led_trigger.name = ledinfo->id;
 101
 102        err = led_trigger_register(&ledinternal->netfilter_led_trigger);
 103        if (err) {
 104                printk(KERN_CRIT KBUILD_MODNAME
 105                        ": led_trigger_register() failed\n");
 106                if (err == -EEXIST)
 107                        printk(KERN_ERR KBUILD_MODNAME
 108                                ": Trigger name is already in use.\n");
 109                goto exit_alloc;
 110        }
 111
 112        /* See if we need to set up a timer */
 113        if (ledinfo->delay > 0)
 114                setup_timer(&ledinternal->timer, led_timeout_callback,
 115                            (unsigned long)ledinfo);
 116
 117        ledinfo->internal_data = ledinternal;
 118
 119        return true;
 120
 121exit_alloc:
 122        kfree(ledinternal);
 123
 124        return false;
 125}
 126
 127static void led_tg_destroy(const struct xt_tgdtor_param *par)
 128{
 129        const struct xt_led_info *ledinfo = par->targinfo;
 130        struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
 131
 132        if (ledinfo->delay > 0)
 133                del_timer_sync(&ledinternal->timer);
 134
 135        led_trigger_unregister(&ledinternal->netfilter_led_trigger);
 136        kfree(ledinternal);
 137}
 138
 139static struct xt_target led_tg_reg __read_mostly = {
 140        .name           = "LED",
 141        .revision       = 0,
 142        .family         = NFPROTO_UNSPEC,
 143        .target         = led_tg,
 144        .targetsize     = XT_ALIGN(sizeof(struct xt_led_info)),
 145        .checkentry     = led_tg_check,
 146        .destroy        = led_tg_destroy,
 147        .me             = THIS_MODULE,
 148};
 149
 150static int __init led_tg_init(void)
 151{
 152        return xt_register_target(&led_tg_reg);
 153}
 154
 155static void __exit led_tg_exit(void)
 156{
 157        xt_unregister_target(&led_tg_reg);
 158}
 159
 160module_init(led_tg_init);
 161module_exit(led_tg_exit);
 162