aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-03-24 16:24:36 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-24 16:24:36 -0400
commitb5bb14386eabcb4229ade2bc0a2b237ca166d37d (patch)
tree1966e65479f0d12cec0a204443a95b8eb57946db /net/ipv4
parentbb4f92b3a33bfc31f55098da85be44702bea2d16 (diff)
parent1d45209d89e647e9f27e4afa1f47338df73bc112 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/Kconfig30
-rw-r--r--net/ipv4/netfilter/Makefile2
-rw-r--r--net/ipv4/netfilter/arp_tables.c159
-rw-r--r--net/ipv4/netfilter/arptable_filter.c2
-rw-r--r--net/ipv4/netfilter/ip_queue.c2
-rw-r--r--net/ipv4/netfilter/ip_tables.c153
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c2
-rw-r--r--net/ipv4/netfilter/ipt_TTL.c97
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c2
-rw-r--r--net/ipv4/netfilter/ipt_ttl.c63
-rw-r--r--net/ipv4/netfilter/iptable_filter.c1
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c1
-rw-r--r--net/ipv4/netfilter/iptable_raw.c1
-rw-r--r--net/ipv4/netfilter/iptable_security.c1
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c1
16 files changed, 249 insertions, 272 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 3816e1dc9295..1833bdbf9805 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -31,7 +31,7 @@ config NF_CONNTRACK_PROC_COMPAT
31 default y 31 default y
32 help 32 help
33 This option enables /proc and sysctl compatibility with the old 33 This option enables /proc and sysctl compatibility with the old
34 layer 3 dependant connection tracking. This is needed to keep 34 layer 3 dependent connection tracking. This is needed to keep
35 old programs that have not been adapted to the new names working. 35 old programs that have not been adapted to the new names working.
36 36
37 If unsure, say Y. 37 If unsure, say Y.
@@ -95,11 +95,11 @@ config IP_NF_MATCH_ECN
95config IP_NF_MATCH_TTL 95config IP_NF_MATCH_TTL
96 tristate '"ttl" match support' 96 tristate '"ttl" match support'
97 depends on NETFILTER_ADVANCED 97 depends on NETFILTER_ADVANCED
98 help 98 select NETFILTER_XT_MATCH_HL
99 This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user 99 ---help---
100 to match packets by their TTL value. 100 This is a backwards-compat option for the user's convenience
101 101 (e.g. when running oldconfig). It selects
102 To compile it as a module, choose M here. If unsure, say N. 102 CONFIG_NETFILTER_XT_MATCH_HL.
103 103
104# `filter', generic and specific targets 104# `filter', generic and specific targets
105config IP_NF_FILTER 105config IP_NF_FILTER
@@ -323,19 +323,13 @@ config IP_NF_TARGET_ECN
323 To compile it as a module, choose M here. If unsure, say N. 323 To compile it as a module, choose M here. If unsure, say N.
324 324
325config IP_NF_TARGET_TTL 325config IP_NF_TARGET_TTL
326 tristate 'TTL target support' 326 tristate '"TTL" target support'
327 depends on IP_NF_MANGLE
328 depends on NETFILTER_ADVANCED 327 depends on NETFILTER_ADVANCED
329 help 328 select NETFILTER_XT_TARGET_HL
330 This option adds a `TTL' target, which enables the user to modify 329 ---help---
331 the TTL value of the IP header. 330 This is a backwards-compat option for the user's convenience
332 331 (e.g. when running oldconfig). It selects
333 While it is safe to decrement/lower the TTL, this target also enables 332 CONFIG_NETFILTER_XT_TARGET_HL.
334 functionality to increment and set the TTL value of the IP header to
335 arbitrary values. This is EXTREMELY DANGEROUS since you can easily
336 create immortal packets that loop forever on the network.
337
338 To compile it as a module, choose M here. If unsure, say N.
339 333
340# raw + specific targets 334# raw + specific targets
341config IP_NF_RAW 335config IP_NF_RAW
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 5f9b650d90fc..48111594ee9b 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -51,7 +51,6 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
51obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o 51obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
52obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o 52obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
53obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o 53obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
54obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
55 54
56# targets 55# targets
57obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o 56obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
@@ -61,7 +60,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
61obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o 60obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
62obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o 61obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
63obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o 62obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
64obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
65obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o 63obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
66 64
67# generic ARP tables 65# generic ARP tables
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 7ea88b61cb0d..64a7c6ce0b98 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -73,6 +73,36 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
73 return (ret != 0); 73 return (ret != 0);
74} 74}
75 75
76/*
77 * Unfortunatly, _b and _mask are not aligned to an int (or long int)
78 * Some arches dont care, unrolling the loop is a win on them.
79 */
80static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
81{
82#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
83 const unsigned long *a = (const unsigned long *)_a;
84 const unsigned long *b = (const unsigned long *)_b;
85 const unsigned long *mask = (const unsigned long *)_mask;
86 unsigned long ret;
87
88 ret = (a[0] ^ b[0]) & mask[0];
89 if (IFNAMSIZ > sizeof(unsigned long))
90 ret |= (a[1] ^ b[1]) & mask[1];
91 if (IFNAMSIZ > 2 * sizeof(unsigned long))
92 ret |= (a[2] ^ b[2]) & mask[2];
93 if (IFNAMSIZ > 3 * sizeof(unsigned long))
94 ret |= (a[3] ^ b[3]) & mask[3];
95 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
96#else
97 unsigned long ret = 0;
98 int i;
99
100 for (i = 0; i < IFNAMSIZ; i++)
101 ret |= (_a[i] ^ _b[i]) & _mask[i];
102#endif
103 return ret;
104}
105
76/* Returns whether packet matches rule or not. */ 106/* Returns whether packet matches rule or not. */
77static inline int arp_packet_match(const struct arphdr *arphdr, 107static inline int arp_packet_match(const struct arphdr *arphdr,
78 struct net_device *dev, 108 struct net_device *dev,
@@ -83,7 +113,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
83 const char *arpptr = (char *)(arphdr + 1); 113 const char *arpptr = (char *)(arphdr + 1);
84 const char *src_devaddr, *tgt_devaddr; 114 const char *src_devaddr, *tgt_devaddr;
85 __be32 src_ipaddr, tgt_ipaddr; 115 __be32 src_ipaddr, tgt_ipaddr;
86 int i, ret; 116 long ret;
87 117
88#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) 118#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg)))
89 119
@@ -156,10 +186,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
156 } 186 }
157 187
158 /* Look for ifname matches. */ 188 /* Look for ifname matches. */
159 for (i = 0, ret = 0; i < IFNAMSIZ; i++) { 189 ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
160 ret |= (indev[i] ^ arpinfo->iniface[i])
161 & arpinfo->iniface_mask[i];
162 }
163 190
164 if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { 191 if (FWINV(ret != 0, ARPT_INV_VIA_IN)) {
165 dprintf("VIA in mismatch (%s vs %s).%s\n", 192 dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -168,10 +195,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
168 return 0; 195 return 0;
169 } 196 }
170 197
171 for (i = 0, ret = 0; i < IFNAMSIZ; i++) { 198 ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
172 ret |= (outdev[i] ^ arpinfo->outiface[i])
173 & arpinfo->outiface_mask[i];
174 }
175 199
176 if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) { 200 if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) {
177 dprintf("VIA out mismatch (%s vs %s).%s\n", 201 dprintf("VIA out mismatch (%s vs %s).%s\n",
@@ -221,7 +245,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
221 const struct net_device *out, 245 const struct net_device *out,
222 struct xt_table *table) 246 struct xt_table *table)
223{ 247{
224 static const char nulldevname[IFNAMSIZ]; 248 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
225 unsigned int verdict = NF_DROP; 249 unsigned int verdict = NF_DROP;
226 const struct arphdr *arp; 250 const struct arphdr *arp;
227 bool hotdrop = false; 251 bool hotdrop = false;
@@ -237,9 +261,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
237 indev = in ? in->name : nulldevname; 261 indev = in ? in->name : nulldevname;
238 outdev = out ? out->name : nulldevname; 262 outdev = out ? out->name : nulldevname;
239 263
240 read_lock_bh(&table->lock); 264 rcu_read_lock();
241 private = table->private; 265 private = rcu_dereference(table->private);
242 table_base = (void *)private->entries[smp_processor_id()]; 266 table_base = rcu_dereference(private->entries[smp_processor_id()]);
267
243 e = get_entry(table_base, private->hook_entry[hook]); 268 e = get_entry(table_base, private->hook_entry[hook]);
244 back = get_entry(table_base, private->underflow[hook]); 269 back = get_entry(table_base, private->underflow[hook]);
245 270
@@ -311,7 +336,8 @@ unsigned int arpt_do_table(struct sk_buff *skb,
311 e = (void *)e + e->next_offset; 336 e = (void *)e + e->next_offset;
312 } 337 }
313 } while (!hotdrop); 338 } while (!hotdrop);
314 read_unlock_bh(&table->lock); 339
340 rcu_read_unlock();
315 341
316 if (hotdrop) 342 if (hotdrop)
317 return NF_DROP; 343 return NF_DROP;
@@ -714,11 +740,65 @@ static void get_counters(const struct xt_table_info *t,
714 } 740 }
715} 741}
716 742
717static inline struct xt_counters *alloc_counters(struct xt_table *table) 743
744/* We're lazy, and add to the first CPU; overflow works its fey magic
745 * and everything is OK. */
746static int
747add_counter_to_entry(struct arpt_entry *e,
748 const struct xt_counters addme[],
749 unsigned int *i)
750{
751 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
752
753 (*i)++;
754 return 0;
755}
756
757/* Take values from counters and add them back onto the current cpu */
758static void put_counters(struct xt_table_info *t,
759 const struct xt_counters counters[])
760{
761 unsigned int i, cpu;
762
763 local_bh_disable();
764 cpu = smp_processor_id();
765 i = 0;
766 ARPT_ENTRY_ITERATE(t->entries[cpu],
767 t->size,
768 add_counter_to_entry,
769 counters,
770 &i);
771 local_bh_enable();
772}
773
774static inline int
775zero_entry_counter(struct arpt_entry *e, void *arg)
776{
777 e->counters.bcnt = 0;
778 e->counters.pcnt = 0;
779 return 0;
780}
781
782static void
783clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
784{
785 unsigned int cpu;
786 const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
787
788 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
789 for_each_possible_cpu(cpu) {
790 memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
791 ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
792 zero_entry_counter, NULL);
793 }
794}
795
796static struct xt_counters *alloc_counters(struct xt_table *table)
718{ 797{
719 unsigned int countersize; 798 unsigned int countersize;
720 struct xt_counters *counters; 799 struct xt_counters *counters;
721 const struct xt_table_info *private = table->private; 800 struct xt_table_info *private = table->private;
801 struct xt_table_info *info;
722 802
723 /* We need atomic snapshot of counters: rest doesn't change 803 /* We need atomic snapshot of counters: rest doesn't change
724 * (other than comefrom, which userspace doesn't care 804 * (other than comefrom, which userspace doesn't care
@@ -728,14 +808,30 @@ static inline struct xt_counters *alloc_counters(struct xt_table *table)
728 counters = vmalloc_node(countersize, numa_node_id()); 808 counters = vmalloc_node(countersize, numa_node_id());
729 809
730 if (counters == NULL) 810 if (counters == NULL)
731 return ERR_PTR(-ENOMEM); 811 goto nomem;
812
813 info = xt_alloc_table_info(private->size);
814 if (!info)
815 goto free_counters;
816
817 clone_counters(info, private);
818
819 mutex_lock(&table->lock);
820 xt_table_entry_swap_rcu(private, info);
821 synchronize_net(); /* Wait until smoke has cleared */
822
823 get_counters(info, counters);
824 put_counters(private, counters);
825 mutex_unlock(&table->lock);
732 826
733 /* First, sum counters... */ 827 xt_free_table_info(info);
734 write_lock_bh(&table->lock);
735 get_counters(private, counters);
736 write_unlock_bh(&table->lock);
737 828
738 return counters; 829 return counters;
830
831 free_counters:
832 vfree(counters);
833 nomem:
834 return ERR_PTR(-ENOMEM);
739} 835}
740 836
741static int copy_entries_to_user(unsigned int total_size, 837static int copy_entries_to_user(unsigned int total_size,
@@ -1075,20 +1171,6 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
1075 return ret; 1171 return ret;
1076} 1172}
1077 1173
1078/* We're lazy, and add to the first CPU; overflow works its fey magic
1079 * and everything is OK.
1080 */
1081static inline int add_counter_to_entry(struct arpt_entry *e,
1082 const struct xt_counters addme[],
1083 unsigned int *i)
1084{
1085
1086 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1087
1088 (*i)++;
1089 return 0;
1090}
1091
1092static int do_add_counters(struct net *net, void __user *user, unsigned int len, 1174static int do_add_counters(struct net *net, void __user *user, unsigned int len,
1093 int compat) 1175 int compat)
1094{ 1176{
@@ -1148,13 +1230,14 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
1148 goto free; 1230 goto free;
1149 } 1231 }
1150 1232
1151 write_lock_bh(&t->lock); 1233 mutex_lock(&t->lock);
1152 private = t->private; 1234 private = t->private;
1153 if (private->number != num_counters) { 1235 if (private->number != num_counters) {
1154 ret = -EINVAL; 1236 ret = -EINVAL;
1155 goto unlock_up_free; 1237 goto unlock_up_free;
1156 } 1238 }
1157 1239
1240 preempt_disable();
1158 i = 0; 1241 i = 0;
1159 /* Choose the copy that is on our node */ 1242 /* Choose the copy that is on our node */
1160 loc_cpu_entry = private->entries[smp_processor_id()]; 1243 loc_cpu_entry = private->entries[smp_processor_id()];
@@ -1163,8 +1246,10 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
1163 add_counter_to_entry, 1246 add_counter_to_entry,
1164 paddc, 1247 paddc,
1165 &i); 1248 &i);
1249 preempt_enable();
1166 unlock_up_free: 1250 unlock_up_free:
1167 write_unlock_bh(&t->lock); 1251 mutex_unlock(&t->lock);
1252
1168 xt_table_unlock(t); 1253 xt_table_unlock(t);
1169 module_put(t->me); 1254 module_put(t->me);
1170 free: 1255 free:
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index e091187e864f..6ecfdae7c589 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -48,8 +48,6 @@ static struct
48static struct xt_table packet_filter = { 48static struct xt_table packet_filter = {
49 .name = "filter", 49 .name = "filter",
50 .valid_hooks = FILTER_VALID_HOOKS, 50 .valid_hooks = FILTER_VALID_HOOKS,
51 .lock = __RW_LOCK_UNLOCKED(packet_filter.lock),
52 .private = NULL,
53 .me = THIS_MODULE, 51 .me = THIS_MODULE,
54 .af = NFPROTO_ARP, 52 .af = NFPROTO_ARP,
55}; 53};
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 432ce9d1c11c..5f22c91c6e15 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -24,6 +24,7 @@
24#include <linux/proc_fs.h> 24#include <linux/proc_fs.h>
25#include <linux/seq_file.h> 25#include <linux/seq_file.h>
26#include <linux/security.h> 26#include <linux/security.h>
27#include <linux/net.h>
27#include <linux/mutex.h> 28#include <linux/mutex.h>
28#include <net/net_namespace.h> 29#include <net/net_namespace.h>
29#include <net/sock.h> 30#include <net/sock.h>
@@ -640,6 +641,7 @@ static void __exit ip_queue_fini(void)
640MODULE_DESCRIPTION("IPv4 packet queue handler"); 641MODULE_DESCRIPTION("IPv4 packet queue handler");
641MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); 642MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
642MODULE_LICENSE("GPL"); 643MODULE_LICENSE("GPL");
644MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_FIREWALL);
643 645
644module_init(ip_queue_init); 646module_init(ip_queue_init);
645module_exit(ip_queue_fini); 647module_exit(ip_queue_fini);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index ef8b6ca068b2..e5294aec967d 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -74,6 +74,25 @@ do { \
74 74
75 Hence the start of any table is given by get_table() below. */ 75 Hence the start of any table is given by get_table() below. */
76 76
77static unsigned long ifname_compare(const char *_a, const char *_b,
78 const unsigned char *_mask)
79{
80 const unsigned long *a = (const unsigned long *)_a;
81 const unsigned long *b = (const unsigned long *)_b;
82 const unsigned long *mask = (const unsigned long *)_mask;
83 unsigned long ret;
84
85 ret = (a[0] ^ b[0]) & mask[0];
86 if (IFNAMSIZ > sizeof(unsigned long))
87 ret |= (a[1] ^ b[1]) & mask[1];
88 if (IFNAMSIZ > 2 * sizeof(unsigned long))
89 ret |= (a[2] ^ b[2]) & mask[2];
90 if (IFNAMSIZ > 3 * sizeof(unsigned long))
91 ret |= (a[3] ^ b[3]) & mask[3];
92 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
93 return ret;
94}
95
77/* Returns whether matches rule or not. */ 96/* Returns whether matches rule or not. */
78/* Performance critical - called for every packet */ 97/* Performance critical - called for every packet */
79static inline bool 98static inline bool
@@ -83,7 +102,6 @@ ip_packet_match(const struct iphdr *ip,
83 const struct ipt_ip *ipinfo, 102 const struct ipt_ip *ipinfo,
84 int isfrag) 103 int isfrag)
85{ 104{
86 size_t i;
87 unsigned long ret; 105 unsigned long ret;
88 106
89#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) 107#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
@@ -103,12 +121,7 @@ ip_packet_match(const struct iphdr *ip,
103 return false; 121 return false;
104 } 122 }
105 123
106 /* Look for ifname matches; this should unroll nicely. */ 124 ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask);
107 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
108 ret |= (((const unsigned long *)indev)[i]
109 ^ ((const unsigned long *)ipinfo->iniface)[i])
110 & ((const unsigned long *)ipinfo->iniface_mask)[i];
111 }
112 125
113 if (FWINV(ret != 0, IPT_INV_VIA_IN)) { 126 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
114 dprintf("VIA in mismatch (%s vs %s).%s\n", 127 dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -117,11 +130,7 @@ ip_packet_match(const struct iphdr *ip,
117 return false; 130 return false;
118 } 131 }
119 132
120 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { 133 ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask);
121 ret |= (((const unsigned long *)outdev)[i]
122 ^ ((const unsigned long *)ipinfo->outiface)[i])
123 & ((const unsigned long *)ipinfo->outiface_mask)[i];
124 }
125 134
126 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { 135 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
127 dprintf("VIA out mismatch (%s vs %s).%s\n", 136 dprintf("VIA out mismatch (%s vs %s).%s\n",
@@ -347,10 +356,12 @@ ipt_do_table(struct sk_buff *skb,
347 mtpar.family = tgpar.family = NFPROTO_IPV4; 356 mtpar.family = tgpar.family = NFPROTO_IPV4;
348 tgpar.hooknum = hook; 357 tgpar.hooknum = hook;
349 358
350 read_lock_bh(&table->lock);
351 IP_NF_ASSERT(table->valid_hooks & (1 << hook)); 359 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
352 private = table->private; 360
353 table_base = (void *)private->entries[smp_processor_id()]; 361 rcu_read_lock();
362 private = rcu_dereference(table->private);
363 table_base = rcu_dereference(private->entries[smp_processor_id()]);
364
354 e = get_entry(table_base, private->hook_entry[hook]); 365 e = get_entry(table_base, private->hook_entry[hook]);
355 366
356 /* For return from builtin chain */ 367 /* For return from builtin chain */
@@ -445,7 +456,7 @@ ipt_do_table(struct sk_buff *skb,
445 } 456 }
446 } while (!hotdrop); 457 } while (!hotdrop);
447 458
448 read_unlock_bh(&table->lock); 459 rcu_read_unlock();
449 460
450#ifdef DEBUG_ALLOW_ALL 461#ifdef DEBUG_ALLOW_ALL
451 return NF_ACCEPT; 462 return NF_ACCEPT;
@@ -924,13 +935,68 @@ get_counters(const struct xt_table_info *t,
924 counters, 935 counters,
925 &i); 936 &i);
926 } 937 }
938
939}
940
941/* We're lazy, and add to the first CPU; overflow works its fey magic
942 * and everything is OK. */
943static int
944add_counter_to_entry(struct ipt_entry *e,
945 const struct xt_counters addme[],
946 unsigned int *i)
947{
948 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
949
950 (*i)++;
951 return 0;
952}
953
954/* Take values from counters and add them back onto the current cpu */
955static void put_counters(struct xt_table_info *t,
956 const struct xt_counters counters[])
957{
958 unsigned int i, cpu;
959
960 local_bh_disable();
961 cpu = smp_processor_id();
962 i = 0;
963 IPT_ENTRY_ITERATE(t->entries[cpu],
964 t->size,
965 add_counter_to_entry,
966 counters,
967 &i);
968 local_bh_enable();
969}
970
971
972static inline int
973zero_entry_counter(struct ipt_entry *e, void *arg)
974{
975 e->counters.bcnt = 0;
976 e->counters.pcnt = 0;
977 return 0;
978}
979
980static void
981clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
982{
983 unsigned int cpu;
984 const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
985
986 memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
987 for_each_possible_cpu(cpu) {
988 memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
989 IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
990 zero_entry_counter, NULL);
991 }
927} 992}
928 993
929static struct xt_counters * alloc_counters(struct xt_table *table) 994static struct xt_counters * alloc_counters(struct xt_table *table)
930{ 995{
931 unsigned int countersize; 996 unsigned int countersize;
932 struct xt_counters *counters; 997 struct xt_counters *counters;
933 const struct xt_table_info *private = table->private; 998 struct xt_table_info *private = table->private;
999 struct xt_table_info *info;
934 1000
935 /* We need atomic snapshot of counters: rest doesn't change 1001 /* We need atomic snapshot of counters: rest doesn't change
936 (other than comefrom, which userspace doesn't care 1002 (other than comefrom, which userspace doesn't care
@@ -939,14 +1005,30 @@ static struct xt_counters * alloc_counters(struct xt_table *table)
939 counters = vmalloc_node(countersize, numa_node_id()); 1005 counters = vmalloc_node(countersize, numa_node_id());
940 1006
941 if (counters == NULL) 1007 if (counters == NULL)
942 return ERR_PTR(-ENOMEM); 1008 goto nomem;
1009
1010 info = xt_alloc_table_info(private->size);
1011 if (!info)
1012 goto free_counters;
943 1013
944 /* First, sum counters... */ 1014 clone_counters(info, private);
945 write_lock_bh(&table->lock); 1015
946 get_counters(private, counters); 1016 mutex_lock(&table->lock);
947 write_unlock_bh(&table->lock); 1017 xt_table_entry_swap_rcu(private, info);
1018 synchronize_net(); /* Wait until smoke has cleared */
1019
1020 get_counters(info, counters);
1021 put_counters(private, counters);
1022 mutex_unlock(&table->lock);
1023
1024 xt_free_table_info(info);
948 1025
949 return counters; 1026 return counters;
1027
1028 free_counters:
1029 vfree(counters);
1030 nomem:
1031 return ERR_PTR(-ENOMEM);
950} 1032}
951 1033
952static int 1034static int
@@ -1312,27 +1394,6 @@ do_replace(struct net *net, void __user *user, unsigned int len)
1312 return ret; 1394 return ret;
1313} 1395}
1314 1396
1315/* We're lazy, and add to the first CPU; overflow works its fey magic
1316 * and everything is OK. */
1317static int
1318add_counter_to_entry(struct ipt_entry *e,
1319 const struct xt_counters addme[],
1320 unsigned int *i)
1321{
1322#if 0
1323 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1324 *i,
1325 (long unsigned int)e->counters.pcnt,
1326 (long unsigned int)e->counters.bcnt,
1327 (long unsigned int)addme[*i].pcnt,
1328 (long unsigned int)addme[*i].bcnt);
1329#endif
1330
1331 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1332
1333 (*i)++;
1334 return 0;
1335}
1336 1397
1337static int 1398static int
1338do_add_counters(struct net *net, void __user *user, unsigned int len, int compat) 1399do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
@@ -1393,13 +1454,14 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat
1393 goto free; 1454 goto free;
1394 } 1455 }
1395 1456
1396 write_lock_bh(&t->lock); 1457 mutex_lock(&t->lock);
1397 private = t->private; 1458 private = t->private;
1398 if (private->number != num_counters) { 1459 if (private->number != num_counters) {
1399 ret = -EINVAL; 1460 ret = -EINVAL;
1400 goto unlock_up_free; 1461 goto unlock_up_free;
1401 } 1462 }
1402 1463
1464 preempt_disable();
1403 i = 0; 1465 i = 0;
1404 /* Choose the copy that is on our node */ 1466 /* Choose the copy that is on our node */
1405 loc_cpu_entry = private->entries[raw_smp_processor_id()]; 1467 loc_cpu_entry = private->entries[raw_smp_processor_id()];
@@ -1408,8 +1470,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat
1408 add_counter_to_entry, 1470 add_counter_to_entry,
1409 paddc, 1471 paddc,
1410 &i); 1472 &i);
1473 preempt_enable();
1411 unlock_up_free: 1474 unlock_up_free:
1412 write_unlock_bh(&t->lock); 1475 mutex_unlock(&t->lock);
1413 xt_table_unlock(t); 1476 xt_table_unlock(t);
1414 module_put(t->me); 1477 module_put(t->me);
1415 free: 1478 free:
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 27a78fbbd92b..acc44c69eb68 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -464,7 +464,7 @@ static struct xt_target log_tg_reg __read_mostly = {
464 .me = THIS_MODULE, 464 .me = THIS_MODULE,
465}; 465};
466 466
467static const struct nf_logger ipt_log_logger ={ 467static struct nf_logger ipt_log_logger __read_mostly = {
468 .name = "ipt_LOG", 468 .name = "ipt_LOG",
469 .logfn = &ipt_log_packet, 469 .logfn = &ipt_log_packet,
470 .me = THIS_MODULE, 470 .me = THIS_MODULE,
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
deleted file mode 100644
index 6d76aae90cc0..000000000000
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ /dev/null
@@ -1,97 +0,0 @@
1/* TTL modification target for IP tables
2 * (C) 2000,2005 by Harald Welte <laforge@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/module.h>
11#include <linux/skbuff.h>
12#include <linux/ip.h>
13#include <net/checksum.h>
14
15#include <linux/netfilter/x_tables.h>
16#include <linux/netfilter_ipv4/ipt_TTL.h>
17
18MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
19MODULE_DESCRIPTION("Xtables: IPv4 TTL field modification target");
20MODULE_LICENSE("GPL");
21
22static unsigned int
23ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
24{
25 struct iphdr *iph;
26 const struct ipt_TTL_info *info = par->targinfo;
27 int new_ttl;
28
29 if (!skb_make_writable(skb, skb->len))
30 return NF_DROP;
31
32 iph = ip_hdr(skb);
33
34 switch (info->mode) {
35 case IPT_TTL_SET:
36 new_ttl = info->ttl;
37 break;
38 case IPT_TTL_INC:
39 new_ttl = iph->ttl + info->ttl;
40 if (new_ttl > 255)
41 new_ttl = 255;
42 break;
43 case IPT_TTL_DEC:
44 new_ttl = iph->ttl - info->ttl;
45 if (new_ttl < 0)
46 new_ttl = 0;
47 break;
48 default:
49 new_ttl = iph->ttl;
50 break;
51 }
52
53 if (new_ttl != iph->ttl) {
54 csum_replace2(&iph->check, htons(iph->ttl << 8),
55 htons(new_ttl << 8));
56 iph->ttl = new_ttl;
57 }
58
59 return XT_CONTINUE;
60}
61
62static bool ttl_tg_check(const struct xt_tgchk_param *par)
63{
64 const struct ipt_TTL_info *info = par->targinfo;
65
66 if (info->mode > IPT_TTL_MAXMODE) {
67 printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
68 info->mode);
69 return false;
70 }
71 if (info->mode != IPT_TTL_SET && info->ttl == 0)
72 return false;
73 return true;
74}
75
76static struct xt_target ttl_tg_reg __read_mostly = {
77 .name = "TTL",
78 .family = NFPROTO_IPV4,
79 .target = ttl_tg,
80 .targetsize = sizeof(struct ipt_TTL_info),
81 .table = "mangle",
82 .checkentry = ttl_tg_check,
83 .me = THIS_MODULE,
84};
85
86static int __init ttl_tg_init(void)
87{
88 return xt_register_target(&ttl_tg_reg);
89}
90
91static void __exit ttl_tg_exit(void)
92{
93 xt_unregister_target(&ttl_tg_reg);
94}
95
96module_init(ttl_tg_init);
97module_exit(ttl_tg_exit);
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 18a2826b57c6..d32cc4bb328a 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -379,7 +379,7 @@ static struct xt_target ulog_tg_reg __read_mostly = {
379 .me = THIS_MODULE, 379 .me = THIS_MODULE,
380}; 380};
381 381
382static struct nf_logger ipt_ulog_logger = { 382static struct nf_logger ipt_ulog_logger __read_mostly = {
383 .name = "ipt_ULOG", 383 .name = "ipt_ULOG",
384 .logfn = ipt_logfn, 384 .logfn = ipt_logfn,
385 .me = THIS_MODULE, 385 .me = THIS_MODULE,
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
deleted file mode 100644
index 297f1cbf4ff5..000000000000
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ /dev/null
@@ -1,63 +0,0 @@
1/* IP tables module for matching the value of the TTL
2 *
3 * (C) 2000,2001 by Harald Welte <laforge@netfilter.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/ip.h>
11#include <linux/module.h>
12#include <linux/skbuff.h>
13
14#include <linux/netfilter_ipv4/ipt_ttl.h>
15#include <linux/netfilter/x_tables.h>
16
17MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
18MODULE_DESCRIPTION("Xtables: IPv4 TTL field match");
19MODULE_LICENSE("GPL");
20
21static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
22{
23 const struct ipt_ttl_info *info = par->matchinfo;
24 const u8 ttl = ip_hdr(skb)->ttl;
25
26 switch (info->mode) {
27 case IPT_TTL_EQ:
28 return ttl == info->ttl;
29 case IPT_TTL_NE:
30 return ttl != info->ttl;
31 case IPT_TTL_LT:
32 return ttl < info->ttl;
33 case IPT_TTL_GT:
34 return ttl > info->ttl;
35 default:
36 printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
37 info->mode);
38 return false;
39 }
40
41 return false;
42}
43
44static struct xt_match ttl_mt_reg __read_mostly = {
45 .name = "ttl",
46 .family = NFPROTO_IPV4,
47 .match = ttl_mt,
48 .matchsize = sizeof(struct ipt_ttl_info),
49 .me = THIS_MODULE,
50};
51
52static int __init ttl_mt_init(void)
53{
54 return xt_register_match(&ttl_mt_reg);
55}
56
57static void __exit ttl_mt_exit(void)
58{
59 xt_unregister_match(&ttl_mt_reg);
60}
61
62module_init(ttl_mt_init);
63module_exit(ttl_mt_exit);
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 52cb6939d093..c30a969724f8 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -56,7 +56,6 @@ static struct
56static struct xt_table packet_filter = { 56static struct xt_table packet_filter = {
57 .name = "filter", 57 .name = "filter",
58 .valid_hooks = FILTER_VALID_HOOKS, 58 .valid_hooks = FILTER_VALID_HOOKS,
59 .lock = __RW_LOCK_UNLOCKED(packet_filter.lock),
60 .me = THIS_MODULE, 59 .me = THIS_MODULE,
61 .af = AF_INET, 60 .af = AF_INET,
62}; 61};
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 3929d20b9e45..4087614d9519 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -67,7 +67,6 @@ static struct
67static struct xt_table packet_mangler = { 67static struct xt_table packet_mangler = {
68 .name = "mangle", 68 .name = "mangle",
69 .valid_hooks = MANGLE_VALID_HOOKS, 69 .valid_hooks = MANGLE_VALID_HOOKS,
70 .lock = __RW_LOCK_UNLOCKED(packet_mangler.lock),
71 .me = THIS_MODULE, 70 .me = THIS_MODULE,
72 .af = AF_INET, 71 .af = AF_INET,
73}; 72};
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 7f65d18333e3..e5356da1fb54 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -39,7 +39,6 @@ static struct
39static struct xt_table packet_raw = { 39static struct xt_table packet_raw = {
40 .name = "raw", 40 .name = "raw",
41 .valid_hooks = RAW_VALID_HOOKS, 41 .valid_hooks = RAW_VALID_HOOKS,
42 .lock = __RW_LOCK_UNLOCKED(packet_raw.lock),
43 .me = THIS_MODULE, 42 .me = THIS_MODULE,
44 .af = AF_INET, 43 .af = AF_INET,
45}; 44};
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index a52a35f4a584..29ab630f240a 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -60,7 +60,6 @@ static struct
60static struct xt_table security_table = { 60static struct xt_table security_table = {
61 .name = "security", 61 .name = "security",
62 .valid_hooks = SECURITY_VALID_HOOKS, 62 .valid_hooks = SECURITY_VALID_HOOKS,
63 .lock = __RW_LOCK_UNLOCKED(security_table.lock),
64 .me = THIS_MODULE, 63 .me = THIS_MODULE,
65 .af = AF_INET, 64 .af = AF_INET,
66}; 65};
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 4beb04fac588..8b681f24e271 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -120,8 +120,10 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
120 typeof(nf_nat_seq_adjust_hook) seq_adjust; 120 typeof(nf_nat_seq_adjust_hook) seq_adjust;
121 121
122 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); 122 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
123 if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) 123 if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) {
124 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
124 return NF_DROP; 125 return NF_DROP;
126 }
125 } 127 }
126out: 128out:
127 /* We've seen it coming out the other side: confirm it */ 129 /* We've seen it coming out the other side: confirm it */
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index a7eb04719044..6348a793936e 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -61,7 +61,6 @@ static struct
61static struct xt_table nat_table = { 61static struct xt_table nat_table = {
62 .name = "nat", 62 .name = "nat",
63 .valid_hooks = NAT_VALID_HOOKS, 63 .valid_hooks = NAT_VALID_HOOKS,
64 .lock = __RW_LOCK_UNLOCKED(nat_table.lock),
65 .me = THIS_MODULE, 64 .me = THIS_MODULE,
66 .af = AF_INET, 65 .af = AF_INET,
67}; 66};