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 | |
parent | fb977e2ca607a7e74946a1de798f474d1b80b9d6 (diff) | |
parent | 0f234214d15fa914436d304ecf5c3e43449e79f9 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
-rw-r--r-- | include/linux/netfilter/x_tables.h | 17 | ||||
-rw-r--r-- | include/linux/netfilter_arp/arp_tables.h | 10 | ||||
-rw-r--r-- | include/linux/netfilter_ipv4/ip_tables.h | 15 | ||||
-rw-r--r-- | include/linux/netfilter_ipv6/ip6_tables.h | 14 | ||||
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 301 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 436 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 436 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 8 | ||||
-rw-r--r-- | net/netfilter/xt_TCPMSS.c | 12 | ||||
-rw-r--r-- | net/netfilter/xt_recent.c | 4 |
10 files changed, 597 insertions, 656 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index a18119fb88f0..84c7c928e9eb 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
@@ -120,6 +120,7 @@ struct xt_counters_info { | |||
120 | 120 | ||
121 | #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ | 121 | #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ |
122 | 122 | ||
123 | #ifndef __KERNEL__ | ||
123 | /* fn returns 0 to continue iteration */ | 124 | /* fn returns 0 to continue iteration */ |
124 | #define XT_MATCH_ITERATE(type, e, fn, args...) \ | 125 | #define XT_MATCH_ITERATE(type, e, fn, args...) \ |
125 | ({ \ | 126 | ({ \ |
@@ -163,6 +164,22 @@ struct xt_counters_info { | |||
163 | #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ | 164 | #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ |
164 | XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) | 165 | XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) |
165 | 166 | ||
167 | #endif /* !__KERNEL__ */ | ||
168 | |||
169 | /* pos is normally a struct ipt_entry/ip6t_entry/etc. */ | ||
170 | #define xt_entry_foreach(pos, ehead, esize) \ | ||
171 | for ((pos) = (typeof(pos))(ehead); \ | ||
172 | (pos) < (typeof(pos))((char *)(ehead) + (esize)); \ | ||
173 | (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset)) | ||
174 | |||
175 | /* can only be xt_entry_match, so no use of typeof here */ | ||
176 | #define xt_ematch_foreach(pos, entry) \ | ||
177 | for ((pos) = (struct xt_entry_match *)entry->elems; \ | ||
178 | (pos) < (struct xt_entry_match *)((char *)(entry) + \ | ||
179 | (entry)->target_offset); \ | ||
180 | (pos) = (struct xt_entry_match *)((char *)(pos) + \ | ||
181 | (pos)->u.match_size)) | ||
182 | |||
166 | #ifdef __KERNEL__ | 183 | #ifdef __KERNEL__ |
167 | 184 | ||
168 | #include <linux/netdevice.h> | 185 | #include <linux/netdevice.h> |
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 0b33980611b2..e9948c0560f6 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h | |||
@@ -211,9 +211,11 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e | |||
211 | return (void *)e + e->target_offset; | 211 | return (void *)e + e->target_offset; |
212 | } | 212 | } |
213 | 213 | ||
214 | #ifndef __KERNEL__ | ||
214 | /* fn returns 0 to continue iteration */ | 215 | /* fn returns 0 to continue iteration */ |
215 | #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ | 216 | #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ |
216 | XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) | 217 | XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) |
218 | #endif | ||
217 | 219 | ||
218 | /* | 220 | /* |
219 | * Main firewall chains definitions and global var's definitions. | 221 | * Main firewall chains definitions and global var's definitions. |
@@ -291,14 +293,6 @@ compat_arpt_get_target(struct compat_arpt_entry *e) | |||
291 | 293 | ||
292 | #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) | 294 | #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) |
293 | 295 | ||
294 | /* fn returns 0 to continue iteration */ | ||
295 | #define COMPAT_ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ | ||
296 | XT_ENTRY_ITERATE(struct compat_arpt_entry, entries, size, fn, ## args) | ||
297 | |||
298 | #define COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ | ||
299 | XT_ENTRY_ITERATE_CONTINUE(struct compat_arpt_entry, entries, size, n, \ | ||
300 | fn, ## args) | ||
301 | |||
302 | #endif /* CONFIG_COMPAT */ | 296 | #endif /* CONFIG_COMPAT */ |
303 | #endif /*__KERNEL__*/ | 297 | #endif /*__KERNEL__*/ |
304 | #endif /* _ARPTABLES_H */ | 298 | #endif /* _ARPTABLES_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 364973b42133..704a7b6e8169 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h | |||
@@ -223,6 +223,7 @@ ipt_get_target(struct ipt_entry *e) | |||
223 | return (void *)e + e->target_offset; | 223 | return (void *)e + e->target_offset; |
224 | } | 224 | } |
225 | 225 | ||
226 | #ifndef __KERNEL__ | ||
226 | /* fn returns 0 to continue iteration */ | 227 | /* fn returns 0 to continue iteration */ |
227 | #define IPT_MATCH_ITERATE(e, fn, args...) \ | 228 | #define IPT_MATCH_ITERATE(e, fn, args...) \ |
228 | XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) | 229 | XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) |
@@ -230,6 +231,7 @@ ipt_get_target(struct ipt_entry *e) | |||
230 | /* fn returns 0 to continue iteration */ | 231 | /* fn returns 0 to continue iteration */ |
231 | #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ | 232 | #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ |
232 | XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) | 233 | XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) |
234 | #endif | ||
233 | 235 | ||
234 | /* | 236 | /* |
235 | * Main firewall chains definitions and global var's definitions. | 237 | * Main firewall chains definitions and global var's definitions. |
@@ -313,19 +315,6 @@ compat_ipt_get_target(struct compat_ipt_entry *e) | |||
313 | 315 | ||
314 | #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) | 316 | #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) |
315 | 317 | ||
316 | /* fn returns 0 to continue iteration */ | ||
317 | #define COMPAT_IPT_MATCH_ITERATE(e, fn, args...) \ | ||
318 | XT_MATCH_ITERATE(struct compat_ipt_entry, e, fn, ## args) | ||
319 | |||
320 | /* fn returns 0 to continue iteration */ | ||
321 | #define COMPAT_IPT_ENTRY_ITERATE(entries, size, fn, args...) \ | ||
322 | XT_ENTRY_ITERATE(struct compat_ipt_entry, entries, size, fn, ## args) | ||
323 | |||
324 | /* fn returns 0 to continue iteration */ | ||
325 | #define COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ | ||
326 | XT_ENTRY_ITERATE_CONTINUE(struct compat_ipt_entry, entries, size, n, \ | ||
327 | fn, ## args) | ||
328 | |||
329 | #endif /* CONFIG_COMPAT */ | 318 | #endif /* CONFIG_COMPAT */ |
330 | #endif /*__KERNEL__*/ | 319 | #endif /*__KERNEL__*/ |
331 | #endif /* _IPTABLES_H */ | 320 | #endif /* _IPTABLES_H */ |
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 8031eb486a10..e5ba03d783c6 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
@@ -280,6 +280,7 @@ ip6t_get_target(struct ip6t_entry *e) | |||
280 | return (void *)e + e->target_offset; | 280 | return (void *)e + e->target_offset; |
281 | } | 281 | } |
282 | 282 | ||
283 | #ifndef __KERNEL__ | ||
283 | /* fn returns 0 to continue iteration */ | 284 | /* fn returns 0 to continue iteration */ |
284 | #define IP6T_MATCH_ITERATE(e, fn, args...) \ | 285 | #define IP6T_MATCH_ITERATE(e, fn, args...) \ |
285 | XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) | 286 | XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) |
@@ -287,6 +288,7 @@ ip6t_get_target(struct ip6t_entry *e) | |||
287 | /* fn returns 0 to continue iteration */ | 288 | /* fn returns 0 to continue iteration */ |
288 | #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ | 289 | #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ |
289 | XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) | 290 | XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) |
291 | #endif | ||
290 | 292 | ||
291 | /* | 293 | /* |
292 | * Main firewall chains definitions and global var's definitions. | 294 | * Main firewall chains definitions and global var's definitions. |
@@ -341,18 +343,6 @@ compat_ip6t_get_target(struct compat_ip6t_entry *e) | |||
341 | 343 | ||
342 | #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) | 344 | #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) |
343 | 345 | ||
344 | /* fn returns 0 to continue iteration */ | ||
345 | #define COMPAT_IP6T_MATCH_ITERATE(e, fn, args...) \ | ||
346 | XT_MATCH_ITERATE(struct compat_ip6t_entry, e, fn, ## args) | ||
347 | |||
348 | /* fn returns 0 to continue iteration */ | ||
349 | #define COMPAT_IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ | ||
350 | XT_ENTRY_ITERATE(struct compat_ip6t_entry, entries, size, fn, ## args) | ||
351 | |||
352 | #define COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ | ||
353 | XT_ENTRY_ITERATE_CONTINUE(struct compat_ip6t_entry, entries, size, n, \ | ||
354 | fn, ## args) | ||
355 | |||
356 | #endif /* CONFIG_COMPAT */ | 346 | #endif /* CONFIG_COMPAT */ |
357 | #endif /*__KERNEL__*/ | 347 | #endif /*__KERNEL__*/ |
358 | #endif /* _IP6_TABLES_H */ | 348 | #endif /* _IP6_TABLES_H */ |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 4db5c1ece0f9..57098dcda294 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -512,8 +512,7 @@ static inline int check_target(struct arpt_entry *e, const char *name) | |||
512 | } | 512 | } |
513 | 513 | ||
514 | static inline int | 514 | static inline int |
515 | find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, | 515 | find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) |
516 | unsigned int *i) | ||
517 | { | 516 | { |
518 | struct arpt_entry_target *t; | 517 | struct arpt_entry_target *t; |
519 | struct xt_target *target; | 518 | struct xt_target *target; |
@@ -538,8 +537,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, | |||
538 | ret = check_target(e, name); | 537 | ret = check_target(e, name); |
539 | if (ret) | 538 | if (ret) |
540 | goto err; | 539 | goto err; |
541 | |||
542 | (*i)++; | ||
543 | return 0; | 540 | return 0; |
544 | err: | 541 | err: |
545 | module_put(t->u.kernel.target->me); | 542 | module_put(t->u.kernel.target->me); |
@@ -568,8 +565,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, | |||
568 | const unsigned char *limit, | 565 | const unsigned char *limit, |
569 | const unsigned int *hook_entries, | 566 | const unsigned int *hook_entries, |
570 | const unsigned int *underflows, | 567 | const unsigned int *underflows, |
571 | unsigned int valid_hooks, | 568 | unsigned int valid_hooks) |
572 | unsigned int *i) | ||
573 | { | 569 | { |
574 | unsigned int h; | 570 | unsigned int h; |
575 | 571 | ||
@@ -606,19 +602,14 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, | |||
606 | /* Clear counters and comefrom */ | 602 | /* Clear counters and comefrom */ |
607 | e->counters = ((struct xt_counters) { 0, 0 }); | 603 | e->counters = ((struct xt_counters) { 0, 0 }); |
608 | e->comefrom = 0; | 604 | e->comefrom = 0; |
609 | |||
610 | (*i)++; | ||
611 | return 0; | 605 | return 0; |
612 | } | 606 | } |
613 | 607 | ||
614 | static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | 608 | static inline void cleanup_entry(struct arpt_entry *e) |
615 | { | 609 | { |
616 | struct xt_tgdtor_param par; | 610 | struct xt_tgdtor_param par; |
617 | struct arpt_entry_target *t; | 611 | struct arpt_entry_target *t; |
618 | 612 | ||
619 | if (i && (*i)-- == 0) | ||
620 | return 1; | ||
621 | |||
622 | t = arpt_get_target(e); | 613 | t = arpt_get_target(e); |
623 | par.target = t->u.kernel.target; | 614 | par.target = t->u.kernel.target; |
624 | par.targinfo = t->data; | 615 | par.targinfo = t->data; |
@@ -626,26 +617,20 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | |||
626 | if (par.target->destroy != NULL) | 617 | if (par.target->destroy != NULL) |
627 | par.target->destroy(&par); | 618 | par.target->destroy(&par); |
628 | module_put(par.target->me); | 619 | module_put(par.target->me); |
629 | return 0; | ||
630 | } | 620 | } |
631 | 621 | ||
632 | /* Checks and translates the user-supplied table segment (held in | 622 | /* Checks and translates the user-supplied table segment (held in |
633 | * newinfo). | 623 | * newinfo). |
634 | */ | 624 | */ |
635 | static int translate_table(const char *name, | 625 | static int translate_table(struct xt_table_info *newinfo, void *entry0, |
636 | unsigned int valid_hooks, | 626 | const struct arpt_replace *repl) |
637 | struct xt_table_info *newinfo, | ||
638 | void *entry0, | ||
639 | unsigned int size, | ||
640 | unsigned int number, | ||
641 | const unsigned int *hook_entries, | ||
642 | const unsigned int *underflows) | ||
643 | { | 627 | { |
628 | struct arpt_entry *iter; | ||
644 | unsigned int i; | 629 | unsigned int i; |
645 | int ret; | 630 | int ret = 0; |
646 | 631 | ||
647 | newinfo->size = size; | 632 | newinfo->size = repl->size; |
648 | newinfo->number = number; | 633 | newinfo->number = repl->num_entries; |
649 | 634 | ||
650 | /* Init all hooks to impossible value. */ | 635 | /* Init all hooks to impossible value. */ |
651 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { | 636 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { |
@@ -657,52 +642,61 @@ static int translate_table(const char *name, | |||
657 | i = 0; | 642 | i = 0; |
658 | 643 | ||
659 | /* Walk through entries, checking offsets. */ | 644 | /* Walk through entries, checking offsets. */ |
660 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 645 | xt_entry_foreach(iter, entry0, newinfo->size) { |
661 | check_entry_size_and_hooks, | 646 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
662 | newinfo, | 647 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
663 | entry0, | 648 | repl->valid_hooks); |
664 | entry0 + size, | 649 | if (ret != 0) |
665 | hook_entries, underflows, valid_hooks, &i); | 650 | break; |
651 | ++i; | ||
652 | } | ||
666 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); | 653 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); |
667 | if (ret != 0) | 654 | if (ret != 0) |
668 | return ret; | 655 | return ret; |
669 | 656 | ||
670 | if (i != number) { | 657 | if (i != repl->num_entries) { |
671 | duprintf("translate_table: %u not %u entries\n", | 658 | duprintf("translate_table: %u not %u entries\n", |
672 | i, number); | 659 | i, repl->num_entries); |
673 | return -EINVAL; | 660 | return -EINVAL; |
674 | } | 661 | } |
675 | 662 | ||
676 | /* Check hooks all assigned */ | 663 | /* Check hooks all assigned */ |
677 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { | 664 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { |
678 | /* Only hooks which are valid */ | 665 | /* Only hooks which are valid */ |
679 | if (!(valid_hooks & (1 << i))) | 666 | if (!(repl->valid_hooks & (1 << i))) |
680 | continue; | 667 | continue; |
681 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 668 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
682 | duprintf("Invalid hook entry %u %u\n", | 669 | duprintf("Invalid hook entry %u %u\n", |
683 | i, hook_entries[i]); | 670 | i, repl->hook_entry[i]); |
684 | return -EINVAL; | 671 | return -EINVAL; |
685 | } | 672 | } |
686 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 673 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
687 | duprintf("Invalid underflow %u %u\n", | 674 | duprintf("Invalid underflow %u %u\n", |
688 | i, underflows[i]); | 675 | i, repl->underflow[i]); |
689 | return -EINVAL; | 676 | return -EINVAL; |
690 | } | 677 | } |
691 | } | 678 | } |
692 | 679 | ||
693 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) { | 680 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { |
694 | duprintf("Looping hook\n"); | 681 | duprintf("Looping hook\n"); |
695 | return -ELOOP; | 682 | return -ELOOP; |
696 | } | 683 | } |
697 | 684 | ||
698 | /* Finally, each sanity check must pass */ | 685 | /* Finally, each sanity check must pass */ |
699 | i = 0; | 686 | i = 0; |
700 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 687 | xt_entry_foreach(iter, entry0, newinfo->size) { |
701 | find_check_entry, name, size, &i); | 688 | ret = find_check_entry(iter, repl->name, repl->size); |
689 | if (ret != 0) | ||
690 | break; | ||
691 | ++i; | ||
692 | } | ||
702 | 693 | ||
703 | if (ret != 0) { | 694 | if (ret != 0) { |
704 | ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 695 | xt_entry_foreach(iter, entry0, newinfo->size) { |
705 | cleanup_entry, &i); | 696 | if (i-- == 0) |
697 | break; | ||
698 | cleanup_entry(iter); | ||
699 | } | ||
706 | return ret; | 700 | return ret; |
707 | } | 701 | } |
708 | 702 | ||
@@ -715,30 +709,10 @@ static int translate_table(const char *name, | |||
715 | return ret; | 709 | return ret; |
716 | } | 710 | } |
717 | 711 | ||
718 | /* Gets counters. */ | ||
719 | static inline int add_entry_to_counter(const struct arpt_entry *e, | ||
720 | struct xt_counters total[], | ||
721 | unsigned int *i) | ||
722 | { | ||
723 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
724 | |||
725 | (*i)++; | ||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static inline int set_entry_to_counter(const struct arpt_entry *e, | ||
730 | struct xt_counters total[], | ||
731 | unsigned int *i) | ||
732 | { | ||
733 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
734 | |||
735 | (*i)++; | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static void get_counters(const struct xt_table_info *t, | 712 | static void get_counters(const struct xt_table_info *t, |
740 | struct xt_counters counters[]) | 713 | struct xt_counters counters[]) |
741 | { | 714 | { |
715 | struct arpt_entry *iter; | ||
742 | unsigned int cpu; | 716 | unsigned int cpu; |
743 | unsigned int i; | 717 | unsigned int i; |
744 | unsigned int curcpu; | 718 | unsigned int curcpu; |
@@ -754,22 +728,22 @@ static void get_counters(const struct xt_table_info *t, | |||
754 | curcpu = smp_processor_id(); | 728 | curcpu = smp_processor_id(); |
755 | 729 | ||
756 | i = 0; | 730 | i = 0; |
757 | ARPT_ENTRY_ITERATE(t->entries[curcpu], | 731 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
758 | t->size, | 732 | SET_COUNTER(counters[i], iter->counters.bcnt, |
759 | set_entry_to_counter, | 733 | iter->counters.pcnt); |
760 | counters, | 734 | ++i; |
761 | &i); | 735 | } |
762 | 736 | ||
763 | for_each_possible_cpu(cpu) { | 737 | for_each_possible_cpu(cpu) { |
764 | if (cpu == curcpu) | 738 | if (cpu == curcpu) |
765 | continue; | 739 | continue; |
766 | i = 0; | 740 | i = 0; |
767 | xt_info_wrlock(cpu); | 741 | xt_info_wrlock(cpu); |
768 | ARPT_ENTRY_ITERATE(t->entries[cpu], | 742 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
769 | t->size, | 743 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
770 | add_entry_to_counter, | 744 | iter->counters.pcnt); |
771 | counters, | 745 | ++i; |
772 | &i); | 746 | } |
773 | xt_info_wrunlock(cpu); | 747 | xt_info_wrunlock(cpu); |
774 | } | 748 | } |
775 | local_bh_enable(); | 749 | local_bh_enable(); |
@@ -899,7 +873,9 @@ static int compat_calc_entry(const struct arpt_entry *e, | |||
899 | static int compat_table_info(const struct xt_table_info *info, | 873 | static int compat_table_info(const struct xt_table_info *info, |
900 | struct xt_table_info *newinfo) | 874 | struct xt_table_info *newinfo) |
901 | { | 875 | { |
876 | struct arpt_entry *iter; | ||
902 | void *loc_cpu_entry; | 877 | void *loc_cpu_entry; |
878 | int ret; | ||
903 | 879 | ||
904 | if (!newinfo || !info) | 880 | if (!newinfo || !info) |
905 | return -EINVAL; | 881 | return -EINVAL; |
@@ -908,9 +884,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
908 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 884 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
909 | newinfo->initial_entries = 0; | 885 | newinfo->initial_entries = 0; |
910 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 886 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
911 | return ARPT_ENTRY_ITERATE(loc_cpu_entry, info->size, | 887 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
912 | compat_calc_entry, info, loc_cpu_entry, | 888 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
913 | newinfo); | 889 | if (ret != 0) |
890 | return ret; | ||
891 | } | ||
892 | return 0; | ||
914 | } | 893 | } |
915 | #endif | 894 | #endif |
916 | 895 | ||
@@ -1025,6 +1004,7 @@ static int __do_replace(struct net *net, const char *name, | |||
1025 | struct xt_table_info *oldinfo; | 1004 | struct xt_table_info *oldinfo; |
1026 | struct xt_counters *counters; | 1005 | struct xt_counters *counters; |
1027 | void *loc_cpu_old_entry; | 1006 | void *loc_cpu_old_entry; |
1007 | struct arpt_entry *iter; | ||
1028 | 1008 | ||
1029 | ret = 0; | 1009 | ret = 0; |
1030 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), | 1010 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), |
@@ -1068,8 +1048,8 @@ static int __do_replace(struct net *net, const char *name, | |||
1068 | 1048 | ||
1069 | /* Decrease module usage counts and free resource */ | 1049 | /* Decrease module usage counts and free resource */ |
1070 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1050 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1071 | ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1051 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1072 | NULL); | 1052 | cleanup_entry(iter); |
1073 | 1053 | ||
1074 | xt_free_table_info(oldinfo); | 1054 | xt_free_table_info(oldinfo); |
1075 | if (copy_to_user(counters_ptr, counters, | 1055 | if (copy_to_user(counters_ptr, counters, |
@@ -1095,6 +1075,7 @@ static int do_replace(struct net *net, const void __user *user, | |||
1095 | struct arpt_replace tmp; | 1075 | struct arpt_replace tmp; |
1096 | struct xt_table_info *newinfo; | 1076 | struct xt_table_info *newinfo; |
1097 | void *loc_cpu_entry; | 1077 | void *loc_cpu_entry; |
1078 | struct arpt_entry *iter; | ||
1098 | 1079 | ||
1099 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1080 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1100 | return -EFAULT; | 1081 | return -EFAULT; |
@@ -1115,9 +1096,7 @@ static int do_replace(struct net *net, const void __user *user, | |||
1115 | goto free_newinfo; | 1096 | goto free_newinfo; |
1116 | } | 1097 | } |
1117 | 1098 | ||
1118 | ret = translate_table(tmp.name, tmp.valid_hooks, | 1099 | ret = translate_table(newinfo, loc_cpu_entry, &tmp); |
1119 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
1120 | tmp.hook_entry, tmp.underflow); | ||
1121 | if (ret != 0) | 1100 | if (ret != 0) |
1122 | goto free_newinfo; | 1101 | goto free_newinfo; |
1123 | 1102 | ||
@@ -1130,25 +1109,13 @@ static int do_replace(struct net *net, const void __user *user, | |||
1130 | return 0; | 1109 | return 0; |
1131 | 1110 | ||
1132 | free_newinfo_untrans: | 1111 | free_newinfo_untrans: |
1133 | ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1112 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1113 | cleanup_entry(iter); | ||
1134 | free_newinfo: | 1114 | free_newinfo: |
1135 | xt_free_table_info(newinfo); | 1115 | xt_free_table_info(newinfo); |
1136 | return ret; | 1116 | return ret; |
1137 | } | 1117 | } |
1138 | 1118 | ||
1139 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1140 | * and everything is OK. */ | ||
1141 | static int | ||
1142 | add_counter_to_entry(struct arpt_entry *e, | ||
1143 | const struct xt_counters addme[], | ||
1144 | unsigned int *i) | ||
1145 | { | ||
1146 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1147 | |||
1148 | (*i)++; | ||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | static int do_add_counters(struct net *net, const void __user *user, | 1119 | static int do_add_counters(struct net *net, const void __user *user, |
1153 | unsigned int len, int compat) | 1120 | unsigned int len, int compat) |
1154 | { | 1121 | { |
@@ -1163,6 +1130,7 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1163 | const struct xt_table_info *private; | 1130 | const struct xt_table_info *private; |
1164 | int ret = 0; | 1131 | int ret = 0; |
1165 | void *loc_cpu_entry; | 1132 | void *loc_cpu_entry; |
1133 | struct arpt_entry *iter; | ||
1166 | #ifdef CONFIG_COMPAT | 1134 | #ifdef CONFIG_COMPAT |
1167 | struct compat_xt_counters_info compat_tmp; | 1135 | struct compat_xt_counters_info compat_tmp; |
1168 | 1136 | ||
@@ -1220,11 +1188,10 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1220 | curcpu = smp_processor_id(); | 1188 | curcpu = smp_processor_id(); |
1221 | loc_cpu_entry = private->entries[curcpu]; | 1189 | loc_cpu_entry = private->entries[curcpu]; |
1222 | xt_info_wrlock(curcpu); | 1190 | xt_info_wrlock(curcpu); |
1223 | ARPT_ENTRY_ITERATE(loc_cpu_entry, | 1191 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1224 | private->size, | 1192 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1225 | add_counter_to_entry, | 1193 | ++i; |
1226 | paddc, | 1194 | } |
1227 | &i); | ||
1228 | xt_info_wrunlock(curcpu); | 1195 | xt_info_wrunlock(curcpu); |
1229 | unlock_up_free: | 1196 | unlock_up_free: |
1230 | local_bh_enable(); | 1197 | local_bh_enable(); |
@@ -1237,17 +1204,12 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1237 | } | 1204 | } |
1238 | 1205 | ||
1239 | #ifdef CONFIG_COMPAT | 1206 | #ifdef CONFIG_COMPAT |
1240 | static inline int | 1207 | static inline void compat_release_entry(struct compat_arpt_entry *e) |
1241 | compat_release_entry(struct compat_arpt_entry *e, unsigned int *i) | ||
1242 | { | 1208 | { |
1243 | struct arpt_entry_target *t; | 1209 | struct arpt_entry_target *t; |
1244 | 1210 | ||
1245 | if (i && (*i)-- == 0) | ||
1246 | return 1; | ||
1247 | |||
1248 | t = compat_arpt_get_target(e); | 1211 | t = compat_arpt_get_target(e); |
1249 | module_put(t->u.kernel.target->me); | 1212 | module_put(t->u.kernel.target->me); |
1250 | return 0; | ||
1251 | } | 1213 | } |
1252 | 1214 | ||
1253 | static inline int | 1215 | static inline int |
@@ -1258,7 +1220,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
1258 | const unsigned char *limit, | 1220 | const unsigned char *limit, |
1259 | const unsigned int *hook_entries, | 1221 | const unsigned int *hook_entries, |
1260 | const unsigned int *underflows, | 1222 | const unsigned int *underflows, |
1261 | unsigned int *i, | ||
1262 | const char *name) | 1223 | const char *name) |
1263 | { | 1224 | { |
1264 | struct arpt_entry_target *t; | 1225 | struct arpt_entry_target *t; |
@@ -1318,8 +1279,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
1318 | /* Clear counters and comefrom */ | 1279 | /* Clear counters and comefrom */ |
1319 | memset(&e->counters, 0, sizeof(e->counters)); | 1280 | memset(&e->counters, 0, sizeof(e->counters)); |
1320 | e->comefrom = 0; | 1281 | e->comefrom = 0; |
1321 | |||
1322 | (*i)++; | ||
1323 | return 0; | 1282 | return 0; |
1324 | 1283 | ||
1325 | release_target: | 1284 | release_target: |
@@ -1363,19 +1322,6 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, | |||
1363 | return ret; | 1322 | return ret; |
1364 | } | 1323 | } |
1365 | 1324 | ||
1366 | static inline int compat_check_entry(struct arpt_entry *e, const char *name, | ||
1367 | unsigned int *i) | ||
1368 | { | ||
1369 | int ret; | ||
1370 | |||
1371 | ret = check_target(e, name); | ||
1372 | if (ret) | ||
1373 | return ret; | ||
1374 | |||
1375 | (*i)++; | ||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | static int translate_compat_table(const char *name, | 1325 | static int translate_compat_table(const char *name, |
1380 | unsigned int valid_hooks, | 1326 | unsigned int valid_hooks, |
1381 | struct xt_table_info **pinfo, | 1327 | struct xt_table_info **pinfo, |
@@ -1388,8 +1334,10 @@ static int translate_compat_table(const char *name, | |||
1388 | unsigned int i, j; | 1334 | unsigned int i, j; |
1389 | struct xt_table_info *newinfo, *info; | 1335 | struct xt_table_info *newinfo, *info; |
1390 | void *pos, *entry0, *entry1; | 1336 | void *pos, *entry0, *entry1; |
1337 | struct compat_arpt_entry *iter0; | ||
1338 | struct arpt_entry *iter1; | ||
1391 | unsigned int size; | 1339 | unsigned int size; |
1392 | int ret; | 1340 | int ret = 0; |
1393 | 1341 | ||
1394 | info = *pinfo; | 1342 | info = *pinfo; |
1395 | entry0 = *pentry0; | 1343 | entry0 = *pentry0; |
@@ -1406,13 +1354,14 @@ static int translate_compat_table(const char *name, | |||
1406 | j = 0; | 1354 | j = 0; |
1407 | xt_compat_lock(NFPROTO_ARP); | 1355 | xt_compat_lock(NFPROTO_ARP); |
1408 | /* Walk through entries, checking offsets. */ | 1356 | /* Walk through entries, checking offsets. */ |
1409 | ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, | 1357 | xt_entry_foreach(iter0, entry0, total_size) { |
1410 | check_compat_entry_size_and_hooks, | 1358 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1411 | info, &size, entry0, | 1359 | entry0, entry0 + total_size, hook_entries, underflows, |
1412 | entry0 + total_size, | 1360 | name); |
1413 | hook_entries, underflows, &j, name); | 1361 | if (ret != 0) |
1414 | if (ret != 0) | 1362 | goto out_unlock; |
1415 | goto out_unlock; | 1363 | ++j; |
1364 | } | ||
1416 | 1365 | ||
1417 | ret = -EINVAL; | 1366 | ret = -EINVAL; |
1418 | if (j != number) { | 1367 | if (j != number) { |
@@ -1451,9 +1400,12 @@ static int translate_compat_table(const char *name, | |||
1451 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1400 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
1452 | pos = entry1; | 1401 | pos = entry1; |
1453 | size = total_size; | 1402 | size = total_size; |
1454 | ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, | 1403 | xt_entry_foreach(iter0, entry0, total_size) { |
1455 | compat_copy_entry_from_user, | 1404 | ret = compat_copy_entry_from_user(iter0, &pos, |
1456 | &pos, &size, name, newinfo, entry1); | 1405 | &size, name, newinfo, entry1); |
1406 | if (ret != 0) | ||
1407 | break; | ||
1408 | } | ||
1457 | xt_compat_flush_offsets(NFPROTO_ARP); | 1409 | xt_compat_flush_offsets(NFPROTO_ARP); |
1458 | xt_compat_unlock(NFPROTO_ARP); | 1410 | xt_compat_unlock(NFPROTO_ARP); |
1459 | if (ret) | 1411 | if (ret) |
@@ -1464,13 +1416,32 @@ static int translate_compat_table(const char *name, | |||
1464 | goto free_newinfo; | 1416 | goto free_newinfo; |
1465 | 1417 | ||
1466 | i = 0; | 1418 | i = 0; |
1467 | ret = ARPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1419 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1468 | name, &i); | 1420 | ret = check_target(iter1, name); |
1421 | if (ret != 0) | ||
1422 | break; | ||
1423 | ++i; | ||
1424 | } | ||
1469 | if (ret) { | 1425 | if (ret) { |
1426 | /* | ||
1427 | * The first i matches need cleanup_entry (calls ->destroy) | ||
1428 | * because they had called ->check already. The other j-i | ||
1429 | * entries need only release. | ||
1430 | */ | ||
1431 | int skip = i; | ||
1470 | j -= i; | 1432 | j -= i; |
1471 | COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1433 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1472 | compat_release_entry, &j); | 1434 | if (skip-- > 0) |
1473 | ARPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); | 1435 | continue; |
1436 | if (j-- == 0) | ||
1437 | break; | ||
1438 | compat_release_entry(iter0); | ||
1439 | } | ||
1440 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
1441 | if (i-- == 0) | ||
1442 | break; | ||
1443 | cleanup_entry(iter1); | ||
1444 | } | ||
1474 | xt_free_table_info(newinfo); | 1445 | xt_free_table_info(newinfo); |
1475 | return ret; | 1446 | return ret; |
1476 | } | 1447 | } |
@@ -1488,7 +1459,11 @@ static int translate_compat_table(const char *name, | |||
1488 | free_newinfo: | 1459 | free_newinfo: |
1489 | xt_free_table_info(newinfo); | 1460 | xt_free_table_info(newinfo); |
1490 | out: | 1461 | out: |
1491 | COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1462 | xt_entry_foreach(iter0, entry0, total_size) { |
1463 | if (j-- == 0) | ||
1464 | break; | ||
1465 | compat_release_entry(iter0); | ||
1466 | } | ||
1492 | return ret; | 1467 | return ret; |
1493 | out_unlock: | 1468 | out_unlock: |
1494 | xt_compat_flush_offsets(NFPROTO_ARP); | 1469 | xt_compat_flush_offsets(NFPROTO_ARP); |
@@ -1515,6 +1490,7 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
1515 | struct compat_arpt_replace tmp; | 1490 | struct compat_arpt_replace tmp; |
1516 | struct xt_table_info *newinfo; | 1491 | struct xt_table_info *newinfo; |
1517 | void *loc_cpu_entry; | 1492 | void *loc_cpu_entry; |
1493 | struct arpt_entry *iter; | ||
1518 | 1494 | ||
1519 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1495 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1520 | return -EFAULT; | 1496 | return -EFAULT; |
@@ -1552,7 +1528,8 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
1552 | return 0; | 1528 | return 0; |
1553 | 1529 | ||
1554 | free_newinfo_untrans: | 1530 | free_newinfo_untrans: |
1555 | ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1531 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1532 | cleanup_entry(iter); | ||
1556 | free_newinfo: | 1533 | free_newinfo: |
1557 | xt_free_table_info(newinfo); | 1534 | xt_free_table_info(newinfo); |
1558 | return ret; | 1535 | return ret; |
@@ -1586,7 +1563,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, | |||
1586 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | 1563 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, |
1587 | compat_uint_t *size, | 1564 | compat_uint_t *size, |
1588 | struct xt_counters *counters, | 1565 | struct xt_counters *counters, |
1589 | unsigned int *i) | 1566 | unsigned int i) |
1590 | { | 1567 | { |
1591 | struct arpt_entry_target *t; | 1568 | struct arpt_entry_target *t; |
1592 | struct compat_arpt_entry __user *ce; | 1569 | struct compat_arpt_entry __user *ce; |
@@ -1594,14 +1571,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
1594 | compat_uint_t origsize; | 1571 | compat_uint_t origsize; |
1595 | int ret; | 1572 | int ret; |
1596 | 1573 | ||
1597 | ret = -EFAULT; | ||
1598 | origsize = *size; | 1574 | origsize = *size; |
1599 | ce = (struct compat_arpt_entry __user *)*dstptr; | 1575 | ce = (struct compat_arpt_entry __user *)*dstptr; |
1600 | if (copy_to_user(ce, e, sizeof(struct arpt_entry))) | 1576 | if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || |
1601 | goto out; | 1577 | copy_to_user(&ce->counters, &counters[i], |
1602 | 1578 | sizeof(counters[i])) != 0) | |
1603 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1579 | return -EFAULT; |
1604 | goto out; | ||
1605 | 1580 | ||
1606 | *dstptr += sizeof(struct compat_arpt_entry); | 1581 | *dstptr += sizeof(struct compat_arpt_entry); |
1607 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); | 1582 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); |
@@ -1611,18 +1586,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
1611 | t = arpt_get_target(e); | 1586 | t = arpt_get_target(e); |
1612 | ret = xt_compat_target_to_user(t, dstptr, size); | 1587 | ret = xt_compat_target_to_user(t, dstptr, size); |
1613 | if (ret) | 1588 | if (ret) |
1614 | goto out; | 1589 | return ret; |
1615 | ret = -EFAULT; | ||
1616 | next_offset = e->next_offset - (origsize - *size); | 1590 | next_offset = e->next_offset - (origsize - *size); |
1617 | if (put_user(target_offset, &ce->target_offset)) | 1591 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1618 | goto out; | 1592 | put_user(next_offset, &ce->next_offset) != 0) |
1619 | if (put_user(next_offset, &ce->next_offset)) | 1593 | return -EFAULT; |
1620 | goto out; | ||
1621 | |||
1622 | (*i)++; | ||
1623 | return 0; | 1594 | return 0; |
1624 | out: | ||
1625 | return ret; | ||
1626 | } | 1595 | } |
1627 | 1596 | ||
1628 | static int compat_copy_entries_to_user(unsigned int total_size, | 1597 | static int compat_copy_entries_to_user(unsigned int total_size, |
@@ -1636,6 +1605,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, | |||
1636 | int ret = 0; | 1605 | int ret = 0; |
1637 | void *loc_cpu_entry; | 1606 | void *loc_cpu_entry; |
1638 | unsigned int i = 0; | 1607 | unsigned int i = 0; |
1608 | struct arpt_entry *iter; | ||
1639 | 1609 | ||
1640 | counters = alloc_counters(table); | 1610 | counters = alloc_counters(table); |
1641 | if (IS_ERR(counters)) | 1611 | if (IS_ERR(counters)) |
@@ -1645,9 +1615,12 @@ static int compat_copy_entries_to_user(unsigned int total_size, | |||
1645 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1615 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1646 | pos = userptr; | 1616 | pos = userptr; |
1647 | size = total_size; | 1617 | size = total_size; |
1648 | ret = ARPT_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1618 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1649 | compat_copy_entry_to_user, | 1619 | ret = compat_copy_entry_to_user(iter, &pos, |
1650 | &pos, &size, counters, &i); | 1620 | &size, counters, i++); |
1621 | if (ret != 0) | ||
1622 | break; | ||
1623 | } | ||
1651 | vfree(counters); | 1624 | vfree(counters); |
1652 | return ret; | 1625 | return ret; |
1653 | } | 1626 | } |
@@ -1815,12 +1788,7 @@ struct xt_table *arpt_register_table(struct net *net, | |||
1815 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 1788 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
1816 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 1789 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
1817 | 1790 | ||
1818 | ret = translate_table(table->name, table->valid_hooks, | 1791 | ret = translate_table(newinfo, loc_cpu_entry, repl); |
1819 | newinfo, loc_cpu_entry, repl->size, | ||
1820 | repl->num_entries, | ||
1821 | repl->hook_entry, | ||
1822 | repl->underflow); | ||
1823 | |||
1824 | duprintf("arpt_register_table: translate table gives %d\n", ret); | 1792 | duprintf("arpt_register_table: translate table gives %d\n", ret); |
1825 | if (ret != 0) | 1793 | if (ret != 0) |
1826 | goto out_free; | 1794 | goto out_free; |
@@ -1843,13 +1811,14 @@ void arpt_unregister_table(struct xt_table *table) | |||
1843 | struct xt_table_info *private; | 1811 | struct xt_table_info *private; |
1844 | void *loc_cpu_entry; | 1812 | void *loc_cpu_entry; |
1845 | struct module *table_owner = table->me; | 1813 | struct module *table_owner = table->me; |
1814 | struct arpt_entry *iter; | ||
1846 | 1815 | ||
1847 | private = xt_unregister_table(table); | 1816 | private = xt_unregister_table(table); |
1848 | 1817 | ||
1849 | /* Decrease module usage counts and free resources */ | 1818 | /* Decrease module usage counts and free resources */ |
1850 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1819 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1851 | ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size, | 1820 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
1852 | cleanup_entry, NULL); | 1821 | cleanup_entry(iter); |
1853 | if (private->number > private->initial_entries) | 1822 | if (private->number > private->initial_entries) |
1854 | module_put(table_owner); | 1823 | module_put(table_owner); |
1855 | xt_free_table_info(private); | 1824 | xt_free_table_info(private); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index e94c18bdfc68..c92f4e541cf6 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -288,6 +288,7 @@ static void trace_packet(const struct sk_buff *skb, | |||
288 | const void *table_base; | 288 | const void *table_base; |
289 | const struct ipt_entry *root; | 289 | const struct ipt_entry *root; |
290 | const char *hookname, *chainname, *comment; | 290 | const char *hookname, *chainname, *comment; |
291 | const struct ipt_entry *iter; | ||
291 | unsigned int rulenum = 0; | 292 | unsigned int rulenum = 0; |
292 | 293 | ||
293 | table_base = private->entries[smp_processor_id()]; | 294 | table_base = private->entries[smp_processor_id()]; |
@@ -296,10 +297,10 @@ static void trace_packet(const struct sk_buff *skb, | |||
296 | hookname = chainname = hooknames[hook]; | 297 | hookname = chainname = hooknames[hook]; |
297 | comment = comments[NF_IP_TRACE_COMMENT_RULE]; | 298 | comment = comments[NF_IP_TRACE_COMMENT_RULE]; |
298 | 299 | ||
299 | IPT_ENTRY_ITERATE(root, | 300 | xt_entry_foreach(iter, root, private->size - private->hook_entry[hook]) |
300 | private->size - private->hook_entry[hook], | 301 | if (get_chainname_rulenum(iter, e, hookname, |
301 | get_chainname_rulenum, | 302 | &chainname, &comment, &rulenum) != 0) |
302 | e, hookname, &chainname, &comment, &rulenum); | 303 | break; |
303 | 304 | ||
304 | nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo, | 305 | nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo, |
305 | "TRACE: %s:%s:%s:%u ", | 306 | "TRACE: %s:%s:%s:%u ", |
@@ -365,16 +366,21 @@ ipt_do_table(struct sk_buff *skb, | |||
365 | 366 | ||
366 | do { | 367 | do { |
367 | const struct ipt_entry_target *t; | 368 | const struct ipt_entry_target *t; |
369 | const struct xt_entry_match *ematch; | ||
368 | 370 | ||
369 | IP_NF_ASSERT(e); | 371 | IP_NF_ASSERT(e); |
370 | IP_NF_ASSERT(back); | 372 | IP_NF_ASSERT(back); |
371 | if (!ip_packet_match(ip, indev, outdev, | 373 | if (!ip_packet_match(ip, indev, outdev, |
372 | &e->ip, mtpar.fragoff) || | 374 | &e->ip, mtpar.fragoff)) { |
373 | IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { | 375 | no_match: |
374 | e = ipt_next_entry(e); | 376 | e = ipt_next_entry(e); |
375 | continue; | 377 | continue; |
376 | } | 378 | } |
377 | 379 | ||
380 | xt_ematch_foreach(ematch, e) | ||
381 | if (do_match(ematch, skb, &mtpar) != 0) | ||
382 | goto no_match; | ||
383 | |||
378 | ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); | 384 | ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); |
379 | 385 | ||
380 | t = ipt_get_target(e); | 386 | t = ipt_get_target(e); |
@@ -566,14 +572,10 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
566 | return 1; | 572 | return 1; |
567 | } | 573 | } |
568 | 574 | ||
569 | static int | 575 | static void cleanup_match(struct ipt_entry_match *m, struct net *net) |
570 | cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) | ||
571 | { | 576 | { |
572 | struct xt_mtdtor_param par; | 577 | struct xt_mtdtor_param par; |
573 | 578 | ||
574 | if (i && (*i)-- == 0) | ||
575 | return 1; | ||
576 | |||
577 | par.net = net; | 579 | par.net = net; |
578 | par.match = m->u.kernel.match; | 580 | par.match = m->u.kernel.match; |
579 | par.matchinfo = m->data; | 581 | par.matchinfo = m->data; |
@@ -581,7 +583,6 @@ cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) | |||
581 | if (par.match->destroy != NULL) | 583 | if (par.match->destroy != NULL) |
582 | par.match->destroy(&par); | 584 | par.match->destroy(&par); |
583 | module_put(par.match->me); | 585 | module_put(par.match->me); |
584 | return 0; | ||
585 | } | 586 | } |
586 | 587 | ||
587 | static int | 588 | static int |
@@ -606,8 +607,7 @@ check_entry(const struct ipt_entry *e, const char *name) | |||
606 | } | 607 | } |
607 | 608 | ||
608 | static int | 609 | static int |
609 | check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | 610 | check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par) |
610 | unsigned int *i) | ||
611 | { | 611 | { |
612 | const struct ipt_ip *ip = par->entryinfo; | 612 | const struct ipt_ip *ip = par->entryinfo; |
613 | int ret; | 613 | int ret; |
@@ -622,13 +622,11 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | |||
622 | par.match->name); | 622 | par.match->name); |
623 | return ret; | 623 | return ret; |
624 | } | 624 | } |
625 | ++*i; | ||
626 | return 0; | 625 | return 0; |
627 | } | 626 | } |
628 | 627 | ||
629 | static int | 628 | static int |
630 | find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | 629 | find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par) |
631 | unsigned int *i) | ||
632 | { | 630 | { |
633 | struct xt_match *match; | 631 | struct xt_match *match; |
634 | int ret; | 632 | int ret; |
@@ -642,7 +640,7 @@ find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | |||
642 | } | 640 | } |
643 | m->u.kernel.match = match; | 641 | m->u.kernel.match = match; |
644 | 642 | ||
645 | ret = check_match(m, par, i); | 643 | ret = check_match(m, par); |
646 | if (ret) | 644 | if (ret) |
647 | goto err; | 645 | goto err; |
648 | 646 | ||
@@ -678,13 +676,14 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name) | |||
678 | 676 | ||
679 | static int | 677 | static int |
680 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 678 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, |
681 | unsigned int size, unsigned int *i) | 679 | unsigned int size) |
682 | { | 680 | { |
683 | struct ipt_entry_target *t; | 681 | struct ipt_entry_target *t; |
684 | struct xt_target *target; | 682 | struct xt_target *target; |
685 | int ret; | 683 | int ret; |
686 | unsigned int j; | 684 | unsigned int j; |
687 | struct xt_mtchk_param mtpar; | 685 | struct xt_mtchk_param mtpar; |
686 | struct xt_entry_match *ematch; | ||
688 | 687 | ||
689 | ret = check_entry(e, name); | 688 | ret = check_entry(e, name); |
690 | if (ret) | 689 | if (ret) |
@@ -696,9 +695,12 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
696 | mtpar.entryinfo = &e->ip; | 695 | mtpar.entryinfo = &e->ip; |
697 | mtpar.hook_mask = e->comefrom; | 696 | mtpar.hook_mask = e->comefrom; |
698 | mtpar.family = NFPROTO_IPV4; | 697 | mtpar.family = NFPROTO_IPV4; |
699 | ret = IPT_MATCH_ITERATE(e, find_check_match, &mtpar, &j); | 698 | xt_ematch_foreach(ematch, e) { |
700 | if (ret != 0) | 699 | ret = find_check_match(ematch, &mtpar); |
701 | goto cleanup_matches; | 700 | if (ret != 0) |
701 | goto cleanup_matches; | ||
702 | ++j; | ||
703 | } | ||
702 | 704 | ||
703 | t = ipt_get_target(e); | 705 | t = ipt_get_target(e); |
704 | target = try_then_request_module(xt_find_target(AF_INET, | 706 | target = try_then_request_module(xt_find_target(AF_INET, |
@@ -715,13 +717,15 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
715 | ret = check_target(e, net, name); | 717 | ret = check_target(e, net, name); |
716 | if (ret) | 718 | if (ret) |
717 | goto err; | 719 | goto err; |
718 | |||
719 | (*i)++; | ||
720 | return 0; | 720 | return 0; |
721 | err: | 721 | err: |
722 | module_put(t->u.kernel.target->me); | 722 | module_put(t->u.kernel.target->me); |
723 | cleanup_matches: | 723 | cleanup_matches: |
724 | IPT_MATCH_ITERATE(e, cleanup_match, net, &j); | 724 | xt_ematch_foreach(ematch, e) { |
725 | if (j-- == 0) | ||
726 | break; | ||
727 | cleanup_match(ematch, net); | ||
728 | } | ||
725 | return ret; | 729 | return ret; |
726 | } | 730 | } |
727 | 731 | ||
@@ -747,8 +751,7 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
747 | const unsigned char *limit, | 751 | const unsigned char *limit, |
748 | const unsigned int *hook_entries, | 752 | const unsigned int *hook_entries, |
749 | const unsigned int *underflows, | 753 | const unsigned int *underflows, |
750 | unsigned int valid_hooks, | 754 | unsigned int valid_hooks) |
751 | unsigned int *i) | ||
752 | { | 755 | { |
753 | unsigned int h; | 756 | unsigned int h; |
754 | 757 | ||
@@ -785,22 +788,19 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
785 | /* Clear counters and comefrom */ | 788 | /* Clear counters and comefrom */ |
786 | e->counters = ((struct xt_counters) { 0, 0 }); | 789 | e->counters = ((struct xt_counters) { 0, 0 }); |
787 | e->comefrom = 0; | 790 | e->comefrom = 0; |
788 | |||
789 | (*i)++; | ||
790 | return 0; | 791 | return 0; |
791 | } | 792 | } |
792 | 793 | ||
793 | static int | 794 | static void |
794 | cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | 795 | cleanup_entry(struct ipt_entry *e, struct net *net) |
795 | { | 796 | { |
796 | struct xt_tgdtor_param par; | 797 | struct xt_tgdtor_param par; |
797 | struct ipt_entry_target *t; | 798 | struct ipt_entry_target *t; |
798 | 799 | struct xt_entry_match *ematch; | |
799 | if (i && (*i)-- == 0) | ||
800 | return 1; | ||
801 | 800 | ||
802 | /* Cleanup all matches */ | 801 | /* Cleanup all matches */ |
803 | IPT_MATCH_ITERATE(e, cleanup_match, net, NULL); | 802 | xt_ematch_foreach(ematch, e) |
803 | cleanup_match(ematch, net); | ||
804 | t = ipt_get_target(e); | 804 | t = ipt_get_target(e); |
805 | 805 | ||
806 | par.net = net; | 806 | par.net = net; |
@@ -810,27 +810,20 @@ cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | |||
810 | if (par.target->destroy != NULL) | 810 | if (par.target->destroy != NULL) |
811 | par.target->destroy(&par); | 811 | par.target->destroy(&par); |
812 | module_put(par.target->me); | 812 | module_put(par.target->me); |
813 | return 0; | ||
814 | } | 813 | } |
815 | 814 | ||
816 | /* Checks and translates the user-supplied table segment (held in | 815 | /* Checks and translates the user-supplied table segment (held in |
817 | newinfo) */ | 816 | newinfo) */ |
818 | static int | 817 | static int |
819 | translate_table(struct net *net, | 818 | translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, |
820 | const char *name, | 819 | const struct ipt_replace *repl) |
821 | unsigned int valid_hooks, | ||
822 | struct xt_table_info *newinfo, | ||
823 | void *entry0, | ||
824 | unsigned int size, | ||
825 | unsigned int number, | ||
826 | const unsigned int *hook_entries, | ||
827 | const unsigned int *underflows) | ||
828 | { | 820 | { |
821 | struct ipt_entry *iter; | ||
829 | unsigned int i; | 822 | unsigned int i; |
830 | int ret; | 823 | int ret = 0; |
831 | 824 | ||
832 | newinfo->size = size; | 825 | newinfo->size = repl->size; |
833 | newinfo->number = number; | 826 | newinfo->number = repl->num_entries; |
834 | 827 | ||
835 | /* Init all hooks to impossible value. */ | 828 | /* Init all hooks to impossible value. */ |
836 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 829 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
@@ -841,49 +834,56 @@ translate_table(struct net *net, | |||
841 | duprintf("translate_table: size %u\n", newinfo->size); | 834 | duprintf("translate_table: size %u\n", newinfo->size); |
842 | i = 0; | 835 | i = 0; |
843 | /* Walk through entries, checking offsets. */ | 836 | /* Walk through entries, checking offsets. */ |
844 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, | 837 | xt_entry_foreach(iter, entry0, newinfo->size) { |
845 | check_entry_size_and_hooks, | 838 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
846 | newinfo, | 839 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
847 | entry0, | 840 | repl->valid_hooks); |
848 | entry0 + size, | 841 | if (ret != 0) |
849 | hook_entries, underflows, valid_hooks, &i); | 842 | return ret; |
850 | if (ret != 0) | 843 | ++i; |
851 | return ret; | 844 | } |
852 | 845 | ||
853 | if (i != number) { | 846 | if (i != repl->num_entries) { |
854 | duprintf("translate_table: %u not %u entries\n", | 847 | duprintf("translate_table: %u not %u entries\n", |
855 | i, number); | 848 | i, repl->num_entries); |
856 | return -EINVAL; | 849 | return -EINVAL; |
857 | } | 850 | } |
858 | 851 | ||
859 | /* Check hooks all assigned */ | 852 | /* Check hooks all assigned */ |
860 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 853 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
861 | /* Only hooks which are valid */ | 854 | /* Only hooks which are valid */ |
862 | if (!(valid_hooks & (1 << i))) | 855 | if (!(repl->valid_hooks & (1 << i))) |
863 | continue; | 856 | continue; |
864 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 857 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
865 | duprintf("Invalid hook entry %u %u\n", | 858 | duprintf("Invalid hook entry %u %u\n", |
866 | i, hook_entries[i]); | 859 | i, repl->hook_entry[i]); |
867 | return -EINVAL; | 860 | return -EINVAL; |
868 | } | 861 | } |
869 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 862 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
870 | duprintf("Invalid underflow %u %u\n", | 863 | duprintf("Invalid underflow %u %u\n", |
871 | i, underflows[i]); | 864 | i, repl->underflow[i]); |
872 | return -EINVAL; | 865 | return -EINVAL; |
873 | } | 866 | } |
874 | } | 867 | } |
875 | 868 | ||
876 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | 869 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) |
877 | return -ELOOP; | 870 | return -ELOOP; |
878 | 871 | ||
879 | /* Finally, each sanity check must pass */ | 872 | /* Finally, each sanity check must pass */ |
880 | i = 0; | 873 | i = 0; |
881 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, | 874 | xt_entry_foreach(iter, entry0, newinfo->size) { |
882 | find_check_entry, net, name, size, &i); | 875 | ret = find_check_entry(iter, net, repl->name, repl->size); |
876 | if (ret != 0) | ||
877 | break; | ||
878 | ++i; | ||
879 | } | ||
883 | 880 | ||
884 | if (ret != 0) { | 881 | if (ret != 0) { |
885 | IPT_ENTRY_ITERATE(entry0, newinfo->size, | 882 | xt_entry_foreach(iter, entry0, newinfo->size) { |
886 | cleanup_entry, net, &i); | 883 | if (i-- == 0) |
884 | break; | ||
885 | cleanup_entry(iter, net); | ||
886 | } | ||
887 | return ret; | 887 | return ret; |
888 | } | 888 | } |
889 | 889 | ||
@@ -896,33 +896,11 @@ translate_table(struct net *net, | |||
896 | return ret; | 896 | return ret; |
897 | } | 897 | } |
898 | 898 | ||
899 | /* Gets counters. */ | ||
900 | static inline int | ||
901 | add_entry_to_counter(const struct ipt_entry *e, | ||
902 | struct xt_counters total[], | ||
903 | unsigned int *i) | ||
904 | { | ||
905 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
906 | |||
907 | (*i)++; | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static inline int | ||
912 | set_entry_to_counter(const struct ipt_entry *e, | ||
913 | struct ipt_counters total[], | ||
914 | unsigned int *i) | ||
915 | { | ||
916 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
917 | |||
918 | (*i)++; | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static void | 899 | static void |
923 | get_counters(const struct xt_table_info *t, | 900 | get_counters(const struct xt_table_info *t, |
924 | struct xt_counters counters[]) | 901 | struct xt_counters counters[]) |
925 | { | 902 | { |
903 | struct ipt_entry *iter; | ||
926 | unsigned int cpu; | 904 | unsigned int cpu; |
927 | unsigned int i; | 905 | unsigned int i; |
928 | unsigned int curcpu; | 906 | unsigned int curcpu; |
@@ -938,22 +916,22 @@ get_counters(const struct xt_table_info *t, | |||
938 | curcpu = smp_processor_id(); | 916 | curcpu = smp_processor_id(); |
939 | 917 | ||
940 | i = 0; | 918 | i = 0; |
941 | IPT_ENTRY_ITERATE(t->entries[curcpu], | 919 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
942 | t->size, | 920 | SET_COUNTER(counters[i], iter->counters.bcnt, |
943 | set_entry_to_counter, | 921 | iter->counters.pcnt); |
944 | counters, | 922 | ++i; |
945 | &i); | 923 | } |
946 | 924 | ||
947 | for_each_possible_cpu(cpu) { | 925 | for_each_possible_cpu(cpu) { |
948 | if (cpu == curcpu) | 926 | if (cpu == curcpu) |
949 | continue; | 927 | continue; |
950 | i = 0; | 928 | i = 0; |
951 | xt_info_wrlock(cpu); | 929 | xt_info_wrlock(cpu); |
952 | IPT_ENTRY_ITERATE(t->entries[cpu], | 930 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
953 | t->size, | 931 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
954 | add_entry_to_counter, | 932 | iter->counters.pcnt); |
955 | counters, | 933 | ++i; /* macro does multi eval of i */ |
956 | &i); | 934 | } |
957 | xt_info_wrunlock(cpu); | 935 | xt_info_wrunlock(cpu); |
958 | } | 936 | } |
959 | local_bh_enable(); | 937 | local_bh_enable(); |
@@ -1072,24 +1050,19 @@ static int compat_standard_to_user(void __user *dst, const void *src) | |||
1072 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1050 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
1073 | } | 1051 | } |
1074 | 1052 | ||
1075 | static inline int | ||
1076 | compat_calc_match(const struct ipt_entry_match *m, int *size) | ||
1077 | { | ||
1078 | *size += xt_compat_match_offset(m->u.kernel.match); | ||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1082 | static int compat_calc_entry(const struct ipt_entry *e, | 1053 | static int compat_calc_entry(const struct ipt_entry *e, |
1083 | const struct xt_table_info *info, | 1054 | const struct xt_table_info *info, |
1084 | const void *base, struct xt_table_info *newinfo) | 1055 | const void *base, struct xt_table_info *newinfo) |
1085 | { | 1056 | { |
1057 | const struct xt_entry_match *ematch; | ||
1086 | const struct ipt_entry_target *t; | 1058 | const struct ipt_entry_target *t; |
1087 | unsigned int entry_offset; | 1059 | unsigned int entry_offset; |
1088 | int off, i, ret; | 1060 | int off, i, ret; |
1089 | 1061 | ||
1090 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1062 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1091 | entry_offset = (void *)e - base; | 1063 | entry_offset = (void *)e - base; |
1092 | IPT_MATCH_ITERATE(e, compat_calc_match, &off); | 1064 | xt_ematch_foreach(ematch, e) |
1065 | off += xt_compat_match_offset(ematch->u.kernel.match); | ||
1093 | t = ipt_get_target_c(e); | 1066 | t = ipt_get_target_c(e); |
1094 | off += xt_compat_target_offset(t->u.kernel.target); | 1067 | off += xt_compat_target_offset(t->u.kernel.target); |
1095 | newinfo->size -= off; | 1068 | newinfo->size -= off; |
@@ -1111,7 +1084,9 @@ static int compat_calc_entry(const struct ipt_entry *e, | |||
1111 | static int compat_table_info(const struct xt_table_info *info, | 1084 | static int compat_table_info(const struct xt_table_info *info, |
1112 | struct xt_table_info *newinfo) | 1085 | struct xt_table_info *newinfo) |
1113 | { | 1086 | { |
1087 | struct ipt_entry *iter; | ||
1114 | void *loc_cpu_entry; | 1088 | void *loc_cpu_entry; |
1089 | int ret; | ||
1115 | 1090 | ||
1116 | if (!newinfo || !info) | 1091 | if (!newinfo || !info) |
1117 | return -EINVAL; | 1092 | return -EINVAL; |
@@ -1120,9 +1095,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1120 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1095 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
1121 | newinfo->initial_entries = 0; | 1096 | newinfo->initial_entries = 0; |
1122 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1097 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
1123 | return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size, | 1098 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1124 | compat_calc_entry, info, loc_cpu_entry, | 1099 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1125 | newinfo); | 1100 | if (ret != 0) |
1101 | return ret; | ||
1102 | } | ||
1103 | return 0; | ||
1126 | } | 1104 | } |
1127 | #endif | 1105 | #endif |
1128 | 1106 | ||
@@ -1236,6 +1214,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1236 | struct xt_table_info *oldinfo; | 1214 | struct xt_table_info *oldinfo; |
1237 | struct xt_counters *counters; | 1215 | struct xt_counters *counters; |
1238 | void *loc_cpu_old_entry; | 1216 | void *loc_cpu_old_entry; |
1217 | struct ipt_entry *iter; | ||
1239 | 1218 | ||
1240 | ret = 0; | 1219 | ret = 0; |
1241 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); | 1220 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); |
@@ -1278,8 +1257,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1278 | 1257 | ||
1279 | /* Decrease module usage counts and free resource */ | 1258 | /* Decrease module usage counts and free resource */ |
1280 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1259 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1281 | IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1260 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1282 | net, NULL); | 1261 | cleanup_entry(iter, net); |
1262 | |||
1283 | xt_free_table_info(oldinfo); | 1263 | xt_free_table_info(oldinfo); |
1284 | if (copy_to_user(counters_ptr, counters, | 1264 | if (copy_to_user(counters_ptr, counters, |
1285 | sizeof(struct xt_counters) * num_counters) != 0) | 1265 | sizeof(struct xt_counters) * num_counters) != 0) |
@@ -1304,6 +1284,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1304 | struct ipt_replace tmp; | 1284 | struct ipt_replace tmp; |
1305 | struct xt_table_info *newinfo; | 1285 | struct xt_table_info *newinfo; |
1306 | void *loc_cpu_entry; | 1286 | void *loc_cpu_entry; |
1287 | struct ipt_entry *iter; | ||
1307 | 1288 | ||
1308 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1289 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1309 | return -EFAULT; | 1290 | return -EFAULT; |
@@ -1324,9 +1305,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1324 | goto free_newinfo; | 1305 | goto free_newinfo; |
1325 | } | 1306 | } |
1326 | 1307 | ||
1327 | ret = translate_table(net, tmp.name, tmp.valid_hooks, | 1308 | ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); |
1328 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
1329 | tmp.hook_entry, tmp.underflow); | ||
1330 | if (ret != 0) | 1309 | if (ret != 0) |
1331 | goto free_newinfo; | 1310 | goto free_newinfo; |
1332 | 1311 | ||
@@ -1339,25 +1318,13 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1339 | return 0; | 1318 | return 0; |
1340 | 1319 | ||
1341 | free_newinfo_untrans: | 1320 | free_newinfo_untrans: |
1342 | IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1321 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1322 | cleanup_entry(iter, net); | ||
1343 | free_newinfo: | 1323 | free_newinfo: |
1344 | xt_free_table_info(newinfo); | 1324 | xt_free_table_info(newinfo); |
1345 | return ret; | 1325 | return ret; |
1346 | } | 1326 | } |
1347 | 1327 | ||
1348 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1349 | * and everything is OK. */ | ||
1350 | static int | ||
1351 | add_counter_to_entry(struct ipt_entry *e, | ||
1352 | const struct xt_counters addme[], | ||
1353 | unsigned int *i) | ||
1354 | { | ||
1355 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1356 | |||
1357 | (*i)++; | ||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | static int | 1328 | static int |
1362 | do_add_counters(struct net *net, const void __user *user, | 1329 | do_add_counters(struct net *net, const void __user *user, |
1363 | unsigned int len, int compat) | 1330 | unsigned int len, int compat) |
@@ -1373,6 +1340,7 @@ do_add_counters(struct net *net, const void __user *user, | |||
1373 | const struct xt_table_info *private; | 1340 | const struct xt_table_info *private; |
1374 | int ret = 0; | 1341 | int ret = 0; |
1375 | void *loc_cpu_entry; | 1342 | void *loc_cpu_entry; |
1343 | struct ipt_entry *iter; | ||
1376 | #ifdef CONFIG_COMPAT | 1344 | #ifdef CONFIG_COMPAT |
1377 | struct compat_xt_counters_info compat_tmp; | 1345 | struct compat_xt_counters_info compat_tmp; |
1378 | 1346 | ||
@@ -1430,11 +1398,10 @@ do_add_counters(struct net *net, const void __user *user, | |||
1430 | curcpu = smp_processor_id(); | 1398 | curcpu = smp_processor_id(); |
1431 | loc_cpu_entry = private->entries[curcpu]; | 1399 | loc_cpu_entry = private->entries[curcpu]; |
1432 | xt_info_wrlock(curcpu); | 1400 | xt_info_wrlock(curcpu); |
1433 | IPT_ENTRY_ITERATE(loc_cpu_entry, | 1401 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1434 | private->size, | 1402 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1435 | add_counter_to_entry, | 1403 | ++i; |
1436 | paddc, | 1404 | } |
1437 | &i); | ||
1438 | xt_info_wrunlock(curcpu); | 1405 | xt_info_wrunlock(curcpu); |
1439 | unlock_up_free: | 1406 | unlock_up_free: |
1440 | local_bh_enable(); | 1407 | local_bh_enable(); |
@@ -1462,45 +1429,40 @@ struct compat_ipt_replace { | |||
1462 | static int | 1429 | static int |
1463 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, | 1430 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, |
1464 | unsigned int *size, struct xt_counters *counters, | 1431 | unsigned int *size, struct xt_counters *counters, |
1465 | unsigned int *i) | 1432 | unsigned int i) |
1466 | { | 1433 | { |
1467 | struct ipt_entry_target *t; | 1434 | struct ipt_entry_target *t; |
1468 | struct compat_ipt_entry __user *ce; | 1435 | struct compat_ipt_entry __user *ce; |
1469 | u_int16_t target_offset, next_offset; | 1436 | u_int16_t target_offset, next_offset; |
1470 | compat_uint_t origsize; | 1437 | compat_uint_t origsize; |
1471 | int ret; | 1438 | const struct xt_entry_match *ematch; |
1439 | int ret = 0; | ||
1472 | 1440 | ||
1473 | ret = -EFAULT; | ||
1474 | origsize = *size; | 1441 | origsize = *size; |
1475 | ce = (struct compat_ipt_entry __user *)*dstptr; | 1442 | ce = (struct compat_ipt_entry __user *)*dstptr; |
1476 | if (copy_to_user(ce, e, sizeof(struct ipt_entry))) | 1443 | if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || |
1477 | goto out; | 1444 | copy_to_user(&ce->counters, &counters[i], |
1478 | 1445 | sizeof(counters[i])) != 0) | |
1479 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1446 | return -EFAULT; |
1480 | goto out; | ||
1481 | 1447 | ||
1482 | *dstptr += sizeof(struct compat_ipt_entry); | 1448 | *dstptr += sizeof(struct compat_ipt_entry); |
1483 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1449 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1484 | 1450 | ||
1485 | ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1451 | xt_ematch_foreach(ematch, e) { |
1452 | ret = xt_compat_match_to_user(ematch, dstptr, size); | ||
1453 | if (ret != 0) | ||
1454 | return ret; | ||
1455 | } | ||
1486 | target_offset = e->target_offset - (origsize - *size); | 1456 | target_offset = e->target_offset - (origsize - *size); |
1487 | if (ret) | ||
1488 | goto out; | ||
1489 | t = ipt_get_target(e); | 1457 | t = ipt_get_target(e); |
1490 | ret = xt_compat_target_to_user(t, dstptr, size); | 1458 | ret = xt_compat_target_to_user(t, dstptr, size); |
1491 | if (ret) | 1459 | if (ret) |
1492 | goto out; | 1460 | return ret; |
1493 | ret = -EFAULT; | ||
1494 | next_offset = e->next_offset - (origsize - *size); | 1461 | next_offset = e->next_offset - (origsize - *size); |
1495 | if (put_user(target_offset, &ce->target_offset)) | 1462 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1496 | goto out; | 1463 | put_user(next_offset, &ce->next_offset) != 0) |
1497 | if (put_user(next_offset, &ce->next_offset)) | 1464 | return -EFAULT; |
1498 | goto out; | ||
1499 | |||
1500 | (*i)++; | ||
1501 | return 0; | 1465 | return 0; |
1502 | out: | ||
1503 | return ret; | ||
1504 | } | 1466 | } |
1505 | 1467 | ||
1506 | static int | 1468 | static int |
@@ -1508,7 +1470,7 @@ compat_find_calc_match(struct ipt_entry_match *m, | |||
1508 | const char *name, | 1470 | const char *name, |
1509 | const struct ipt_ip *ip, | 1471 | const struct ipt_ip *ip, |
1510 | unsigned int hookmask, | 1472 | unsigned int hookmask, |
1511 | int *size, unsigned int *i) | 1473 | int *size) |
1512 | { | 1474 | { |
1513 | struct xt_match *match; | 1475 | struct xt_match *match; |
1514 | 1476 | ||
@@ -1522,34 +1484,19 @@ compat_find_calc_match(struct ipt_entry_match *m, | |||
1522 | } | 1484 | } |
1523 | m->u.kernel.match = match; | 1485 | m->u.kernel.match = match; |
1524 | *size += xt_compat_match_offset(match); | 1486 | *size += xt_compat_match_offset(match); |
1525 | |||
1526 | (*i)++; | ||
1527 | return 0; | 1487 | return 0; |
1528 | } | 1488 | } |
1529 | 1489 | ||
1530 | static int | 1490 | static void compat_release_entry(struct compat_ipt_entry *e) |
1531 | compat_release_match(struct ipt_entry_match *m, unsigned int *i) | ||
1532 | { | ||
1533 | if (i && (*i)-- == 0) | ||
1534 | return 1; | ||
1535 | |||
1536 | module_put(m->u.kernel.match->me); | ||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | static int | ||
1541 | compat_release_entry(struct compat_ipt_entry *e, unsigned int *i) | ||
1542 | { | 1491 | { |
1543 | struct ipt_entry_target *t; | 1492 | struct ipt_entry_target *t; |
1544 | 1493 | struct xt_entry_match *ematch; | |
1545 | if (i && (*i)-- == 0) | ||
1546 | return 1; | ||
1547 | 1494 | ||
1548 | /* Cleanup all matches */ | 1495 | /* Cleanup all matches */ |
1549 | COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL); | 1496 | xt_ematch_foreach(ematch, e) |
1497 | module_put(ematch->u.kernel.match->me); | ||
1550 | t = compat_ipt_get_target(e); | 1498 | t = compat_ipt_get_target(e); |
1551 | module_put(t->u.kernel.target->me); | 1499 | module_put(t->u.kernel.target->me); |
1552 | return 0; | ||
1553 | } | 1500 | } |
1554 | 1501 | ||
1555 | static int | 1502 | static int |
@@ -1560,9 +1507,9 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1560 | const unsigned char *limit, | 1507 | const unsigned char *limit, |
1561 | const unsigned int *hook_entries, | 1508 | const unsigned int *hook_entries, |
1562 | const unsigned int *underflows, | 1509 | const unsigned int *underflows, |
1563 | unsigned int *i, | ||
1564 | const char *name) | 1510 | const char *name) |
1565 | { | 1511 | { |
1512 | struct xt_entry_match *ematch; | ||
1566 | struct ipt_entry_target *t; | 1513 | struct ipt_entry_target *t; |
1567 | struct xt_target *target; | 1514 | struct xt_target *target; |
1568 | unsigned int entry_offset; | 1515 | unsigned int entry_offset; |
@@ -1591,10 +1538,13 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1591 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1538 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1592 | entry_offset = (void *)e - (void *)base; | 1539 | entry_offset = (void *)e - (void *)base; |
1593 | j = 0; | 1540 | j = 0; |
1594 | ret = COMPAT_IPT_MATCH_ITERATE(e, compat_find_calc_match, name, | 1541 | xt_ematch_foreach(ematch, e) { |
1595 | &e->ip, e->comefrom, &off, &j); | 1542 | ret = compat_find_calc_match(ematch, name, |
1596 | if (ret != 0) | 1543 | &e->ip, e->comefrom, &off); |
1597 | goto release_matches; | 1544 | if (ret != 0) |
1545 | goto release_matches; | ||
1546 | ++j; | ||
1547 | } | ||
1598 | 1548 | ||
1599 | t = compat_ipt_get_target(e); | 1549 | t = compat_ipt_get_target(e); |
1600 | target = try_then_request_module(xt_find_target(AF_INET, | 1550 | target = try_then_request_module(xt_find_target(AF_INET, |
@@ -1626,14 +1576,16 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1626 | /* Clear counters and comefrom */ | 1576 | /* Clear counters and comefrom */ |
1627 | memset(&e->counters, 0, sizeof(e->counters)); | 1577 | memset(&e->counters, 0, sizeof(e->counters)); |
1628 | e->comefrom = 0; | 1578 | e->comefrom = 0; |
1629 | |||
1630 | (*i)++; | ||
1631 | return 0; | 1579 | return 0; |
1632 | 1580 | ||
1633 | out: | 1581 | out: |
1634 | module_put(t->u.kernel.target->me); | 1582 | module_put(t->u.kernel.target->me); |
1635 | release_matches: | 1583 | release_matches: |
1636 | IPT_MATCH_ITERATE(e, compat_release_match, &j); | 1584 | xt_ematch_foreach(ematch, e) { |
1585 | if (j-- == 0) | ||
1586 | break; | ||
1587 | module_put(ematch->u.kernel.match->me); | ||
1588 | } | ||
1637 | return ret; | 1589 | return ret; |
1638 | } | 1590 | } |
1639 | 1591 | ||
@@ -1647,6 +1599,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
1647 | struct ipt_entry *de; | 1599 | struct ipt_entry *de; |
1648 | unsigned int origsize; | 1600 | unsigned int origsize; |
1649 | int ret, h; | 1601 | int ret, h; |
1602 | struct xt_entry_match *ematch; | ||
1650 | 1603 | ||
1651 | ret = 0; | 1604 | ret = 0; |
1652 | origsize = *size; | 1605 | origsize = *size; |
@@ -1657,10 +1610,11 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
1657 | *dstptr += sizeof(struct ipt_entry); | 1610 | *dstptr += sizeof(struct ipt_entry); |
1658 | *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1611 | *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
1659 | 1612 | ||
1660 | ret = COMPAT_IPT_MATCH_ITERATE(e, xt_compat_match_from_user, | 1613 | xt_ematch_foreach(ematch, e) { |
1661 | dstptr, size); | 1614 | ret = xt_compat_match_from_user(ematch, dstptr, size); |
1662 | if (ret) | 1615 | if (ret != 0) |
1663 | return ret; | 1616 | return ret; |
1617 | } | ||
1664 | de->target_offset = e->target_offset - (origsize - *size); | 1618 | de->target_offset = e->target_offset - (origsize - *size); |
1665 | t = compat_ipt_get_target(e); | 1619 | t = compat_ipt_get_target(e); |
1666 | target = t->u.kernel.target; | 1620 | target = t->u.kernel.target; |
@@ -1677,12 +1631,12 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
1677 | } | 1631 | } |
1678 | 1632 | ||
1679 | static int | 1633 | static int |
1680 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 1634 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name) |
1681 | unsigned int *i) | ||
1682 | { | 1635 | { |
1636 | struct xt_entry_match *ematch; | ||
1683 | struct xt_mtchk_param mtpar; | 1637 | struct xt_mtchk_param mtpar; |
1684 | unsigned int j; | 1638 | unsigned int j; |
1685 | int ret; | 1639 | int ret = 0; |
1686 | 1640 | ||
1687 | j = 0; | 1641 | j = 0; |
1688 | mtpar.net = net; | 1642 | mtpar.net = net; |
@@ -1690,19 +1644,24 @@ compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
1690 | mtpar.entryinfo = &e->ip; | 1644 | mtpar.entryinfo = &e->ip; |
1691 | mtpar.hook_mask = e->comefrom; | 1645 | mtpar.hook_mask = e->comefrom; |
1692 | mtpar.family = NFPROTO_IPV4; | 1646 | mtpar.family = NFPROTO_IPV4; |
1693 | ret = IPT_MATCH_ITERATE(e, check_match, &mtpar, &j); | 1647 | xt_ematch_foreach(ematch, e) { |
1694 | if (ret) | 1648 | ret = check_match(ematch, &mtpar); |
1695 | goto cleanup_matches; | 1649 | if (ret != 0) |
1650 | goto cleanup_matches; | ||
1651 | ++j; | ||
1652 | } | ||
1696 | 1653 | ||
1697 | ret = check_target(e, net, name); | 1654 | ret = check_target(e, net, name); |
1698 | if (ret) | 1655 | if (ret) |
1699 | goto cleanup_matches; | 1656 | goto cleanup_matches; |
1700 | |||
1701 | (*i)++; | ||
1702 | return 0; | 1657 | return 0; |
1703 | 1658 | ||
1704 | cleanup_matches: | 1659 | cleanup_matches: |
1705 | IPT_MATCH_ITERATE(e, cleanup_match, net, &j); | 1660 | xt_ematch_foreach(ematch, e) { |
1661 | if (j-- == 0) | ||
1662 | break; | ||
1663 | cleanup_match(ematch, net); | ||
1664 | } | ||
1706 | return ret; | 1665 | return ret; |
1707 | } | 1666 | } |
1708 | 1667 | ||
@@ -1720,6 +1679,8 @@ translate_compat_table(struct net *net, | |||
1720 | unsigned int i, j; | 1679 | unsigned int i, j; |
1721 | struct xt_table_info *newinfo, *info; | 1680 | struct xt_table_info *newinfo, *info; |
1722 | void *pos, *entry0, *entry1; | 1681 | void *pos, *entry0, *entry1; |
1682 | struct compat_ipt_entry *iter0; | ||
1683 | struct ipt_entry *iter1; | ||
1723 | unsigned int size; | 1684 | unsigned int size; |
1724 | int ret; | 1685 | int ret; |
1725 | 1686 | ||
@@ -1738,13 +1699,14 @@ translate_compat_table(struct net *net, | |||
1738 | j = 0; | 1699 | j = 0; |
1739 | xt_compat_lock(AF_INET); | 1700 | xt_compat_lock(AF_INET); |
1740 | /* Walk through entries, checking offsets. */ | 1701 | /* Walk through entries, checking offsets. */ |
1741 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, | 1702 | xt_entry_foreach(iter0, entry0, total_size) { |
1742 | check_compat_entry_size_and_hooks, | 1703 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1743 | info, &size, entry0, | 1704 | entry0, entry0 + total_size, hook_entries, underflows, |
1744 | entry0 + total_size, | 1705 | name); |
1745 | hook_entries, underflows, &j, name); | 1706 | if (ret != 0) |
1746 | if (ret != 0) | 1707 | goto out_unlock; |
1747 | goto out_unlock; | 1708 | ++j; |
1709 | } | ||
1748 | 1710 | ||
1749 | ret = -EINVAL; | 1711 | ret = -EINVAL; |
1750 | if (j != number) { | 1712 | if (j != number) { |
@@ -1783,9 +1745,12 @@ translate_compat_table(struct net *net, | |||
1783 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1745 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
1784 | pos = entry1; | 1746 | pos = entry1; |
1785 | size = total_size; | 1747 | size = total_size; |
1786 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, | 1748 | xt_entry_foreach(iter0, entry0, total_size) { |
1787 | compat_copy_entry_from_user, | 1749 | ret = compat_copy_entry_from_user(iter0, &pos, |
1788 | &pos, &size, name, newinfo, entry1); | 1750 | &size, name, newinfo, entry1); |
1751 | if (ret != 0) | ||
1752 | break; | ||
1753 | } | ||
1789 | xt_compat_flush_offsets(AF_INET); | 1754 | xt_compat_flush_offsets(AF_INET); |
1790 | xt_compat_unlock(AF_INET); | 1755 | xt_compat_unlock(AF_INET); |
1791 | if (ret) | 1756 | if (ret) |
@@ -1796,13 +1761,32 @@ translate_compat_table(struct net *net, | |||
1796 | goto free_newinfo; | 1761 | goto free_newinfo; |
1797 | 1762 | ||
1798 | i = 0; | 1763 | i = 0; |
1799 | ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1764 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1800 | net, name, &i); | 1765 | ret = compat_check_entry(iter1, net, name); |
1766 | if (ret != 0) | ||
1767 | break; | ||
1768 | ++i; | ||
1769 | } | ||
1801 | if (ret) { | 1770 | if (ret) { |
1771 | /* | ||
1772 | * The first i matches need cleanup_entry (calls ->destroy) | ||
1773 | * because they had called ->check already. The other j-i | ||
1774 | * entries need only release. | ||
1775 | */ | ||
1776 | int skip = i; | ||
1802 | j -= i; | 1777 | j -= i; |
1803 | COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1778 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1804 | compat_release_entry, &j); | 1779 | if (skip-- > 0) |
1805 | IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i); | 1780 | continue; |
1781 | if (j-- == 0) | ||
1782 | break; | ||
1783 | compat_release_entry(iter0); | ||
1784 | } | ||
1785 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
1786 | if (i-- == 0) | ||
1787 | break; | ||
1788 | cleanup_entry(iter1, net); | ||
1789 | } | ||
1806 | xt_free_table_info(newinfo); | 1790 | xt_free_table_info(newinfo); |
1807 | return ret; | 1791 | return ret; |
1808 | } | 1792 | } |
@@ -1820,7 +1804,11 @@ translate_compat_table(struct net *net, | |||
1820 | free_newinfo: | 1804 | free_newinfo: |
1821 | xt_free_table_info(newinfo); | 1805 | xt_free_table_info(newinfo); |
1822 | out: | 1806 | out: |
1823 | COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1807 | xt_entry_foreach(iter0, entry0, total_size) { |
1808 | if (j-- == 0) | ||
1809 | break; | ||
1810 | compat_release_entry(iter0); | ||
1811 | } | ||
1824 | return ret; | 1812 | return ret; |
1825 | out_unlock: | 1813 | out_unlock: |
1826 | xt_compat_flush_offsets(AF_INET); | 1814 | xt_compat_flush_offsets(AF_INET); |
@@ -1835,6 +1823,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1835 | struct compat_ipt_replace tmp; | 1823 | struct compat_ipt_replace tmp; |
1836 | struct xt_table_info *newinfo; | 1824 | struct xt_table_info *newinfo; |
1837 | void *loc_cpu_entry; | 1825 | void *loc_cpu_entry; |
1826 | struct ipt_entry *iter; | ||
1838 | 1827 | ||
1839 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1828 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1840 | return -EFAULT; | 1829 | return -EFAULT; |
@@ -1873,7 +1862,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1873 | return 0; | 1862 | return 0; |
1874 | 1863 | ||
1875 | free_newinfo_untrans: | 1864 | free_newinfo_untrans: |
1876 | IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1865 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1866 | cleanup_entry(iter, net); | ||
1877 | free_newinfo: | 1867 | free_newinfo: |
1878 | xt_free_table_info(newinfo); | 1868 | xt_free_table_info(newinfo); |
1879 | return ret; | 1869 | return ret; |
@@ -1922,6 +1912,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1922 | int ret = 0; | 1912 | int ret = 0; |
1923 | const void *loc_cpu_entry; | 1913 | const void *loc_cpu_entry; |
1924 | unsigned int i = 0; | 1914 | unsigned int i = 0; |
1915 | struct ipt_entry *iter; | ||
1925 | 1916 | ||
1926 | counters = alloc_counters(table); | 1917 | counters = alloc_counters(table); |
1927 | if (IS_ERR(counters)) | 1918 | if (IS_ERR(counters)) |
@@ -1934,9 +1925,12 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1934 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1925 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1935 | pos = userptr; | 1926 | pos = userptr; |
1936 | size = total_size; | 1927 | size = total_size; |
1937 | ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1928 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1938 | compat_copy_entry_to_user, | 1929 | ret = compat_copy_entry_to_user(iter, &pos, |
1939 | &pos, &size, counters, &i); | 1930 | &size, counters, i++); |
1931 | if (ret != 0) | ||
1932 | break; | ||
1933 | } | ||
1940 | 1934 | ||
1941 | vfree(counters); | 1935 | vfree(counters); |
1942 | return ret; | 1936 | return ret; |
@@ -2110,11 +2104,7 @@ struct xt_table *ipt_register_table(struct net *net, | |||
2110 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 2104 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
2111 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 2105 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
2112 | 2106 | ||
2113 | ret = translate_table(net, table->name, table->valid_hooks, | 2107 | ret = translate_table(net, newinfo, loc_cpu_entry, repl); |
2114 | newinfo, loc_cpu_entry, repl->size, | ||
2115 | repl->num_entries, | ||
2116 | repl->hook_entry, | ||
2117 | repl->underflow); | ||
2118 | if (ret != 0) | 2108 | if (ret != 0) |
2119 | goto out_free; | 2109 | goto out_free; |
2120 | 2110 | ||
@@ -2137,12 +2127,14 @@ void ipt_unregister_table(struct net *net, struct xt_table *table) | |||
2137 | struct xt_table_info *private; | 2127 | struct xt_table_info *private; |
2138 | void *loc_cpu_entry; | 2128 | void *loc_cpu_entry; |
2139 | struct module *table_owner = table->me; | 2129 | struct module *table_owner = table->me; |
2130 | struct ipt_entry *iter; | ||
2140 | 2131 | ||
2141 | private = xt_unregister_table(table); | 2132 | private = xt_unregister_table(table); |
2142 | 2133 | ||
2143 | /* Decrease module usage counts and free resources */ | 2134 | /* Decrease module usage counts and free resources */ |
2144 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2135 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
2145 | IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL); | 2136 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
2137 | cleanup_entry(iter, net); | ||
2146 | if (private->number > private->initial_entries) | 2138 | if (private->number > private->initial_entries) |
2147 | module_put(table_owner); | 2139 | module_put(table_owner); |
2148 | xt_free_table_info(private); | 2140 | xt_free_table_info(private); |
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 | ||
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 6f21b4377dbb..0e357ac9a2a8 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c | |||
@@ -239,6 +239,7 @@ static bool tcpmss_tg4_check(const struct xt_tgchk_param *par) | |||
239 | { | 239 | { |
240 | const struct xt_tcpmss_info *info = par->targinfo; | 240 | const struct xt_tcpmss_info *info = par->targinfo; |
241 | const struct ipt_entry *e = par->entryinfo; | 241 | const struct ipt_entry *e = par->entryinfo; |
242 | const struct xt_entry_match *ematch; | ||
242 | 243 | ||
243 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && | 244 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && |
244 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | | 245 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | |
@@ -248,8 +249,9 @@ static bool tcpmss_tg4_check(const struct xt_tgchk_param *par) | |||
248 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); | 249 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); |
249 | return false; | 250 | return false; |
250 | } | 251 | } |
251 | if (IPT_MATCH_ITERATE(e, find_syn_match)) | 252 | xt_ematch_foreach(ematch, e) |
252 | return true; | 253 | if (find_syn_match(ematch)) |
254 | return true; | ||
253 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); | 255 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); |
254 | return false; | 256 | return false; |
255 | } | 257 | } |
@@ -259,6 +261,7 @@ static bool tcpmss_tg6_check(const struct xt_tgchk_param *par) | |||
259 | { | 261 | { |
260 | const struct xt_tcpmss_info *info = par->targinfo; | 262 | const struct xt_tcpmss_info *info = par->targinfo; |
261 | const struct ip6t_entry *e = par->entryinfo; | 263 | const struct ip6t_entry *e = par->entryinfo; |
264 | const struct xt_entry_match *ematch; | ||
262 | 265 | ||
263 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && | 266 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && |
264 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | | 267 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | |
@@ -268,8 +271,9 @@ static bool tcpmss_tg6_check(const struct xt_tgchk_param *par) | |||
268 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); | 271 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); |
269 | return false; | 272 | return false; |
270 | } | 273 | } |
271 | if (IP6T_MATCH_ITERATE(e, find_syn_match)) | 274 | xt_ematch_foreach(ematch, e) |
272 | return true; | 275 | if (find_syn_match(ematch)) |
276 | return true; | ||
273 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); | 277 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); |
274 | return false; | 278 | return false; |
275 | } | 279 | } |
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 132cfaa84cdc..7073dbb8100c 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c | |||
@@ -177,10 +177,10 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr, | |||
177 | 177 | ||
178 | static void recent_entry_update(struct recent_table *t, struct recent_entry *e) | 178 | static void recent_entry_update(struct recent_table *t, struct recent_entry *e) |
179 | { | 179 | { |
180 | e->index %= ip_pkt_list_tot; | ||
180 | e->stamps[e->index++] = jiffies; | 181 | e->stamps[e->index++] = jiffies; |
181 | if (e->index > e->nstamps) | 182 | if (e->index > e->nstamps) |
182 | e->nstamps = e->index; | 183 | e->nstamps = e->index; |
183 | e->index %= ip_pkt_list_tot; | ||
184 | list_move_tail(&e->lru_list, &t->lru_list); | 184 | list_move_tail(&e->lru_list, &t->lru_list); |
185 | } | 185 | } |
186 | 186 | ||
@@ -267,7 +267,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |||
267 | for (i = 0; i < e->nstamps; i++) { | 267 | for (i = 0; i < e->nstamps; i++) { |
268 | if (info->seconds && time_after(time, e->stamps[i])) | 268 | if (info->seconds && time_after(time, e->stamps[i])) |
269 | continue; | 269 | continue; |
270 | if (++hits >= info->hit_count) { | 270 | if (info->hit_count && ++hits >= info->hit_count) { |
271 | ret = !ret; | 271 | ret = !ret; |
272 | break; | 272 | break; |
273 | } | 273 | } |