diff options
| -rw-r--r-- | include/linux/netfilter/nfnetlink_queue.h | 1 | ||||
| -rw-r--r-- | net/netfilter/nfnetlink_queue.c | 248 |
2 files changed, 221 insertions, 28 deletions
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h index edb463a87eb4..e142b0ff7c08 100644 --- a/include/linux/netfilter/nfnetlink_queue.h +++ b/include/linux/netfilter/nfnetlink_queue.h | |||
| @@ -81,5 +81,6 @@ enum nfqnl_attr_config { | |||
| 81 | NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */ | 81 | NFQA_CFG_PARAMS, /* nfqnl_msg_config_params */ |
| 82 | __NFQA_CFG_MAX | 82 | __NFQA_CFG_MAX |
| 83 | }; | 83 | }; |
| 84 | #define NFQA_CFG_MAX (__NFQA_CFG_MAX-1) | ||
| 84 | 85 | ||
| 85 | #endif /* _NFNETLINK_QUEUE_H */ | 86 | #endif /* _NFNETLINK_QUEUE_H */ |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 24032610c425..eab309e3d42e 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/notifier.h> | 20 | #include <linux/notifier.h> |
| 21 | #include <linux/netdevice.h> | 21 | #include <linux/netdevice.h> |
| 22 | #include <linux/netfilter.h> | 22 | #include <linux/netfilter.h> |
| 23 | #include <linux/proc_fs.h> | ||
| 23 | #include <linux/netfilter_ipv4.h> | 24 | #include <linux/netfilter_ipv4.h> |
| 24 | #include <linux/netfilter_ipv6.h> | 25 | #include <linux/netfilter_ipv6.h> |
| 25 | #include <linux/netfilter/nfnetlink.h> | 26 | #include <linux/netfilter/nfnetlink.h> |
| @@ -48,6 +49,7 @@ struct nfqnl_queue_entry { | |||
| 48 | 49 | ||
| 49 | struct nfqnl_instance { | 50 | struct nfqnl_instance { |
| 50 | struct hlist_node hlist; /* global list of queues */ | 51 | struct hlist_node hlist; /* global list of queues */ |
| 52 | atomic_t use; | ||
| 51 | 53 | ||
| 52 | int peer_pid; | 54 | int peer_pid; |
| 53 | unsigned int queue_maxlen; | 55 | unsigned int queue_maxlen; |
| @@ -105,17 +107,28 @@ __instance_lookup(u_int16_t queue_num) | |||
| 105 | } | 107 | } |
| 106 | 108 | ||
| 107 | static struct nfqnl_instance * | 109 | static struct nfqnl_instance * |
| 108 | instance_lookup(u_int16_t queue_num) | 110 | instance_lookup_get(u_int16_t queue_num) |
| 109 | { | 111 | { |
| 110 | struct nfqnl_instance *inst; | 112 | struct nfqnl_instance *inst; |
| 111 | 113 | ||
| 112 | read_lock_bh(&instances_lock); | 114 | read_lock_bh(&instances_lock); |
| 113 | inst = __instance_lookup(queue_num); | 115 | inst = __instance_lookup(queue_num); |
| 116 | if (inst) | ||
| 117 | atomic_inc(&inst->use); | ||
| 114 | read_unlock_bh(&instances_lock); | 118 | read_unlock_bh(&instances_lock); |
| 115 | 119 | ||
| 116 | return inst; | 120 | return inst; |
| 117 | } | 121 | } |
| 118 | 122 | ||
| 123 | static void | ||
| 124 | instance_put(struct nfqnl_instance *inst) | ||
| 125 | { | ||
| 126 | if (inst && atomic_dec_and_test(&inst->use)) { | ||
| 127 | QDEBUG("kfree(inst=%p)\n", inst); | ||
| 128 | kfree(inst); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 119 | static struct nfqnl_instance * | 132 | static struct nfqnl_instance * |
| 120 | instance_create(u_int16_t queue_num, int pid) | 133 | instance_create(u_int16_t queue_num, int pid) |
| 121 | { | 134 | { |
| @@ -141,6 +154,8 @@ instance_create(u_int16_t queue_num, int pid) | |||
| 141 | inst->copy_range = 0xfffff; | 154 | inst->copy_range = 0xfffff; |
| 142 | inst->copy_mode = NFQNL_COPY_NONE; | 155 | inst->copy_mode = NFQNL_COPY_NONE; |
| 143 | atomic_set(&inst->id_sequence, 0); | 156 | atomic_set(&inst->id_sequence, 0); |
| 157 | /* needs to be two, since we _put() after creation */ | ||
| 158 | atomic_set(&inst->use, 2); | ||
| 144 | inst->lock = SPIN_LOCK_UNLOCKED; | 159 | inst->lock = SPIN_LOCK_UNLOCKED; |
| 145 | INIT_LIST_HEAD(&inst->queue_list); | 160 | INIT_LIST_HEAD(&inst->queue_list); |
| 146 | 161 | ||
| @@ -182,8 +197,8 @@ _instance_destroy2(struct nfqnl_instance *inst, int lock) | |||
| 182 | /* then flush all pending skbs from the queue */ | 197 | /* then flush all pending skbs from the queue */ |
| 183 | nfqnl_flush(inst, NF_DROP); | 198 | nfqnl_flush(inst, NF_DROP); |
| 184 | 199 | ||
| 185 | /* and finally free the data structure */ | 200 | /* and finally put the refcount */ |
| 186 | kfree(inst); | 201 | instance_put(inst); |
| 187 | 202 | ||
| 188 | module_put(THIS_MODULE); | 203 | module_put(THIS_MODULE); |
| 189 | } | 204 | } |
| @@ -471,7 +486,7 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info, | |||
| 471 | 486 | ||
| 472 | QDEBUG("entered\n"); | 487 | QDEBUG("entered\n"); |
| 473 | 488 | ||
| 474 | queue = instance_lookup(queuenum); | 489 | queue = instance_lookup_get(queuenum); |
| 475 | if (!queue) { | 490 | if (!queue) { |
| 476 | QDEBUG("no queue instance matching\n"); | 491 | QDEBUG("no queue instance matching\n"); |
| 477 | return -EINVAL; | 492 | return -EINVAL; |
| @@ -479,7 +494,8 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info, | |||
| 479 | 494 | ||
| 480 | if (queue->copy_mode == NFQNL_COPY_NONE) { | 495 | if (queue->copy_mode == NFQNL_COPY_NONE) { |
| 481 | QDEBUG("mode COPY_NONE, aborting\n"); | 496 | QDEBUG("mode COPY_NONE, aborting\n"); |
| 482 | return -EAGAIN; | 497 | status = -EAGAIN; |
| 498 | goto err_out_put; | ||
| 483 | } | 499 | } |
| 484 | 500 | ||
| 485 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | 501 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); |
| @@ -487,7 +503,8 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info, | |||
| 487 | if (net_ratelimit()) | 503 | if (net_ratelimit()) |
| 488 | printk(KERN_ERR | 504 | printk(KERN_ERR |
| 489 | "nf_queue: OOM in nfqnl_enqueue_packet()\n"); | 505 | "nf_queue: OOM in nfqnl_enqueue_packet()\n"); |
| 490 | return -ENOMEM; | 506 | status = -ENOMEM; |
| 507 | goto err_out_put; | ||
| 491 | } | 508 | } |
| 492 | 509 | ||
| 493 | entry->info = info; | 510 | entry->info = info; |
| @@ -523,6 +540,7 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info, | |||
| 523 | __enqueue_entry(queue, entry); | 540 | __enqueue_entry(queue, entry); |
| 524 | 541 | ||
| 525 | spin_unlock_bh(&queue->lock); | 542 | spin_unlock_bh(&queue->lock); |
| 543 | instance_put(queue); | ||
| 526 | return status; | 544 | return status; |
| 527 | 545 | ||
| 528 | err_out_free_nskb: | 546 | err_out_free_nskb: |
| @@ -533,6 +551,8 @@ err_out_unlock: | |||
| 533 | 551 | ||
| 534 | err_out_free: | 552 | err_out_free: |
| 535 | kfree(entry); | 553 | kfree(entry); |
| 554 | err_out_put: | ||
| 555 | instance_put(queue); | ||
| 536 | return status; | 556 | return status; |
| 537 | } | 557 | } |
| 538 | 558 | ||
| @@ -685,6 +705,12 @@ static struct notifier_block nfqnl_rtnl_notifier = { | |||
| 685 | .notifier_call = nfqnl_rcv_nl_event, | 705 | .notifier_call = nfqnl_rcv_nl_event, |
| 686 | }; | 706 | }; |
| 687 | 707 | ||
| 708 | static const int nfqa_verdict_min[NFQA_MAX] = { | ||
| 709 | [NFQA_VERDICT_HDR-1] = sizeof(struct nfqnl_msg_verdict_hdr), | ||
| 710 | [NFQA_MARK-1] = sizeof(u_int32_t), | ||
| 711 | [NFQA_PAYLOAD-1] = 0, | ||
| 712 | }; | ||
| 713 | |||
| 688 | static int | 714 | static int |
| 689 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | 715 | nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, |
| 690 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) | 716 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) |
| @@ -696,26 +722,40 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | |||
| 696 | struct nfqnl_instance *queue; | 722 | struct nfqnl_instance *queue; |
| 697 | unsigned int verdict; | 723 | unsigned int verdict; |
| 698 | struct nfqnl_queue_entry *entry; | 724 | struct nfqnl_queue_entry *entry; |
| 725 | int err; | ||
| 699 | 726 | ||
| 700 | queue = instance_lookup(queue_num); | 727 | if (nfattr_bad_size(nfqa, NFQA_MAX, nfqa_verdict_min)) { |
| 728 | QDEBUG("bad attribute size\n"); | ||
| 729 | return -EINVAL; | ||
| 730 | } | ||
| 731 | |||
| 732 | queue = instance_lookup_get(queue_num); | ||
| 701 | if (!queue) | 733 | if (!queue) |
| 702 | return -ENODEV; | 734 | return -ENODEV; |
| 703 | 735 | ||
| 704 | if (queue->peer_pid != NETLINK_CB(skb).pid) | 736 | if (queue->peer_pid != NETLINK_CB(skb).pid) { |
| 705 | return -EPERM; | 737 | err = -EPERM; |
| 738 | goto err_out_put; | ||
| 739 | } | ||
| 706 | 740 | ||
| 707 | if (!nfqa[NFQA_VERDICT_HDR-1]) | 741 | if (!nfqa[NFQA_VERDICT_HDR-1]) { |
| 708 | return -EINVAL; | 742 | err = -EINVAL; |
| 743 | goto err_out_put; | ||
| 744 | } | ||
| 709 | 745 | ||
| 710 | vhdr = NFA_DATA(nfqa[NFQA_VERDICT_HDR-1]); | 746 | vhdr = NFA_DATA(nfqa[NFQA_VERDICT_HDR-1]); |
| 711 | verdict = ntohl(vhdr->verdict); | 747 | verdict = ntohl(vhdr->verdict); |
| 712 | 748 | ||
| 713 | if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) | 749 | if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) { |
| 714 | return -EINVAL; | 750 | err = -EINVAL; |
| 751 | goto err_out_put; | ||
| 752 | } | ||
| 715 | 753 | ||
| 716 | entry = find_dequeue_entry(queue, id_cmp, ntohl(vhdr->id)); | 754 | entry = find_dequeue_entry(queue, id_cmp, ntohl(vhdr->id)); |
| 717 | if (entry == NULL) | 755 | if (entry == NULL) { |
| 718 | return -ENOENT; | 756 | err = -ENOENT; |
| 757 | goto err_out_put; | ||
| 758 | } | ||
| 719 | 759 | ||
| 720 | if (nfqa[NFQA_PAYLOAD-1]) { | 760 | if (nfqa[NFQA_PAYLOAD-1]) { |
| 721 | if (nfqnl_mangle(NFA_DATA(nfqa[NFQA_PAYLOAD-1]), | 761 | if (nfqnl_mangle(NFA_DATA(nfqa[NFQA_PAYLOAD-1]), |
| @@ -727,7 +767,12 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, | |||
| 727 | skb->nfmark = ntohl(*(u_int32_t *)NFA_DATA(nfqa[NFQA_MARK-1])); | 767 | skb->nfmark = ntohl(*(u_int32_t *)NFA_DATA(nfqa[NFQA_MARK-1])); |
| 728 | 768 | ||
| 729 | issue_verdict(entry, verdict); | 769 | issue_verdict(entry, verdict); |
| 770 | instance_put(queue); | ||
| 730 | return 0; | 771 | return 0; |
| 772 | |||
| 773 | err_out_put: | ||
| 774 | instance_put(queue); | ||
| 775 | return err; | ||
| 731 | } | 776 | } |
| 732 | 777 | ||
| 733 | static int | 778 | static int |
| @@ -737,6 +782,11 @@ nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, | |||
| 737 | return -ENOTSUPP; | 782 | return -ENOTSUPP; |
| 738 | } | 783 | } |
| 739 | 784 | ||
| 785 | static const int nfqa_cfg_min[NFQA_CFG_MAX] = { | ||
| 786 | [NFQA_CFG_CMD-1] = sizeof(struct nfqnl_msg_config_cmd), | ||
| 787 | [NFQA_CFG_PARAMS-1] = sizeof(struct nfqnl_msg_config_params), | ||
| 788 | }; | ||
| 789 | |||
| 740 | static int | 790 | static int |
| 741 | nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | 791 | nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, |
| 742 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) | 792 | struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp) |
| @@ -744,10 +794,16 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
| 744 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | 794 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); |
| 745 | u_int16_t queue_num = ntohs(nfmsg->res_id); | 795 | u_int16_t queue_num = ntohs(nfmsg->res_id); |
| 746 | struct nfqnl_instance *queue; | 796 | struct nfqnl_instance *queue; |
| 797 | int ret = 0; | ||
| 747 | 798 | ||
| 748 | QDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type)); | 799 | QDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type)); |
| 749 | 800 | ||
| 750 | queue = instance_lookup(queue_num); | 801 | if (nfattr_bad_size(nfqa, NFQA_CFG_MAX, nfqa_cfg_min)) { |
| 802 | QDEBUG("bad attribute size\n"); | ||
| 803 | return -EINVAL; | ||
| 804 | } | ||
| 805 | |||
| 806 | queue = instance_lookup_get(queue_num); | ||
| 751 | if (nfqa[NFQA_CFG_CMD-1]) { | 807 | if (nfqa[NFQA_CFG_CMD-1]) { |
| 752 | struct nfqnl_msg_config_cmd *cmd; | 808 | struct nfqnl_msg_config_cmd *cmd; |
| 753 | cmd = NFA_DATA(nfqa[NFQA_CFG_CMD-1]); | 809 | cmd = NFA_DATA(nfqa[NFQA_CFG_CMD-1]); |
| @@ -766,17 +822,19 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
| 766 | if (!queue) | 822 | if (!queue) |
| 767 | return -ENODEV; | 823 | return -ENODEV; |
| 768 | 824 | ||
| 769 | if (queue->peer_pid != NETLINK_CB(skb).pid) | 825 | if (queue->peer_pid != NETLINK_CB(skb).pid) { |
| 770 | return -EPERM; | 826 | ret = -EPERM; |
| 827 | goto out_put; | ||
| 828 | } | ||
| 771 | 829 | ||
| 772 | instance_destroy(queue); | 830 | instance_destroy(queue); |
| 773 | break; | 831 | break; |
| 774 | case NFQNL_CFG_CMD_PF_BIND: | 832 | case NFQNL_CFG_CMD_PF_BIND: |
| 775 | QDEBUG("registering queue handler for pf=%u\n", | 833 | QDEBUG("registering queue handler for pf=%u\n", |
| 776 | ntohs(cmd->pf)); | 834 | ntohs(cmd->pf)); |
| 777 | return nf_register_queue_handler(ntohs(cmd->pf), | 835 | ret = nf_register_queue_handler(ntohs(cmd->pf), |
| 778 | nfqnl_enqueue_packet, | 836 | nfqnl_enqueue_packet, |
| 779 | NULL); | 837 | NULL); |
| 780 | 838 | ||
| 781 | break; | 839 | break; |
| 782 | case NFQNL_CFG_CMD_PF_UNBIND: | 840 | case NFQNL_CFG_CMD_PF_UNBIND: |
| @@ -784,20 +842,23 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
| 784 | ntohs(cmd->pf)); | 842 | ntohs(cmd->pf)); |
| 785 | /* This is a bug and a feature. We can unregister | 843 | /* This is a bug and a feature. We can unregister |
| 786 | * other handlers(!) */ | 844 | * other handlers(!) */ |
| 787 | return nf_unregister_queue_handler(ntohs(cmd->pf)); | 845 | ret = nf_unregister_queue_handler(ntohs(cmd->pf)); |
| 788 | break; | 846 | break; |
| 789 | default: | 847 | default: |
| 790 | return -EINVAL; | 848 | ret = -EINVAL; |
| 849 | break; | ||
| 791 | } | 850 | } |
| 792 | } else { | 851 | } else { |
| 793 | if (!queue) { | 852 | if (!queue) { |
| 794 | QDEBUG("no config command, and no instance ENOENT\n"); | 853 | QDEBUG("no config command, and no instance ENOENT\n"); |
| 795 | return -ENOENT; | 854 | ret = -ENOENT; |
| 855 | goto out_put; | ||
| 796 | } | 856 | } |
| 797 | 857 | ||
| 798 | if (queue->peer_pid != NETLINK_CB(skb).pid) { | 858 | if (queue->peer_pid != NETLINK_CB(skb).pid) { |
| 799 | QDEBUG("no config command, and wrong pid\n"); | 859 | QDEBUG("no config command, and wrong pid\n"); |
| 800 | return -EPERM; | 860 | ret = -EPERM; |
| 861 | goto out_put; | ||
| 801 | } | 862 | } |
| 802 | } | 863 | } |
| 803 | 864 | ||
| @@ -809,7 +870,9 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
| 809 | ntohl(params->copy_range)); | 870 | ntohl(params->copy_range)); |
| 810 | } | 871 | } |
| 811 | 872 | ||
| 812 | return 0; | 873 | out_put: |
| 874 | instance_put(queue); | ||
| 875 | return ret; | ||
| 813 | } | 876 | } |
| 814 | 877 | ||
| 815 | static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { | 878 | static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { |
| @@ -829,14 +892,132 @@ static struct nfnetlink_subsystem nfqnl_subsys = { | |||
| 829 | .cb = nfqnl_cb, | 892 | .cb = nfqnl_cb, |
| 830 | }; | 893 | }; |
| 831 | 894 | ||
| 895 | #ifdef CONFIG_PROC_FS | ||
| 896 | struct iter_state { | ||
| 897 | unsigned int bucket; | ||
| 898 | }; | ||
| 899 | |||
| 900 | static struct hlist_node *get_first(struct seq_file *seq) | ||
| 901 | { | ||
| 902 | struct iter_state *st = seq->private; | ||
| 903 | |||
| 904 | if (!st) | ||
| 905 | return NULL; | ||
| 906 | |||
| 907 | for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { | ||
| 908 | if (!hlist_empty(&instance_table[st->bucket])) | ||
| 909 | return instance_table[st->bucket].first; | ||
| 910 | } | ||
| 911 | return NULL; | ||
| 912 | } | ||
| 913 | |||
| 914 | static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) | ||
| 915 | { | ||
| 916 | struct iter_state *st = seq->private; | ||
| 917 | |||
| 918 | h = h->next; | ||
| 919 | while (!h) { | ||
| 920 | if (++st->bucket >= INSTANCE_BUCKETS) | ||
| 921 | return NULL; | ||
| 922 | |||
| 923 | h = instance_table[st->bucket].first; | ||
| 924 | } | ||
| 925 | return h; | ||
| 926 | } | ||
| 927 | |||
| 928 | static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) | ||
| 929 | { | ||
| 930 | struct hlist_node *head; | ||
| 931 | head = get_first(seq); | ||
| 932 | |||
| 933 | if (head) | ||
| 934 | while (pos && (head = get_next(seq, head))) | ||
| 935 | pos--; | ||
| 936 | return pos ? NULL : head; | ||
| 937 | } | ||
| 938 | |||
| 939 | static void *seq_start(struct seq_file *seq, loff_t *pos) | ||
| 940 | { | ||
| 941 | read_lock_bh(&instances_lock); | ||
| 942 | return get_idx(seq, *pos); | ||
| 943 | } | ||
| 944 | |||
| 945 | static void *seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
| 946 | { | ||
| 947 | (*pos)++; | ||
| 948 | return get_next(s, v); | ||
| 949 | } | ||
| 950 | |||
| 951 | static void seq_stop(struct seq_file *s, void *v) | ||
| 952 | { | ||
| 953 | read_unlock_bh(&instances_lock); | ||
| 954 | } | ||
| 955 | |||
| 956 | static int seq_show(struct seq_file *s, void *v) | ||
| 957 | { | ||
| 958 | const struct nfqnl_instance *inst = v; | ||
| 959 | |||
| 960 | return seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d\n", | ||
| 961 | inst->queue_num, | ||
| 962 | inst->peer_pid, inst->queue_total, | ||
| 963 | inst->copy_mode, inst->copy_range, | ||
| 964 | inst->queue_dropped, inst->queue_user_dropped, | ||
| 965 | atomic_read(&inst->id_sequence), | ||
| 966 | atomic_read(&inst->use)); | ||
| 967 | } | ||
| 968 | |||
| 969 | static struct seq_operations nfqnl_seq_ops = { | ||
| 970 | .start = seq_start, | ||
| 971 | .next = seq_next, | ||
| 972 | .stop = seq_stop, | ||
| 973 | .show = seq_show, | ||
| 974 | }; | ||
| 975 | |||
| 976 | static int nfqnl_open(struct inode *inode, struct file *file) | ||
| 977 | { | ||
| 978 | struct seq_file *seq; | ||
| 979 | struct iter_state *is; | ||
| 980 | int ret; | ||
| 981 | |||
| 982 | is = kmalloc(sizeof(*is), GFP_KERNEL); | ||
| 983 | if (!is) | ||
| 984 | return -ENOMEM; | ||
| 985 | memset(is, 0, sizeof(*is)); | ||
| 986 | ret = seq_open(file, &nfqnl_seq_ops); | ||
| 987 | if (ret < 0) | ||
| 988 | goto out_free; | ||
| 989 | seq = file->private_data; | ||
| 990 | seq->private = is; | ||
| 991 | return ret; | ||
| 992 | out_free: | ||
| 993 | kfree(is); | ||
| 994 | return ret; | ||
| 995 | } | ||
| 996 | |||
| 997 | static struct file_operations nfqnl_file_ops = { | ||
| 998 | .owner = THIS_MODULE, | ||
| 999 | .open = nfqnl_open, | ||
| 1000 | .read = seq_read, | ||
| 1001 | .llseek = seq_lseek, | ||
| 1002 | .release = seq_release_private, | ||
| 1003 | }; | ||
| 1004 | |||
| 1005 | #endif /* PROC_FS */ | ||
| 1006 | |||
| 832 | static int | 1007 | static int |
| 833 | init_or_cleanup(int init) | 1008 | init_or_cleanup(int init) |
| 834 | { | 1009 | { |
| 835 | int status = -ENOMEM; | 1010 | int i, status = -ENOMEM; |
| 1011 | #ifdef CONFIG_PROC_FS | ||
| 1012 | struct proc_dir_entry *proc_nfqueue; | ||
| 1013 | #endif | ||
| 836 | 1014 | ||
| 837 | if (!init) | 1015 | if (!init) |
| 838 | goto cleanup; | 1016 | goto cleanup; |
| 839 | 1017 | ||
| 1018 | for (i = 0; i < INSTANCE_BUCKETS; i++) | ||
| 1019 | INIT_HLIST_HEAD(&instance_table[i]); | ||
| 1020 | |||
| 840 | netlink_register_notifier(&nfqnl_rtnl_notifier); | 1021 | netlink_register_notifier(&nfqnl_rtnl_notifier); |
| 841 | status = nfnetlink_subsys_register(&nfqnl_subsys); | 1022 | status = nfnetlink_subsys_register(&nfqnl_subsys); |
| 842 | if (status < 0) { | 1023 | if (status < 0) { |
| @@ -844,14 +1025,25 @@ init_or_cleanup(int init) | |||
| 844 | goto cleanup_netlink_notifier; | 1025 | goto cleanup_netlink_notifier; |
| 845 | } | 1026 | } |
| 846 | 1027 | ||
| 1028 | #ifdef CONFIG_PROC_FS | ||
| 1029 | proc_nfqueue = create_proc_entry("nfnetlink_queue", 0440, | ||
| 1030 | proc_net_netfilter); | ||
| 1031 | if (!proc_nfqueue) | ||
| 1032 | goto cleanup_subsys; | ||
| 1033 | proc_nfqueue->proc_fops = &nfqnl_file_ops; | ||
| 1034 | #endif | ||
| 1035 | |||
| 847 | register_netdevice_notifier(&nfqnl_dev_notifier); | 1036 | register_netdevice_notifier(&nfqnl_dev_notifier); |
| 1037 | |||
| 848 | return status; | 1038 | return status; |
| 849 | 1039 | ||
| 850 | cleanup: | 1040 | cleanup: |
| 851 | nf_unregister_queue_handlers(nfqnl_enqueue_packet); | 1041 | nf_unregister_queue_handlers(nfqnl_enqueue_packet); |
| 852 | unregister_netdevice_notifier(&nfqnl_dev_notifier); | 1042 | unregister_netdevice_notifier(&nfqnl_dev_notifier); |
| 1043 | #ifdef CONFIG_PROC_FS | ||
| 1044 | cleanup_subsys: | ||
| 1045 | #endif | ||
| 853 | nfnetlink_subsys_unregister(&nfqnl_subsys); | 1046 | nfnetlink_subsys_unregister(&nfqnl_subsys); |
| 854 | |||
| 855 | cleanup_netlink_notifier: | 1047 | cleanup_netlink_notifier: |
| 856 | netlink_unregister_notifier(&nfqnl_rtnl_notifier); | 1048 | netlink_unregister_notifier(&nfqnl_rtnl_notifier); |
| 857 | return status; | 1049 | return status; |
