diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack.h | 56 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 22 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 39 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 119 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_ftp.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 39 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_standalone.c | 1 | ||||
-rw-r--r-- | net/netfilter/xt_helper.c | 8 |
8 files changed, 148 insertions, 138 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 6d075ca16e6e..2743c156caa0 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -67,6 +67,18 @@ do { \ | |||
67 | 67 | ||
68 | struct nf_conntrack_helper; | 68 | struct nf_conntrack_helper; |
69 | 69 | ||
70 | /* nf_conn feature for connections that have a helper */ | ||
71 | struct nf_conn_help { | ||
72 | /* Helper. if any */ | ||
73 | struct nf_conntrack_helper *helper; | ||
74 | |||
75 | union nf_conntrack_help help; | ||
76 | |||
77 | /* Current number of expected connections */ | ||
78 | unsigned int expecting; | ||
79 | }; | ||
80 | |||
81 | |||
70 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 82 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
71 | struct nf_conn | 83 | struct nf_conn |
72 | { | 84 | { |
@@ -81,6 +93,9 @@ struct nf_conn | |||
81 | /* Have we seen traffic both ways yet? (bitset) */ | 93 | /* Have we seen traffic both ways yet? (bitset) */ |
82 | unsigned long status; | 94 | unsigned long status; |
83 | 95 | ||
96 | /* If we were expected by an expectation, this will be it */ | ||
97 | struct nf_conn *master; | ||
98 | |||
84 | /* Timer function; drops refcnt when it goes off. */ | 99 | /* Timer function; drops refcnt when it goes off. */ |
85 | struct timer_list timeout; | 100 | struct timer_list timeout; |
86 | 101 | ||
@@ -88,38 +103,22 @@ struct nf_conn | |||
88 | /* Accounting Information (same cache line as other written members) */ | 103 | /* Accounting Information (same cache line as other written members) */ |
89 | struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; | 104 | struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; |
90 | #endif | 105 | #endif |
91 | /* If we were expected by an expectation, this will be it */ | ||
92 | struct nf_conn *master; | ||
93 | |||
94 | /* Current number of expected connections */ | ||
95 | unsigned int expecting; | ||
96 | 106 | ||
97 | /* Unique ID that identifies this conntrack*/ | 107 | /* Unique ID that identifies this conntrack*/ |
98 | unsigned int id; | 108 | unsigned int id; |
99 | 109 | ||
100 | /* Helper. if any */ | ||
101 | struct nf_conntrack_helper *helper; | ||
102 | |||
103 | /* features - nat, helper, ... used by allocating system */ | 110 | /* features - nat, helper, ... used by allocating system */ |
104 | u_int32_t features; | 111 | u_int32_t features; |
105 | 112 | ||
106 | /* Storage reserved for other modules: */ | ||
107 | |||
108 | union nf_conntrack_proto proto; | ||
109 | |||
110 | #if defined(CONFIG_NF_CONNTRACK_MARK) | 113 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
111 | u_int32_t mark; | 114 | u_int32_t mark; |
112 | #endif | 115 | #endif |
113 | 116 | ||
114 | /* These members are dynamically allocated. */ | 117 | /* Storage reserved for other modules: */ |
115 | 118 | union nf_conntrack_proto proto; | |
116 | union nf_conntrack_help *help; | ||
117 | 119 | ||
118 | /* Layer 3 dependent members. (ex: NAT) */ | 120 | /* features dynamically at the end: helper, nat (both optional) */ |
119 | union { | 121 | char data[0]; |
120 | struct nf_conntrack_ipv4 *ipv4; | ||
121 | } l3proto; | ||
122 | void *data[0]; | ||
123 | }; | 122 | }; |
124 | 123 | ||
125 | struct nf_conntrack_expect | 124 | struct nf_conntrack_expect |
@@ -373,10 +372,23 @@ nf_conntrack_expect_event(enum ip_conntrack_expect_events event, | |||
373 | #define NF_CT_F_NUM 4 | 372 | #define NF_CT_F_NUM 4 |
374 | 373 | ||
375 | extern int | 374 | extern int |
376 | nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size, | 375 | nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size); |
377 | int (*init_conntrack)(struct nf_conn *, u_int32_t)); | ||
378 | extern void | 376 | extern void |
379 | nf_conntrack_unregister_cache(u_int32_t features); | 377 | nf_conntrack_unregister_cache(u_int32_t features); |
380 | 378 | ||
379 | /* valid combinations: | ||
380 | * basic: nf_conn, nf_conn .. nf_conn_help | ||
381 | * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help | ||
382 | */ | ||
383 | static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) | ||
384 | { | ||
385 | unsigned int offset = sizeof(struct nf_conn); | ||
386 | |||
387 | if (!(ct->features & NF_CT_F_HELP)) | ||
388 | return NULL; | ||
389 | |||
390 | return (struct nf_conn_help *) ((void *)ct + offset); | ||
391 | } | ||
392 | |||
381 | #endif /* __KERNEL__ */ | 393 | #endif /* __KERNEL__ */ |
382 | #endif /* _NF_CONNTRACK_H */ | 394 | #endif /* _NF_CONNTRACK_H */ |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 6c8624a54933..cb9c661f3f33 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -141,19 +141,21 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum, | |||
141 | { | 141 | { |
142 | struct nf_conn *ct; | 142 | struct nf_conn *ct; |
143 | enum ip_conntrack_info ctinfo; | 143 | enum ip_conntrack_info ctinfo; |
144 | struct nf_conn_help *help; | ||
144 | 145 | ||
145 | /* This is where we call the helper: as the packet goes out. */ | 146 | /* This is where we call the helper: as the packet goes out. */ |
146 | ct = nf_ct_get(*pskb, &ctinfo); | 147 | ct = nf_ct_get(*pskb, &ctinfo); |
147 | if (ct && ct->helper) { | 148 | if (!ct) |
148 | unsigned int ret; | 149 | return NF_ACCEPT; |
149 | ret = ct->helper->help(pskb, | 150 | |
150 | (*pskb)->nh.raw - (*pskb)->data | 151 | help = nfct_help(ct); |
151 | + (*pskb)->nh.iph->ihl*4, | 152 | if (!help || !help->helper) |
152 | ct, ctinfo); | 153 | return NF_ACCEPT; |
153 | if (ret != NF_ACCEPT) | 154 | |
154 | return ret; | 155 | return help->helper->help(pskb, |
155 | } | 156 | (*pskb)->nh.raw - (*pskb)->data |
156 | return NF_ACCEPT; | 157 | + (*pskb)->nh.iph->ihl*4, |
158 | ct, ctinfo); | ||
157 | } | 159 | } |
158 | 160 | ||
159 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, | 161 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index ac702a29dd16..ac35f9526368 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -179,31 +179,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
179 | int (*okfn)(struct sk_buff *)) | 179 | int (*okfn)(struct sk_buff *)) |
180 | { | 180 | { |
181 | struct nf_conn *ct; | 181 | struct nf_conn *ct; |
182 | struct nf_conn_help *help; | ||
182 | enum ip_conntrack_info ctinfo; | 183 | enum ip_conntrack_info ctinfo; |
184 | unsigned int ret, protoff; | ||
185 | unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) | ||
186 | - (*pskb)->data; | ||
187 | unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
188 | |||
183 | 189 | ||
184 | /* This is where we call the helper: as the packet goes out. */ | 190 | /* This is where we call the helper: as the packet goes out. */ |
185 | ct = nf_ct_get(*pskb, &ctinfo); | 191 | ct = nf_ct_get(*pskb, &ctinfo); |
186 | if (ct && ct->helper) { | 192 | if (!ct) |
187 | unsigned int ret, protoff; | 193 | goto out; |
188 | unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) | ||
189 | - (*pskb)->data; | ||
190 | unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
191 | |||
192 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
193 | (*pskb)->len - extoff); | ||
194 | if (protoff < 0 || protoff > (*pskb)->len || | ||
195 | pnum == NEXTHDR_FRAGMENT) { | ||
196 | DEBUGP("proto header not found\n"); | ||
197 | return NF_ACCEPT; | ||
198 | } | ||
199 | 194 | ||
200 | ret = ct->helper->help(pskb, protoff, ct, ctinfo); | 195 | help = nfct_help(ct); |
201 | if (ret != NF_ACCEPT) | 196 | if (!help || !help->helper) |
202 | return ret; | 197 | goto out; |
198 | |||
199 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
200 | (*pskb)->len - extoff); | ||
201 | if (protoff < 0 || protoff > (*pskb)->len || | ||
202 | pnum == NEXTHDR_FRAGMENT) { | ||
203 | DEBUGP("proto header not found\n"); | ||
204 | return NF_ACCEPT; | ||
203 | } | 205 | } |
204 | 206 | ||
207 | ret = help->helper->help(pskb, protoff, ct, ctinfo); | ||
208 | if (ret != NF_ACCEPT) | ||
209 | return ret; | ||
210 | out: | ||
205 | /* We've seen it coming out the other side: confirm it */ | 211 | /* We've seen it coming out the other side: confirm it */ |
206 | |||
207 | return nf_conntrack_confirm(pskb); | 212 | return nf_conntrack_confirm(pskb); |
208 | } | 213 | } |
209 | 214 | ||
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index d622ddf08bb0..dc68d0022218 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -3,7 +3,7 @@ | |||
3 | extension. */ | 3 | extension. */ |
4 | 4 | ||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | 5 | /* (C) 1999-2001 Paul `Rusty' Russell |
6 | * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org> | 6 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> |
7 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> | 7 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
@@ -20,6 +20,9 @@ | |||
20 | * - generalize L3 protocol denendent part. | 20 | * - generalize L3 protocol denendent part. |
21 | * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | 21 | * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> |
22 | * - add support various size of conntrack structures. | 22 | * - add support various size of conntrack structures. |
23 | * 26 Jan 2006: Harald Welte <laforge@netfilter.org> | ||
24 | * - restructure nf_conn (introduce nf_conn_help) | ||
25 | * - redesign 'features' how they were originally intended | ||
23 | * | 26 | * |
24 | * Derived from net/ipv4/netfilter/ip_conntrack_core.c | 27 | * Derived from net/ipv4/netfilter/ip_conntrack_core.c |
25 | */ | 28 | */ |
@@ -55,7 +58,7 @@ | |||
55 | #include <net/netfilter/nf_conntrack_core.h> | 58 | #include <net/netfilter/nf_conntrack_core.h> |
56 | #include <linux/netfilter_ipv4/listhelp.h> | 59 | #include <linux/netfilter_ipv4/listhelp.h> |
57 | 60 | ||
58 | #define NF_CONNTRACK_VERSION "0.4.1" | 61 | #define NF_CONNTRACK_VERSION "0.5.0" |
59 | 62 | ||
60 | #if 0 | 63 | #if 0 |
61 | #define DEBUGP printk | 64 | #define DEBUGP printk |
@@ -259,21 +262,8 @@ static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple) | |||
259 | nf_conntrack_hash_rnd); | 262 | nf_conntrack_hash_rnd); |
260 | } | 263 | } |
261 | 264 | ||
262 | /* Initialize "struct nf_conn" which has spaces for helper */ | ||
263 | static int | ||
264 | init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features) | ||
265 | { | ||
266 | |||
267 | conntrack->help = (union nf_conntrack_help *) | ||
268 | (((unsigned long)conntrack->data | ||
269 | + (__alignof__(union nf_conntrack_help) - 1)) | ||
270 | & (~((unsigned long)(__alignof__(union nf_conntrack_help) -1)))); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | int nf_conntrack_register_cache(u_int32_t features, const char *name, | 265 | int nf_conntrack_register_cache(u_int32_t features, const char *name, |
275 | size_t size, | 266 | size_t size) |
276 | int (*init)(struct nf_conn *, u_int32_t)) | ||
277 | { | 267 | { |
278 | int ret = 0; | 268 | int ret = 0; |
279 | char *cache_name; | 269 | char *cache_name; |
@@ -296,8 +286,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, | |||
296 | DEBUGP("nf_conntrack_register_cache: already resisterd.\n"); | 286 | DEBUGP("nf_conntrack_register_cache: already resisterd.\n"); |
297 | if ((!strncmp(nf_ct_cache[features].name, name, | 287 | if ((!strncmp(nf_ct_cache[features].name, name, |
298 | NF_CT_FEATURES_NAMELEN)) | 288 | NF_CT_FEATURES_NAMELEN)) |
299 | && nf_ct_cache[features].size == size | 289 | && nf_ct_cache[features].size == size) { |
300 | && nf_ct_cache[features].init_conntrack == init) { | ||
301 | DEBUGP("nf_conntrack_register_cache: reusing.\n"); | 290 | DEBUGP("nf_conntrack_register_cache: reusing.\n"); |
302 | nf_ct_cache[features].use++; | 291 | nf_ct_cache[features].use++; |
303 | ret = 0; | 292 | ret = 0; |
@@ -340,7 +329,6 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, | |||
340 | write_lock_bh(&nf_ct_cache_lock); | 329 | write_lock_bh(&nf_ct_cache_lock); |
341 | nf_ct_cache[features].use = 1; | 330 | nf_ct_cache[features].use = 1; |
342 | nf_ct_cache[features].size = size; | 331 | nf_ct_cache[features].size = size; |
343 | nf_ct_cache[features].init_conntrack = init; | ||
344 | nf_ct_cache[features].cachep = cachep; | 332 | nf_ct_cache[features].cachep = cachep; |
345 | nf_ct_cache[features].name = cache_name; | 333 | nf_ct_cache[features].name = cache_name; |
346 | write_unlock_bh(&nf_ct_cache_lock); | 334 | write_unlock_bh(&nf_ct_cache_lock); |
@@ -377,7 +365,6 @@ void nf_conntrack_unregister_cache(u_int32_t features) | |||
377 | name = nf_ct_cache[features].name; | 365 | name = nf_ct_cache[features].name; |
378 | nf_ct_cache[features].cachep = NULL; | 366 | nf_ct_cache[features].cachep = NULL; |
379 | nf_ct_cache[features].name = NULL; | 367 | nf_ct_cache[features].name = NULL; |
380 | nf_ct_cache[features].init_conntrack = NULL; | ||
381 | nf_ct_cache[features].size = 0; | 368 | nf_ct_cache[features].size = 0; |
382 | write_unlock_bh(&nf_ct_cache_lock); | 369 | write_unlock_bh(&nf_ct_cache_lock); |
383 | 370 | ||
@@ -432,11 +419,15 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, | |||
432 | /* nf_conntrack_expect helper functions */ | 419 | /* nf_conntrack_expect helper functions */ |
433 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) | 420 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) |
434 | { | 421 | { |
422 | struct nf_conn_help *master_help = nfct_help(exp->master); | ||
423 | |||
424 | NF_CT_ASSERT(master_help); | ||
435 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); | 425 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); |
436 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); | 426 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); |
427 | |||
437 | list_del(&exp->list); | 428 | list_del(&exp->list); |
438 | NF_CT_STAT_INC(expect_delete); | 429 | NF_CT_STAT_INC(expect_delete); |
439 | exp->master->expecting--; | 430 | master_help->expecting--; |
440 | nf_conntrack_expect_put(exp); | 431 | nf_conntrack_expect_put(exp); |
441 | } | 432 | } |
442 | 433 | ||
@@ -508,9 +499,10 @@ find_expectation(const struct nf_conntrack_tuple *tuple) | |||
508 | void nf_ct_remove_expectations(struct nf_conn *ct) | 499 | void nf_ct_remove_expectations(struct nf_conn *ct) |
509 | { | 500 | { |
510 | struct nf_conntrack_expect *i, *tmp; | 501 | struct nf_conntrack_expect *i, *tmp; |
502 | struct nf_conn_help *help = nfct_help(ct); | ||
511 | 503 | ||
512 | /* Optimization: most connection never expect any others. */ | 504 | /* Optimization: most connection never expect any others. */ |
513 | if (ct->expecting == 0) | 505 | if (!help || help->expecting == 0) |
514 | return; | 506 | return; |
515 | 507 | ||
516 | list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) { | 508 | list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) { |
@@ -713,6 +705,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb) | |||
713 | conntrack_tuple_cmp, | 705 | conntrack_tuple_cmp, |
714 | struct nf_conntrack_tuple_hash *, | 706 | struct nf_conntrack_tuple_hash *, |
715 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { | 707 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { |
708 | struct nf_conn_help *help; | ||
716 | /* Remove from unconfirmed list */ | 709 | /* Remove from unconfirmed list */ |
717 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | 710 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); |
718 | 711 | ||
@@ -726,7 +719,8 @@ __nf_conntrack_confirm(struct sk_buff **pskb) | |||
726 | set_bit(IPS_CONFIRMED_BIT, &ct->status); | 719 | set_bit(IPS_CONFIRMED_BIT, &ct->status); |
727 | NF_CT_STAT_INC(insert); | 720 | NF_CT_STAT_INC(insert); |
728 | write_unlock_bh(&nf_conntrack_lock); | 721 | write_unlock_bh(&nf_conntrack_lock); |
729 | if (ct->helper) | 722 | help = nfct_help(ct); |
723 | if (help && help->helper) | ||
730 | nf_conntrack_event_cache(IPCT_HELPER, *pskb); | 724 | nf_conntrack_event_cache(IPCT_HELPER, *pskb); |
731 | #ifdef CONFIG_NF_NAT_NEEDED | 725 | #ifdef CONFIG_NF_NAT_NEEDED |
732 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || | 726 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || |
@@ -842,8 +836,9 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
842 | { | 836 | { |
843 | struct nf_conn *conntrack = NULL; | 837 | struct nf_conn *conntrack = NULL; |
844 | u_int32_t features = 0; | 838 | u_int32_t features = 0; |
839 | struct nf_conntrack_helper *helper; | ||
845 | 840 | ||
846 | if (!nf_conntrack_hash_rnd_initted) { | 841 | if (unlikely(!nf_conntrack_hash_rnd_initted)) { |
847 | get_random_bytes(&nf_conntrack_hash_rnd, 4); | 842 | get_random_bytes(&nf_conntrack_hash_rnd, 4); |
848 | nf_conntrack_hash_rnd_initted = 1; | 843 | nf_conntrack_hash_rnd_initted = 1; |
849 | } | 844 | } |
@@ -863,8 +858,11 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
863 | 858 | ||
864 | /* find features needed by this conntrack. */ | 859 | /* find features needed by this conntrack. */ |
865 | features = l3proto->get_features(orig); | 860 | features = l3proto->get_features(orig); |
861 | |||
862 | /* FIXME: protect helper list per RCU */ | ||
866 | read_lock_bh(&nf_conntrack_lock); | 863 | read_lock_bh(&nf_conntrack_lock); |
867 | if (__nf_ct_helper_find(repl) != NULL) | 864 | helper = __nf_ct_helper_find(repl); |
865 | if (helper) | ||
868 | features |= NF_CT_F_HELP; | 866 | features |= NF_CT_F_HELP; |
869 | read_unlock_bh(&nf_conntrack_lock); | 867 | read_unlock_bh(&nf_conntrack_lock); |
870 | 868 | ||
@@ -872,7 +870,7 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
872 | 870 | ||
873 | read_lock_bh(&nf_ct_cache_lock); | 871 | read_lock_bh(&nf_ct_cache_lock); |
874 | 872 | ||
875 | if (!nf_ct_cache[features].use) { | 873 | if (unlikely(!nf_ct_cache[features].use)) { |
876 | DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n", | 874 | DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n", |
877 | features); | 875 | features); |
878 | goto out; | 876 | goto out; |
@@ -886,12 +884,10 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
886 | 884 | ||
887 | memset(conntrack, 0, nf_ct_cache[features].size); | 885 | memset(conntrack, 0, nf_ct_cache[features].size); |
888 | conntrack->features = features; | 886 | conntrack->features = features; |
889 | if (nf_ct_cache[features].init_conntrack && | 887 | if (helper) { |
890 | nf_ct_cache[features].init_conntrack(conntrack, features) < 0) { | 888 | struct nf_conn_help *help = nfct_help(conntrack); |
891 | DEBUGP("nf_conntrack_alloc: failed to init\n"); | 889 | NF_CT_ASSERT(help); |
892 | kmem_cache_free(nf_ct_cache[features].cachep, conntrack); | 890 | help->helper = helper; |
893 | conntrack = NULL; | ||
894 | goto out; | ||
895 | } | 891 | } |
896 | 892 | ||
897 | atomic_set(&conntrack->ct_general.use, 1); | 893 | atomic_set(&conntrack->ct_general.use, 1); |
@@ -972,11 +968,8 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
972 | #endif | 968 | #endif |
973 | nf_conntrack_get(&conntrack->master->ct_general); | 969 | nf_conntrack_get(&conntrack->master->ct_general); |
974 | NF_CT_STAT_INC(expect_new); | 970 | NF_CT_STAT_INC(expect_new); |
975 | } else { | 971 | } else |
976 | conntrack->helper = __nf_ct_helper_find(&repl_tuple); | ||
977 | |||
978 | NF_CT_STAT_INC(new); | 972 | NF_CT_STAT_INC(new); |
979 | } | ||
980 | 973 | ||
981 | /* Overload tuple linked list to put us in unconfirmed list. */ | 974 | /* Overload tuple linked list to put us in unconfirmed list. */ |
982 | list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); | 975 | list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); |
@@ -1206,14 +1199,16 @@ void nf_conntrack_expect_put(struct nf_conntrack_expect *exp) | |||
1206 | 1199 | ||
1207 | static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) | 1200 | static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) |
1208 | { | 1201 | { |
1202 | struct nf_conn_help *master_help = nfct_help(exp->master); | ||
1203 | |||
1209 | atomic_inc(&exp->use); | 1204 | atomic_inc(&exp->use); |
1210 | exp->master->expecting++; | 1205 | master_help->expecting++; |
1211 | list_add(&exp->list, &nf_conntrack_expect_list); | 1206 | list_add(&exp->list, &nf_conntrack_expect_list); |
1212 | 1207 | ||
1213 | init_timer(&exp->timeout); | 1208 | init_timer(&exp->timeout); |
1214 | exp->timeout.data = (unsigned long)exp; | 1209 | exp->timeout.data = (unsigned long)exp; |
1215 | exp->timeout.function = expectation_timed_out; | 1210 | exp->timeout.function = expectation_timed_out; |
1216 | exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; | 1211 | exp->timeout.expires = jiffies + master_help->helper->timeout * HZ; |
1217 | add_timer(&exp->timeout); | 1212 | add_timer(&exp->timeout); |
1218 | 1213 | ||
1219 | exp->id = ++nf_conntrack_expect_next_id; | 1214 | exp->id = ++nf_conntrack_expect_next_id; |
@@ -1239,10 +1234,12 @@ static void evict_oldest_expect(struct nf_conn *master) | |||
1239 | 1234 | ||
1240 | static inline int refresh_timer(struct nf_conntrack_expect *i) | 1235 | static inline int refresh_timer(struct nf_conntrack_expect *i) |
1241 | { | 1236 | { |
1237 | struct nf_conn_help *master_help = nfct_help(i->master); | ||
1238 | |||
1242 | if (!del_timer(&i->timeout)) | 1239 | if (!del_timer(&i->timeout)) |
1243 | return 0; | 1240 | return 0; |
1244 | 1241 | ||
1245 | i->timeout.expires = jiffies + i->master->helper->timeout*HZ; | 1242 | i->timeout.expires = jiffies + master_help->helper->timeout*HZ; |
1246 | add_timer(&i->timeout); | 1243 | add_timer(&i->timeout); |
1247 | return 1; | 1244 | return 1; |
1248 | } | 1245 | } |
@@ -1251,8 +1248,11 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | |||
1251 | { | 1248 | { |
1252 | struct nf_conntrack_expect *i; | 1249 | struct nf_conntrack_expect *i; |
1253 | struct nf_conn *master = expect->master; | 1250 | struct nf_conn *master = expect->master; |
1251 | struct nf_conn_help *master_help = nfct_help(master); | ||
1254 | int ret; | 1252 | int ret; |
1255 | 1253 | ||
1254 | NF_CT_ASSERT(master_help); | ||
1255 | |||
1256 | DEBUGP("nf_conntrack_expect_related %p\n", related_to); | 1256 | DEBUGP("nf_conntrack_expect_related %p\n", related_to); |
1257 | DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple); | 1257 | DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple); |
1258 | DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask); | 1258 | DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask); |
@@ -1271,8 +1271,8 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | |||
1271 | } | 1271 | } |
1272 | } | 1272 | } |
1273 | /* Will be over limit? */ | 1273 | /* Will be over limit? */ |
1274 | if (master->helper->max_expected && | 1274 | if (master_help->helper->max_expected && |
1275 | master->expecting >= master->helper->max_expected) | 1275 | master_help->expecting >= master_help->helper->max_expected) |
1276 | evict_oldest_expect(master); | 1276 | evict_oldest_expect(master); |
1277 | 1277 | ||
1278 | nf_conntrack_expect_insert(expect); | 1278 | nf_conntrack_expect_insert(expect); |
@@ -1283,24 +1283,6 @@ out: | |||
1283 | return ret; | 1283 | return ret; |
1284 | } | 1284 | } |
1285 | 1285 | ||
1286 | /* Alter reply tuple (maybe alter helper). This is for NAT, and is | ||
1287 | implicitly racy: see __nf_conntrack_confirm */ | ||
1288 | void nf_conntrack_alter_reply(struct nf_conn *conntrack, | ||
1289 | const struct nf_conntrack_tuple *newreply) | ||
1290 | { | ||
1291 | write_lock_bh(&nf_conntrack_lock); | ||
1292 | /* Should be unconfirmed, so not in hash table yet */ | ||
1293 | NF_CT_ASSERT(!nf_ct_is_confirmed(conntrack)); | ||
1294 | |||
1295 | DEBUGP("Altering reply tuple of %p to ", conntrack); | ||
1296 | NF_CT_DUMP_TUPLE(newreply); | ||
1297 | |||
1298 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | ||
1299 | if (!conntrack->master && conntrack->expecting == 0) | ||
1300 | conntrack->helper = __nf_ct_helper_find(newreply); | ||
1301 | write_unlock_bh(&nf_conntrack_lock); | ||
1302 | } | ||
1303 | |||
1304 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | 1286 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) |
1305 | { | 1287 | { |
1306 | int ret; | 1288 | int ret; |
@@ -1308,9 +1290,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | |||
1308 | 1290 | ||
1309 | ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", | 1291 | ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", |
1310 | sizeof(struct nf_conn) | 1292 | sizeof(struct nf_conn) |
1311 | + sizeof(union nf_conntrack_help) | 1293 | + sizeof(struct nf_conn_help) |
1312 | + __alignof__(union nf_conntrack_help), | 1294 | + __alignof__(struct nf_conn_help)); |
1313 | init_conntrack_for_helper); | ||
1314 | if (ret < 0) { | 1295 | if (ret < 0) { |
1315 | printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n"); | 1296 | printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n"); |
1316 | return ret; | 1297 | return ret; |
@@ -1338,9 +1319,12 @@ __nf_conntrack_helper_find_byname(const char *name) | |||
1338 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, | 1319 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, |
1339 | const struct nf_conntrack_helper *me) | 1320 | const struct nf_conntrack_helper *me) |
1340 | { | 1321 | { |
1341 | if (nf_ct_tuplehash_to_ctrack(i)->helper == me) { | 1322 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i); |
1342 | nf_conntrack_event(IPCT_HELPER, nf_ct_tuplehash_to_ctrack(i)); | 1323 | struct nf_conn_help *help = nfct_help(ct); |
1343 | nf_ct_tuplehash_to_ctrack(i)->helper = NULL; | 1324 | |
1325 | if (help && help->helper == me) { | ||
1326 | nf_conntrack_event(IPCT_HELPER, ct); | ||
1327 | help->helper = NULL; | ||
1344 | } | 1328 | } |
1345 | return 0; | 1329 | return 0; |
1346 | } | 1330 | } |
@@ -1356,7 +1340,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | |||
1356 | 1340 | ||
1357 | /* Get rid of expectations */ | 1341 | /* Get rid of expectations */ |
1358 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { | 1342 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { |
1359 | if (exp->master->helper == me && del_timer(&exp->timeout)) { | 1343 | struct nf_conn_help *help = nfct_help(exp->master); |
1344 | if (help->helper == me && del_timer(&exp->timeout)) { | ||
1360 | nf_ct_unlink_expect(exp); | 1345 | nf_ct_unlink_expect(exp); |
1361 | nf_conntrack_expect_put(exp); | 1346 | nf_conntrack_expect_put(exp); |
1362 | } | 1347 | } |
@@ -1697,7 +1682,7 @@ int __init nf_conntrack_init(void) | |||
1697 | } | 1682 | } |
1698 | 1683 | ||
1699 | ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic", | 1684 | ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic", |
1700 | sizeof(struct nf_conn), NULL); | 1685 | sizeof(struct nf_conn)); |
1701 | if (ret < 0) { | 1686 | if (ret < 0) { |
1702 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); | 1687 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); |
1703 | goto err_free_hash; | 1688 | goto err_free_hash; |
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 6f210f399762..cd191b0d4ac7 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c | |||
@@ -440,7 +440,7 @@ static int help(struct sk_buff **pskb, | |||
440 | u32 seq; | 440 | u32 seq; |
441 | int dir = CTINFO2DIR(ctinfo); | 441 | int dir = CTINFO2DIR(ctinfo); |
442 | unsigned int matchlen, matchoff; | 442 | unsigned int matchlen, matchoff; |
443 | struct ip_ct_ftp_master *ct_ftp_info = &ct->help->ct_ftp_info; | 443 | struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; |
444 | struct nf_conntrack_expect *exp; | 444 | struct nf_conntrack_expect *exp; |
445 | struct nf_conntrack_man cmd = {}; | 445 | struct nf_conntrack_man cmd = {}; |
446 | 446 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 9ff3463037e1..aef3cb41131f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * protocol helpers and general trouble making from userspace. | 2 | * protocol helpers and general trouble making from userspace. |
3 | * | 3 | * |
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | 4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> |
5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> | 5 | * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> |
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | 6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> |
7 | * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> | 7 | * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> |
8 | * | 8 | * |
@@ -44,7 +44,7 @@ | |||
44 | 44 | ||
45 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
46 | 46 | ||
47 | static char __initdata version[] = "0.92"; | 47 | static char __initdata version[] = "0.93"; |
48 | 48 | ||
49 | #if 0 | 49 | #if 0 |
50 | #define DEBUGP printk | 50 | #define DEBUGP printk |
@@ -165,15 +165,16 @@ static inline int | |||
165 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) | 165 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) |
166 | { | 166 | { |
167 | struct nfattr *nest_helper; | 167 | struct nfattr *nest_helper; |
168 | const struct nf_conn_help *help = nfct_help(ct); | ||
168 | 169 | ||
169 | if (!ct->helper) | 170 | if (!help || !help->helper) |
170 | return 0; | 171 | return 0; |
171 | 172 | ||
172 | nest_helper = NFA_NEST(skb, CTA_HELP); | 173 | nest_helper = NFA_NEST(skb, CTA_HELP); |
173 | NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); | 174 | NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name); |
174 | 175 | ||
175 | if (ct->helper->to_nfattr) | 176 | if (help->helper->to_nfattr) |
176 | ct->helper->to_nfattr(skb, ct); | 177 | help->helper->to_nfattr(skb, ct); |
177 | 178 | ||
178 | NFA_NEST_END(skb, nest_helper); | 179 | NFA_NEST_END(skb, nest_helper); |
179 | 180 | ||
@@ -903,11 +904,17 @@ static inline int | |||
903 | ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | 904 | ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) |
904 | { | 905 | { |
905 | struct nf_conntrack_helper *helper; | 906 | struct nf_conntrack_helper *helper; |
907 | struct nf_conn_help *help = nfct_help(ct); | ||
906 | char *helpname; | 908 | char *helpname; |
907 | int err; | 909 | int err; |
908 | 910 | ||
909 | DEBUGP("entered %s\n", __FUNCTION__); | 911 | DEBUGP("entered %s\n", __FUNCTION__); |
910 | 912 | ||
913 | if (!help) { | ||
914 | /* FIXME: we need to reallocate and rehash */ | ||
915 | return -EBUSY; | ||
916 | } | ||
917 | |||
911 | /* don't change helper of sibling connections */ | 918 | /* don't change helper of sibling connections */ |
912 | if (ct->master) | 919 | if (ct->master) |
913 | return -EINVAL; | 920 | return -EINVAL; |
@@ -924,18 +931,18 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | |||
924 | return -EINVAL; | 931 | return -EINVAL; |
925 | } | 932 | } |
926 | 933 | ||
927 | if (ct->helper) { | 934 | if (help->helper) { |
928 | if (!helper) { | 935 | if (!helper) { |
929 | /* we had a helper before ... */ | 936 | /* we had a helper before ... */ |
930 | nf_ct_remove_expectations(ct); | 937 | nf_ct_remove_expectations(ct); |
931 | ct->helper = NULL; | 938 | help->helper = NULL; |
932 | } else { | 939 | } else { |
933 | /* need to zero data of old helper */ | 940 | /* need to zero data of old helper */ |
934 | memset(&ct->help, 0, sizeof(ct->help)); | 941 | memset(&help->help, 0, sizeof(help->help)); |
935 | } | 942 | } |
936 | } | 943 | } |
937 | 944 | ||
938 | ct->helper = helper; | 945 | help->helper = helper; |
939 | 946 | ||
940 | return 0; | 947 | return 0; |
941 | } | 948 | } |
@@ -1050,14 +1057,9 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
1050 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | 1057 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); |
1051 | #endif | 1058 | #endif |
1052 | 1059 | ||
1053 | ct->helper = nf_ct_helper_find_get(rtuple); | ||
1054 | |||
1055 | add_timer(&ct->timeout); | 1060 | add_timer(&ct->timeout); |
1056 | nf_conntrack_hash_insert(ct); | 1061 | nf_conntrack_hash_insert(ct); |
1057 | 1062 | ||
1058 | if (ct->helper) | ||
1059 | nf_ct_helper_put(ct->helper); | ||
1060 | |||
1061 | DEBUGP("conntrack with id %u inserted\n", ct->id); | 1063 | DEBUGP("conntrack with id %u inserted\n", ct->id); |
1062 | return 0; | 1064 | return 0; |
1063 | 1065 | ||
@@ -1417,7 +1419,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1417 | } | 1419 | } |
1418 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, | 1420 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, |
1419 | list) { | 1421 | list) { |
1420 | if (exp->master->helper == h | 1422 | struct nf_conn_help *m_help = nfct_help(exp->master); |
1423 | if (m_help->helper == h | ||
1421 | && del_timer(&exp->timeout)) { | 1424 | && del_timer(&exp->timeout)) { |
1422 | nf_ct_unlink_expect(exp); | 1425 | nf_ct_unlink_expect(exp); |
1423 | nf_conntrack_expect_put(exp); | 1426 | nf_conntrack_expect_put(exp); |
@@ -1452,6 +1455,7 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) | |||
1452 | struct nf_conntrack_tuple_hash *h = NULL; | 1455 | struct nf_conntrack_tuple_hash *h = NULL; |
1453 | struct nf_conntrack_expect *exp; | 1456 | struct nf_conntrack_expect *exp; |
1454 | struct nf_conn *ct; | 1457 | struct nf_conn *ct; |
1458 | struct nf_conn_help *help; | ||
1455 | int err = 0; | 1459 | int err = 0; |
1456 | 1460 | ||
1457 | DEBUGP("entered %s\n", __FUNCTION__); | 1461 | DEBUGP("entered %s\n", __FUNCTION__); |
@@ -1472,8 +1476,9 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) | |||
1472 | if (!h) | 1476 | if (!h) |
1473 | return -ENOENT; | 1477 | return -ENOENT; |
1474 | ct = nf_ct_tuplehash_to_ctrack(h); | 1478 | ct = nf_ct_tuplehash_to_ctrack(h); |
1479 | help = nfct_help(ct); | ||
1475 | 1480 | ||
1476 | if (!ct->helper) { | 1481 | if (!help || !help->helper) { |
1477 | /* such conntrack hasn't got any helper, abort */ | 1482 | /* such conntrack hasn't got any helper, abort */ |
1478 | err = -EINVAL; | 1483 | err = -EINVAL; |
1479 | goto out; | 1484 | goto out; |
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 617599aeeead..290d5a0c559b 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -839,7 +839,6 @@ EXPORT_SYMBOL(nf_conntrack_l3proto_unregister); | |||
839 | EXPORT_SYMBOL(nf_conntrack_protocol_register); | 839 | EXPORT_SYMBOL(nf_conntrack_protocol_register); |
840 | EXPORT_SYMBOL(nf_conntrack_protocol_unregister); | 840 | EXPORT_SYMBOL(nf_conntrack_protocol_unregister); |
841 | EXPORT_SYMBOL(nf_ct_invert_tuplepr); | 841 | EXPORT_SYMBOL(nf_ct_invert_tuplepr); |
842 | EXPORT_SYMBOL(nf_conntrack_alter_reply); | ||
843 | EXPORT_SYMBOL(nf_conntrack_destroyed); | 842 | EXPORT_SYMBOL(nf_conntrack_destroyed); |
844 | EXPORT_SYMBOL(need_conntrack); | 843 | EXPORT_SYMBOL(need_conntrack); |
845 | EXPORT_SYMBOL(nf_conntrack_helper_register); | 844 | EXPORT_SYMBOL(nf_conntrack_helper_register); |
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c index 38b6715e1db4..0ddb32363d06 100644 --- a/net/netfilter/xt_helper.c +++ b/net/netfilter/xt_helper.c | |||
@@ -96,6 +96,7 @@ match(const struct sk_buff *skb, | |||
96 | { | 96 | { |
97 | const struct xt_helper_info *info = matchinfo; | 97 | const struct xt_helper_info *info = matchinfo; |
98 | struct nf_conn *ct; | 98 | struct nf_conn *ct; |
99 | struct nf_conn_help *master_help; | ||
99 | enum ip_conntrack_info ctinfo; | 100 | enum ip_conntrack_info ctinfo; |
100 | int ret = info->invert; | 101 | int ret = info->invert; |
101 | 102 | ||
@@ -111,7 +112,8 @@ match(const struct sk_buff *skb, | |||
111 | } | 112 | } |
112 | 113 | ||
113 | read_lock_bh(&nf_conntrack_lock); | 114 | read_lock_bh(&nf_conntrack_lock); |
114 | if (!ct->master->helper) { | 115 | master_help = nfct_help(ct->master); |
116 | if (!master_help || !master_help->helper) { | ||
115 | DEBUGP("xt_helper: master ct %p has no helper\n", | 117 | DEBUGP("xt_helper: master ct %p has no helper\n", |
116 | exp->expectant); | 118 | exp->expectant); |
117 | goto out_unlock; | 119 | goto out_unlock; |
@@ -123,8 +125,8 @@ match(const struct sk_buff *skb, | |||
123 | if (info->name[0] == '\0') | 125 | if (info->name[0] == '\0') |
124 | ret ^= 1; | 126 | ret ^= 1; |
125 | else | 127 | else |
126 | ret ^= !strncmp(ct->master->helper->name, info->name, | 128 | ret ^= !strncmp(master_help->helper->name, info->name, |
127 | strlen(ct->master->helper->name)); | 129 | strlen(master_help->helper->name)); |
128 | out_unlock: | 130 | out_unlock: |
129 | read_unlock_bh(&nf_conntrack_lock); | 131 | read_unlock_bh(&nf_conntrack_lock); |
130 | return ret; | 132 | return ret; |