diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack.h | 49 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_core.h | 7 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_expect.h | 72 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_helper.h | 10 | ||||
-rw-r--r-- | net/netfilter/Makefile | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 265 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 365 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_ftp.c | 1 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 1 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_standalone.c | 81 |
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 | ||
127 | struct 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 | |||
165 | static inline struct nf_conn * | 127 | static inline struct nf_conn * |
166 | nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) | 128 | nf_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 | ||
209 | extern void nf_conntrack_hash_insert(struct nf_conn *ct); | 171 | extern void nf_conntrack_hash_insert(struct nf_conn *ct); |
210 | 172 | ||
211 | extern struct nf_conntrack_expect * | ||
212 | __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); | ||
213 | |||
214 | extern struct nf_conntrack_expect * | ||
215 | nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); | ||
216 | |||
217 | extern void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); | ||
218 | |||
219 | extern void nf_ct_remove_expectations(struct nf_conn *ct); | ||
220 | |||
221 | extern void nf_conntrack_flush(void); | 173 | extern void nf_conntrack_flush(void); |
222 | 174 | ||
223 | extern struct nf_conntrack_helper * | 175 | extern 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 | ||
299 | struct nf_conntrack_ecache { | 252 | struct 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 | ||
71 | extern void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb); | 73 | extern void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb); |
72 | 74 | ||
75 | int | ||
76 | print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, | ||
77 | struct nf_conntrack_l3proto *l3proto, | ||
78 | struct nf_conntrack_protocol *proto); | ||
79 | |||
73 | extern struct list_head *nf_conntrack_hash; | 80 | extern struct list_head *nf_conntrack_hash; |
74 | extern struct list_head nf_conntrack_expect_list; | 81 | extern struct list_head nf_conntrack_expect_list; |
75 | extern rwlock_t nf_conntrack_lock ; | 82 | extern 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 | |||
9 | extern struct list_head nf_conntrack_expect_list; | ||
10 | extern kmem_cache_t *nf_conntrack_expect_cachep; | ||
11 | extern struct file_operations exp_file_ops; | ||
12 | |||
13 | struct 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 | |||
52 | struct nf_conntrack_expect * | ||
53 | __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); | ||
54 | |||
55 | struct nf_conntrack_expect * | ||
56 | nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); | ||
57 | |||
58 | struct nf_conntrack_expect * | ||
59 | find_expectation(const struct nf_conntrack_tuple *tuple); | ||
60 | |||
61 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); | ||
62 | void nf_ct_remove_expectations(struct nf_conn *ct); | ||
63 | void 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. */ | ||
67 | struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me); | ||
68 | void nf_conntrack_expect_put(struct nf_conntrack_expect *exp); | ||
69 | int 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 | |||
40 | extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); | 40 | extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); |
41 | extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); | 41 | extern 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. */ | ||
45 | extern struct nf_conntrack_expect * | ||
46 | nf_conntrack_expect_alloc(struct nf_conn *master); | ||
47 | extern void nf_conntrack_expect_put(struct nf_conntrack_expect *exp); | ||
48 | |||
49 | /* Add an expected connection: can have more than one per connection */ | ||
50 | extern int nf_conntrack_expect_related(struct nf_conntrack_expect *exp); | ||
51 | extern 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 @@ | |||
1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o | 1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o |
2 | nf_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 | 2 | nf_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 | ||
4 | obj-$(CONFIG_NETFILTER) = netfilter.o | 4 | obj-$(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); | |||
72 | atomic_t nf_conntrack_count = ATOMIC_INIT(0); | 73 | atomic_t nf_conntrack_count = ATOMIC_INIT(0); |
73 | 74 | ||
74 | void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL; | 75 | void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL; |
75 | LIST_HEAD(nf_conntrack_expect_list); | ||
76 | struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly; | 76 | struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly; |
77 | struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly; | 77 | struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly; |
78 | static LIST_HEAD(helpers); | 78 | static LIST_HEAD(helpers); |
79 | unsigned int nf_conntrack_htable_size __read_mostly = 0; | 79 | unsigned int nf_conntrack_htable_size __read_mostly = 0; |
80 | int nf_conntrack_max __read_mostly; | 80 | int nf_conntrack_max __read_mostly; |
81 | struct list_head *nf_conntrack_hash __read_mostly; | 81 | struct list_head *nf_conntrack_hash __read_mostly; |
82 | static kmem_cache_t *nf_conntrack_expect_cachep __read_mostly; | ||
83 | struct nf_conn nf_conntrack_untracked; | 82 | struct nf_conn nf_conntrack_untracked; |
84 | unsigned int nf_ct_log_invalid __read_mostly; | 83 | unsigned int nf_ct_log_invalid __read_mostly; |
85 | static LIST_HEAD(unconfirmed); | 84 | static LIST_HEAD(unconfirmed); |
86 | static int nf_conntrack_vmalloc __read_mostly; | 85 | static int nf_conntrack_vmalloc __read_mostly; |
87 | 86 | ||
88 | static unsigned int nf_conntrack_next_id; | 87 | static unsigned int nf_conntrack_next_id; |
89 | static unsigned int nf_conntrack_expect_next_id; | 88 | |
90 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 89 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
91 | ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); | 90 | ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); |
92 | ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain); | 91 | ATOMIC_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 */ | ||
442 | void 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 | |||
456 | static 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 | |||
466 | struct 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. */ | ||
479 | struct nf_conntrack_expect * | ||
480 | nf_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. */ | ||
495 | static struct nf_conntrack_expect * | ||
496 | find_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 */ | ||
521 | void 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 | |||
538 | static void | 440 | static void |
539 | clean_from_lists(struct nf_conn *ct) | 441 | clean_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? */ | ||
1137 | static 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 | |||
1164 | static 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. */ | ||
1173 | void 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 */ | ||
1193 | struct 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 | |||
1207 | void 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 | |||
1213 | static 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. */ | ||
1233 | static 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 | |||
1248 | static 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 | |||
1260 | int 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; | ||
1294 | out: | ||
1295 | write_unlock_bh(&nf_conntrack_lock); | ||
1296 | return ret; | ||
1297 | } | ||
1298 | |||
1299 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | 1038 | int 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 | |||
29 | LIST_HEAD(nf_conntrack_expect_list); | ||
30 | kmem_cache_t *nf_conntrack_expect_cachep __read_mostly; | ||
31 | DECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat); | ||
32 | static unsigned int nf_conntrack_expect_next_id; | ||
33 | |||
34 | /* nf_conntrack_expect helper functions */ | ||
35 | void 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 | |||
48 | static 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 | |||
58 | struct 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. */ | ||
71 | struct nf_conntrack_expect * | ||
72 | nf_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. */ | ||
87 | struct nf_conntrack_expect * | ||
88 | find_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 */ | ||
113 | void 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? */ | ||
131 | static 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 | |||
158 | static 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. */ | ||
167 | void 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 */ | ||
187 | struct 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 | |||
200 | void 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 | |||
206 | static 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. */ | ||
226 | static 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 | |||
241 | static 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 | |||
253 | int 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; | ||
283 | out: | ||
284 | write_unlock_bh(&nf_conntrack_lock); | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | #ifdef CONFIG_PROC_FS | ||
289 | static 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 | |||
309 | static 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 | |||
322 | static void exp_seq_stop(struct seq_file *s, void *v) | ||
323 | { | ||
324 | read_unlock_bh(&nf_conntrack_lock); | ||
325 | } | ||
326 | |||
327 | static 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 | |||
346 | static 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 | |||
353 | static int exp_open(struct inode *inode, struct file *file) | ||
354 | { | ||
355 | return seq_open(file, &exp_seq_ops); | ||
356 | } | ||
357 | |||
358 | struct 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 |
69 | static int | 70 | int |
70 | print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, | 71 | print_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 */ | ||
262 | static 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 | |||
282 | static 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 | |||
295 | static void exp_seq_stop(struct seq_file *s, void *v) | ||
296 | { | ||
297 | read_unlock_bh(&nf_conntrack_lock); | ||
298 | } | ||
299 | |||
300 | static 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 | |||
319 | static 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 | |||
326 | static int exp_open(struct inode *inode, struct file *file) | ||
327 | { | ||
328 | return seq_open(file, &exp_seq_ops); | ||
329 | } | ||
330 | |||
331 | static 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 | |||
339 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) | 262 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) |
340 | { | 263 | { |
341 | int cpu; | 264 | int cpu; |