diff options
author | David S. Miller <davem@davemloft.net> | 2010-06-15 16:49:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-15 16:49:24 -0400 |
commit | 16fb62b6b4d57339a0ec931b3fb8c8d0ca6414e8 (patch) | |
tree | a1041342f31a626baf3a08d09d5c81a65dd8ef28 /net/netfilter | |
parent | a3433f35a55f7604742cae620c6dc6edfc70db6a (diff) | |
parent | f9181f4ffc71d7b7dd1906c9a11d51d6659220ae (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/Kconfig | 12 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 40 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 2 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 67 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 33 | ||||
-rw-r--r-- | net/netfilter/xt_CT.c | 4 | ||||
-rw-r--r-- | net/netfilter/xt_IDLETIMER.c | 314 | ||||
-rw-r--r-- | net/netfilter/xt_NOTRACK.c | 2 | ||||
-rw-r--r-- | net/netfilter/xt_TEE.c | 4 | ||||
-rw-r--r-- | net/netfilter/xt_cluster.c | 2 | ||||
-rw-r--r-- | net/netfilter/xt_conntrack.c | 11 | ||||
-rw-r--r-- | net/netfilter/xt_sctp.c | 3 | ||||
-rw-r--r-- | net/netfilter/xt_socket.c | 2 | ||||
-rw-r--r-- | net/netfilter/xt_state.c | 14 | ||||
-rw-r--r-- | net/netfilter/xt_statistic.c | 19 |
16 files changed, 444 insertions, 86 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 8593a77cfea..413ed24a968 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -424,6 +424,18 @@ config NETFILTER_XT_TARGET_HL | |||
424 | since you can easily create immortal packets that loop | 424 | since you can easily create immortal packets that loop |
425 | forever on the network. | 425 | forever on the network. |
426 | 426 | ||
427 | config NETFILTER_XT_TARGET_IDLETIMER | ||
428 | tristate "IDLETIMER target support" | ||
429 | depends on NETFILTER_ADVANCED | ||
430 | help | ||
431 | |||
432 | This option adds the `IDLETIMER' target. Each matching packet | ||
433 | resets the timer associated with label specified when the rule is | ||
434 | added. When the timer expires, it triggers a sysfs notification. | ||
435 | The remaining time for expiration can be read via sysfs. | ||
436 | |||
437 | To compile it as a module, choose M here. If unsure, say N. | ||
438 | |||
427 | config NETFILTER_XT_TARGET_LED | 439 | config NETFILTER_XT_TARGET_LED |
428 | tristate '"LED" target support' | 440 | tristate '"LED" target support' |
429 | depends on LEDS_CLASS && LEDS_TRIGGERS | 441 | depends on LEDS_CLASS && LEDS_TRIGGERS |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 14e3a8fd818..e28420aac5e 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -61,6 +61,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o | |||
61 | obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o | 61 | obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o |
62 | obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o | 62 | obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o |
63 | obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o | 63 | obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o |
64 | obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o | ||
64 | 65 | ||
65 | # matches | 66 | # matches |
66 | obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o | 67 | obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 77288980fae..16b41b4e2a3 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -62,8 +62,8 @@ EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); | |||
62 | unsigned int nf_conntrack_max __read_mostly; | 62 | unsigned int nf_conntrack_max __read_mostly; |
63 | EXPORT_SYMBOL_GPL(nf_conntrack_max); | 63 | EXPORT_SYMBOL_GPL(nf_conntrack_max); |
64 | 64 | ||
65 | struct nf_conn nf_conntrack_untracked __read_mostly; | 65 | DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked); |
66 | EXPORT_SYMBOL_GPL(nf_conntrack_untracked); | 66 | EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked); |
67 | 67 | ||
68 | static int nf_conntrack_hash_rnd_initted; | 68 | static int nf_conntrack_hash_rnd_initted; |
69 | static unsigned int nf_conntrack_hash_rnd; | 69 | static unsigned int nf_conntrack_hash_rnd; |
@@ -1181,10 +1181,21 @@ static void nf_ct_release_dying_list(struct net *net) | |||
1181 | spin_unlock_bh(&nf_conntrack_lock); | 1181 | spin_unlock_bh(&nf_conntrack_lock); |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | static int untrack_refs(void) | ||
1185 | { | ||
1186 | int cnt = 0, cpu; | ||
1187 | |||
1188 | for_each_possible_cpu(cpu) { | ||
1189 | struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu); | ||
1190 | |||
1191 | cnt += atomic_read(&ct->ct_general.use) - 1; | ||
1192 | } | ||
1193 | return cnt; | ||
1194 | } | ||
1195 | |||
1184 | static void nf_conntrack_cleanup_init_net(void) | 1196 | static void nf_conntrack_cleanup_init_net(void) |
1185 | { | 1197 | { |
1186 | /* wait until all references to nf_conntrack_untracked are dropped */ | 1198 | while (untrack_refs() > 0) |
1187 | while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1) | ||
1188 | schedule(); | 1199 | schedule(); |
1189 | 1200 | ||
1190 | nf_conntrack_helper_fini(); | 1201 | nf_conntrack_helper_fini(); |
@@ -1319,10 +1330,19 @@ EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize); | |||
1319 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, | 1330 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, |
1320 | &nf_conntrack_htable_size, 0600); | 1331 | &nf_conntrack_htable_size, 0600); |
1321 | 1332 | ||
1333 | void nf_ct_untracked_status_or(unsigned long bits) | ||
1334 | { | ||
1335 | int cpu; | ||
1336 | |||
1337 | for_each_possible_cpu(cpu) | ||
1338 | per_cpu(nf_conntrack_untracked, cpu).status |= bits; | ||
1339 | } | ||
1340 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); | ||
1341 | |||
1322 | static int nf_conntrack_init_init_net(void) | 1342 | static int nf_conntrack_init_init_net(void) |
1323 | { | 1343 | { |
1324 | int max_factor = 8; | 1344 | int max_factor = 8; |
1325 | int ret; | 1345 | int ret, cpu; |
1326 | 1346 | ||
1327 | /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB | 1347 | /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB |
1328 | * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ | 1348 | * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ |
@@ -1361,11 +1381,13 @@ static int nf_conntrack_init_init_net(void) | |||
1361 | goto err_extend; | 1381 | goto err_extend; |
1362 | #endif | 1382 | #endif |
1363 | /* Set up fake conntrack: to never be deleted, not in any hashes */ | 1383 | /* Set up fake conntrack: to never be deleted, not in any hashes */ |
1364 | write_pnet(&nf_conntrack_untracked.ct_net, &init_net); | 1384 | for_each_possible_cpu(cpu) { |
1365 | atomic_set(&nf_conntrack_untracked.ct_general.use, 1); | 1385 | struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu); |
1386 | write_pnet(&ct->ct_net, &init_net); | ||
1387 | atomic_set(&ct->ct_general.use, 1); | ||
1388 | } | ||
1366 | /* - and look it like as a confirmed connection */ | 1389 | /* - and look it like as a confirmed connection */ |
1367 | set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); | 1390 | nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED); |
1368 | |||
1369 | return 0; | 1391 | return 0; |
1370 | 1392 | ||
1371 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 1393 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index c42ff6aa441..5bae1cd15ee 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -480,7 +480,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) | |||
480 | int err; | 480 | int err; |
481 | 481 | ||
482 | /* ignore our fake conntrack entry */ | 482 | /* ignore our fake conntrack entry */ |
483 | if (ct == &nf_conntrack_untracked) | 483 | if (nf_ct_is_untracked(ct)) |
484 | return 0; | 484 | return 0; |
485 | 485 | ||
486 | if (events & (1 << IPCT_DESTROY)) { | 486 | if (events & (1 << IPCT_DESTROY)) { |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index e0504e90a0f..6a1572b0ab4 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -66,9 +66,10 @@ struct nfulnl_instance { | |||
66 | u_int16_t group_num; /* number of this queue */ | 66 | u_int16_t group_num; /* number of this queue */ |
67 | u_int16_t flags; | 67 | u_int16_t flags; |
68 | u_int8_t copy_mode; | 68 | u_int8_t copy_mode; |
69 | struct rcu_head rcu; | ||
69 | }; | 70 | }; |
70 | 71 | ||
71 | static DEFINE_RWLOCK(instances_lock); | 72 | static DEFINE_SPINLOCK(instances_lock); |
72 | static atomic_t global_seq; | 73 | static atomic_t global_seq; |
73 | 74 | ||
74 | #define INSTANCE_BUCKETS 16 | 75 | #define INSTANCE_BUCKETS 16 |
@@ -88,7 +89,7 @@ __instance_lookup(u_int16_t group_num) | |||
88 | struct nfulnl_instance *inst; | 89 | struct nfulnl_instance *inst; |
89 | 90 | ||
90 | head = &instance_table[instance_hashfn(group_num)]; | 91 | head = &instance_table[instance_hashfn(group_num)]; |
91 | hlist_for_each_entry(inst, pos, head, hlist) { | 92 | hlist_for_each_entry_rcu(inst, pos, head, hlist) { |
92 | if (inst->group_num == group_num) | 93 | if (inst->group_num == group_num) |
93 | return inst; | 94 | return inst; |
94 | } | 95 | } |
@@ -106,22 +107,26 @@ instance_lookup_get(u_int16_t group_num) | |||
106 | { | 107 | { |
107 | struct nfulnl_instance *inst; | 108 | struct nfulnl_instance *inst; |
108 | 109 | ||
109 | read_lock_bh(&instances_lock); | 110 | rcu_read_lock_bh(); |
110 | inst = __instance_lookup(group_num); | 111 | inst = __instance_lookup(group_num); |
111 | if (inst) | 112 | if (inst && !atomic_inc_not_zero(&inst->use)) |
112 | instance_get(inst); | 113 | inst = NULL; |
113 | read_unlock_bh(&instances_lock); | 114 | rcu_read_unlock_bh(); |
114 | 115 | ||
115 | return inst; | 116 | return inst; |
116 | } | 117 | } |
117 | 118 | ||
119 | static void nfulnl_instance_free_rcu(struct rcu_head *head) | ||
120 | { | ||
121 | kfree(container_of(head, struct nfulnl_instance, rcu)); | ||
122 | module_put(THIS_MODULE); | ||
123 | } | ||
124 | |||
118 | static void | 125 | static void |
119 | instance_put(struct nfulnl_instance *inst) | 126 | instance_put(struct nfulnl_instance *inst) |
120 | { | 127 | { |
121 | if (inst && atomic_dec_and_test(&inst->use)) { | 128 | if (inst && atomic_dec_and_test(&inst->use)) |
122 | kfree(inst); | 129 | call_rcu_bh(&inst->rcu, nfulnl_instance_free_rcu); |
123 | module_put(THIS_MODULE); | ||
124 | } | ||
125 | } | 130 | } |
126 | 131 | ||
127 | static void nfulnl_timer(unsigned long data); | 132 | static void nfulnl_timer(unsigned long data); |
@@ -132,7 +137,7 @@ instance_create(u_int16_t group_num, int pid) | |||
132 | struct nfulnl_instance *inst; | 137 | struct nfulnl_instance *inst; |
133 | int err; | 138 | int err; |
134 | 139 | ||
135 | write_lock_bh(&instances_lock); | 140 | spin_lock_bh(&instances_lock); |
136 | if (__instance_lookup(group_num)) { | 141 | if (__instance_lookup(group_num)) { |
137 | err = -EEXIST; | 142 | err = -EEXIST; |
138 | goto out_unlock; | 143 | goto out_unlock; |
@@ -166,32 +171,37 @@ instance_create(u_int16_t group_num, int pid) | |||
166 | inst->copy_mode = NFULNL_COPY_PACKET; | 171 | inst->copy_mode = NFULNL_COPY_PACKET; |
167 | inst->copy_range = NFULNL_COPY_RANGE_MAX; | 172 | inst->copy_range = NFULNL_COPY_RANGE_MAX; |
168 | 173 | ||
169 | hlist_add_head(&inst->hlist, | 174 | hlist_add_head_rcu(&inst->hlist, |
170 | &instance_table[instance_hashfn(group_num)]); | 175 | &instance_table[instance_hashfn(group_num)]); |
171 | 176 | ||
172 | write_unlock_bh(&instances_lock); | 177 | spin_unlock_bh(&instances_lock); |
173 | 178 | ||
174 | return inst; | 179 | return inst; |
175 | 180 | ||
176 | out_unlock: | 181 | out_unlock: |
177 | write_unlock_bh(&instances_lock); | 182 | spin_unlock_bh(&instances_lock); |
178 | return ERR_PTR(err); | 183 | return ERR_PTR(err); |
179 | } | 184 | } |
180 | 185 | ||
181 | static void __nfulnl_flush(struct nfulnl_instance *inst); | 186 | static void __nfulnl_flush(struct nfulnl_instance *inst); |
182 | 187 | ||
188 | /* called with BH disabled */ | ||
183 | static void | 189 | static void |
184 | __instance_destroy(struct nfulnl_instance *inst) | 190 | __instance_destroy(struct nfulnl_instance *inst) |
185 | { | 191 | { |
186 | /* first pull it out of the global list */ | 192 | /* first pull it out of the global list */ |
187 | hlist_del(&inst->hlist); | 193 | hlist_del_rcu(&inst->hlist); |
188 | 194 | ||
189 | /* then flush all pending packets from skb */ | 195 | /* then flush all pending packets from skb */ |
190 | 196 | ||
191 | spin_lock_bh(&inst->lock); | 197 | spin_lock(&inst->lock); |
198 | |||
199 | /* lockless readers wont be able to use us */ | ||
200 | inst->copy_mode = NFULNL_COPY_DISABLED; | ||
201 | |||
192 | if (inst->skb) | 202 | if (inst->skb) |
193 | __nfulnl_flush(inst); | 203 | __nfulnl_flush(inst); |
194 | spin_unlock_bh(&inst->lock); | 204 | spin_unlock(&inst->lock); |
195 | 205 | ||
196 | /* and finally put the refcount */ | 206 | /* and finally put the refcount */ |
197 | instance_put(inst); | 207 | instance_put(inst); |
@@ -200,9 +210,9 @@ __instance_destroy(struct nfulnl_instance *inst) | |||
200 | static inline void | 210 | static inline void |
201 | instance_destroy(struct nfulnl_instance *inst) | 211 | instance_destroy(struct nfulnl_instance *inst) |
202 | { | 212 | { |
203 | write_lock_bh(&instances_lock); | 213 | spin_lock_bh(&instances_lock); |
204 | __instance_destroy(inst); | 214 | __instance_destroy(inst); |
205 | write_unlock_bh(&instances_lock); | 215 | spin_unlock_bh(&instances_lock); |
206 | } | 216 | } |
207 | 217 | ||
208 | static int | 218 | static int |
@@ -621,6 +631,7 @@ nfulnl_log_packet(u_int8_t pf, | |||
621 | size += nla_total_size(data_len); | 631 | size += nla_total_size(data_len); |
622 | break; | 632 | break; |
623 | 633 | ||
634 | case NFULNL_COPY_DISABLED: | ||
624 | default: | 635 | default: |
625 | goto unlock_and_release; | 636 | goto unlock_and_release; |
626 | } | 637 | } |
@@ -674,7 +685,7 @@ nfulnl_rcv_nl_event(struct notifier_block *this, | |||
674 | int i; | 685 | int i; |
675 | 686 | ||
676 | /* destroy all instances for this pid */ | 687 | /* destroy all instances for this pid */ |
677 | write_lock_bh(&instances_lock); | 688 | spin_lock_bh(&instances_lock); |
678 | for (i = 0; i < INSTANCE_BUCKETS; i++) { | 689 | for (i = 0; i < INSTANCE_BUCKETS; i++) { |
679 | struct hlist_node *tmp, *t2; | 690 | struct hlist_node *tmp, *t2; |
680 | struct nfulnl_instance *inst; | 691 | struct nfulnl_instance *inst; |
@@ -686,7 +697,7 @@ nfulnl_rcv_nl_event(struct notifier_block *this, | |||
686 | __instance_destroy(inst); | 697 | __instance_destroy(inst); |
687 | } | 698 | } |
688 | } | 699 | } |
689 | write_unlock_bh(&instances_lock); | 700 | spin_unlock_bh(&instances_lock); |
690 | } | 701 | } |
691 | return NOTIFY_DONE; | 702 | return NOTIFY_DONE; |
692 | } | 703 | } |
@@ -863,19 +874,19 @@ static struct hlist_node *get_first(struct iter_state *st) | |||
863 | 874 | ||
864 | for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { | 875 | for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { |
865 | if (!hlist_empty(&instance_table[st->bucket])) | 876 | if (!hlist_empty(&instance_table[st->bucket])) |
866 | return instance_table[st->bucket].first; | 877 | return rcu_dereference_bh(instance_table[st->bucket].first); |
867 | } | 878 | } |
868 | return NULL; | 879 | return NULL; |
869 | } | 880 | } |
870 | 881 | ||
871 | static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h) | 882 | static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h) |
872 | { | 883 | { |
873 | h = h->next; | 884 | h = rcu_dereference_bh(h->next); |
874 | while (!h) { | 885 | while (!h) { |
875 | if (++st->bucket >= INSTANCE_BUCKETS) | 886 | if (++st->bucket >= INSTANCE_BUCKETS) |
876 | return NULL; | 887 | return NULL; |
877 | 888 | ||
878 | h = instance_table[st->bucket].first; | 889 | h = rcu_dereference_bh(instance_table[st->bucket].first); |
879 | } | 890 | } |
880 | return h; | 891 | return h; |
881 | } | 892 | } |
@@ -892,9 +903,9 @@ static struct hlist_node *get_idx(struct iter_state *st, loff_t pos) | |||
892 | } | 903 | } |
893 | 904 | ||
894 | static void *seq_start(struct seq_file *seq, loff_t *pos) | 905 | static void *seq_start(struct seq_file *seq, loff_t *pos) |
895 | __acquires(instances_lock) | 906 | __acquires(rcu_bh) |
896 | { | 907 | { |
897 | read_lock_bh(&instances_lock); | 908 | rcu_read_lock_bh(); |
898 | return get_idx(seq->private, *pos); | 909 | return get_idx(seq->private, *pos); |
899 | } | 910 | } |
900 | 911 | ||
@@ -905,9 +916,9 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos) | |||
905 | } | 916 | } |
906 | 917 | ||
907 | static void seq_stop(struct seq_file *s, void *v) | 918 | static void seq_stop(struct seq_file *s, void *v) |
908 | __releases(instances_lock) | 919 | __releases(rcu_bh) |
909 | { | 920 | { |
910 | read_unlock_bh(&instances_lock); | 921 | rcu_read_unlock_bh(); |
911 | } | 922 | } |
912 | 923 | ||
913 | static int seq_show(struct seq_file *s, void *v) | 924 | static int seq_show(struct seq_file *s, void *v) |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index cc3ae861e8f..68e67d19724 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -46,17 +46,19 @@ struct nfqnl_instance { | |||
46 | int peer_pid; | 46 | int peer_pid; |
47 | unsigned int queue_maxlen; | 47 | unsigned int queue_maxlen; |
48 | unsigned int copy_range; | 48 | unsigned int copy_range; |
49 | unsigned int queue_total; | ||
50 | unsigned int queue_dropped; | 49 | unsigned int queue_dropped; |
51 | unsigned int queue_user_dropped; | 50 | unsigned int queue_user_dropped; |
52 | 51 | ||
53 | unsigned int id_sequence; /* 'sequence' of pkt ids */ | ||
54 | 52 | ||
55 | u_int16_t queue_num; /* number of this queue */ | 53 | u_int16_t queue_num; /* number of this queue */ |
56 | u_int8_t copy_mode; | 54 | u_int8_t copy_mode; |
57 | 55 | /* | |
58 | spinlock_t lock; | 56 | * Following fields are dirtied for each queued packet, |
59 | 57 | * keep them in same cache line if possible. | |
58 | */ | ||
59 | spinlock_t lock; | ||
60 | unsigned int queue_total; | ||
61 | atomic_t id_sequence; /* 'sequence' of pkt ids */ | ||
60 | struct list_head queue_list; /* packets in queue */ | 62 | struct list_head queue_list; /* packets in queue */ |
61 | }; | 63 | }; |
62 | 64 | ||
@@ -238,32 +240,24 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
238 | 240 | ||
239 | outdev = entry->outdev; | 241 | outdev = entry->outdev; |
240 | 242 | ||
241 | spin_lock_bh(&queue->lock); | 243 | switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) { |
242 | |||
243 | switch ((enum nfqnl_config_mode)queue->copy_mode) { | ||
244 | case NFQNL_COPY_META: | 244 | case NFQNL_COPY_META: |
245 | case NFQNL_COPY_NONE: | 245 | case NFQNL_COPY_NONE: |
246 | break; | 246 | break; |
247 | 247 | ||
248 | case NFQNL_COPY_PACKET: | 248 | case NFQNL_COPY_PACKET: |
249 | if (entskb->ip_summed == CHECKSUM_PARTIAL && | 249 | if (entskb->ip_summed == CHECKSUM_PARTIAL && |
250 | skb_checksum_help(entskb)) { | 250 | skb_checksum_help(entskb)) |
251 | spin_unlock_bh(&queue->lock); | ||
252 | return NULL; | 251 | return NULL; |
253 | } | 252 | |
254 | if (queue->copy_range == 0 | 253 | data_len = ACCESS_ONCE(queue->copy_range); |
255 | || queue->copy_range > entskb->len) | 254 | if (data_len == 0 || data_len > entskb->len) |
256 | data_len = entskb->len; | 255 | data_len = entskb->len; |
257 | else | ||
258 | data_len = queue->copy_range; | ||
259 | 256 | ||
260 | size += nla_total_size(data_len); | 257 | size += nla_total_size(data_len); |
261 | break; | 258 | break; |
262 | } | 259 | } |
263 | 260 | ||
264 | entry->id = queue->id_sequence++; | ||
265 | |||
266 | spin_unlock_bh(&queue->lock); | ||
267 | 261 | ||
268 | skb = alloc_skb(size, GFP_ATOMIC); | 262 | skb = alloc_skb(size, GFP_ATOMIC); |
269 | if (!skb) | 263 | if (!skb) |
@@ -278,6 +272,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
278 | nfmsg->version = NFNETLINK_V0; | 272 | nfmsg->version = NFNETLINK_V0; |
279 | nfmsg->res_id = htons(queue->queue_num); | 273 | nfmsg->res_id = htons(queue->queue_num); |
280 | 274 | ||
275 | entry->id = atomic_inc_return(&queue->id_sequence); | ||
281 | pmsg.packet_id = htonl(entry->id); | 276 | pmsg.packet_id = htonl(entry->id); |
282 | pmsg.hw_protocol = entskb->protocol; | 277 | pmsg.hw_protocol = entskb->protocol; |
283 | pmsg.hook = entry->hook; | 278 | pmsg.hook = entry->hook; |
@@ -868,7 +863,7 @@ static int seq_show(struct seq_file *s, void *v) | |||
868 | inst->peer_pid, inst->queue_total, | 863 | inst->peer_pid, inst->queue_total, |
869 | inst->copy_mode, inst->copy_range, | 864 | inst->copy_mode, inst->copy_range, |
870 | inst->queue_dropped, inst->queue_user_dropped, | 865 | inst->queue_dropped, inst->queue_user_dropped, |
871 | inst->id_sequence, 1); | 866 | atomic_read(&inst->id_sequence), 1); |
872 | } | 867 | } |
873 | 868 | ||
874 | static const struct seq_operations nfqnl_seq_ops = { | 869 | static const struct seq_operations nfqnl_seq_ops = { |
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 562bf3266e0..0cb6053f02f 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c | |||
@@ -67,7 +67,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par) | |||
67 | return -EINVAL; | 67 | return -EINVAL; |
68 | 68 | ||
69 | if (info->flags & XT_CT_NOTRACK) { | 69 | if (info->flags & XT_CT_NOTRACK) { |
70 | ct = &nf_conntrack_untracked; | 70 | ct = nf_ct_untracked_get(); |
71 | atomic_inc(&ct->ct_general.use); | 71 | atomic_inc(&ct->ct_general.use); |
72 | goto out; | 72 | goto out; |
73 | } | 73 | } |
@@ -132,7 +132,7 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) | |||
132 | struct nf_conn *ct = info->ct; | 132 | struct nf_conn *ct = info->ct; |
133 | struct nf_conn_help *help; | 133 | struct nf_conn_help *help; |
134 | 134 | ||
135 | if (ct != &nf_conntrack_untracked) { | 135 | if (!nf_ct_is_untracked(ct)) { |
136 | help = nfct_help(ct); | 136 | help = nfct_help(ct); |
137 | if (help) | 137 | if (help) |
138 | module_put(help->helper->me); | 138 | module_put(help->helper->me); |
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c new file mode 100644 index 00000000000..e11090a0675 --- /dev/null +++ b/net/netfilter/xt_IDLETIMER.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * linux/net/netfilter/xt_IDLETIMER.c | ||
3 | * | ||
4 | * Netfilter module to trigger a timer when packet matches. | ||
5 | * After timer expires a kevent will be sent. | ||
6 | * | ||
7 | * Copyright (C) 2004, 2010 Nokia Corporation | ||
8 | * Written by Timo Teras <ext-timo.teras@nokia.com> | ||
9 | * | ||
10 | * Converted to x_tables and reworked for upstream inclusion | ||
11 | * by Luciano Coelho <luciano.coelho@nokia.com> | ||
12 | * | ||
13 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | */ | ||
29 | |||
30 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/timer.h> | ||
34 | #include <linux/list.h> | ||
35 | #include <linux/mutex.h> | ||
36 | #include <linux/netfilter.h> | ||
37 | #include <linux/netfilter/x_tables.h> | ||
38 | #include <linux/netfilter/xt_IDLETIMER.h> | ||
39 | #include <linux/kobject.h> | ||
40 | #include <linux/workqueue.h> | ||
41 | #include <linux/sysfs.h> | ||
42 | |||
43 | struct idletimer_tg_attr { | ||
44 | struct attribute attr; | ||
45 | ssize_t (*show)(struct kobject *kobj, | ||
46 | struct attribute *attr, char *buf); | ||
47 | }; | ||
48 | |||
49 | struct idletimer_tg { | ||
50 | struct list_head entry; | ||
51 | struct timer_list timer; | ||
52 | struct work_struct work; | ||
53 | |||
54 | struct kobject *kobj; | ||
55 | struct idletimer_tg_attr attr; | ||
56 | |||
57 | unsigned int refcnt; | ||
58 | }; | ||
59 | |||
60 | static LIST_HEAD(idletimer_tg_list); | ||
61 | static DEFINE_MUTEX(list_mutex); | ||
62 | |||
63 | static struct kobject *idletimer_tg_kobj; | ||
64 | |||
65 | static | ||
66 | struct idletimer_tg *__idletimer_tg_find_by_label(const char *label) | ||
67 | { | ||
68 | struct idletimer_tg *entry; | ||
69 | |||
70 | BUG_ON(!label); | ||
71 | |||
72 | list_for_each_entry(entry, &idletimer_tg_list, entry) { | ||
73 | if (!strcmp(label, entry->attr.attr.name)) | ||
74 | return entry; | ||
75 | } | ||
76 | |||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | static ssize_t idletimer_tg_show(struct kobject *kobj, struct attribute *attr, | ||
81 | char *buf) | ||
82 | { | ||
83 | struct idletimer_tg *timer; | ||
84 | unsigned long expires = 0; | ||
85 | |||
86 | mutex_lock(&list_mutex); | ||
87 | |||
88 | timer = __idletimer_tg_find_by_label(attr->name); | ||
89 | if (timer) | ||
90 | expires = timer->timer.expires; | ||
91 | |||
92 | mutex_unlock(&list_mutex); | ||
93 | |||
94 | if (time_after(expires, jiffies)) | ||
95 | return sprintf(buf, "%u\n", | ||
96 | jiffies_to_msecs(expires - jiffies) / 1000); | ||
97 | |||
98 | return sprintf(buf, "0\n"); | ||
99 | } | ||
100 | |||
101 | static void idletimer_tg_work(struct work_struct *work) | ||
102 | { | ||
103 | struct idletimer_tg *timer = container_of(work, struct idletimer_tg, | ||
104 | work); | ||
105 | |||
106 | sysfs_notify(idletimer_tg_kobj, NULL, timer->attr.attr.name); | ||
107 | } | ||
108 | |||
109 | static void idletimer_tg_expired(unsigned long data) | ||
110 | { | ||
111 | struct idletimer_tg *timer = (struct idletimer_tg *) data; | ||
112 | |||
113 | pr_debug("timer %s expired\n", timer->attr.attr.name); | ||
114 | |||
115 | schedule_work(&timer->work); | ||
116 | } | ||
117 | |||
118 | static int idletimer_tg_create(struct idletimer_tg_info *info) | ||
119 | { | ||
120 | int ret; | ||
121 | |||
122 | info->timer = kmalloc(sizeof(*info->timer), GFP_KERNEL); | ||
123 | if (!info->timer) { | ||
124 | pr_debug("couldn't alloc timer\n"); | ||
125 | ret = -ENOMEM; | ||
126 | goto out; | ||
127 | } | ||
128 | |||
129 | info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL); | ||
130 | if (!info->timer->attr.attr.name) { | ||
131 | pr_debug("couldn't alloc attribute name\n"); | ||
132 | ret = -ENOMEM; | ||
133 | goto out_free_timer; | ||
134 | } | ||
135 | info->timer->attr.attr.mode = S_IRUGO; | ||
136 | info->timer->attr.show = idletimer_tg_show; | ||
137 | |||
138 | ret = sysfs_create_file(idletimer_tg_kobj, &info->timer->attr.attr); | ||
139 | if (ret < 0) { | ||
140 | pr_debug("couldn't add file to sysfs"); | ||
141 | goto out_free_attr; | ||
142 | } | ||
143 | |||
144 | list_add(&info->timer->entry, &idletimer_tg_list); | ||
145 | |||
146 | setup_timer(&info->timer->timer, idletimer_tg_expired, | ||
147 | (unsigned long) info->timer); | ||
148 | info->timer->refcnt = 1; | ||
149 | |||
150 | mod_timer(&info->timer->timer, | ||
151 | msecs_to_jiffies(info->timeout * 1000) + jiffies); | ||
152 | |||
153 | INIT_WORK(&info->timer->work, idletimer_tg_work); | ||
154 | |||
155 | return 0; | ||
156 | |||
157 | out_free_attr: | ||
158 | kfree(info->timer->attr.attr.name); | ||
159 | out_free_timer: | ||
160 | kfree(info->timer); | ||
161 | out: | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * The actual xt_tables plugin. | ||
167 | */ | ||
168 | static unsigned int idletimer_tg_target(struct sk_buff *skb, | ||
169 | const struct xt_action_param *par) | ||
170 | { | ||
171 | const struct idletimer_tg_info *info = par->targinfo; | ||
172 | |||
173 | pr_debug("resetting timer %s, timeout period %u\n", | ||
174 | info->label, info->timeout); | ||
175 | |||
176 | BUG_ON(!info->timer); | ||
177 | |||
178 | mod_timer(&info->timer->timer, | ||
179 | msecs_to_jiffies(info->timeout * 1000) + jiffies); | ||
180 | |||
181 | return XT_CONTINUE; | ||
182 | } | ||
183 | |||
184 | static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) | ||
185 | { | ||
186 | struct idletimer_tg_info *info = par->targinfo; | ||
187 | int ret; | ||
188 | |||
189 | pr_debug("checkentry targinfo%s\n", info->label); | ||
190 | |||
191 | if (info->timeout == 0) { | ||
192 | pr_debug("timeout value is zero\n"); | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | if (info->label[0] == '\0' || | ||
197 | strnlen(info->label, | ||
198 | MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) { | ||
199 | pr_debug("label is empty or not nul-terminated\n"); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | mutex_lock(&list_mutex); | ||
204 | |||
205 | info->timer = __idletimer_tg_find_by_label(info->label); | ||
206 | if (info->timer) { | ||
207 | info->timer->refcnt++; | ||
208 | mod_timer(&info->timer->timer, | ||
209 | msecs_to_jiffies(info->timeout * 1000) + jiffies); | ||
210 | |||
211 | pr_debug("increased refcnt of timer %s to %u\n", | ||
212 | info->label, info->timer->refcnt); | ||
213 | } else { | ||
214 | ret = idletimer_tg_create(info); | ||
215 | if (ret < 0) { | ||
216 | pr_debug("failed to create timer\n"); | ||
217 | mutex_unlock(&list_mutex); | ||
218 | return ret; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | mutex_unlock(&list_mutex); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void idletimer_tg_destroy(const struct xt_tgdtor_param *par) | ||
227 | { | ||
228 | const struct idletimer_tg_info *info = par->targinfo; | ||
229 | |||
230 | pr_debug("destroy targinfo %s\n", info->label); | ||
231 | |||
232 | mutex_lock(&list_mutex); | ||
233 | |||
234 | if (--info->timer->refcnt == 0) { | ||
235 | pr_debug("deleting timer %s\n", info->label); | ||
236 | |||
237 | list_del(&info->timer->entry); | ||
238 | del_timer_sync(&info->timer->timer); | ||
239 | sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr); | ||
240 | kfree(info->timer->attr.attr.name); | ||
241 | kfree(info->timer); | ||
242 | } else { | ||
243 | pr_debug("decreased refcnt of timer %s to %u\n", | ||
244 | info->label, info->timer->refcnt); | ||
245 | } | ||
246 | |||
247 | mutex_unlock(&list_mutex); | ||
248 | } | ||
249 | |||
250 | static struct xt_target idletimer_tg __read_mostly = { | ||
251 | .name = "IDLETIMER", | ||
252 | .family = NFPROTO_UNSPEC, | ||
253 | .target = idletimer_tg_target, | ||
254 | .targetsize = sizeof(struct idletimer_tg_info), | ||
255 | .checkentry = idletimer_tg_checkentry, | ||
256 | .destroy = idletimer_tg_destroy, | ||
257 | .me = THIS_MODULE, | ||
258 | }; | ||
259 | |||
260 | static struct class *idletimer_tg_class; | ||
261 | |||
262 | static struct device *idletimer_tg_device; | ||
263 | |||
264 | static int __init idletimer_tg_init(void) | ||
265 | { | ||
266 | int err; | ||
267 | |||
268 | idletimer_tg_class = class_create(THIS_MODULE, "xt_idletimer"); | ||
269 | err = PTR_ERR(idletimer_tg_class); | ||
270 | if (IS_ERR(idletimer_tg_class)) { | ||
271 | pr_debug("couldn't register device class\n"); | ||
272 | goto out; | ||
273 | } | ||
274 | |||
275 | idletimer_tg_device = device_create(idletimer_tg_class, NULL, | ||
276 | MKDEV(0, 0), NULL, "timers"); | ||
277 | err = PTR_ERR(idletimer_tg_device); | ||
278 | if (IS_ERR(idletimer_tg_device)) { | ||
279 | pr_debug("couldn't register system device\n"); | ||
280 | goto out_class; | ||
281 | } | ||
282 | |||
283 | idletimer_tg_kobj = &idletimer_tg_device->kobj; | ||
284 | |||
285 | err = xt_register_target(&idletimer_tg); | ||
286 | if (err < 0) { | ||
287 | pr_debug("couldn't register xt target\n"); | ||
288 | goto out_dev; | ||
289 | } | ||
290 | |||
291 | return 0; | ||
292 | out_dev: | ||
293 | device_destroy(idletimer_tg_class, MKDEV(0, 0)); | ||
294 | out_class: | ||
295 | class_destroy(idletimer_tg_class); | ||
296 | out: | ||
297 | return err; | ||
298 | } | ||
299 | |||
300 | static void __exit idletimer_tg_exit(void) | ||
301 | { | ||
302 | xt_unregister_target(&idletimer_tg); | ||
303 | |||
304 | device_destroy(idletimer_tg_class, MKDEV(0, 0)); | ||
305 | class_destroy(idletimer_tg_class); | ||
306 | } | ||
307 | |||
308 | module_init(idletimer_tg_init); | ||
309 | module_exit(idletimer_tg_exit); | ||
310 | |||
311 | MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>"); | ||
312 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | ||
313 | MODULE_DESCRIPTION("Xtables: idle time monitor"); | ||
314 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c index 512b9123252..9d782181b6c 100644 --- a/net/netfilter/xt_NOTRACK.c +++ b/net/netfilter/xt_NOTRACK.c | |||
@@ -23,7 +23,7 @@ notrack_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
23 | If there is a real ct entry correspondig to this packet, | 23 | If there is a real ct entry correspondig to this packet, |
24 | it'll hang aroun till timing out. We don't deal with it | 24 | it'll hang aroun till timing out. We don't deal with it |
25 | for performance reasons. JK */ | 25 | for performance reasons. JK */ |
26 | skb->nfct = &nf_conntrack_untracked.ct_general; | 26 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
27 | skb->nfctinfo = IP_CT_NEW; | 27 | skb->nfctinfo = IP_CT_NEW; |
28 | nf_conntrack_get(skb->nfct); | 28 | nf_conntrack_get(skb->nfct); |
29 | 29 | ||
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c index c77a85bbd9e..22a2d421e7e 100644 --- a/net/netfilter/xt_TEE.c +++ b/net/netfilter/xt_TEE.c | |||
@@ -104,7 +104,7 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par) | |||
104 | #ifdef WITH_CONNTRACK | 104 | #ifdef WITH_CONNTRACK |
105 | /* Avoid counting cloned packets towards the original connection. */ | 105 | /* Avoid counting cloned packets towards the original connection. */ |
106 | nf_conntrack_put(skb->nfct); | 106 | nf_conntrack_put(skb->nfct); |
107 | skb->nfct = &nf_conntrack_untracked.ct_general; | 107 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
108 | skb->nfctinfo = IP_CT_NEW; | 108 | skb->nfctinfo = IP_CT_NEW; |
109 | nf_conntrack_get(skb->nfct); | 109 | nf_conntrack_get(skb->nfct); |
110 | #endif | 110 | #endif |
@@ -177,7 +177,7 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
177 | 177 | ||
178 | #ifdef WITH_CONNTRACK | 178 | #ifdef WITH_CONNTRACK |
179 | nf_conntrack_put(skb->nfct); | 179 | nf_conntrack_put(skb->nfct); |
180 | skb->nfct = &nf_conntrack_untracked.ct_general; | 180 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
181 | skb->nfctinfo = IP_CT_NEW; | 181 | skb->nfctinfo = IP_CT_NEW; |
182 | nf_conntrack_get(skb->nfct); | 182 | nf_conntrack_get(skb->nfct); |
183 | #endif | 183 | #endif |
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c index 30b95a1c1c8..f4af1bfafb1 100644 --- a/net/netfilter/xt_cluster.c +++ b/net/netfilter/xt_cluster.c | |||
@@ -120,7 +120,7 @@ xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
120 | if (ct == NULL) | 120 | if (ct == NULL) |
121 | return false; | 121 | return false; |
122 | 122 | ||
123 | if (ct == &nf_conntrack_untracked) | 123 | if (nf_ct_is_untracked(ct)) |
124 | return false; | 124 | return false; |
125 | 125 | ||
126 | if (ct->master) | 126 | if (ct->master) |
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 39681f10291..e536710ad91 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c | |||
@@ -123,11 +123,12 @@ conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par, | |||
123 | 123 | ||
124 | ct = nf_ct_get(skb, &ctinfo); | 124 | ct = nf_ct_get(skb, &ctinfo); |
125 | 125 | ||
126 | if (ct == &nf_conntrack_untracked) | 126 | if (ct) { |
127 | statebit = XT_CONNTRACK_STATE_UNTRACKED; | 127 | if (nf_ct_is_untracked(ct)) |
128 | else if (ct != NULL) | 128 | statebit = XT_CONNTRACK_STATE_UNTRACKED; |
129 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); | 129 | else |
130 | else | 130 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); |
131 | } else | ||
131 | statebit = XT_CONNTRACK_STATE_INVALID; | 132 | statebit = XT_CONNTRACK_STATE_INVALID; |
132 | 133 | ||
133 | if (info->match_flags & XT_CONNTRACK_STATE) { | 134 | if (info->match_flags & XT_CONNTRACK_STATE) { |
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index c04fcf385c5..ef36a56a02c 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/skbuff.h> | 3 | #include <linux/skbuff.h> |
4 | #include <net/ip.h> | 4 | #include <net/ip.h> |
5 | #include <net/ipv6.h> | 5 | #include <net/ipv6.h> |
6 | #include <net/sctp/sctp.h> | ||
6 | #include <linux/sctp.h> | 7 | #include <linux/sctp.h> |
7 | 8 | ||
8 | #include <linux/netfilter/x_tables.h> | 9 | #include <linux/netfilter/x_tables.h> |
@@ -67,7 +68,7 @@ match_packet(const struct sk_buff *skb, | |||
67 | ++i, offset, sch->type, htons(sch->length), | 68 | ++i, offset, sch->type, htons(sch->length), |
68 | sch->flags); | 69 | sch->flags); |
69 | #endif | 70 | #endif |
70 | offset += (ntohs(sch->length) + 3) & ~3; | 71 | offset += WORD_ROUND(ntohs(sch->length)); |
71 | 72 | ||
72 | pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset); | 73 | pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset); |
73 | 74 | ||
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 3d54c236a1b..1ca89908cba 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c | |||
@@ -127,7 +127,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, | |||
127 | * reply packet of an established SNAT-ted connection. */ | 127 | * reply packet of an established SNAT-ted connection. */ |
128 | 128 | ||
129 | ct = nf_ct_get(skb, &ctinfo); | 129 | ct = nf_ct_get(skb, &ctinfo); |
130 | if (ct && (ct != &nf_conntrack_untracked) && | 130 | if (ct && !nf_ct_is_untracked(ct) && |
131 | ((iph->protocol != IPPROTO_ICMP && | 131 | ((iph->protocol != IPPROTO_ICMP && |
132 | ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) || | 132 | ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) || |
133 | (iph->protocol == IPPROTO_ICMP && | 133 | (iph->protocol == IPPROTO_ICMP && |
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c index e12e053d378..a507922d80c 100644 --- a/net/netfilter/xt_state.c +++ b/net/netfilter/xt_state.c | |||
@@ -26,14 +26,16 @@ state_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
26 | const struct xt_state_info *sinfo = par->matchinfo; | 26 | const struct xt_state_info *sinfo = par->matchinfo; |
27 | enum ip_conntrack_info ctinfo; | 27 | enum ip_conntrack_info ctinfo; |
28 | unsigned int statebit; | 28 | unsigned int statebit; |
29 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
29 | 30 | ||
30 | if (nf_ct_is_untracked(skb)) | 31 | if (!ct) |
31 | statebit = XT_STATE_UNTRACKED; | ||
32 | else if (!nf_ct_get(skb, &ctinfo)) | ||
33 | statebit = XT_STATE_INVALID; | 32 | statebit = XT_STATE_INVALID; |
34 | else | 33 | else { |
35 | statebit = XT_STATE_BIT(ctinfo); | 34 | if (nf_ct_is_untracked(ct)) |
36 | 35 | statebit = XT_STATE_UNTRACKED; | |
36 | else | ||
37 | statebit = XT_STATE_BIT(ctinfo); | ||
38 | } | ||
37 | return (sinfo->statemask & statebit); | 39 | return (sinfo->statemask & statebit); |
38 | } | 40 | } |
39 | 41 | ||
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c index 96e62b8fd6b..42ecb71d445 100644 --- a/net/netfilter/xt_statistic.c +++ b/net/netfilter/xt_statistic.c | |||
@@ -18,8 +18,8 @@ | |||
18 | #include <linux/netfilter/x_tables.h> | 18 | #include <linux/netfilter/x_tables.h> |
19 | 19 | ||
20 | struct xt_statistic_priv { | 20 | struct xt_statistic_priv { |
21 | uint32_t count; | 21 | atomic_t count; |
22 | }; | 22 | } ____cacheline_aligned_in_smp; |
23 | 23 | ||
24 | MODULE_LICENSE("GPL"); | 24 | MODULE_LICENSE("GPL"); |
25 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | 25 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); |
@@ -27,13 +27,12 @@ MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)"); | |||
27 | MODULE_ALIAS("ipt_statistic"); | 27 | MODULE_ALIAS("ipt_statistic"); |
28 | MODULE_ALIAS("ip6t_statistic"); | 28 | MODULE_ALIAS("ip6t_statistic"); |
29 | 29 | ||
30 | static DEFINE_SPINLOCK(nth_lock); | ||
31 | |||
32 | static bool | 30 | static bool |
33 | statistic_mt(const struct sk_buff *skb, struct xt_action_param *par) | 31 | statistic_mt(const struct sk_buff *skb, struct xt_action_param *par) |
34 | { | 32 | { |
35 | const struct xt_statistic_info *info = par->matchinfo; | 33 | const struct xt_statistic_info *info = par->matchinfo; |
36 | bool ret = info->flags & XT_STATISTIC_INVERT; | 34 | bool ret = info->flags & XT_STATISTIC_INVERT; |
35 | int nval, oval; | ||
37 | 36 | ||
38 | switch (info->mode) { | 37 | switch (info->mode) { |
39 | case XT_STATISTIC_MODE_RANDOM: | 38 | case XT_STATISTIC_MODE_RANDOM: |
@@ -41,12 +40,12 @@ statistic_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
41 | ret = !ret; | 40 | ret = !ret; |
42 | break; | 41 | break; |
43 | case XT_STATISTIC_MODE_NTH: | 42 | case XT_STATISTIC_MODE_NTH: |
44 | spin_lock_bh(&nth_lock); | 43 | do { |
45 | if (info->master->count++ == info->u.nth.every) { | 44 | oval = atomic_read(&info->master->count); |
46 | info->master->count = 0; | 45 | nval = (oval == info->u.nth.every) ? 0 : oval + 1; |
46 | } while (atomic_cmpxchg(&info->master->count, oval, nval) != oval); | ||
47 | if (nval == 0) | ||
47 | ret = !ret; | 48 | ret = !ret; |
48 | } | ||
49 | spin_unlock_bh(&nth_lock); | ||
50 | break; | 49 | break; |
51 | } | 50 | } |
52 | 51 | ||
@@ -64,7 +63,7 @@ static int statistic_mt_check(const struct xt_mtchk_param *par) | |||
64 | info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); | 63 | info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); |
65 | if (info->master == NULL) | 64 | if (info->master == NULL) |
66 | return -ENOMEM; | 65 | return -ENOMEM; |
67 | info->master->count = info->u.nth.count; | 66 | atomic_set(&info->master->count, info->u.nth.count); |
68 | 67 | ||
69 | return 0; | 68 | return 0; |
70 | } | 69 | } |