Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
[safe/jmp/linux-2.6] / net / ipv6 / netfilter / ip6_queue.c
index 9c50cb1..db4d572 100644 (file)
 #define NET_IPQ_QMAX 2088
 #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
 
-struct ipq_queue_entry {
-       struct list_head list;
-       struct nf_info *info;
-       struct sk_buff *skb;
-};
-
-typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long);
+typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long);
 
 static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
 static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
@@ -59,17 +53,8 @@ static struct sock *ipqnl __read_mostly;
 static LIST_HEAD(queue_list);
 static DEFINE_MUTEX(ipqnl_mutex);
 
-static void
-ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
-{
-       local_bh_disable();
-       nf_reinject(entry->skb, entry->info, verdict);
-       local_bh_enable();
-       kfree(entry);
-}
-
 static inline void
-__ipq_enqueue_entry(struct ipq_queue_entry *entry)
+__ipq_enqueue_entry(struct nf_queue_entry *entry)
 {
        list_add_tail(&entry->list, &queue_list);
        queue_total++;
@@ -112,10 +97,10 @@ __ipq_reset(void)
        __ipq_flush(NULL, 0);
 }
 
-static struct ipq_queue_entry *
+static struct nf_queue_entry *
 ipq_find_dequeue_entry(unsigned long id)
 {
-       struct ipq_queue_entry *entry = NULL, *i;
+       struct nf_queue_entry *entry = NULL, *i;
 
        write_lock_bh(&queue_lock);
 
@@ -138,13 +123,13 @@ ipq_find_dequeue_entry(unsigned long id)
 static void
 __ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
 {
-       struct ipq_queue_entry *entry, *next;
+       struct nf_queue_entry *entry, *next;
 
        list_for_each_entry_safe(entry, next, &queue_list, list) {
                if (!cmpfn || cmpfn(entry, data)) {
                        list_del(&entry->list);
                        queue_total--;
-                       ipq_issue_verdict(entry, NF_DROP);
+                       nf_reinject(entry, NF_DROP);
                }
        }
 }
@@ -158,7 +143,7 @@ ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
 }
 
 static struct sk_buff *
-ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
+ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
 {
        sk_buff_data_t old_tail;
        size_t size = 0;
@@ -174,7 +159,6 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
        case IPQ_COPY_META:
        case IPQ_COPY_NONE:
                size = NLMSG_SPACE(sizeof(*pmsg));
-               data_len = 0;
                break;
 
        case IPQ_COPY_PACKET:
@@ -215,20 +199,20 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
        pmsg->timestamp_sec   = tv.tv_sec;
        pmsg->timestamp_usec  = tv.tv_usec;
        pmsg->mark            = entry->skb->mark;
-       pmsg->hook            = entry->info->hook;
+       pmsg->hook            = entry->hook;
        pmsg->hw_protocol     = entry->skb->protocol;
 
-       if (entry->info->indev)
-               strcpy(pmsg->indev_name, entry->info->indev->name);
+       if (entry->indev)
+               strcpy(pmsg->indev_name, entry->indev->name);
        else
                pmsg->indev_name[0] = '\0';
 
-       if (entry->info->outdev)
-               strcpy(pmsg->outdev_name, entry->info->outdev->name);
+       if (entry->outdev)
+               strcpy(pmsg->outdev_name, entry->outdev->name);
        else
                pmsg->outdev_name[0] = '\0';
 
-       if (entry->info->indev && entry->skb->dev) {
+       if (entry->indev && entry->skb->dev) {
                pmsg->hw_type = entry->skb->dev->type;
                pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr);
        }
@@ -241,36 +225,23 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
        return skb;
 
 nlmsg_failure:
-       if (skb)
-               kfree_skb(skb);
        *errp = -EINVAL;
        printk(KERN_ERR "ip6_queue: error creating packet message\n");
        return NULL;
 }
 
 static int
-ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
-                  unsigned int queuenum)
+ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
 {
        int status = -EINVAL;
        struct sk_buff *nskb;
-       struct ipq_queue_entry *entry;
 
        if (copy_mode == IPQ_COPY_NONE)
                return -EAGAIN;
 
-       entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
-       if (entry == NULL) {
-               printk(KERN_ERR "ip6_queue: OOM in ipq_enqueue_packet()\n");
-               return -ENOMEM;
-       }
-
-       entry->info = info;
-       entry->skb = skb;
-
        nskb = ipq_build_packet_message(entry, &status);
        if (nskb == NULL)
-               goto err_out_free;
+               return status;
 
        write_lock_bh(&queue_lock);
 
@@ -304,18 +275,15 @@ err_out_free_nskb:
 
 err_out_unlock:
        write_unlock_bh(&queue_lock);
-
-err_out_free:
-       kfree(entry);
        return status;
 }
 
 static int
-ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
+ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e)
 {
        int diff;
-       int err;
        struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
+       struct sk_buff *nskb;
 
        if (v->data_len < sizeof(*user_iph))
                return 0;
@@ -327,14 +295,15 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
                if (v->data_len > 0xFFFF)
                        return -EINVAL;
                if (diff > skb_tailroom(e->skb)) {
-                       err = pskb_expand_head(e->skb, 0,
-                                              diff - skb_tailroom(e->skb),
-                                              GFP_ATOMIC);
-                       if (err) {
+                       nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
+                                              diff, GFP_ATOMIC);
+                       if (!nskb) {
                                printk(KERN_WARNING "ip6_queue: OOM "
                                      "in mangle, dropping packet\n");
-                               return err;
+                               return -ENOMEM;
                        }
+                       kfree_skb(e->skb);
+                       e->skb = nskb;
                }
                skb_put(e->skb, diff);
        }
@@ -349,7 +318,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
 static int
 ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
 {
-       struct ipq_queue_entry *entry;
+       struct nf_queue_entry *entry;
 
        if (vmsg->value > NF_MAX_VERDICT)
                return -EINVAL;
@@ -364,7 +333,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
                        if (ipq_mangle_ipv6(vmsg, entry) < 0)
                                verdict = NF_DROP;
 
-               ipq_issue_verdict(entry, verdict);
+               nf_reinject(entry, verdict);
                return 0;
        }
 }
@@ -409,14 +378,14 @@ ipq_receive_peer(struct ipq_peer_msg *pmsg,
 }
 
 static int
-dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
+dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
 {
-       if (entry->info->indev)
-               if (entry->info->indev->ifindex == ifindex)
+       if (entry->indev)
+               if (entry->indev->ifindex == ifindex)
                        return 1;
 
-       if (entry->info->outdev)
-               if (entry->info->outdev->ifindex == ifindex)
+       if (entry->outdev)
+               if (entry->outdev->ifindex == ifindex)
                        return 1;
 #ifdef CONFIG_BRIDGE_NETFILTER
        if (entry->skb->nf_bridge) {
@@ -511,7 +480,7 @@ ipq_rcv_dev_event(struct notifier_block *this,
 {
        struct net_device *dev = ptr;
 
-       if (dev->nd_net != &init_net)
+       if (!net_eq(dev_net(dev), &init_net))
                return NOTIFY_DONE;
 
        /* Drop any packets associated with the downed device */
@@ -530,10 +499,9 @@ ipq_rcv_nl_event(struct notifier_block *this,
 {
        struct netlink_notify *n = ptr;
 
-       if (event == NETLINK_URELEASE &&
-           n->protocol == NETLINK_IP6_FW && n->pid) {
+       if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) {
                write_lock_bh(&queue_lock);
-               if ((n->net == &init_net) && (n->pid == peer_pid))
+               if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid))
                        __ipq_reset();
                write_unlock_bh(&queue_lock);
        }
@@ -544,6 +512,7 @@ static struct notifier_block ipq_nl_notifier = {
        .notifier_call  = ipq_rcv_nl_event,
 };
 
+#ifdef CONFIG_SYSCTL
 static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
@@ -557,27 +526,9 @@ static ctl_table ipq_table[] = {
        },
        { .ctl_name = 0 }
 };
+#endif
 
-static ctl_table ipq_dir_table[] = {
-       {
-               .ctl_name       = NET_IPV6,
-               .procname       = "ipv6",
-               .mode           = 0555,
-               .child          = ipq_table
-       },
-       { .ctl_name = 0 }
-};
-
-static ctl_table ipq_root_table[] = {
-       {
-               .ctl_name       = CTL_NET,
-               .procname       = "net",
-               .mode           = 0555,
-               .child          = ipq_dir_table
-       },
-       { .ctl_name = 0 }
-};
-
+#ifdef CONFIG_PROC_FS
 static int ip6_queue_show(struct seq_file *m, void *v)
 {
        read_lock_bh(&queue_lock);
@@ -614,6 +565,7 @@ static const struct file_operations ip6_queue_proc_fops = {
        .release        = single_release,
        .owner          = THIS_MODULE,
 };
+#endif
 
 static const struct nf_queue_handler nfqh = {
        .name   = "ip6_queue",
@@ -623,7 +575,7 @@ static const struct nf_queue_handler nfqh = {
 static int __init ip6_queue_init(void)
 {
        int status = -ENOMEM;
-       struct proc_dir_entry *proc;
+       struct proc_dir_entry *proc __maybe_unused;
 
        netlink_register_notifier(&ipq_nl_notifier);
        ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0,
@@ -633,19 +585,19 @@ static int __init ip6_queue_init(void)
                goto cleanup_netlink_notifier;
        }
 
-       proc = create_proc_entry(IPQ_PROC_FS_NAME, 0, init_net.proc_net);
-       if (proc) {
-               proc->owner = THIS_MODULE;
-               proc->proc_fops = &ip6_queue_proc_fops;
-       } else {
+#ifdef CONFIG_PROC_FS
+       proc = proc_create(IPQ_PROC_FS_NAME, 0, init_net.proc_net,
+                          &ip6_queue_proc_fops);
+       if (!proc) {
                printk(KERN_ERR "ip6_queue: failed to create proc entry\n");
                goto cleanup_ipqnl;
        }
-
+#endif
        register_netdevice_notifier(&ipq_dev_notifier);
-       ipq_sysctl_header = register_sysctl_table(ipq_root_table);
-
-       status = nf_register_queue_handler(PF_INET6, &nfqh);
+#ifdef CONFIG_SYSCTL
+       ipq_sysctl_header = register_sysctl_paths(net_ipv6_ctl_path, ipq_table);
+#endif
+       status = nf_register_queue_handler(NFPROTO_IPV6, &nfqh);
        if (status < 0) {
                printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
                goto cleanup_sysctl;
@@ -653,12 +605,14 @@ static int __init ip6_queue_init(void)
        return status;
 
 cleanup_sysctl:
+#ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ipq_sysctl_header);
+#endif
        unregister_netdevice_notifier(&ipq_dev_notifier);
        proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
 
-cleanup_ipqnl:
-       sock_release(ipqnl->sk_socket);
+cleanup_ipqnl: __maybe_unused
+       netlink_kernel_release(ipqnl);
        mutex_lock(&ipqnl_mutex);
        mutex_unlock(&ipqnl_mutex);
 
@@ -670,14 +624,16 @@ cleanup_netlink_notifier:
 static void __exit ip6_queue_fini(void)
 {
        nf_unregister_queue_handlers(&nfqh);
-       synchronize_net();
+
        ipq_flush(NULL, 0);
 
+#ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ipq_sysctl_header);
+#endif
        unregister_netdevice_notifier(&ipq_dev_notifier);
        proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
 
-       sock_release(ipqnl->sk_socket);
+       netlink_kernel_release(ipqnl);
        mutex_lock(&ipqnl_mutex);
        mutex_unlock(&ipqnl_mutex);
 
@@ -686,6 +642,7 @@ static void __exit ip6_queue_fini(void)
 
 MODULE_DESCRIPTION("IPv6 packet queue handler");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_IP6_FW);
 
 module_init(ip6_queue_init);
 module_exit(ip6_queue_fini);