Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / bridge / netfilter / ebt_ulog.c
index 01af4fc..ee5a517 100644 (file)
@@ -3,6 +3,7 @@
  *
  *     Authors:
  *     Bart De Schuymer <bdschuym@pandora.be>
+ *     Harald Welte <laforge@netfilter.org>
  *
  *  November, 2004
  *
@@ -45,7 +46,7 @@
 #define PRINTR(format, args...) do { if (net_ratelimit()) \
                                 printk(format , ## args); } while (0)
 
-static unsigned int nlbufsiz = 4096;
+static unsigned int nlbufsiz = NLMSG_GOODSIZE;
 module_param(nlbufsiz, uint, 0600);
 MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
                            "(defaults to 4096)");
@@ -78,8 +79,8 @@ static void ulog_send(unsigned int nlgroup)
        if (ub->qlen > 1)
                ub->lastnlh->nlmsg_type = NLMSG_DONE;
 
-       NETLINK_CB(ub->skb).dst_groups = 1 << nlgroup;
-       netlink_broadcast(ebtulognl, ub->skb, 0, 1 << nlgroup, GFP_ATOMIC);
+       NETLINK_CB(ub->skb).dst_group = nlgroup + 1;
+       netlink_broadcast(ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC);
 
        ub->qlen = 0;
        ub->skb = NULL;
@@ -97,12 +98,14 @@ static void ulog_timer(unsigned long data)
 static struct sk_buff *ulog_alloc_skb(unsigned int size)
 {
        struct sk_buff *skb;
+       unsigned int n;
 
-       skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+       n = max(size, nlbufsiz);
+       skb = alloc_skb(n, GFP_ATOMIC);
        if (!skb) {
                PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
-                      "of size %ub!\n", nlbufsiz);
-               if (size < nlbufsiz) {
+                      "of size %ub!\n", n);
+               if (n > size) {
                        /* try to allocate only as much as we need for
                         * current packet */
                        skb = alloc_skb(size, GFP_ATOMIC);
@@ -115,14 +118,13 @@ static struct sk_buff *ulog_alloc_skb(unsigned int size)
        return skb;
 }
 
-static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
+static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
    const struct net_device *in, const struct net_device *out,
-   const void *data, unsigned int datalen)
+   const struct ebt_ulog_info *uloginfo, const char *prefix)
 {
        ebt_ulog_packet_msg_t *pm;
        size_t size, copy_len;
        struct nlmsghdr *nlh;
-       struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
        unsigned int group = uloginfo->nlgroup;
        ebt_ulog_buff_t *ub = &ulog_buffers[group];
        spinlock_t *lock = &ub->lock;
@@ -162,7 +164,7 @@ static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
        pm->version = EBT_ULOG_VERSION;
        do_gettimeofday(&pm->stamp);
        if (ub->qlen == 1)
-               ub->skb->stamp = pm->stamp;
+               skb_set_timestamp(ub->skb, &pm->stamp);
        pm->data_len = copy_len;
        pm->mark = skb->nfmark;
        pm->hook = hooknr;
@@ -216,6 +218,39 @@ alloc_failure:
        goto unlock;
 }
 
+/* this function is registered with the netfilter core */
+static void ebt_log_packet(unsigned int pf, unsigned int hooknum,
+   const struct sk_buff *skb, const struct net_device *in,
+   const struct net_device *out, const struct nf_loginfo *li,
+   const char *prefix)
+{
+       struct ebt_ulog_info loginfo;
+
+       if (!li || li->type != NF_LOG_TYPE_ULOG) {
+               loginfo.nlgroup = EBT_ULOG_DEFAULT_NLGROUP;
+               loginfo.cprange = 0;
+               loginfo.qthreshold = EBT_ULOG_DEFAULT_QTHRESHOLD;
+               loginfo.prefix[0] = '\0';
+       } else {
+               loginfo.nlgroup = li->u.ulog.group;
+               loginfo.cprange = li->u.ulog.copy_len;
+               loginfo.qthreshold = li->u.ulog.qthreshold;
+               strlcpy(loginfo.prefix, prefix, sizeof(loginfo.prefix));
+       }
+
+       ebt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
+}
+
+static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
+{
+       struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
+
+       ebt_ulog_packet(hooknr, skb, in, out, uloginfo, NULL);
+}
+
+
 static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
@@ -240,7 +275,13 @@ static struct ebt_watcher ulog = {
        .me             = THIS_MODULE,
 };
 
-static int __init init(void)
+static struct nf_logger ebt_ulog_logger = {
+       .name           = EBT_ULOG_WATCHER,
+       .logfn          = &ebt_log_packet,
+       .me             = THIS_MODULE,
+};
+
+static int __init ebt_ulog_init(void)
 {
        int i, ret = 0;
 
@@ -258,20 +299,29 @@ static int __init init(void)
                spin_lock_init(&ulog_buffers[i].lock);
        }
 
-       ebtulognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
+       ebtulognl = netlink_kernel_create(NETLINK_NFLOG, EBT_ULOG_MAXNLGROUPS,
+                                         NULL, THIS_MODULE);
        if (!ebtulognl)
                ret = -ENOMEM;
        else if ((ret = ebt_register_watcher(&ulog)))
                sock_release(ebtulognl->sk_socket);
 
+       if (nf_log_register(PF_BRIDGE, &ebt_ulog_logger) < 0) {
+               printk(KERN_WARNING "ebt_ulog: not logging via ulog "
+                      "since somebody else already registered for PF_BRIDGE\n");
+               /* we cannot make module load fail here, since otherwise
+                * ebtables userspace would abort */
+       }
+
        return ret;
 }
 
-static void __exit fini(void)
+static void __exit ebt_ulog_fini(void)
 {
        ebt_ulog_buff_t *ub;
        int i;
 
+       nf_log_unregister_logger(&ebt_ulog_logger);
        ebt_unregister_watcher(&ulog);
        for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
                ub = &ulog_buffers[i];
@@ -287,8 +337,8 @@ static void __exit fini(void)
        sock_release(ebtulognl->sk_socket);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ebt_ulog_init);
+module_exit(ebt_ulog_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
 MODULE_DESCRIPTION("ebtables userspace logging module for bridged Ethernet"