diff options
author | Harald Welte <laforge@netfilter.org> | 2005-08-09 22:50:45 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:38:01 -0400 |
commit | 838ab6364956d9bdcefe84712de1621cf20a40b3 (patch) | |
tree | 15f07f237723f682969fd63330097cef366e2aeb | |
parent | 32519f11d38ea8f4f60896763bacec7db1760f9c (diff) |
[NETFILTER]: Add refcounting and /proc/net/netfilter interface to nfnetlink_queue
Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-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; |