diff options
author | Alexey Dobriyan <adobriyan@sw.ru> | 2008-01-31 07:48:54 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 22:28:05 -0500 |
commit | 025d93d148d46bedb26905975f5d9c83d280b46e (patch) | |
tree | 01412e1e7caf60661865a492827e07f5003f1673 /net | |
parent | 09e410def6432458c7d7e771a1807b157f4c2577 (diff) |
[NETFILTER]: x_tables: semi-rewrite of /proc/net/foo_tables_*
There are many small but still wrong things with /proc/net/*_tables_*
so I decided to do overhaul simultaneously making it more suitable for
per-netns /proc/net/*_tables_* implementation.
Fix
a) xt_get_idx() duplicating now standard seq_list_start/seq_list_next
iterators
b) tables/matches/targets list was chosen again and again on every ->next
c) multiple useless "af >= NPROTO" checks -- we simple don't supply invalid
AFs there and registration function should BUG_ON instead.
Regardless, the one in ->next() is the most useless -- ->next doesn't
run at all if ->start fails.
d) Don't use mutex_lock_interruptible() -- it can fail and ->stop is
executed even if ->start failed, so unlock without lock is possible.
As side effect, streamline code by splitting xt_tgt_ops into xt_target_ops,
xt_matches_ops, xt_tables_ops.
xt_tables_ops hooks will be changed by per-netns code. Code of
xt_matches_ops, xt_target_ops is identical except the list chosen for
iterating, but I think consolidating code for two files not worth it
given "<< 16" hacks needed for it.
[Patrick: removed unused enum in x_tables.c]
Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/x_tables.c | 230 |
1 files changed, 145 insertions, 85 deletions
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index cd78fc853a5d..89e322d3b361 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -58,12 +58,6 @@ static struct xt_af *xt; | |||
58 | #define duprintf(format, args...) | 58 | #define duprintf(format, args...) |
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | enum { | ||
62 | TABLE, | ||
63 | TARGET, | ||
64 | MATCH, | ||
65 | }; | ||
66 | |||
67 | static const char *xt_prefix[NPROTO] = { | 61 | static const char *xt_prefix[NPROTO] = { |
68 | [AF_INET] = "ip", | 62 | [AF_INET] = "ip", |
69 | [AF_INET6] = "ip6", | 63 | [AF_INET6] = "ip6", |
@@ -726,124 +720,190 @@ void *xt_unregister_table(struct xt_table *table) | |||
726 | EXPORT_SYMBOL_GPL(xt_unregister_table); | 720 | EXPORT_SYMBOL_GPL(xt_unregister_table); |
727 | 721 | ||
728 | #ifdef CONFIG_PROC_FS | 722 | #ifdef CONFIG_PROC_FS |
729 | static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos) | 723 | static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) |
730 | { | 724 | { |
731 | struct list_head *head = list->next; | 725 | struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; |
726 | u_int16_t af = (unsigned long)pde->data; | ||
732 | 727 | ||
733 | if (!head || list_empty(list)) | 728 | mutex_lock(&xt[af].mutex); |
734 | return NULL; | 729 | return seq_list_start(&init_net.xt.tables[af], *pos); |
730 | } | ||
735 | 731 | ||
736 | while (pos && (head = head->next)) { | 732 | static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
737 | if (head == list) | 733 | { |
738 | return NULL; | 734 | struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; |
739 | pos--; | 735 | u_int16_t af = (unsigned long)pde->data; |
740 | } | ||
741 | return pos ? NULL : head; | ||
742 | } | ||
743 | |||
744 | static struct list_head *type2list(u_int16_t af, u_int16_t type) | ||
745 | { | ||
746 | struct list_head *list; | ||
747 | |||
748 | switch (type) { | ||
749 | case TARGET: | ||
750 | list = &xt[af].target; | ||
751 | break; | ||
752 | case MATCH: | ||
753 | list = &xt[af].match; | ||
754 | break; | ||
755 | case TABLE: | ||
756 | list = &init_net.xt.tables[af]; | ||
757 | break; | ||
758 | default: | ||
759 | list = NULL; | ||
760 | break; | ||
761 | } | ||
762 | 736 | ||
763 | return list; | 737 | return seq_list_next(v, &init_net.xt.tables[af], pos); |
764 | } | 738 | } |
765 | 739 | ||
766 | static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos) | 740 | static void xt_table_seq_stop(struct seq_file *seq, void *v) |
767 | { | 741 | { |
768 | struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private; | 742 | struct proc_dir_entry *pde = seq->private; |
769 | u_int16_t af = (unsigned long)pde->data & 0xffff; | 743 | u_int16_t af = (unsigned long)pde->data; |
770 | u_int16_t type = (unsigned long)pde->data >> 16; | ||
771 | struct list_head *list; | ||
772 | 744 | ||
773 | if (af >= NPROTO) | 745 | mutex_unlock(&xt[af].mutex); |
774 | return NULL; | 746 | } |
775 | 747 | ||
776 | list = type2list(af, type); | 748 | static int xt_table_seq_show(struct seq_file *seq, void *v) |
777 | if (!list) | 749 | { |
778 | return NULL; | 750 | struct xt_table *table = list_entry(v, struct xt_table, list); |
779 | 751 | ||
780 | if (mutex_lock_interruptible(&xt[af].mutex) != 0) | 752 | if (strlen(table->name)) |
781 | return NULL; | 753 | return seq_printf(seq, "%s\n", table->name); |
754 | else | ||
755 | return 0; | ||
756 | } | ||
782 | 757 | ||
783 | return xt_get_idx(list, seq, *pos); | 758 | static const struct seq_operations xt_table_seq_ops = { |
759 | .start = xt_table_seq_start, | ||
760 | .next = xt_table_seq_next, | ||
761 | .stop = xt_table_seq_stop, | ||
762 | .show = xt_table_seq_show, | ||
763 | }; | ||
764 | |||
765 | static int xt_table_open(struct inode *inode, struct file *file) | ||
766 | { | ||
767 | int ret; | ||
768 | |||
769 | ret = seq_open(file, &xt_table_seq_ops); | ||
770 | if (!ret) { | ||
771 | struct seq_file *seq = file->private_data; | ||
772 | |||
773 | seq->private = PDE(inode); | ||
774 | } | ||
775 | return ret; | ||
784 | } | 776 | } |
785 | 777 | ||
786 | static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 778 | static const struct file_operations xt_table_ops = { |
779 | .owner = THIS_MODULE, | ||
780 | .open = xt_table_open, | ||
781 | .read = seq_read, | ||
782 | .llseek = seq_lseek, | ||
783 | .release = seq_release, | ||
784 | }; | ||
785 | |||
786 | static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) | ||
787 | { | 787 | { |
788 | struct proc_dir_entry *pde = seq->private; | 788 | struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; |
789 | u_int16_t af = (unsigned long)pde->data & 0xffff; | 789 | u_int16_t af = (unsigned long)pde->data; |
790 | u_int16_t type = (unsigned long)pde->data >> 16; | ||
791 | struct list_head *list; | ||
792 | 790 | ||
793 | if (af >= NPROTO) | 791 | mutex_lock(&xt[af].mutex); |
794 | return NULL; | 792 | return seq_list_start(&xt[af].match, *pos); |
793 | } | ||
795 | 794 | ||
796 | list = type2list(af, type); | 795 | static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
797 | if (!list) | 796 | { |
798 | return NULL; | 797 | struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; |
798 | u_int16_t af = (unsigned long)pde->data; | ||
799 | 799 | ||
800 | (*pos)++; | 800 | return seq_list_next(v, &xt[af].match, pos); |
801 | return xt_get_idx(list, seq, *pos); | ||
802 | } | 801 | } |
803 | 802 | ||
804 | static void xt_tgt_seq_stop(struct seq_file *seq, void *v) | 803 | static void xt_match_seq_stop(struct seq_file *seq, void *v) |
805 | { | 804 | { |
806 | struct proc_dir_entry *pde = seq->private; | 805 | struct proc_dir_entry *pde = seq->private; |
807 | u_int16_t af = (unsigned long)pde->data & 0xffff; | 806 | u_int16_t af = (unsigned long)pde->data; |
808 | 807 | ||
809 | mutex_unlock(&xt[af].mutex); | 808 | mutex_unlock(&xt[af].mutex); |
810 | } | 809 | } |
811 | 810 | ||
812 | static int xt_name_seq_show(struct seq_file *seq, void *v) | 811 | static int xt_match_seq_show(struct seq_file *seq, void *v) |
813 | { | 812 | { |
814 | char *name = (char *)v + sizeof(struct list_head); | 813 | struct xt_match *match = list_entry(v, struct xt_match, list); |
815 | 814 | ||
816 | if (strlen(name)) | 815 | if (strlen(match->name)) |
817 | return seq_printf(seq, "%s\n", name); | 816 | return seq_printf(seq, "%s\n", match->name); |
818 | else | 817 | else |
819 | return 0; | 818 | return 0; |
820 | } | 819 | } |
821 | 820 | ||
822 | static const struct seq_operations xt_tgt_seq_ops = { | 821 | static const struct seq_operations xt_match_seq_ops = { |
823 | .start = xt_tgt_seq_start, | 822 | .start = xt_match_seq_start, |
824 | .next = xt_tgt_seq_next, | 823 | .next = xt_match_seq_next, |
825 | .stop = xt_tgt_seq_stop, | 824 | .stop = xt_match_seq_stop, |
826 | .show = xt_name_seq_show, | 825 | .show = xt_match_seq_show, |
827 | }; | 826 | }; |
828 | 827 | ||
829 | static int xt_tgt_open(struct inode *inode, struct file *file) | 828 | static int xt_match_open(struct inode *inode, struct file *file) |
830 | { | 829 | { |
831 | int ret; | 830 | int ret; |
832 | 831 | ||
833 | ret = seq_open(file, &xt_tgt_seq_ops); | 832 | ret = seq_open(file, &xt_match_seq_ops); |
834 | if (!ret) { | 833 | if (!ret) { |
835 | struct seq_file *seq = file->private_data; | 834 | struct seq_file *seq = file->private_data; |
836 | struct proc_dir_entry *pde = PDE(inode); | ||
837 | 835 | ||
838 | seq->private = pde; | 836 | seq->private = PDE(inode); |
839 | } | 837 | } |
838 | return ret; | ||
839 | } | ||
840 | |||
841 | static const struct file_operations xt_match_ops = { | ||
842 | .owner = THIS_MODULE, | ||
843 | .open = xt_match_open, | ||
844 | .read = seq_read, | ||
845 | .llseek = seq_lseek, | ||
846 | .release = seq_release, | ||
847 | }; | ||
840 | 848 | ||
849 | static void *xt_target_seq_start(struct seq_file *seq, loff_t *pos) | ||
850 | { | ||
851 | struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; | ||
852 | u_int16_t af = (unsigned long)pde->data; | ||
853 | |||
854 | mutex_lock(&xt[af].mutex); | ||
855 | return seq_list_start(&xt[af].target, *pos); | ||
856 | } | ||
857 | |||
858 | static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
859 | { | ||
860 | struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; | ||
861 | u_int16_t af = (unsigned long)pde->data; | ||
862 | |||
863 | return seq_list_next(v, &xt[af].target, pos); | ||
864 | } | ||
865 | |||
866 | static void xt_target_seq_stop(struct seq_file *seq, void *v) | ||
867 | { | ||
868 | struct proc_dir_entry *pde = seq->private; | ||
869 | u_int16_t af = (unsigned long)pde->data; | ||
870 | |||
871 | mutex_unlock(&xt[af].mutex); | ||
872 | } | ||
873 | |||
874 | static int xt_target_seq_show(struct seq_file *seq, void *v) | ||
875 | { | ||
876 | struct xt_target *target = list_entry(v, struct xt_target, list); | ||
877 | |||
878 | if (strlen(target->name)) | ||
879 | return seq_printf(seq, "%s\n", target->name); | ||
880 | else | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | static const struct seq_operations xt_target_seq_ops = { | ||
885 | .start = xt_target_seq_start, | ||
886 | .next = xt_target_seq_next, | ||
887 | .stop = xt_target_seq_stop, | ||
888 | .show = xt_target_seq_show, | ||
889 | }; | ||
890 | |||
891 | static int xt_target_open(struct inode *inode, struct file *file) | ||
892 | { | ||
893 | int ret; | ||
894 | |||
895 | ret = seq_open(file, &xt_target_seq_ops); | ||
896 | if (!ret) { | ||
897 | struct seq_file *seq = file->private_data; | ||
898 | |||
899 | seq->private = PDE(inode); | ||
900 | } | ||
841 | return ret; | 901 | return ret; |
842 | } | 902 | } |
843 | 903 | ||
844 | static const struct file_operations xt_file_ops = { | 904 | static const struct file_operations xt_target_ops = { |
845 | .owner = THIS_MODULE, | 905 | .owner = THIS_MODULE, |
846 | .open = xt_tgt_open, | 906 | .open = xt_target_open, |
847 | .read = seq_read, | 907 | .read = seq_read, |
848 | .llseek = seq_lseek, | 908 | .llseek = seq_lseek, |
849 | .release = seq_release, | 909 | .release = seq_release, |
@@ -869,25 +929,25 @@ int xt_proto_init(int af) | |||
869 | #ifdef CONFIG_PROC_FS | 929 | #ifdef CONFIG_PROC_FS |
870 | strlcpy(buf, xt_prefix[af], sizeof(buf)); | 930 | strlcpy(buf, xt_prefix[af], sizeof(buf)); |
871 | strlcat(buf, FORMAT_TABLES, sizeof(buf)); | 931 | strlcat(buf, FORMAT_TABLES, sizeof(buf)); |
872 | proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); | 932 | proc = proc_net_fops_create(&init_net, buf, 0440, &xt_table_ops); |
873 | if (!proc) | 933 | if (!proc) |
874 | goto out; | 934 | goto out; |
875 | proc->data = (void *) ((unsigned long) af | (TABLE << 16)); | 935 | proc->data = (void *)(unsigned long)af; |
876 | 936 | ||
877 | 937 | ||
878 | strlcpy(buf, xt_prefix[af], sizeof(buf)); | 938 | strlcpy(buf, xt_prefix[af], sizeof(buf)); |
879 | strlcat(buf, FORMAT_MATCHES, sizeof(buf)); | 939 | strlcat(buf, FORMAT_MATCHES, sizeof(buf)); |
880 | proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); | 940 | proc = proc_net_fops_create(&init_net, buf, 0440, &xt_match_ops); |
881 | if (!proc) | 941 | if (!proc) |
882 | goto out_remove_tables; | 942 | goto out_remove_tables; |
883 | proc->data = (void *) ((unsigned long) af | (MATCH << 16)); | 943 | proc->data = (void *)(unsigned long)af; |
884 | 944 | ||
885 | strlcpy(buf, xt_prefix[af], sizeof(buf)); | 945 | strlcpy(buf, xt_prefix[af], sizeof(buf)); |
886 | strlcat(buf, FORMAT_TARGETS, sizeof(buf)); | 946 | strlcat(buf, FORMAT_TARGETS, sizeof(buf)); |
887 | proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops); | 947 | proc = proc_net_fops_create(&init_net, buf, 0440, &xt_target_ops); |
888 | if (!proc) | 948 | if (!proc) |
889 | goto out_remove_matches; | 949 | goto out_remove_matches; |
890 | proc->data = (void *) ((unsigned long) af | (TARGET << 16)); | 950 | proc->data = (void *)(unsigned long)af; |
891 | #endif | 951 | #endif |
892 | 952 | ||
893 | return 0; | 953 | return 0; |