aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/nf_conntrack.h49
-rw-r--r--include/net/netfilter/nf_conntrack_core.h7
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h72
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h10
-rw-r--r--net/netfilter/Makefile2
-rw-r--r--net/netfilter/nf_conntrack_core.c265
-rw-r--r--net/netfilter/nf_conntrack_expect.c365
-rw-r--r--net/netfilter/nf_conntrack_ftp.c1
-rw-r--r--net/netfilter/nf_conntrack_netlink.c1
-rw-r--r--net/netfilter/nf_conntrack_standalone.c81
10 files changed, 452 insertions, 401 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 1fbd8193d5f1..9d2581fc04be 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -124,44 +124,6 @@ struct nf_conn
124 char data[0]; 124 char data[0];
125}; 125};
126 126
127struct nf_conntrack_expect
128{
129 /* Internal linked list (global expectation list) */
130 struct list_head list;
131
132 /* We expect this tuple, with the following mask */
133 struct nf_conntrack_tuple tuple, mask;
134
135 /* Function to call after setup and insertion */
136 void (*expectfn)(struct nf_conn *new,
137 struct nf_conntrack_expect *this);
138
139 /* The conntrack of the master connection */
140 struct nf_conn *master;
141
142 /* Timer function; deletes the expectation. */
143 struct timer_list timeout;
144
145 /* Usage count. */
146 atomic_t use;
147
148 /* Unique ID */
149 unsigned int id;
150
151 /* Flags */
152 unsigned int flags;
153
154#ifdef CONFIG_NF_NAT_NEEDED
155 /* This is the original per-proto part, used to map the
156 * expected connection the way the recipient expects. */
157 union nf_conntrack_manip_proto saved_proto;
158 /* Direction relative to the master connection. */
159 enum ip_conntrack_dir dir;
160#endif
161};
162
163#define NF_CT_EXPECT_PERMANENT 0x1
164
165static inline struct nf_conn * 127static inline struct nf_conn *
166nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) 128nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash)
167{ 129{
@@ -208,16 +170,6 @@ __nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
208 170
209extern void nf_conntrack_hash_insert(struct nf_conn *ct); 171extern void nf_conntrack_hash_insert(struct nf_conn *ct);
210 172
211extern struct nf_conntrack_expect *
212__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
213
214extern struct nf_conntrack_expect *
215nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
216
217extern void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
218
219extern void nf_ct_remove_expectations(struct nf_conn *ct);
220
221extern void nf_conntrack_flush(void); 173extern void nf_conntrack_flush(void);
222 174
223extern struct nf_conntrack_helper * 175extern struct nf_conntrack_helper *
@@ -295,6 +247,7 @@ extern int nf_conntrack_checksum;
295#ifdef CONFIG_NF_CONNTRACK_EVENTS 247#ifdef CONFIG_NF_CONNTRACK_EVENTS
296#include <linux/notifier.h> 248#include <linux/notifier.h>
297#include <linux/interrupt.h> 249#include <linux/interrupt.h>
250#include <net/netfilter/nf_conntrack_expect.h>
298 251
299struct nf_conntrack_ecache { 252struct nf_conntrack_ecache {
300 struct nf_conn *ct; 253 struct nf_conn *ct;
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index da254525a4ce..84a8e01941fb 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -13,6 +13,8 @@
13#define _NF_CONNTRACK_CORE_H 13#define _NF_CONNTRACK_CORE_H
14 14
15#include <linux/netfilter.h> 15#include <linux/netfilter.h>
16#include <net/netfilter/nf_conntrack_l3proto.h>
17#include <net/netfilter/nf_conntrack_protocol.h>
16 18
17/* This header is used to share core functionality between the 19/* This header is used to share core functionality between the
18 standalone connection tracking module, and the compatibility layer's use 20 standalone connection tracking module, and the compatibility layer's use
@@ -70,6 +72,11 @@ static inline int nf_conntrack_confirm(struct sk_buff **pskb)
70 72
71extern void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb); 73extern void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb);
72 74
75int
76print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
77 struct nf_conntrack_l3proto *l3proto,
78 struct nf_conntrack_protocol *proto);
79
73extern struct list_head *nf_conntrack_hash; 80extern struct list_head *nf_conntrack_hash;
74extern struct list_head nf_conntrack_expect_list; 81extern struct list_head nf_conntrack_expect_list;
75extern rwlock_t nf_conntrack_lock ; 82extern rwlock_t nf_conntrack_lock ;
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
new file mode 100644
index 000000000000..5aa483e03455
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -0,0 +1,72 @@
1/*
2 * connection tracking expectations.
3 */
4
5#ifndef _NF_CONNTRACK_EXPECT_H
6#define _NF_CONNTRACK_EXPECT_H
7#include <net/netfilter/nf_conntrack.h>
8
9extern struct list_head nf_conntrack_expect_list;
10extern kmem_cache_t *nf_conntrack_expect_cachep;
11extern struct file_operations exp_file_ops;
12
13struct nf_conntrack_expect
14{
15 /* Internal linked list (global expectation list) */
16 struct list_head list;
17
18 /* We expect this tuple, with the following mask */
19 struct nf_conntrack_tuple tuple, mask;
20
21 /* Function to call after setup and insertion */
22 void (*expectfn)(struct nf_conn *new,
23 struct nf_conntrack_expect *this);
24
25 /* The conntrack of the master connection */
26 struct nf_conn *master;
27
28 /* Timer function; deletes the expectation. */
29 struct timer_list timeout;
30
31 /* Usage count. */
32 atomic_t use;
33
34 /* Unique ID */
35 unsigned int id;
36
37 /* Flags */
38 unsigned int flags;
39
40#ifdef CONFIG_NF_NAT_NEEDED
41 /* This is the original per-proto part, used to map the
42 * expected connection the way the recipient expects. */
43 union nf_conntrack_manip_proto saved_proto;
44 /* Direction relative to the master connection. */
45 enum ip_conntrack_dir dir;
46#endif
47};
48
49#define NF_CT_EXPECT_PERMANENT 0x1
50
51
52struct nf_conntrack_expect *
53__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
54
55struct nf_conntrack_expect *
56nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
57
58struct nf_conntrack_expect *
59find_expectation(const struct nf_conntrack_tuple *tuple);
60
61void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
62void nf_ct_remove_expectations(struct nf_conn *ct);
63void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp);
64
65/* Allocate space for an expectation: this is mandatory before calling
66 nf_conntrack_expect_related. You will have to call put afterwards. */
67struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me);
68void nf_conntrack_expect_put(struct nf_conntrack_expect *exp);
69int nf_conntrack_expect_related(struct nf_conntrack_expect *expect);
70
71#endif /*_NF_CONNTRACK_EXPECT_H*/
72
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 86ec8174ad02..3cbd13e22160 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -40,14 +40,4 @@ struct nf_conntrack_helper
40extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); 40extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
41extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); 41extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
42 42
43/* Allocate space for an expectation: this is mandatory before calling
44 nf_conntrack_expect_related. You will have to call put afterwards. */
45extern struct nf_conntrack_expect *
46nf_conntrack_expect_alloc(struct nf_conn *master);
47extern void nf_conntrack_expect_put(struct nf_conntrack_expect *exp);
48
49/* Add an expected connection: can have more than one per connection */
50extern int nf_conntrack_expect_related(struct nf_conntrack_expect *exp);
51extern void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp);
52
53#endif /*_NF_CONNTRACK_HELPER_H*/ 43#endif /*_NF_CONNTRACK_HELPER_H*/
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index a74be492fd0a..d33b9ac01aa7 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -1,5 +1,5 @@
1netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o 1netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
2nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o 2nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
3 3
4obj-$(CONFIG_NETFILTER) = netfilter.o 4obj-$(CONFIG_NETFILTER) = netfilter.o
5 5
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index de0567b1f422..72fbae4e594c 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -55,6 +55,7 @@
55#include <net/netfilter/nf_conntrack.h> 55#include <net/netfilter/nf_conntrack.h>
56#include <net/netfilter/nf_conntrack_l3proto.h> 56#include <net/netfilter/nf_conntrack_l3proto.h>
57#include <net/netfilter/nf_conntrack_protocol.h> 57#include <net/netfilter/nf_conntrack_protocol.h>
58#include <net/netfilter/nf_conntrack_expect.h>
58#include <net/netfilter/nf_conntrack_helper.h> 59#include <net/netfilter/nf_conntrack_helper.h>
59#include <net/netfilter/nf_conntrack_core.h> 60#include <net/netfilter/nf_conntrack_core.h>
60 61
@@ -72,21 +73,19 @@ DEFINE_RWLOCK(nf_conntrack_lock);
72atomic_t nf_conntrack_count = ATOMIC_INIT(0); 73atomic_t nf_conntrack_count = ATOMIC_INIT(0);
73 74
74void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL; 75void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL;
75LIST_HEAD(nf_conntrack_expect_list);
76struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly; 76struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly;
77struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly; 77struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly;
78static LIST_HEAD(helpers); 78static LIST_HEAD(helpers);
79unsigned int nf_conntrack_htable_size __read_mostly = 0; 79unsigned int nf_conntrack_htable_size __read_mostly = 0;
80int nf_conntrack_max __read_mostly; 80int nf_conntrack_max __read_mostly;
81struct list_head *nf_conntrack_hash __read_mostly; 81struct list_head *nf_conntrack_hash __read_mostly;
82static kmem_cache_t *nf_conntrack_expect_cachep __read_mostly;
83struct nf_conn nf_conntrack_untracked; 82struct nf_conn nf_conntrack_untracked;
84unsigned int nf_ct_log_invalid __read_mostly; 83unsigned int nf_ct_log_invalid __read_mostly;
85static LIST_HEAD(unconfirmed); 84static LIST_HEAD(unconfirmed);
86static int nf_conntrack_vmalloc __read_mostly; 85static int nf_conntrack_vmalloc __read_mostly;
87 86
88static unsigned int nf_conntrack_next_id; 87static unsigned int nf_conntrack_next_id;
89static unsigned int nf_conntrack_expect_next_id; 88
90#ifdef CONFIG_NF_CONNTRACK_EVENTS 89#ifdef CONFIG_NF_CONNTRACK_EVENTS
91ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); 90ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain);
92ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain); 91ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain);
@@ -438,103 +437,6 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
438 return protocol->invert_tuple(inverse, orig); 437 return protocol->invert_tuple(inverse, orig);
439} 438}
440 439
441/* nf_conntrack_expect helper functions */
442void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
443{
444 struct nf_conn_help *master_help = nfct_help(exp->master);
445
446 NF_CT_ASSERT(master_help);
447 ASSERT_WRITE_LOCK(&nf_conntrack_lock);
448 NF_CT_ASSERT(!timer_pending(&exp->timeout));
449
450 list_del(&exp->list);
451 NF_CT_STAT_INC(expect_delete);
452 master_help->expecting--;
453 nf_conntrack_expect_put(exp);
454}
455
456static void expectation_timed_out(unsigned long ul_expect)
457{
458 struct nf_conntrack_expect *exp = (void *)ul_expect;
459
460 write_lock_bh(&nf_conntrack_lock);
461 nf_ct_unlink_expect(exp);
462 write_unlock_bh(&nf_conntrack_lock);
463 nf_conntrack_expect_put(exp);
464}
465
466struct nf_conntrack_expect *
467__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple)
468{
469 struct nf_conntrack_expect *i;
470
471 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
472 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
473 return i;
474 }
475 return NULL;
476}
477
478/* Just find a expectation corresponding to a tuple. */
479struct nf_conntrack_expect *
480nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple)
481{
482 struct nf_conntrack_expect *i;
483
484 read_lock_bh(&nf_conntrack_lock);
485 i = __nf_conntrack_expect_find(tuple);
486 if (i)
487 atomic_inc(&i->use);
488 read_unlock_bh(&nf_conntrack_lock);
489
490 return i;
491}
492
493/* If an expectation for this connection is found, it gets delete from
494 * global list then returned. */
495static struct nf_conntrack_expect *
496find_expectation(const struct nf_conntrack_tuple *tuple)
497{
498 struct nf_conntrack_expect *i;
499
500 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
501 /* If master is not in hash table yet (ie. packet hasn't left
502 this machine yet), how can other end know about expected?
503 Hence these are not the droids you are looking for (if
504 master ct never got confirmed, we'd hold a reference to it
505 and weird things would happen to future packets). */
506 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
507 && nf_ct_is_confirmed(i->master)) {
508 if (i->flags & NF_CT_EXPECT_PERMANENT) {
509 atomic_inc(&i->use);
510 return i;
511 } else if (del_timer(&i->timeout)) {
512 nf_ct_unlink_expect(i);
513 return i;
514 }
515 }
516 }
517 return NULL;
518}
519
520/* delete all expectations for this conntrack */
521void nf_ct_remove_expectations(struct nf_conn *ct)
522{
523 struct nf_conntrack_expect *i, *tmp;
524 struct nf_conn_help *help = nfct_help(ct);
525
526 /* Optimization: most connection never expect any others. */
527 if (!help || help->expecting == 0)
528 return;
529
530 list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) {
531 if (i->master == ct && del_timer(&i->timeout)) {
532 nf_ct_unlink_expect(i);
533 nf_conntrack_expect_put(i);
534 }
535 }
536}
537
538static void 440static void
539clean_from_lists(struct nf_conn *ct) 441clean_from_lists(struct nf_conn *ct)
540{ 442{
@@ -1133,169 +1035,6 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
1133 orig->dst.protonum)); 1035 orig->dst.protonum));
1134} 1036}
1135 1037
1136/* Would two expected things clash? */
1137static inline int expect_clash(const struct nf_conntrack_expect *a,
1138 const struct nf_conntrack_expect *b)
1139{
1140 /* Part covered by intersection of masks must be unequal,
1141 otherwise they clash */
1142 struct nf_conntrack_tuple intersect_mask;
1143 int count;
1144
1145 intersect_mask.src.l3num = a->mask.src.l3num & b->mask.src.l3num;
1146 intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
1147 intersect_mask.dst.u.all = a->mask.dst.u.all & b->mask.dst.u.all;
1148 intersect_mask.dst.protonum = a->mask.dst.protonum
1149 & b->mask.dst.protonum;
1150
1151 for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
1152 intersect_mask.src.u3.all[count] =
1153 a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
1154 }
1155
1156 for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
1157 intersect_mask.dst.u3.all[count] =
1158 a->mask.dst.u3.all[count] & b->mask.dst.u3.all[count];
1159 }
1160
1161 return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
1162}
1163
1164static inline int expect_matches(const struct nf_conntrack_expect *a,
1165 const struct nf_conntrack_expect *b)
1166{
1167 return a->master == b->master
1168 && nf_ct_tuple_equal(&a->tuple, &b->tuple)
1169 && nf_ct_tuple_equal(&a->mask, &b->mask);
1170}
1171
1172/* Generally a bad idea to call this: could have matched already. */
1173void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp)
1174{
1175 struct nf_conntrack_expect *i;
1176
1177 write_lock_bh(&nf_conntrack_lock);
1178 /* choose the the oldest expectation to evict */
1179 list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
1180 if (expect_matches(i, exp) && del_timer(&i->timeout)) {
1181 nf_ct_unlink_expect(i);
1182 write_unlock_bh(&nf_conntrack_lock);
1183 nf_conntrack_expect_put(i);
1184 return;
1185 }
1186 }
1187 write_unlock_bh(&nf_conntrack_lock);
1188}
1189
1190/* We don't increase the master conntrack refcount for non-fulfilled
1191 * conntracks. During the conntrack destruction, the expectations are
1192 * always killed before the conntrack itself */
1193struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me)
1194{
1195 struct nf_conntrack_expect *new;
1196
1197 new = kmem_cache_alloc(nf_conntrack_expect_cachep, GFP_ATOMIC);
1198 if (!new) {
1199 DEBUGP("expect_related: OOM allocating expect\n");
1200 return NULL;
1201 }
1202 new->master = me;
1203 atomic_set(&new->use, 1);
1204 return new;
1205}
1206
1207void nf_conntrack_expect_put(struct nf_conntrack_expect *exp)
1208{
1209 if (atomic_dec_and_test(&exp->use))
1210 kmem_cache_free(nf_conntrack_expect_cachep, exp);
1211}
1212
1213static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
1214{
1215 struct nf_conn_help *master_help = nfct_help(exp->master);
1216
1217 atomic_inc(&exp->use);
1218 master_help->expecting++;
1219 list_add(&exp->list, &nf_conntrack_expect_list);
1220
1221 init_timer(&exp->timeout);
1222 exp->timeout.data = (unsigned long)exp;
1223 exp->timeout.function = expectation_timed_out;
1224 exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
1225 add_timer(&exp->timeout);
1226
1227 exp->id = ++nf_conntrack_expect_next_id;
1228 atomic_inc(&exp->use);
1229 NF_CT_STAT_INC(expect_create);
1230}
1231
1232/* Race with expectations being used means we could have none to find; OK. */
1233static void evict_oldest_expect(struct nf_conn *master)
1234{
1235 struct nf_conntrack_expect *i;
1236
1237 list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
1238 if (i->master == master) {
1239 if (del_timer(&i->timeout)) {
1240 nf_ct_unlink_expect(i);
1241 nf_conntrack_expect_put(i);
1242 }
1243 break;
1244 }
1245 }
1246}
1247
1248static inline int refresh_timer(struct nf_conntrack_expect *i)
1249{
1250 struct nf_conn_help *master_help = nfct_help(i->master);
1251
1252 if (!del_timer(&i->timeout))
1253 return 0;
1254
1255 i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
1256 add_timer(&i->timeout);
1257 return 1;
1258}
1259
1260int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
1261{
1262 struct nf_conntrack_expect *i;
1263 struct nf_conn *master = expect->master;
1264 struct nf_conn_help *master_help = nfct_help(master);
1265 int ret;
1266
1267 NF_CT_ASSERT(master_help);
1268
1269 DEBUGP("nf_conntrack_expect_related %p\n", related_to);
1270 DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple);
1271 DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask);
1272
1273 write_lock_bh(&nf_conntrack_lock);
1274 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
1275 if (expect_matches(i, expect)) {
1276 /* Refresh timer: if it's dying, ignore.. */
1277 if (refresh_timer(i)) {
1278 ret = 0;
1279 goto out;
1280 }
1281 } else if (expect_clash(i, expect)) {
1282 ret = -EBUSY;
1283 goto out;
1284 }
1285 }
1286 /* Will be over limit? */
1287 if (master_help->helper->max_expected &&
1288 master_help->expecting >= master_help->helper->max_expected)
1289 evict_oldest_expect(master);
1290
1291 nf_conntrack_expect_insert(expect);
1292 nf_conntrack_expect_event(IPEXP_NEW, expect);
1293 ret = 0;
1294out:
1295 write_unlock_bh(&nf_conntrack_lock);
1296 return ret;
1297}
1298
1299int nf_conntrack_helper_register(struct nf_conntrack_helper *me) 1038int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
1300{ 1039{
1301 int ret; 1040 int ret;
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
new file mode 100644
index 000000000000..076e678b3188
--- /dev/null
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -0,0 +1,365 @@
1/* Expectation handling for nf_conntrack. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/types.h>
13#include <linux/netfilter.h>
14#include <linux/skbuff.h>
15#include <linux/proc_fs.h>
16#include <linux/seq_file.h>
17#include <linux/stddef.h>
18#include <linux/slab.h>
19#include <linux/err.h>
20#include <linux/percpu.h>
21#include <linux/kernel.h>
22
23#include <net/netfilter/nf_conntrack.h>
24#include <net/netfilter/nf_conntrack_core.h>
25#include <net/netfilter/nf_conntrack_expect.h>
26#include <net/netfilter/nf_conntrack_helper.h>
27#include <net/netfilter/nf_conntrack_tuple.h>
28
29LIST_HEAD(nf_conntrack_expect_list);
30kmem_cache_t *nf_conntrack_expect_cachep __read_mostly;
31DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
32static unsigned int nf_conntrack_expect_next_id;
33
34/* nf_conntrack_expect helper functions */
35void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
36{
37 struct nf_conn_help *master_help = nfct_help(exp->master);
38
39 NF_CT_ASSERT(master_help);
40 NF_CT_ASSERT(!timer_pending(&exp->timeout));
41
42 list_del(&exp->list);
43 NF_CT_STAT_INC(expect_delete);
44 master_help->expecting--;
45 nf_conntrack_expect_put(exp);
46}
47
48static void expectation_timed_out(unsigned long ul_expect)
49{
50 struct nf_conntrack_expect *exp = (void *)ul_expect;
51
52 write_lock_bh(&nf_conntrack_lock);
53 nf_ct_unlink_expect(exp);
54 write_unlock_bh(&nf_conntrack_lock);
55 nf_conntrack_expect_put(exp);
56}
57
58struct nf_conntrack_expect *
59__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple)
60{
61 struct nf_conntrack_expect *i;
62
63 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
64 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
65 return i;
66 }
67 return NULL;
68}
69
70/* Just find a expectation corresponding to a tuple. */
71struct nf_conntrack_expect *
72nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple)
73{
74 struct nf_conntrack_expect *i;
75
76 read_lock_bh(&nf_conntrack_lock);
77 i = __nf_conntrack_expect_find(tuple);
78 if (i)
79 atomic_inc(&i->use);
80 read_unlock_bh(&nf_conntrack_lock);
81
82 return i;
83}
84
85/* If an expectation for this connection is found, it gets delete from
86 * global list then returned. */
87struct nf_conntrack_expect *
88find_expectation(const struct nf_conntrack_tuple *tuple)
89{
90 struct nf_conntrack_expect *i;
91
92 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
93 /* If master is not in hash table yet (ie. packet hasn't left
94 this machine yet), how can other end know about expected?
95 Hence these are not the droids you are looking for (if
96 master ct never got confirmed, we'd hold a reference to it
97 and weird things would happen to future packets). */
98 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
99 && nf_ct_is_confirmed(i->master)) {
100 if (i->flags & NF_CT_EXPECT_PERMANENT) {
101 atomic_inc(&i->use);
102 return i;
103 } else if (del_timer(&i->timeout)) {
104 nf_ct_unlink_expect(i);
105 return i;
106 }
107 }
108 }
109 return NULL;
110}
111
112/* delete all expectations for this conntrack */
113void nf_ct_remove_expectations(struct nf_conn *ct)
114{
115 struct nf_conntrack_expect *i, *tmp;
116 struct nf_conn_help *help = nfct_help(ct);
117
118 /* Optimization: most connection never expect any others. */
119 if (!help || help->expecting == 0)
120 return;
121
122 list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) {
123 if (i->master == ct && del_timer(&i->timeout)) {
124 nf_ct_unlink_expect(i);
125 nf_conntrack_expect_put(i);
126 }
127 }
128}
129
130/* Would two expected things clash? */
131static inline int expect_clash(const struct nf_conntrack_expect *a,
132 const struct nf_conntrack_expect *b)
133{
134 /* Part covered by intersection of masks must be unequal,
135 otherwise they clash */
136 struct nf_conntrack_tuple intersect_mask;
137 int count;
138
139 intersect_mask.src.l3num = a->mask.src.l3num & b->mask.src.l3num;
140 intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
141 intersect_mask.dst.u.all = a->mask.dst.u.all & b->mask.dst.u.all;
142 intersect_mask.dst.protonum = a->mask.dst.protonum
143 & b->mask.dst.protonum;
144
145 for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
146 intersect_mask.src.u3.all[count] =
147 a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
148 }
149
150 for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
151 intersect_mask.dst.u3.all[count] =
152 a->mask.dst.u3.all[count] & b->mask.dst.u3.all[count];
153 }
154
155 return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
156}
157
158static inline int expect_matches(const struct nf_conntrack_expect *a,
159 const struct nf_conntrack_expect *b)
160{
161 return a->master == b->master
162 && nf_ct_tuple_equal(&a->tuple, &b->tuple)
163 && nf_ct_tuple_equal(&a->mask, &b->mask);
164}
165
166/* Generally a bad idea to call this: could have matched already. */
167void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp)
168{
169 struct nf_conntrack_expect *i;
170
171 write_lock_bh(&nf_conntrack_lock);
172 /* choose the the oldest expectation to evict */
173 list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
174 if (expect_matches(i, exp) && del_timer(&i->timeout)) {
175 nf_ct_unlink_expect(i);
176 write_unlock_bh(&nf_conntrack_lock);
177 nf_conntrack_expect_put(i);
178 return;
179 }
180 }
181 write_unlock_bh(&nf_conntrack_lock);
182}
183
184/* We don't increase the master conntrack refcount for non-fulfilled
185 * conntracks. During the conntrack destruction, the expectations are
186 * always killed before the conntrack itself */
187struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me)
188{
189 struct nf_conntrack_expect *new;
190
191 new = kmem_cache_alloc(nf_conntrack_expect_cachep, GFP_ATOMIC);
192 if (!new)
193 return NULL;
194
195 new->master = me;
196 atomic_set(&new->use, 1);
197 return new;
198}
199
200void nf_conntrack_expect_put(struct nf_conntrack_expect *exp)
201{
202 if (atomic_dec_and_test(&exp->use))
203 kmem_cache_free(nf_conntrack_expect_cachep, exp);
204}
205
206static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
207{
208 struct nf_conn_help *master_help = nfct_help(exp->master);
209
210 atomic_inc(&exp->use);
211 master_help->expecting++;
212 list_add(&exp->list, &nf_conntrack_expect_list);
213
214 init_timer(&exp->timeout);
215 exp->timeout.data = (unsigned long)exp;
216 exp->timeout.function = expectation_timed_out;
217 exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
218 add_timer(&exp->timeout);
219
220 exp->id = ++nf_conntrack_expect_next_id;
221 atomic_inc(&exp->use);
222 NF_CT_STAT_INC(expect_create);
223}
224
225/* Race with expectations being used means we could have none to find; OK. */
226static void evict_oldest_expect(struct nf_conn *master)
227{
228 struct nf_conntrack_expect *i;
229
230 list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
231 if (i->master == master) {
232 if (del_timer(&i->timeout)) {
233 nf_ct_unlink_expect(i);
234 nf_conntrack_expect_put(i);
235 }
236 break;
237 }
238 }
239}
240
241static inline int refresh_timer(struct nf_conntrack_expect *i)
242{
243 struct nf_conn_help *master_help = nfct_help(i->master);
244
245 if (!del_timer(&i->timeout))
246 return 0;
247
248 i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
249 add_timer(&i->timeout);
250 return 1;
251}
252
253int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
254{
255 struct nf_conntrack_expect *i;
256 struct nf_conn *master = expect->master;
257 struct nf_conn_help *master_help = nfct_help(master);
258 int ret;
259
260 NF_CT_ASSERT(master_help);
261
262 write_lock_bh(&nf_conntrack_lock);
263 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
264 if (expect_matches(i, expect)) {
265 /* Refresh timer: if it's dying, ignore.. */
266 if (refresh_timer(i)) {
267 ret = 0;
268 goto out;
269 }
270 } else if (expect_clash(i, expect)) {
271 ret = -EBUSY;
272 goto out;
273 }
274 }
275 /* Will be over limit? */
276 if (master_help->helper->max_expected &&
277 master_help->expecting >= master_help->helper->max_expected)
278 evict_oldest_expect(master);
279
280 nf_conntrack_expect_insert(expect);
281 nf_conntrack_expect_event(IPEXP_NEW, expect);
282 ret = 0;
283out:
284 write_unlock_bh(&nf_conntrack_lock);
285 return ret;
286}
287
288#ifdef CONFIG_PROC_FS
289static void *exp_seq_start(struct seq_file *s, loff_t *pos)
290{
291 struct list_head *e = &nf_conntrack_expect_list;
292 loff_t i;
293
294 /* strange seq_file api calls stop even if we fail,
295 * thus we need to grab lock since stop unlocks */
296 read_lock_bh(&nf_conntrack_lock);
297
298 if (list_empty(e))
299 return NULL;
300
301 for (i = 0; i <= *pos; i++) {
302 e = e->next;
303 if (e == &nf_conntrack_expect_list)
304 return NULL;
305 }
306 return e;
307}
308
309static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
310{
311 struct list_head *e = v;
312
313 ++*pos;
314 e = e->next;
315
316 if (e == &nf_conntrack_expect_list)
317 return NULL;
318
319 return e;
320}
321
322static void exp_seq_stop(struct seq_file *s, void *v)
323{
324 read_unlock_bh(&nf_conntrack_lock);
325}
326
327static int exp_seq_show(struct seq_file *s, void *v)
328{
329 struct nf_conntrack_expect *expect = v;
330
331 if (expect->timeout.function)
332 seq_printf(s, "%ld ", timer_pending(&expect->timeout)
333 ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
334 else
335 seq_printf(s, "- ");
336 seq_printf(s, "l3proto = %u proto=%u ",
337 expect->tuple.src.l3num,
338 expect->tuple.dst.protonum);
339 print_tuple(s, &expect->tuple,
340 __nf_ct_l3proto_find(expect->tuple.src.l3num),
341 __nf_ct_proto_find(expect->tuple.src.l3num,
342 expect->tuple.dst.protonum));
343 return seq_putc(s, '\n');
344}
345
346static struct seq_operations exp_seq_ops = {
347 .start = exp_seq_start,
348 .next = exp_seq_next,
349 .stop = exp_seq_stop,
350 .show = exp_seq_show
351};
352
353static int exp_open(struct inode *inode, struct file *file)
354{
355 return seq_open(file, &exp_seq_ops);
356}
357
358struct file_operations exp_file_ops = {
359 .owner = THIS_MODULE,
360 .open = exp_open,
361 .read = seq_read,
362 .llseek = seq_lseek,
363 .release = seq_release
364};
365#endif /* CONFIG_PROC_FS */
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 0c17a5bd112b..503fabf18843 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -26,6 +26,7 @@
26#include <net/tcp.h> 26#include <net/tcp.h>
27 27
28#include <net/netfilter/nf_conntrack.h> 28#include <net/netfilter/nf_conntrack.h>
29#include <net/netfilter/nf_conntrack_expect.h>
29#include <net/netfilter/nf_conntrack_helper.h> 30#include <net/netfilter/nf_conntrack_helper.h>
30#include <linux/netfilter/nf_conntrack_ftp.h> 31#include <linux/netfilter/nf_conntrack_ftp.h>
31 32
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index cfb35fd8d9b9..c3d53d91929f 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -35,6 +35,7 @@
35#include <linux/netfilter.h> 35#include <linux/netfilter.h>
36#include <net/netfilter/nf_conntrack.h> 36#include <net/netfilter/nf_conntrack.h>
37#include <net/netfilter/nf_conntrack_core.h> 37#include <net/netfilter/nf_conntrack_core.h>
38#include <net/netfilter/nf_conntrack_expect.h>
38#include <net/netfilter/nf_conntrack_helper.h> 39#include <net/netfilter/nf_conntrack_helper.h>
39#include <net/netfilter/nf_conntrack_l3proto.h> 40#include <net/netfilter/nf_conntrack_l3proto.h>
40#include <net/netfilter/nf_conntrack_protocol.h> 41#include <net/netfilter/nf_conntrack_protocol.h>
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 5954f6773810..72643d32cab3 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -36,6 +36,7 @@
36#include <net/netfilter/nf_conntrack_l3proto.h> 36#include <net/netfilter/nf_conntrack_l3proto.h>
37#include <net/netfilter/nf_conntrack_protocol.h> 37#include <net/netfilter/nf_conntrack_protocol.h>
38#include <net/netfilter/nf_conntrack_core.h> 38#include <net/netfilter/nf_conntrack_core.h>
39#include <net/netfilter/nf_conntrack_expect.h>
39#include <net/netfilter/nf_conntrack_helper.h> 40#include <net/netfilter/nf_conntrack_helper.h>
40 41
41#if 0 42#if 0
@@ -66,7 +67,7 @@ static int kill_proto(struct nf_conn *i, void *data)
66} 67}
67 68
68#ifdef CONFIG_PROC_FS 69#ifdef CONFIG_PROC_FS
69static int 70int
70print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, 71print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
71 struct nf_conntrack_l3proto *l3proto, 72 struct nf_conntrack_l3proto *l3proto,
72 struct nf_conntrack_protocol *proto) 73 struct nf_conntrack_protocol *proto)
@@ -258,84 +259,6 @@ static struct file_operations ct_file_ops = {
258 .release = seq_release_private, 259 .release = seq_release_private,
259}; 260};
260 261
261/* expects */
262static void *exp_seq_start(struct seq_file *s, loff_t *pos)
263{
264 struct list_head *e = &nf_conntrack_expect_list;
265 loff_t i;
266
267 /* strange seq_file api calls stop even if we fail,
268 * thus we need to grab lock since stop unlocks */
269 read_lock_bh(&nf_conntrack_lock);
270
271 if (list_empty(e))
272 return NULL;
273
274 for (i = 0; i <= *pos; i++) {
275 e = e->next;
276 if (e == &nf_conntrack_expect_list)
277 return NULL;
278 }
279 return e;
280}
281
282static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
283{
284 struct list_head *e = v;
285
286 ++*pos;
287 e = e->next;
288
289 if (e == &nf_conntrack_expect_list)
290 return NULL;
291
292 return e;
293}
294
295static void exp_seq_stop(struct seq_file *s, void *v)
296{
297 read_unlock_bh(&nf_conntrack_lock);
298}
299
300static int exp_seq_show(struct seq_file *s, void *v)
301{
302 struct nf_conntrack_expect *expect = v;
303
304 if (expect->timeout.function)
305 seq_printf(s, "%ld ", timer_pending(&expect->timeout)
306 ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
307 else
308 seq_printf(s, "- ");
309 seq_printf(s, "l3proto = %u proto=%u ",
310 expect->tuple.src.l3num,
311 expect->tuple.dst.protonum);
312 print_tuple(s, &expect->tuple,
313 __nf_ct_l3proto_find(expect->tuple.src.l3num),
314 __nf_ct_proto_find(expect->tuple.src.l3num,
315 expect->tuple.dst.protonum));
316 return seq_putc(s, '\n');
317}
318
319static struct seq_operations exp_seq_ops = {
320 .start = exp_seq_start,
321 .next = exp_seq_next,
322 .stop = exp_seq_stop,
323 .show = exp_seq_show
324};
325
326static int exp_open(struct inode *inode, struct file *file)
327{
328 return seq_open(file, &exp_seq_ops);
329}
330
331static struct file_operations exp_file_ops = {
332 .owner = THIS_MODULE,
333 .open = exp_open,
334 .read = seq_read,
335 .llseek = seq_lseek,
336 .release = seq_release
337};
338
339static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) 262static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
340{ 263{
341 int cpu; 264 int cpu;