OSDN Git Service

Merge android-4.4-p.198 (dbd0162) into msm-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / net / netfilter / xt_quota2.c
index 834594a..8c481e3 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
+#include <linux/workqueue.h>
 #include <asm/atomic.h>
 #include <net/netlink.h>
 
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_quota2.h>
 
+#define QUOTA2_SYSFS_WORK_MAX_SIZE 64
+#define QUOTA2_SYSFS_NUM_ENVP 3
+
 #ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
 /* For compatibility, these definitions are copied from the
  * deprecated header file <linux/netfilter_ipv4/ipt_ULOG.h> */
@@ -54,17 +58,16 @@ struct xt_quota_counter {
        atomic_t ref;
        char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)];
        struct proc_dir_entry *procfs_entry;
+       char last_iface[QUOTA2_SYSFS_WORK_MAX_SIZE];
+       char last_prefix[QUOTA2_SYSFS_WORK_MAX_SIZE];
+       struct work_struct work;
 };
 
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-/* Harald's favorite number +1 :D From ipt_ULOG.C */
-static int qlog_nl_event = 112;
-module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(event_num,
-                "Event number for NETLINK_NFLOG message. 0 disables log."
-                "111 is what ipt_ULOG uses.");
-static struct sock *nflognl;
-#endif
+#define to_quota_counter(x) container_of(x, struct xt_quota_counter, work)
+
+static struct class *quota_class;
+static struct device *quota_device;
+static struct kobject *quota_kobj;
 
 static LIST_HEAD(counter_list);
 static DEFINE_SPINLOCK(counter_list_lock);
@@ -75,68 +78,39 @@ static kuid_t quota_list_uid = KUIDT_INIT(0);
 static kgid_t quota_list_gid = KGIDT_INIT(0);
 module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
 
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-static void quota2_log(unsigned int hooknum,
-                      const struct sk_buff *skb,
-                      const struct net_device *in,
+static void quota2_work(struct work_struct *work)
+{
+       char alert_msg[QUOTA2_SYSFS_WORK_MAX_SIZE];
+       char iface_name[QUOTA2_SYSFS_WORK_MAX_SIZE];
+       char *envp[QUOTA2_SYSFS_NUM_ENVP] = {alert_msg, iface_name,  NULL};
+       struct xt_quota_counter *counter = to_quota_counter(work);
+
+       snprintf(alert_msg, sizeof(alert_msg), "ALERT_NAME=%s", counter->name);
+       snprintf(iface_name, sizeof(iface_name), "INTERFACE=%s",
+                counter->last_iface);
+
+       kobject_uevent_env(quota_kobj, KOBJ_CHANGE, envp);
+}
+
+static void quota2_log(const struct net_device *in,
                       const struct net_device *out,
+                      struct  xt_quota_counter *q,
                       const char *prefix)
 {
-       ulog_packet_msg_t *pm;
-       struct sk_buff *log_skb;
-       size_t size;
-       struct nlmsghdr *nlh;
-
-       if (!qlog_nl_event)
+       if (!prefix)
                return;
 
-       size = NLMSG_SPACE(sizeof(*pm));
-       size = max(size, (size_t)NLMSG_GOODSIZE);
-       log_skb = alloc_skb(size, GFP_ATOMIC);
-       if (!log_skb) {
-               pr_err("xt_quota2: cannot alloc skb for logging\n");
-               return;
-       }
+       strlcpy(q->last_prefix, prefix, QUOTA2_SYSFS_WORK_MAX_SIZE);
 
-       nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event,
-                       sizeof(*pm), 0);
-       if (!nlh) {
-               pr_err("xt_quota2: nlmsg_put failed\n");
-               kfree_skb(log_skb);
-               return;
-       }
-       pm = nlmsg_data(nlh);
-       if (skb->tstamp.tv64 == 0)
-               __net_timestamp((struct sk_buff *)skb);
-       pm->data_len = 0;
-       pm->hook = hooknum;
-       if (prefix != NULL)
-               strlcpy(pm->prefix, prefix, sizeof(pm->prefix));
-       else
-               *(pm->prefix) = '\0';
        if (in)
-               strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+               strlcpy(q->last_iface, in->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
+       else if (out)
+               strlcpy(q->last_iface, out->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
        else
-               pm->indev_name[0] = '\0';
+               strlcpy(q->last_iface, "UNKNOWN", QUOTA2_SYSFS_WORK_MAX_SIZE);
 
-       if (out)
-               strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
-       else
-               pm->outdev_name[0] = '\0';
-
-       NETLINK_CB(log_skb).dst_group = 1;
-       pr_debug("throwing 1 packets to netlink group 1\n");
-       netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC);
-}
-#else
-static void quota2_log(unsigned int hooknum,
-                      const struct sk_buff *skb,
-                      const struct net_device *in,
-                      const struct net_device *out,
-                      const char *prefix)
-{
+       schedule_work(&q->work);
 }
-#endif  /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
 
 static ssize_t quota_proc_read(struct file *file, char __user *buf,
                           size_t size, loff_t *ppos)
@@ -193,6 +167,9 @@ q2_new_counter(const struct xt_quota_mtinfo2 *q, bool anon)
                INIT_LIST_HEAD(&e->list);
                atomic_set(&e->ref, 1);
                strlcpy(e->name, q->name, sizeof(e->name));
+               strlcpy(e->last_prefix, "UNSET", sizeof(e->last_prefix));
+               strlcpy(e->last_iface, "UNSET", sizeof(e->last_iface));
+               INIT_WORK(&e->work, quota2_work);
        }
        return e;
 }
