diff options
author | Ashish Sharma <ashishsharma@google.com> | 2012-03-29 13:02:27 -0700 |
---|---|---|
committer | JP Abgrall <jpa@google.com> | 2012-04-05 18:32:40 -0700 |
commit | beb914e987cbbd368988d2b94a6661cb907c4d5a (patch) | |
tree | 33f75ade6a9db4bfe6cb89437491ec12368ad108 | |
parent | 499149639354dc2ca0ae0f45716511a5c3a8d533 (diff) | |
download | kernel_samsung_aries-beb914e987cbbd368988d2b94a6661cb907c4d5a.zip kernel_samsung_aries-beb914e987cbbd368988d2b94a6661cb907c4d5a.tar.gz kernel_samsung_aries-beb914e987cbbd368988d2b94a6661cb907c4d5a.tar.bz2 |
xt_IDLETIMER:
Add new netlink msg type for IDLETIMER.
Send notifications when the label becomes active after an idle period.
Send netlink message notifications in addition to sysfs notifications.
Change-Id: I31677ef00c94b5f82c8457e5bf9e5e584c23c523
Signed-off-by: Ashish Sharma <ashishsharma@google.com>
-rw-r--r-- | include/linux/netfilter/xt_IDLETIMER.h | 8 | ||||
-rw-r--r-- | include/linux/netlink.h | 1 | ||||
-rw-r--r-- | net/netfilter/xt_IDLETIMER.c | 105 |
3 files changed, 107 insertions, 7 deletions
diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h index 208ae93..faaa28b 100644 --- a/include/linux/netfilter/xt_IDLETIMER.h +++ b/include/linux/netfilter/xt_IDLETIMER.h @@ -4,6 +4,7 @@ * Header file for Xtables timer target module. * * Copyright (C) 2004, 2010 Nokia Corporation + * * Written by Timo Teras <ext-timo.teras@nokia.com> * * Converted to x_tables and forward-ported to 2.6.34 @@ -32,12 +33,19 @@ #include <linux/types.h> #define MAX_IDLETIMER_LABEL_SIZE 28 +#define NLMSG_MAX_SIZE 64 + +#define NL_EVENT_TYPE_INACTIVE 0 +#define NL_EVENT_TYPE_ACTIVE 1 struct idletimer_tg_info { __u32 timeout; char label[MAX_IDLETIMER_LABEL_SIZE]; + /* Use netlink messages for notification in addition to sysfs */ + __u8 send_nl_msg; + /* for kernel module internal use only */ struct idletimer_tg *timer __attribute__((aligned(8))); }; diff --git a/include/linux/netlink.h b/include/linux/netlink.h index a9dd895..f434363 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -25,6 +25,7 @@ #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ #define NETLINK_ECRYPTFS 19 #define NETLINK_RDMA 20 +#define NETLINK_IDLETIMER 21 #define MAX_LINKS 32 diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index 3bdd443..a192f55 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -5,6 +5,7 @@ * After timer expires a kevent will be sent. * * Copyright (C) 2004, 2010 Nokia Corporation + * * Written by Timo Teras <ext-timo.teras@nokia.com> * * Converted to x_tables and reworked for upstream inclusion @@ -36,10 +37,15 @@ #include <linux/netfilter.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_IDLETIMER.h> +#include <linux/netlink.h> #include <linux/kdev_t.h> #include <linux/kobject.h> +#include <linux/skbuff.h> #include <linux/workqueue.h> #include <linux/sysfs.h> +#include <net/net_namespace.h> + +static struct sock *nl_sk; struct idletimer_tg_attr { struct attribute attr; @@ -56,6 +62,8 @@ struct idletimer_tg { struct idletimer_tg_attr attr; unsigned int refcnt; + bool send_nl_msg; + bool active; }; static LIST_HEAD(idletimer_tg_list); @@ -63,6 +71,46 @@ static DEFINE_MUTEX(list_mutex); static struct kobject *idletimer_tg_kobj; +static void notify_netlink(const char *iface, struct idletimer_tg *timer) +{ + struct sk_buff *log_skb; + size_t size; + struct nlmsghdr *nlh; + char str[NLMSG_MAX_SIZE]; + int event_type, res; + + size = NLMSG_SPACE(NLMSG_MAX_SIZE); + size = max(size, (size_t)NLMSG_GOODSIZE); + log_skb = alloc_skb(size, GFP_ATOMIC); + if (!log_skb) { + pr_err("xt_cannot alloc skb for logging\n"); + return; + } + + event_type = timer->active ? NL_EVENT_TYPE_ACTIVE + : NL_EVENT_TYPE_INACTIVE; + res = snprintf(str, NLMSG_MAX_SIZE, "%s %s\n", iface, + timer->active ? "ACTIVE" : "INACTIVE"); + if (NLMSG_MAX_SIZE <= res) + goto nlmsg_failure; + + /* NLMSG_PUT() uses "goto nlmsg_failure" */ + nlh = NLMSG_PUT(log_skb, /*pid*/0, /*seq*/0, event_type, + /* Size of message */NLMSG_MAX_SIZE); + + strncpy(NLMSG_DATA(nlh), str, MAX_IDLETIMER_LABEL_SIZE); + + NETLINK_CB(log_skb).dst_group = 1; + netlink_broadcast(nl_sk, log_skb, 0, 1, GFP_ATOMIC); + + pr_debug("putting nlmsg: %s", str); + return; + +nlmsg_failure: /* Used within NLMSG_PUT() */ + consume_skb(log_skb); + pr_debug("Failed nlmsg_put\n"); +} + static struct idletimer_tg *__idletimer_tg_find_by_label(const char *label) { @@ -83,6 +131,7 @@ static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr, { struct idletimer_tg *timer; unsigned long expires = 0; + unsigned long now = jiffies; mutex_lock(&list_mutex); @@ -92,11 +141,15 @@ static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr, mutex_unlock(&list_mutex); - if (time_after(expires, jiffies)) + if (time_after(expires, now)) return sprintf(buf, "%u\n", - jiffies_to_msecs(expires - jiffies) / 1000); + jiffies_to_msecs(expires - now) / 1000); - return sprintf(buf, "0\n"); + if (timer->send_nl_msg) + return sprintf(buf, "0 %d\n", + jiffies_to_msecs(now - expires) / 1000); + else + return sprintf(buf, "0\n"); } static void idletimer_tg_work(struct work_struct *work) @@ -105,6 +158,9 @@ static void idletimer_tg_work(struct work_struct *work) work); sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name); + + if (timer->send_nl_msg) + notify_netlink(timer->attr.attr.name, timer); } static void idletimer_tg_expired(unsigned long data) @@ -113,6 +169,7 @@ static void idletimer_tg_expired(unsigned long data) pr_debug("timer %s expired\n", timer->attr.attr.name); + timer->active = false; schedule_work(&timer->work); } @@ -147,6 +204,8 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) setup_timer(&info->timer->timer, idletimer_tg_expired, (unsigned long) info->timer); info->timer->refcnt = 1; + info->timer->send_nl_msg = (info->send_nl_msg == 0) ? false : true; + info->timer->active = true; mod_timer(&info->timer->timer, msecs_to_jiffies(info->timeout * 1000) + jiffies); @@ -170,14 +229,24 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb, const struct xt_action_param *par) { const struct idletimer_tg_info *info = par->targinfo; + unsigned long now = jiffies; pr_debug("resetting timer %s, timeout period %u\n", info->label, info->timeout); BUG_ON(!info->timer); + info->timer->active = true; + + if (time_before(info->timer->timer.expires, now)) { + schedule_work(&info->timer->work); + pr_debug("Starting timer %s (Expired, Jiffies): %lu, %lu\n", + info->label, info->timer->timer.expires, now); + } + + /* TODO: Avoid modifying timers on each packet */ mod_timer(&info->timer->timer, - msecs_to_jiffies(info->timeout * 1000) + jiffies); + msecs_to_jiffies(info->timeout * 1000) + now); return XT_CONTINUE; } @@ -186,8 +255,9 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) { struct idletimer_tg_info *info = par->targinfo; int ret; + unsigned long now = jiffies; - pr_debug("checkentry targinfo%s\n", info->label); + pr_debug("checkentry targinfo %s\n", info->label); if (info->timeout == 0) { pr_debug("timeout value is zero\n"); @@ -206,8 +276,17 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) info->timer = __idletimer_tg_find_by_label(info->label); if (info->timer) { info->timer->refcnt++; + info->timer->active = true; + + if (time_before(info->timer->timer.expires, now)) { + schedule_work(&info->timer->work); + pr_debug("Starting Checkentry timer" + "(Expired, Jiffies): %lu, %lu\n", + info->timer->timer.expires, now); + } + mod_timer(&info->timer->timer, - msecs_to_jiffies(info->timeout * 1000) + jiffies); + msecs_to_jiffies(info->timeout * 1000) + now); pr_debug("increased refcnt of timer %s to %u\n", info->label, info->timer->refcnt); @@ -221,6 +300,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) } mutex_unlock(&list_mutex); + return 0; } @@ -242,7 +322,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) kfree(info->timer); } else { pr_debug("decreased refcnt of timer %s to %u\n", - info->label, info->timer->refcnt); + info->label, info->timer->refcnt); } mutex_unlock(&list_mutex); @@ -250,6 +330,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) static struct xt_target idletimer_tg __read_mostly = { .name = "IDLETIMER", + .revision = 1, .family = NFPROTO_UNSPEC, .target = idletimer_tg_target, .targetsize = sizeof(struct idletimer_tg_info), @@ -289,6 +370,15 @@ static int __init idletimer_tg_init(void) goto out_dev; } + nl_sk = netlink_kernel_create(&init_net, + NETLINK_IDLETIMER, 1, NULL, + NULL, THIS_MODULE); + + if (!nl_sk) { + pr_err("Failed to create netlink socket\n"); + return -ENOMEM; + } + return 0; out_dev: device_destroy(idletimer_tg_class, MKDEV(0, 0)); @@ -315,3 +405,4 @@ MODULE_DESCRIPTION("Xtables: idle time monitor"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("ipt_IDLETIMER"); MODULE_ALIAS("ip6t_IDLETIMER"); +MODULE_ALIAS("arpt_IDLETIMER"); |