diff options
author | David S. Miller <davem@davemloft.net> | 2010-02-24 21:23:37 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-24 21:23:37 -0500 |
commit | 54831a83bfe656c4c54e287c734c6b0ccaa3719b (patch) | |
tree | abd5bef16d1a6011f629a36d4e245a2ed4f3df3c /net/ipv6 | |
parent | fb977e2ca607a7e74946a1de798f474d1b80b9d6 (diff) | |
parent | 0f234214d15fa914436d304ecf5c3e43449e79f9 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 436 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 8 |
2 files changed, 215 insertions, 229 deletions
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 4185099c2943..f7042869198e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -318,6 +318,7 @@ static void trace_packet(const struct sk_buff *skb, | |||
318 | const void *table_base; | 318 | const void *table_base; |
319 | const struct ip6t_entry *root; | 319 | const struct ip6t_entry *root; |
320 | const char *hookname, *chainname, *comment; | 320 | const char *hookname, *chainname, *comment; |
321 | const struct ip6t_entry *iter; | ||
321 | unsigned int rulenum = 0; | 322 | unsigned int rulenum = 0; |
322 | 323 | ||
323 | table_base = private->entries[smp_processor_id()]; | 324 | table_base = private->entries[smp_processor_id()]; |
@@ -326,10 +327,10 @@ static void trace_packet(const struct sk_buff *skb, | |||
326 | hookname = chainname = hooknames[hook]; | 327 | hookname = chainname = hooknames[hook]; |
327 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; | 328 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; |
328 | 329 | ||
329 | IP6T_ENTRY_ITERATE(root, | 330 | xt_entry_foreach(iter, root, private->size - private->hook_entry[hook]) |
330 | private->size - private->hook_entry[hook], | 331 | if (get_chainname_rulenum(iter, e, hookname, |
331 | get_chainname_rulenum, | 332 | &chainname, &comment, &rulenum) != 0) |
332 | e, hookname, &chainname, &comment, &rulenum); | 333 | break; |
333 | 334 | ||
334 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, | 335 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, |
335 | "TRACE: %s:%s:%s:%u ", | 336 | "TRACE: %s:%s:%s:%u ", |
@@ -392,16 +393,21 @@ ip6t_do_table(struct sk_buff *skb, | |||
392 | 393 | ||
393 | do { | 394 | do { |
394 | const struct ip6t_entry_target *t; | 395 | const struct ip6t_entry_target *t; |
396 | const struct xt_entry_match *ematch; | ||
395 | 397 | ||
396 | IP_NF_ASSERT(e); | 398 | IP_NF_ASSERT(e); |
397 | IP_NF_ASSERT(back); | 399 | IP_NF_ASSERT(back); |
398 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, | 400 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, |
399 | &mtpar.thoff, &mtpar.fragoff, &hotdrop) || | 401 | &mtpar.thoff, &mtpar.fragoff, &hotdrop)) { |
400 | IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { | 402 | no_match: |
401 | e = ip6t_next_entry(e); | 403 | e = ip6t_next_entry(e); |
402 | continue; | 404 | continue; |
403 | } | 405 | } |
404 | 406 | ||
407 | xt_ematch_foreach(ematch, e) | ||
408 | if (do_match(ematch, skb, &mtpar) != 0) | ||
409 | goto no_match; | ||
410 | |||
405 | ADD_COUNTER(e->counters, | 411 | ADD_COUNTER(e->counters, |
406 | ntohs(ipv6_hdr(skb)->payload_len) + | 412 | ntohs(ipv6_hdr(skb)->payload_len) + |
407 | sizeof(struct ipv6hdr), 1); | 413 | sizeof(struct ipv6hdr), 1); |
@@ -597,14 +603,10 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
597 | return 1; | 603 | return 1; |
598 | } | 604 | } |
599 | 605 | ||
600 | static int | 606 | static void cleanup_match(struct ip6t_entry_match *m, struct net *net) |
601 | cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i) | ||
602 | { | 607 | { |
603 | struct xt_mtdtor_param par; | 608 | struct xt_mtdtor_param par; |
604 | 609 | ||
605 | if (i && (*i)-- == 0) | ||
606 | return 1; | ||
607 | |||
608 | par.net = net; | 610 | par.net = net; |
609 | par.match = m->u.kernel.match; | 611 | par.match = m->u.kernel.match; |
610 | par.matchinfo = m->data; | 612 | par.matchinfo = m->data; |
@@ -612,7 +614,6 @@ cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i) | |||
612 | if (par.match->destroy != NULL) | 614 | if (par.match->destroy != NULL) |
613 | par.match->destroy(&par); | 615 | par.match->destroy(&par); |
614 | module_put(par.match->me); | 616 | module_put(par.match->me); |
615 | return 0; | ||
616 | } | 617 | } |
617 | 618 | ||
618 | static int | 619 | static int |
@@ -636,8 +637,7 @@ check_entry(const struct ip6t_entry *e, const char *name) | |||
636 | return 0; | 637 | return 0; |
637 | } | 638 | } |
638 | 639 | ||
639 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 640 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
640 | unsigned int *i) | ||
641 | { | 641 | { |
642 | const struct ip6t_ip6 *ipv6 = par->entryinfo; | 642 | const struct ip6t_ip6 *ipv6 = par->entryinfo; |
643 | int ret; | 643 | int ret; |
@@ -652,13 +652,11 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | |||
652 | par.match->name); | 652 | par.match->name); |
653 | return ret; | 653 | return ret; |
654 | } | 654 | } |
655 | ++*i; | ||
656 | return 0; | 655 | return 0; |
657 | } | 656 | } |
658 | 657 | ||
659 | static int | 658 | static int |
660 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 659 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
661 | unsigned int *i) | ||
662 | { | 660 | { |
663 | struct xt_match *match; | 661 | struct xt_match *match; |
664 | int ret; | 662 | int ret; |
@@ -672,7 +670,7 @@ find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | |||
672 | } | 670 | } |
673 | m->u.kernel.match = match; | 671 | m->u.kernel.match = match; |
674 | 672 | ||
675 | ret = check_match(m, par, i); | 673 | ret = check_match(m, par); |
676 | if (ret) | 674 | if (ret) |
677 | goto err; | 675 | goto err; |
678 | 676 | ||
@@ -709,13 +707,14 @@ static int check_target(struct ip6t_entry *e, struct net *net, const char *name) | |||
709 | 707 | ||
710 | static int | 708 | static int |
711 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | 709 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, |
712 | unsigned int size, unsigned int *i) | 710 | unsigned int size) |
713 | { | 711 | { |
714 | struct ip6t_entry_target *t; | 712 | struct ip6t_entry_target *t; |
715 | struct xt_target *target; | 713 | struct xt_target *target; |
716 | int ret; | 714 | int ret; |
717 | unsigned int j; | 715 | unsigned int j; |
718 | struct xt_mtchk_param mtpar; | 716 | struct xt_mtchk_param mtpar; |
717 | struct xt_entry_match *ematch; | ||
719 | 718 | ||
720 | ret = check_entry(e, name); | 719 | ret = check_entry(e, name); |
721 | if (ret) | 720 | if (ret) |
@@ -727,9 +726,12 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | |||
727 | mtpar.entryinfo = &e->ipv6; | 726 | mtpar.entryinfo = &e->ipv6; |
728 | mtpar.hook_mask = e->comefrom; | 727 | mtpar.hook_mask = e->comefrom; |
729 | mtpar.family = NFPROTO_IPV6; | 728 | mtpar.family = NFPROTO_IPV6; |
730 | ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j); | 729 | xt_ematch_foreach(ematch, e) { |
731 | if (ret != 0) | 730 | ret = find_check_match(ematch, &mtpar); |
732 | goto cleanup_matches; | 731 | if (ret != 0) |
732 | goto cleanup_matches; | ||
733 | ++j; | ||
734 | } | ||
733 | 735 | ||
734 | t = ip6t_get_target(e); | 736 | t = ip6t_get_target(e); |
735 | target = try_then_request_module(xt_find_target(AF_INET6, | 737 | target = try_then_request_module(xt_find_target(AF_INET6, |
@@ -746,13 +748,15 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | |||
746 | ret = check_target(e, net, name); | 748 | ret = check_target(e, net, name); |
747 | if (ret) | 749 | if (ret) |
748 | goto err; | 750 | goto err; |
749 | |||
750 | (*i)++; | ||
751 | return 0; | 751 | return 0; |
752 | err: | 752 | err: |
753 | module_put(t->u.kernel.target->me); | 753 | module_put(t->u.kernel.target->me); |
754 | cleanup_matches: | 754 | cleanup_matches: |
755 | IP6T_MATCH_ITERATE(e, cleanup_match, net, &j); | 755 | xt_ematch_foreach(ematch, e) { |
756 | if (j-- == 0) | ||
757 | break; | ||
758 | cleanup_match(ematch, net); | ||
759 | } | ||
756 | return ret; | 760 | return ret; |
757 | } | 761 | } |
758 | 762 | ||
@@ -778,8 +782,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
778 | const unsigned char *limit, | 782 | const unsigned char *limit, |
779 | const unsigned int *hook_entries, | 783 | const unsigned int *hook_entries, |
780 | const unsigned int *underflows, | 784 | const unsigned int *underflows, |
781 | unsigned int valid_hooks, | 785 | unsigned int valid_hooks) |
782 | unsigned int *i) | ||
783 | { | 786 | { |
784 | unsigned int h; | 787 | unsigned int h; |
785 | 788 | ||
@@ -816,22 +819,18 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
816 | /* Clear counters and comefrom */ | 819 | /* Clear counters and comefrom */ |
817 | e->counters = ((struct xt_counters) { 0, 0 }); | 820 | e->counters = ((struct xt_counters) { 0, 0 }); |
818 | e->comefrom = 0; | 821 | e->comefrom = 0; |
819 | |||
820 | (*i)++; | ||
821 | return 0; | 822 | return 0; |
822 | } | 823 | } |
823 | 824 | ||
824 | static int | 825 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) |
825 | cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) | ||
826 | { | 826 | { |
827 | struct xt_tgdtor_param par; | 827 | struct xt_tgdtor_param par; |
828 | struct ip6t_entry_target *t; | 828 | struct ip6t_entry_target *t; |
829 | 829 | struct xt_entry_match *ematch; | |
830 | if (i && (*i)-- == 0) | ||
831 | return 1; | ||
832 | 830 | ||
833 | /* Cleanup all matches */ | 831 | /* Cleanup all matches */ |
834 | IP6T_MATCH_ITERATE(e, cleanup_match, net, NULL); | 832 | xt_ematch_foreach(ematch, e) |
833 | cleanup_match(ematch, net); | ||
835 | t = ip6t_get_target(e); | 834 | t = ip6t_get_target(e); |
836 | 835 | ||
837 | par.net = net; | 836 | par.net = net; |
@@ -841,27 +840,20 @@ cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) | |||
841 | if (par.target->destroy != NULL) | 840 | if (par.target->destroy != NULL) |
842 | par.target->destroy(&par); | 841 | par.target->destroy(&par); |
843 | module_put(par.target->me); | 842 | module_put(par.target->me); |
844 | return 0; | ||
845 | } | 843 | } |
846 | 844 | ||
847 | /* Checks and translates the user-supplied table segment (held in | 845 | /* Checks and translates the user-supplied table segment (held in |
848 | newinfo) */ | 846 | newinfo) */ |
849 | static int | 847 | static int |
850 | translate_table(struct net *net, | 848 | translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, |
851 | const char *name, | 849 | const struct ip6t_replace *repl) |
852 | unsigned int valid_hooks, | ||
853 | struct xt_table_info *newinfo, | ||
854 | void *entry0, | ||
855 | unsigned int size, | ||
856 | unsigned int number, | ||
857 | const unsigned int *hook_entries, | ||
858 | const unsigned int *underflows) | ||
859 | { | 850 | { |
851 | struct ip6t_entry *iter; | ||
860 | unsigned int i; | 852 | unsigned int i; |
861 | int ret; | 853 | int ret = 0; |
862 | 854 | ||
863 | newinfo->size = size; | 855 | newinfo->size = repl->size; |
864 | newinfo->number = number; | 856 | newinfo->number = repl->num_entries; |
865 | 857 | ||
866 | /* Init all hooks to impossible value. */ | 858 | /* Init all hooks to impossible value. */ |
867 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 859 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
@@ -872,49 +864,56 @@ translate_table(struct net *net, | |||
872 | duprintf("translate_table: size %u\n", newinfo->size); | 864 | duprintf("translate_table: size %u\n", newinfo->size); |
873 | i = 0; | 865 | i = 0; |
874 | /* Walk through entries, checking offsets. */ | 866 | /* Walk through entries, checking offsets. */ |
875 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 867 | xt_entry_foreach(iter, entry0, newinfo->size) { |
876 | check_entry_size_and_hooks, | 868 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
877 | newinfo, | 869 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
878 | entry0, | 870 | repl->valid_hooks); |
879 | entry0 + size, | 871 | if (ret != 0) |
880 | hook_entries, underflows, valid_hooks, &i); | 872 | return ret; |
881 | if (ret != 0) | 873 | ++i; |
882 | return ret; | 874 | } |
883 | 875 | ||
884 | if (i != number) { | 876 | if (i != repl->num_entries) { |
885 | duprintf("translate_table: %u not %u entries\n", | 877 | duprintf("translate_table: %u not %u entries\n", |
886 | i, number); | 878 | i, repl->num_entries); |
887 | return -EINVAL; | 879 | return -EINVAL; |
888 | } | 880 | } |
889 | 881 | ||
890 | /* Check hooks all assigned */ | 882 | /* Check hooks all assigned */ |
891 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 883 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
892 | /* Only hooks which are valid */ | 884 | /* Only hooks which are valid */ |
893 | if (!(valid_hooks & (1 << i))) | 885 | if (!(repl->valid_hooks & (1 << i))) |
894 | continue; | 886 | continue; |
895 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 887 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
896 | duprintf("Invalid hook entry %u %u\n", | 888 | duprintf("Invalid hook entry %u %u\n", |
897 | i, hook_entries[i]); | 889 | i, repl->hook_entry[i]); |
898 | return -EINVAL; | 890 | return -EINVAL; |
899 | } | 891 | } |
900 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 892 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
901 | duprintf("Invalid underflow %u %u\n", | 893 | duprintf("Invalid underflow %u %u\n", |
902 | i, underflows[i]); | 894 | i, repl->underflow[i]); |
903 | return -EINVAL; | 895 | return -EINVAL; |
904 | } | 896 | } |
905 | } | 897 | } |
906 | 898 | ||
907 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | 899 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) |
908 | return -ELOOP; | 900 | return -ELOOP; |
909 | 901 | ||
910 | /* Finally, each sanity check must pass */ | 902 | /* Finally, each sanity check must pass */ |
911 | i = 0; | 903 | i = 0; |
912 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 904 | xt_entry_foreach(iter, entry0, newinfo->size) { |
913 | find_check_entry, net, name, size, &i); | 905 | ret = find_check_entry(iter, net, repl->name, repl->size); |
906 | if (ret != 0) | ||
907 | break; | ||
908 | ++i; | ||
909 | } | ||
914 | 910 | ||
915 | if (ret != 0) { | 911 | if (ret != 0) { |
916 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 912 | xt_entry_foreach(iter, entry0, newinfo->size) { |
917 | cleanup_entry, net, &i); | 913 | if (i-- == 0) |
914 | break; | ||
915 | cleanup_entry(iter, net); | ||
916 | } | ||
918 | return ret; | 917 | return ret; |
919 | } | 918 | } |
920 | 919 | ||
@@ -927,33 +926,11 @@ translate_table(struct net *net, | |||
927 | return ret; | 926 | return ret; |
928 | } | 927 | } |
929 | 928 | ||
930 | /* Gets counters. */ | ||
931 | static inline int | ||
932 | add_entry_to_counter(const struct ip6t_entry *e, | ||
933 | struct xt_counters total[], | ||
934 | unsigned int *i) | ||
935 | { | ||
936 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
937 | |||
938 | (*i)++; | ||
939 | return 0; | ||
940 | } | ||
941 | |||
942 | static inline int | ||
943 | set_entry_to_counter(const struct ip6t_entry *e, | ||
944 | struct ip6t_counters total[], | ||
945 | unsigned int *i) | ||
946 | { | ||
947 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
948 | |||
949 | (*i)++; | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static void | 929 | static void |
954 | get_counters(const struct xt_table_info *t, | 930 | get_counters(const struct xt_table_info *t, |
955 | struct xt_counters counters[]) | 931 | struct xt_counters counters[]) |
956 | { | 932 | { |
933 | struct ip6t_entry *iter; | ||
957 | unsigned int cpu; | 934 | unsigned int cpu; |
958 | unsigned int i; | 935 | unsigned int i; |
959 | unsigned int curcpu; | 936 | unsigned int curcpu; |
@@ -969,22 +946,22 @@ get_counters(const struct xt_table_info *t, | |||
969 | curcpu = smp_processor_id(); | 946 | curcpu = smp_processor_id(); |
970 | 947 | ||
971 | i = 0; | 948 | i = 0; |
972 | IP6T_ENTRY_ITERATE(t->entries[curcpu], | 949 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
973 | t->size, | 950 | SET_COUNTER(counters[i], iter->counters.bcnt, |
974 | set_entry_to_counter, | 951 | iter->counters.pcnt); |
975 | counters, | 952 | ++i; |
976 | &i); | 953 | } |
977 | 954 | ||
978 | for_each_possible_cpu(cpu) { | 955 | for_each_possible_cpu(cpu) { |
979 | if (cpu == curcpu) | 956 | if (cpu == curcpu) |
980 | continue; | 957 | continue; |
981 | i = 0; | 958 | i = 0; |
982 | xt_info_wrlock(cpu); | 959 | xt_info_wrlock(cpu); |
983 | IP6T_ENTRY_ITERATE(t->entries[cpu], | 960 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
984 | t->size, | 961 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
985 | add_entry_to_counter, | 962 | iter->counters.pcnt); |
986 | counters, | 963 | ++i; |
987 | &i); | 964 | } |
988 | xt_info_wrunlock(cpu); | 965 | xt_info_wrunlock(cpu); |
989 | } | 966 | } |
990 | local_bh_enable(); | 967 | local_bh_enable(); |
@@ -1103,24 +1080,19 @@ static int compat_standard_to_user(void __user *dst, const void *src) | |||
1103 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1080 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
1104 | } | 1081 | } |
1105 | 1082 | ||
1106 | static inline int | ||
1107 | compat_calc_match(const struct ip6t_entry_match *m, int *size) | ||
1108 | { | ||
1109 | *size += xt_compat_match_offset(m->u.kernel.match); | ||
1110 | return 0; | ||
1111 | } | ||
1112 | |||
1113 | static int compat_calc_entry(const struct ip6t_entry *e, | 1083 | static int compat_calc_entry(const struct ip6t_entry *e, |
1114 | const struct xt_table_info *info, | 1084 | const struct xt_table_info *info, |
1115 | const void *base, struct xt_table_info *newinfo) | 1085 | const void *base, struct xt_table_info *newinfo) |
1116 | { | 1086 | { |
1087 | const struct xt_entry_match *ematch; | ||
1117 | const struct ip6t_entry_target *t; | 1088 | const struct ip6t_entry_target *t; |
1118 | unsigned int entry_offset; | 1089 | unsigned int entry_offset; |
1119 | int off, i, ret; | 1090 | int off, i, ret; |
1120 | 1091 | ||
1121 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1092 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1122 | entry_offset = (void *)e - base; | 1093 | entry_offset = (void *)e - base; |
1123 | IP6T_MATCH_ITERATE(e, compat_calc_match, &off); | 1094 | xt_ematch_foreach(ematch, e) |
1095 | off += xt_compat_match_offset(ematch->u.kernel.match); | ||
1124 | t = ip6t_get_target_c(e); | 1096 | t = ip6t_get_target_c(e); |
1125 | off += xt_compat_target_offset(t->u.kernel.target); | 1097 | off += xt_compat_target_offset(t->u.kernel.target); |
1126 | newinfo->size -= off; | 1098 | newinfo->size -= off; |
@@ -1142,7 +1114,9 @@ static int compat_calc_entry(const struct ip6t_entry *e, | |||
1142 | static int compat_table_info(const struct xt_table_info *info, | 1114 | static int compat_table_info(const struct xt_table_info *info, |
1143 | struct xt_table_info *newinfo) | 1115 | struct xt_table_info *newinfo) |
1144 | { | 1116 | { |
1117 | struct ip6t_entry *iter; | ||
1145 | void *loc_cpu_entry; | 1118 | void *loc_cpu_entry; |
1119 | int ret; | ||
1146 | 1120 | ||
1147 | if (!newinfo || !info) | 1121 | if (!newinfo || !info) |
1148 | return -EINVAL; | 1122 | return -EINVAL; |
@@ -1151,9 +1125,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1151 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1125 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
1152 | newinfo->initial_entries = 0; | 1126 | newinfo->initial_entries = 0; |
1153 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1127 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
1154 | return IP6T_ENTRY_ITERATE(loc_cpu_entry, info->size, | 1128 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1155 | compat_calc_entry, info, loc_cpu_entry, | 1129 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1156 | newinfo); | 1130 | if (ret != 0) |
1131 | return ret; | ||
1132 | } | ||
1133 | return 0; | ||
1157 | } | 1134 | } |
1158 | #endif | 1135 | #endif |
1159 | 1136 | ||
@@ -1267,6 +1244,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1267 | struct xt_table_info *oldinfo; | 1244 | struct xt_table_info *oldinfo; |
1268 | struct xt_counters *counters; | 1245 | struct xt_counters *counters; |
1269 | const void *loc_cpu_old_entry; | 1246 | const void *loc_cpu_old_entry; |
1247 | struct ip6t_entry *iter; | ||
1270 | 1248 | ||
1271 | ret = 0; | 1249 | ret = 0; |
1272 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), | 1250 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), |
@@ -1310,8 +1288,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1310 | 1288 | ||
1311 | /* Decrease module usage counts and free resource */ | 1289 | /* Decrease module usage counts and free resource */ |
1312 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1290 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1313 | IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1291 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1314 | net, NULL); | 1292 | cleanup_entry(iter, net); |
1293 | |||
1315 | xt_free_table_info(oldinfo); | 1294 | xt_free_table_info(oldinfo); |
1316 | if (copy_to_user(counters_ptr, counters, | 1295 | if (copy_to_user(counters_ptr, counters, |
1317 | sizeof(struct xt_counters) * num_counters) != 0) | 1296 | sizeof(struct xt_counters) * num_counters) != 0) |
@@ -1336,6 +1315,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1336 | struct ip6t_replace tmp; | 1315 | struct ip6t_replace tmp; |
1337 | struct xt_table_info *newinfo; | 1316 | struct xt_table_info *newinfo; |
1338 | void *loc_cpu_entry; | 1317 | void *loc_cpu_entry; |
1318 | struct ip6t_entry *iter; | ||
1339 | 1319 | ||
1340 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1320 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1341 | return -EFAULT; | 1321 | return -EFAULT; |
@@ -1356,9 +1336,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1356 | goto free_newinfo; | 1336 | goto free_newinfo; |
1357 | } | 1337 | } |
1358 | 1338 | ||
1359 | ret = translate_table(net, tmp.name, tmp.valid_hooks, | 1339 | ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); |
1360 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
1361 | tmp.hook_entry, tmp.underflow); | ||
1362 | if (ret != 0) | 1340 | if (ret != 0) |
1363 | goto free_newinfo; | 1341 | goto free_newinfo; |
1364 | 1342 | ||
@@ -1371,25 +1349,13 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1371 | return 0; | 1349 | return 0; |
1372 | 1350 | ||
1373 | free_newinfo_untrans: | 1351 | free_newinfo_untrans: |
1374 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1352 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1353 | cleanup_entry(iter, net); | ||
1375 | free_newinfo: | 1354 | free_newinfo: |
1376 | xt_free_table_info(newinfo); | 1355 | xt_free_table_info(newinfo); |
1377 | return ret; | 1356 | return ret; |
1378 | } | 1357 | } |
1379 | 1358 | ||
1380 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1381 | * and everything is OK. */ | ||
1382 | static int | ||
1383 | add_counter_to_entry(struct ip6t_entry *e, | ||
1384 | const struct xt_counters addme[], | ||
1385 | unsigned int *i) | ||
1386 | { | ||
1387 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1388 | |||
1389 | (*i)++; | ||
1390 | return 0; | ||
1391 | } | ||
1392 | |||
1393 | static int | 1359 | static int |
1394 | do_add_counters(struct net *net, const void __user *user, unsigned int len, | 1360 | do_add_counters(struct net *net, const void __user *user, unsigned int len, |
1395 | int compat) | 1361 | int compat) |
@@ -1405,6 +1371,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1405 | const struct xt_table_info *private; | 1371 | const struct xt_table_info *private; |
1406 | int ret = 0; | 1372 | int ret = 0; |
1407 | const void *loc_cpu_entry; | 1373 | const void *loc_cpu_entry; |
1374 | struct ip6t_entry *iter; | ||
1408 | #ifdef CONFIG_COMPAT | 1375 | #ifdef CONFIG_COMPAT |
1409 | struct compat_xt_counters_info compat_tmp; | 1376 | struct compat_xt_counters_info compat_tmp; |
1410 | 1377 | ||
@@ -1463,11 +1430,10 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1463 | curcpu = smp_processor_id(); | 1430 | curcpu = smp_processor_id(); |
1464 | xt_info_wrlock(curcpu); | 1431 | xt_info_wrlock(curcpu); |
1465 | loc_cpu_entry = private->entries[curcpu]; | 1432 | loc_cpu_entry = private->entries[curcpu]; |
1466 | IP6T_ENTRY_ITERATE(loc_cpu_entry, | 1433 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1467 | private->size, | 1434 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1468 | add_counter_to_entry, | 1435 | ++i; |
1469 | paddc, | 1436 | } |
1470 | &i); | ||
1471 | xt_info_wrunlock(curcpu); | 1437 | xt_info_wrunlock(curcpu); |
1472 | 1438 | ||
1473 | unlock_up_free: | 1439 | unlock_up_free: |
@@ -1496,45 +1462,40 @@ struct compat_ip6t_replace { | |||
1496 | static int | 1462 | static int |
1497 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | 1463 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, |
1498 | unsigned int *size, struct xt_counters *counters, | 1464 | unsigned int *size, struct xt_counters *counters, |
1499 | unsigned int *i) | 1465 | unsigned int i) |
1500 | { | 1466 | { |
1501 | struct ip6t_entry_target *t; | 1467 | struct ip6t_entry_target *t; |
1502 | struct compat_ip6t_entry __user *ce; | 1468 | struct compat_ip6t_entry __user *ce; |
1503 | u_int16_t target_offset, next_offset; | 1469 | u_int16_t target_offset, next_offset; |
1504 | compat_uint_t origsize; | 1470 | compat_uint_t origsize; |
1505 | int ret; | 1471 | const struct xt_entry_match *ematch; |
1472 | int ret = 0; | ||
1506 | 1473 | ||
1507 | ret = -EFAULT; | ||
1508 | origsize = *size; | 1474 | origsize = *size; |
1509 | ce = (struct compat_ip6t_entry __user *)*dstptr; | 1475 | ce = (struct compat_ip6t_entry __user *)*dstptr; |
1510 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry))) | 1476 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || |
1511 | goto out; | 1477 | copy_to_user(&ce->counters, &counters[i], |
1512 | 1478 | sizeof(counters[i])) != 0) | |
1513 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1479 | return -EFAULT; |
1514 | goto out; | ||
1515 | 1480 | ||
1516 | *dstptr += sizeof(struct compat_ip6t_entry); | 1481 | *dstptr += sizeof(struct compat_ip6t_entry); |
1517 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1482 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1518 | 1483 | ||
1519 | ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1484 | xt_ematch_foreach(ematch, e) { |
1485 | ret = xt_compat_match_to_user(ematch, dstptr, size); | ||
1486 | if (ret != 0) | ||
1487 | return ret; | ||
1488 | } | ||
1520 | target_offset = e->target_offset - (origsize - *size); | 1489 | target_offset = e->target_offset - (origsize - *size); |
1521 | if (ret) | ||
1522 | goto out; | ||
1523 | t = ip6t_get_target(e); | 1490 | t = ip6t_get_target(e); |
1524 | ret = xt_compat_target_to_user(t, dstptr, size); | 1491 | ret = xt_compat_target_to_user(t, dstptr, size); |
1525 | if (ret) | 1492 | if (ret) |
1526 | goto out; | 1493 | return ret; |
1527 | ret = -EFAULT; | ||
1528 | next_offset = e->next_offset - (origsize - *size); | 1494 | next_offset = e->next_offset - (origsize - *size); |
1529 | if (put_user(target_offset, &ce->target_offset)) | 1495 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1530 | goto out; | 1496 | put_user(next_offset, &ce->next_offset) != 0) |
1531 | if (put_user(next_offset, &ce->next_offset)) | 1497 | return -EFAULT; |
1532 | goto out; | ||
1533 | |||
1534 | (*i)++; | ||
1535 | return 0; | 1498 | return 0; |
1536 | out: | ||
1537 | return ret; | ||
1538 | } | 1499 | } |
1539 | 1500 | ||
1540 | static int | 1501 | static int |
@@ -1542,7 +1503,7 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
1542 | const char *name, | 1503 | const char *name, |
1543 | const struct ip6t_ip6 *ipv6, | 1504 | const struct ip6t_ip6 *ipv6, |
1544 | unsigned int hookmask, | 1505 | unsigned int hookmask, |
1545 | int *size, unsigned int *i) | 1506 | int *size) |
1546 | { | 1507 | { |
1547 | struct xt_match *match; | 1508 | struct xt_match *match; |
1548 | 1509 | ||
@@ -1556,34 +1517,19 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
1556 | } | 1517 | } |
1557 | m->u.kernel.match = match; | 1518 | m->u.kernel.match = match; |
1558 | *size += xt_compat_match_offset(match); | 1519 | *size += xt_compat_match_offset(match); |
1559 | |||
1560 | (*i)++; | ||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | static int | ||
1565 | compat_release_match(struct ip6t_entry_match *m, unsigned int *i) | ||
1566 | { | ||
1567 | if (i && (*i)-- == 0) | ||
1568 | return 1; | ||
1569 | |||
1570 | module_put(m->u.kernel.match->me); | ||
1571 | return 0; | 1520 | return 0; |
1572 | } | 1521 | } |
1573 | 1522 | ||
1574 | static int | 1523 | static void compat_release_entry(struct compat_ip6t_entry *e) |
1575 | compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i) | ||
1576 | { | 1524 | { |
1577 | struct ip6t_entry_target *t; | 1525 | struct ip6t_entry_target *t; |
1578 | 1526 | struct xt_entry_match *ematch; | |
1579 | if (i && (*i)-- == 0) | ||
1580 | return 1; | ||
1581 | 1527 | ||
1582 | /* Cleanup all matches */ | 1528 | /* Cleanup all matches */ |
1583 | COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL); | 1529 | xt_ematch_foreach(ematch, e) |
1530 | module_put(ematch->u.kernel.match->me); | ||
1584 | t = compat_ip6t_get_target(e); | 1531 | t = compat_ip6t_get_target(e); |
1585 | module_put(t->u.kernel.target->me); | 1532 | module_put(t->u.kernel.target->me); |
1586 | return 0; | ||
1587 | } | 1533 | } |
1588 | 1534 | ||
1589 | static int | 1535 | static int |
@@ -1594,9 +1540,9 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1594 | const unsigned char *limit, | 1540 | const unsigned char *limit, |
1595 | const unsigned int *hook_entries, | 1541 | const unsigned int *hook_entries, |
1596 | const unsigned int *underflows, | 1542 | const unsigned int *underflows, |
1597 | unsigned int *i, | ||
1598 | const char *name) | 1543 | const char *name) |
1599 | { | 1544 | { |
1545 | struct xt_entry_match *ematch; | ||
1600 | struct ip6t_entry_target *t; | 1546 | struct ip6t_entry_target *t; |
1601 | struct xt_target *target; | 1547 | struct xt_target *target; |
1602 | unsigned int entry_offset; | 1548 | unsigned int entry_offset; |
@@ -1625,10 +1571,13 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1625 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1571 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1626 | entry_offset = (void *)e - (void *)base; | 1572 | entry_offset = (void *)e - (void *)base; |
1627 | j = 0; | 1573 | j = 0; |
1628 | ret = COMPAT_IP6T_MATCH_ITERATE(e, compat_find_calc_match, name, | 1574 | xt_ematch_foreach(ematch, e) { |
1629 | &e->ipv6, e->comefrom, &off, &j); | 1575 | ret = compat_find_calc_match(ematch, name, |
1630 | if (ret != 0) | 1576 | &e->ipv6, e->comefrom, &off); |
1631 | goto release_matches; | 1577 | if (ret != 0) |
1578 | goto release_matches; | ||
1579 | ++j; | ||
1580 | } | ||
1632 | 1581 | ||
1633 | t = compat_ip6t_get_target(e); | 1582 | t = compat_ip6t_get_target(e); |
1634 | target = try_then_request_module(xt_find_target(AF_INET6, | 1583 | target = try_then_request_module(xt_find_target(AF_INET6, |
@@ -1660,14 +1609,16 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1660 | /* Clear counters and comefrom */ | 1609 | /* Clear counters and comefrom */ |
1661 | memset(&e->counters, 0, sizeof(e->counters)); | 1610 | memset(&e->counters, 0, sizeof(e->counters)); |
1662 | e->comefrom = 0; | 1611 | e->comefrom = 0; |
1663 | |||
1664 | (*i)++; | ||
1665 | return 0; | 1612 | return 0; |
1666 | 1613 | ||
1667 | out: | 1614 | out: |
1668 | module_put(t->u.kernel.target->me); | 1615 | module_put(t->u.kernel.target->me); |
1669 | release_matches: | 1616 | release_matches: |
1670 | IP6T_MATCH_ITERATE(e, compat_release_match, &j); | 1617 | xt_ematch_foreach(ematch, e) { |
1618 | if (j-- == 0) | ||
1619 | break; | ||
1620 | module_put(ematch->u.kernel.match->me); | ||
1621 | } | ||
1671 | return ret; | 1622 | return ret; |
1672 | } | 1623 | } |
1673 | 1624 | ||
@@ -1681,6 +1632,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1681 | struct ip6t_entry *de; | 1632 | struct ip6t_entry *de; |
1682 | unsigned int origsize; | 1633 | unsigned int origsize; |
1683 | int ret, h; | 1634 | int ret, h; |
1635 | struct xt_entry_match *ematch; | ||
1684 | 1636 | ||
1685 | ret = 0; | 1637 | ret = 0; |
1686 | origsize = *size; | 1638 | origsize = *size; |
@@ -1691,10 +1643,11 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1691 | *dstptr += sizeof(struct ip6t_entry); | 1643 | *dstptr += sizeof(struct ip6t_entry); |
1692 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1644 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1693 | 1645 | ||
1694 | ret = COMPAT_IP6T_MATCH_ITERATE(e, xt_compat_match_from_user, | 1646 | xt_ematch_foreach(ematch, e) { |
1695 | dstptr, size); | 1647 | ret = xt_compat_match_from_user(ematch, dstptr, size); |
1696 | if (ret) | 1648 | if (ret != 0) |
1697 | return ret; | 1649 | return ret; |
1650 | } | ||
1698 | de->target_offset = e->target_offset - (origsize - *size); | 1651 | de->target_offset = e->target_offset - (origsize - *size); |
1699 | t = compat_ip6t_get_target(e); | 1652 | t = compat_ip6t_get_target(e); |
1700 | target = t->u.kernel.target; | 1653 | target = t->u.kernel.target; |
@@ -1711,11 +1664,12 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1711 | } | 1664 | } |
1712 | 1665 | ||
1713 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, | 1666 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, |
1714 | const char *name, unsigned int *i) | 1667 | const char *name) |
1715 | { | 1668 | { |
1716 | unsigned int j; | 1669 | unsigned int j; |
1717 | int ret; | 1670 | int ret = 0; |
1718 | struct xt_mtchk_param mtpar; | 1671 | struct xt_mtchk_param mtpar; |
1672 | struct xt_entry_match *ematch; | ||
1719 | 1673 | ||
1720 | j = 0; | 1674 | j = 0; |
1721 | mtpar.net = net; | 1675 | mtpar.net = net; |
@@ -1723,19 +1677,24 @@ static int compat_check_entry(struct ip6t_entry *e, struct net *net, | |||
1723 | mtpar.entryinfo = &e->ipv6; | 1677 | mtpar.entryinfo = &e->ipv6; |
1724 | mtpar.hook_mask = e->comefrom; | 1678 | mtpar.hook_mask = e->comefrom; |
1725 | mtpar.family = NFPROTO_IPV6; | 1679 | mtpar.family = NFPROTO_IPV6; |
1726 | ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j); | 1680 | xt_ematch_foreach(ematch, e) { |
1727 | if (ret) | 1681 | ret = check_match(ematch, &mtpar); |
1728 | goto cleanup_matches; | 1682 | if (ret != 0) |
1683 | goto cleanup_matches; | ||
1684 | ++j; | ||
1685 | } | ||
1729 | 1686 | ||
1730 | ret = check_target(e, net, name); | 1687 | ret = check_target(e, net, name); |
1731 | if (ret) | 1688 | if (ret) |
1732 | goto cleanup_matches; | 1689 | goto cleanup_matches; |
1733 | |||
1734 | (*i)++; | ||
1735 | return 0; | 1690 | return 0; |
1736 | 1691 | ||
1737 | cleanup_matches: | 1692 | cleanup_matches: |
1738 | IP6T_MATCH_ITERATE(e, cleanup_match, net, &j); | 1693 | xt_ematch_foreach(ematch, e) { |
1694 | if (j-- == 0) | ||
1695 | break; | ||
1696 | cleanup_match(ematch, net); | ||
1697 | } | ||
1739 | return ret; | 1698 | return ret; |
1740 | } | 1699 | } |
1741 | 1700 | ||
@@ -1753,8 +1712,10 @@ translate_compat_table(struct net *net, | |||
1753 | unsigned int i, j; | 1712 | unsigned int i, j; |
1754 | struct xt_table_info *newinfo, *info; | 1713 | struct xt_table_info *newinfo, *info; |
1755 | void *pos, *entry0, *entry1; | 1714 | void *pos, *entry0, *entry1; |
1715 | struct compat_ip6t_entry *iter0; | ||
1716 | struct ip6t_entry *iter1; | ||
1756 | unsigned int size; | 1717 | unsigned int size; |
1757 | int ret; | 1718 | int ret = 0; |
1758 | 1719 | ||
1759 | info = *pinfo; | 1720 | info = *pinfo; |
1760 | entry0 = *pentry0; | 1721 | entry0 = *pentry0; |
@@ -1771,13 +1732,14 @@ translate_compat_table(struct net *net, | |||
1771 | j = 0; | 1732 | j = 0; |
1772 | xt_compat_lock(AF_INET6); | 1733 | xt_compat_lock(AF_INET6); |
1773 | /* Walk through entries, checking offsets. */ | 1734 | /* Walk through entries, checking offsets. */ |
1774 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1735 | xt_entry_foreach(iter0, entry0, total_size) { |
1775 | check_compat_entry_size_and_hooks, | 1736 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1776 | info, &size, entry0, | 1737 | entry0, entry0 + total_size, hook_entries, underflows, |
1777 | entry0 + total_size, | 1738 | name); |
1778 | hook_entries, underflows, &j, name); | 1739 | if (ret != 0) |
1779 | if (ret != 0) | 1740 | goto out_unlock; |
1780 | goto out_unlock; | 1741 | ++j; |
1742 | } | ||
1781 | 1743 | ||
1782 | ret = -EINVAL; | 1744 | ret = -EINVAL; |
1783 | if (j != number) { | 1745 | if (j != number) { |
@@ -1816,9 +1778,12 @@ translate_compat_table(struct net *net, | |||
1816 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1778 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
1817 | pos = entry1; | 1779 | pos = entry1; |
1818 | size = total_size; | 1780 | size = total_size; |
1819 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1781 | xt_entry_foreach(iter0, entry0, total_size) { |
1820 | compat_copy_entry_from_user, | 1782 | ret = compat_copy_entry_from_user(iter0, &pos, |
1821 | &pos, &size, name, newinfo, entry1); | 1783 | &size, name, newinfo, entry1); |
1784 | if (ret != 0) | ||
1785 | break; | ||
1786 | } | ||
1822 | xt_compat_flush_offsets(AF_INET6); | 1787 | xt_compat_flush_offsets(AF_INET6); |
1823 | xt_compat_unlock(AF_INET6); | 1788 | xt_compat_unlock(AF_INET6); |
1824 | if (ret) | 1789 | if (ret) |
@@ -1829,13 +1794,32 @@ translate_compat_table(struct net *net, | |||
1829 | goto free_newinfo; | 1794 | goto free_newinfo; |
1830 | 1795 | ||
1831 | i = 0; | 1796 | i = 0; |
1832 | ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1797 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1833 | net, name, &i); | 1798 | ret = compat_check_entry(iter1, net, name); |
1799 | if (ret != 0) | ||
1800 | break; | ||
1801 | ++i; | ||
1802 | } | ||
1834 | if (ret) { | 1803 | if (ret) { |
1804 | /* | ||
1805 | * The first i matches need cleanup_entry (calls ->destroy) | ||
1806 | * because they had called ->check already. The other j-i | ||
1807 | * entries need only release. | ||
1808 | */ | ||
1809 | int skip = i; | ||
1835 | j -= i; | 1810 | j -= i; |
1836 | COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1811 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1837 | compat_release_entry, &j); | 1812 | if (skip-- > 0) |
1838 | IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i); | 1813 | continue; |
1814 | if (j-- == 0) | ||
1815 | break; | ||
1816 | compat_release_entry(iter0); | ||
1817 | } | ||
1818 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
1819 | if (i-- == 0) | ||
1820 | break; | ||
1821 | cleanup_entry(iter1, net); | ||
1822 | } | ||
1839 | xt_free_table_info(newinfo); | 1823 | xt_free_table_info(newinfo); |
1840 | return ret; | 1824 | return ret; |
1841 | } | 1825 | } |
@@ -1853,7 +1837,11 @@ translate_compat_table(struct net *net, | |||
1853 | free_newinfo: | 1837 | free_newinfo: |
1854 | xt_free_table_info(newinfo); | 1838 | xt_free_table_info(newinfo); |
1855 | out: | 1839 | out: |
1856 | COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1840 | xt_entry_foreach(iter0, entry0, total_size) { |
1841 | if (j-- == 0) | ||
1842 | break; | ||
1843 | compat_release_entry(iter0); | ||
1844 | } | ||
1857 | return ret; | 1845 | return ret; |
1858 | out_unlock: | 1846 | out_unlock: |
1859 | xt_compat_flush_offsets(AF_INET6); | 1847 | xt_compat_flush_offsets(AF_INET6); |
@@ -1868,6 +1856,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1868 | struct compat_ip6t_replace tmp; | 1856 | struct compat_ip6t_replace tmp; |
1869 | struct xt_table_info *newinfo; | 1857 | struct xt_table_info *newinfo; |
1870 | void *loc_cpu_entry; | 1858 | void *loc_cpu_entry; |
1859 | struct ip6t_entry *iter; | ||
1871 | 1860 | ||
1872 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1861 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1873 | return -EFAULT; | 1862 | return -EFAULT; |
@@ -1906,7 +1895,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1906 | return 0; | 1895 | return 0; |
1907 | 1896 | ||
1908 | free_newinfo_untrans: | 1897 | free_newinfo_untrans: |
1909 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1898 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1899 | cleanup_entry(iter, net); | ||
1910 | free_newinfo: | 1900 | free_newinfo: |
1911 | xt_free_table_info(newinfo); | 1901 | xt_free_table_info(newinfo); |
1912 | return ret; | 1902 | return ret; |
@@ -1955,6 +1945,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1955 | int ret = 0; | 1945 | int ret = 0; |
1956 | const void *loc_cpu_entry; | 1946 | const void *loc_cpu_entry; |
1957 | unsigned int i = 0; | 1947 | unsigned int i = 0; |
1948 | struct ip6t_entry *iter; | ||
1958 | 1949 | ||
1959 | counters = alloc_counters(table); | 1950 | counters = alloc_counters(table); |
1960 | if (IS_ERR(counters)) | 1951 | if (IS_ERR(counters)) |
@@ -1967,9 +1958,12 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1967 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1958 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1968 | pos = userptr; | 1959 | pos = userptr; |
1969 | size = total_size; | 1960 | size = total_size; |
1970 | ret = IP6T_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1961 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1971 | compat_copy_entry_to_user, | 1962 | ret = compat_copy_entry_to_user(iter, &pos, |
1972 | &pos, &size, counters, &i); | 1963 | &size, counters, i++); |
1964 | if (ret != 0) | ||
1965 | break; | ||
1966 | } | ||
1973 | 1967 | ||
1974 | vfree(counters); | 1968 | vfree(counters); |
1975 | return ret; | 1969 | return ret; |
@@ -2143,11 +2137,7 @@ struct xt_table *ip6t_register_table(struct net *net, | |||
2143 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 2137 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
2144 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 2138 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
2145 | 2139 | ||
2146 | ret = translate_table(net, table->name, table->valid_hooks, | 2140 | ret = translate_table(net, newinfo, loc_cpu_entry, repl); |
2147 | newinfo, loc_cpu_entry, repl->size, | ||
2148 | repl->num_entries, | ||
2149 | repl->hook_entry, | ||
2150 | repl->underflow); | ||
2151 | if (ret != 0) | 2141 | if (ret != 0) |
2152 | goto out_free; | 2142 | goto out_free; |
2153 | 2143 | ||
@@ -2169,12 +2159,14 @@ void ip6t_unregister_table(struct net *net, struct xt_table *table) | |||
2169 | struct xt_table_info *private; | 2159 | struct xt_table_info *private; |
2170 | void *loc_cpu_entry; | 2160 | void *loc_cpu_entry; |
2171 | struct module *table_owner = table->me; | 2161 | struct module *table_owner = table->me; |
2162 | struct ip6t_entry *iter; | ||
2172 | 2163 | ||
2173 | private = xt_unregister_table(table); | 2164 | private = xt_unregister_table(table); |
2174 | 2165 | ||
2175 | /* Decrease module usage counts and free resources */ | 2166 | /* Decrease module usage counts and free resources */ |
2176 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2167 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
2177 | IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL); | 2168 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
2169 | cleanup_entry(iter, net); | ||
2178 | if (private->number > private->initial_entries) | 2170 | if (private->number > private->initial_entries) |
2179 | module_put(table_owner); | 2171 | module_put(table_owner); |
2180 | xt_free_table_info(private); | 2172 | xt_free_table_info(private); |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index ad1fcda6898b..f1171b744650 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -469,7 +469,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
469 | 469 | ||
470 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ | 470 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ |
471 | fp = skb_shinfo(head)->frag_list; | 471 | fp = skb_shinfo(head)->frag_list; |
472 | if (NFCT_FRAG6_CB(fp)->orig == NULL) | 472 | if (fp && NFCT_FRAG6_CB(fp)->orig == NULL) |
473 | /* at above code, head skb is divided into two skbs. */ | 473 | /* at above code, head skb is divided into two skbs. */ |
474 | fp = fp->next; | 474 | fp = fp->next; |
475 | 475 | ||
@@ -595,12 +595,6 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
595 | hdr = ipv6_hdr(clone); | 595 | hdr = ipv6_hdr(clone); |
596 | fhdr = (struct frag_hdr *)skb_transport_header(clone); | 596 | fhdr = (struct frag_hdr *)skb_transport_header(clone); |
597 | 597 | ||
598 | if (!(fhdr->frag_off & htons(0xFFF9))) { | ||
599 | pr_debug("Invalid fragment offset\n"); | ||
600 | /* It is not a fragmented frame */ | ||
601 | goto ret_orig; | ||
602 | } | ||
603 | |||
604 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) | 598 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) |
605 | nf_ct_frag6_evictor(); | 599 | nf_ct_frag6_evictor(); |
606 | 600 | ||