@@ -296,8 +273,8 @@ static void quota_mt2_destroy(const struct xt_mtdtor_param *par)
        }
 
        list_del(&e->list);
-       remove_proc_entry(e->name, proc_xt_quota);
        spin_unlock_bh(&counter_list_lock);
+       remove_proc_entry(e->name, proc_xt_quota);
        kfree(e);
 }
 
@@ -326,11 +303,7 @@ quota_mt2(const struct sk_buff *skb, struct xt_action_param *par)
                } else {
                        /* We are transitioning, log that fact. */
                        if (e->quota) {
-                               quota2_log(par->hooknum,
-                                          skb,
-                                          par->in,
-                                          par->out,
-                                          q->name);
+                               quota2_log(par->in, par->out, e, q->name);
                        }
                        /* we do not allow even small packets from now on */
                        e->quota = 0;
@@ -368,11 +341,25 @@ static int __init quota_mt2_init(void)
        int ret;
        pr_debug("xt_quota2: init()");
 
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-       nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL);
-       if (!nflognl)
-               return -ENOMEM;
-#endif
+       quota_class = class_create(THIS_MODULE, "xt_quota2");
+       ret = PTR_ERR(quota_class);
+       if (IS_ERR(quota_class)) {
+               pr_err("xt_quota2: couldn't create class");
+               class_destroy(quota_class);
+               return ret;
+       }
+
+       quota_device = device_create(quota_class, NULL, MKDEV(0, 0), NULL,
+                                    "counters");
+       ret = PTR_ERR(quota_device);
+       if (IS_ERR(quota_device)) {
+               pr_err("xt_quota2: couldn't create device");
+               device_destroy(quota_class, MKDEV(0, 0));
+               class_destroy(quota_class);
+               return ret;
+       }
+
+       quota_kobj = &quota_device->kobj;
 
        proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
        if (proc_xt_quota == NULL)
@@ -389,6 +376,8 @@ static void __exit quota_mt2_exit(void)
 {
        xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
        remove_proc_entry("xt_quota", init_net.proc_net);
+       device_destroy(quota_class, MKDEV(0, 0));
+       class_destroy(quota_class);
 }
 
 module_init(quota_mt2_init);