aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter.h9
-rw-r--r--include/net/netfilter/nf_conntrack_extend.h2
-rw-r--r--include/net/netfilter/nf_conntrack_seqadj.h49
-rw-r--r--include/net/netfilter/nf_nat.h10
-rw-r--r--include/net/netfilter/nf_nat_helper.h19
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_common.h3
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_conntrack.h15
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c7
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c7
-rw-r--r--net/netfilter/Makefile2
-rw-r--r--net/netfilter/nf_conntrack_core.c16
-rw-r--r--net/netfilter/nf_conntrack_netlink.c115
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c18
-rw-r--r--net/netfilter/nf_conntrack_seqadj.c218
-rw-r--r--net/netfilter/nf_nat_core.c16
-rw-r--r--net/netfilter/nf_nat_helper.c228
-rw-r--r--net/netfilter/nf_nat_sip.c3
-rw-r--r--net/netfilter/nfnetlink_queue_ct.c8
18 files changed, 369 insertions, 376 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index e2cf786be22f..708fe72ab913 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -319,6 +319,7 @@ extern void nf_ct_attach(struct sk_buff *, const struct sk_buff *);
319extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu; 319extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu;
320 320
321struct nf_conn; 321struct nf_conn;
322enum ip_conntrack_info;
322struct nlattr; 323struct nlattr;
323 324
324struct nfq_ct_hook { 325struct nfq_ct_hook {
@@ -327,14 +328,10 @@ struct nfq_ct_hook {
327 int (*parse)(const struct nlattr *attr, struct nf_conn *ct); 328 int (*parse)(const struct nlattr *attr, struct nf_conn *ct);
328 int (*attach_expect)(const struct nlattr *attr, struct nf_conn *ct, 329 int (*attach_expect)(const struct nlattr *attr, struct nf_conn *ct,
329 u32 portid, u32 report); 330 u32 portid, u32 report);
330};
331extern struct nfq_ct_hook __rcu *nfq_ct_hook;
332
333struct nfq_ct_nat_hook {
334 void (*seq_adjust)(struct sk_buff *skb, struct nf_conn *ct, 331 void (*seq_adjust)(struct sk_buff *skb, struct nf_conn *ct,
335 u32 ctinfo, s32 off); 332 enum ip_conntrack_info ctinfo, s32 off);
336}; 333};
337extern struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook; 334extern struct nfq_ct_hook __rcu *nfq_ct_hook;
338#else 335#else
339static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} 336static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
340#endif 337#endif
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index 977bc8a46444..2a22bcbfe6e4 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -9,6 +9,7 @@ enum nf_ct_ext_id {
9 NF_CT_EXT_HELPER, 9 NF_CT_EXT_HELPER,
10#if defined(CONFIG_NF_NAT) || defined(CONFIG_NF_NAT_MODULE) 10#if defined(CONFIG_NF_NAT) || defined(CONFIG_NF_NAT_MODULE)
11 NF_CT_EXT_NAT, 11 NF_CT_EXT_NAT,
12 NF_CT_EXT_SEQADJ,
12#endif 13#endif
13 NF_CT_EXT_ACCT, 14 NF_CT_EXT_ACCT,
14#ifdef CONFIG_NF_CONNTRACK_EVENTS 15#ifdef CONFIG_NF_CONNTRACK_EVENTS
@@ -31,6 +32,7 @@ enum nf_ct_ext_id {
31 32
32#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help 33#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
33#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat 34#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
35#define NF_CT_EXT_SEQADJ_TYPE struct nf_conn_seqadj
34#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter 36#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter
35#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache 37#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
36#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone 38#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
diff --git a/include/net/netfilter/nf_conntrack_seqadj.h b/include/net/netfilter/nf_conntrack_seqadj.h
new file mode 100644
index 000000000000..30bfbbed9f47
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_seqadj.h
@@ -0,0 +1,49 @@
1#ifndef _NF_CONNTRACK_SEQADJ_H
2#define _NF_CONNTRACK_SEQADJ_H
3
4#include <net/netfilter/nf_conntrack_extend.h>
5
6/**
7 * struct nf_ct_seqadj - sequence number adjustment information
8 *
9 * @correction_pos: position of the last TCP sequence number modification
10 * @offset_before: sequence number offset before last modification
11 * @offset_after: sequence number offset after last modification
12 */
13struct nf_ct_seqadj {
14 u32 correction_pos;
15 s32 offset_before;
16 s32 offset_after;
17};
18
19struct nf_conn_seqadj {
20 struct nf_ct_seqadj seq[IP_CT_DIR_MAX];
21};
22
23static inline struct nf_conn_seqadj *nfct_seqadj(const struct nf_conn *ct)
24{
25 return nf_ct_ext_find(ct, NF_CT_EXT_SEQADJ);
26}
27
28static inline struct nf_conn_seqadj *nfct_seqadj_ext_add(struct nf_conn *ct)
29{
30 return nf_ct_ext_add(ct, NF_CT_EXT_SEQADJ, GFP_ATOMIC);
31}
32
33extern int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
34 __be32 seq, s32 off);
35extern void nf_ct_tcp_seqadj_set(struct sk_buff *skb,
36 struct nf_conn *ct,
37 enum ip_conntrack_info ctinfo,
38 s32 off);
39
40extern int nf_ct_seq_adjust(struct sk_buff *skb,
41 struct nf_conn *ct, enum ip_conntrack_info ctinfo,
42 unsigned int protoff);
43extern s32 nf_ct_seq_offset(const struct nf_conn *ct, enum ip_conntrack_dir,
44 u32 seq);
45
46extern int nf_conntrack_seqadj_init(void);
47extern void nf_conntrack_seqadj_fini(void);
48
49#endif /* _NF_CONNTRACK_SEQADJ_H */
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
index e2441413675c..59a192420053 100644
--- a/include/net/netfilter/nf_nat.h
+++ b/include/net/netfilter/nf_nat.h
@@ -13,15 +13,6 @@ enum nf_nat_manip_type {
13#define HOOK2MANIP(hooknum) ((hooknum) != NF_INET_POST_ROUTING && \ 13#define HOOK2MANIP(hooknum) ((hooknum) != NF_INET_POST_ROUTING && \
14 (hooknum) != NF_INET_LOCAL_IN) 14 (hooknum) != NF_INET_LOCAL_IN)
15 15
16/* NAT sequence number modifications */
17struct nf_nat_seq {
18 /* position of the last TCP sequence number modification (if any) */
19 u_int32_t correction_pos;
20
21 /* sequence number offset before and after last modification */
22 int32_t offset_before, offset_after;
23};
24
25#include <linux/list.h> 16#include <linux/list.h>
26#include <linux/netfilter/nf_conntrack_pptp.h> 17#include <linux/netfilter/nf_conntrack_pptp.h>
27#include <net/netfilter/nf_conntrack_extend.h> 18#include <net/netfilter/nf_conntrack_extend.h>
@@ -39,7 +30,6 @@ struct nf_conn;
39/* The structure embedded in the conntrack structure. */ 30/* The structure embedded in the conntrack structure. */
40struct nf_conn_nat { 31struct nf_conn_nat {
41 struct hlist_node bysource; 32 struct hlist_node bysource;
42 struct nf_nat_seq seq[IP_CT_DIR_MAX];
43 struct nf_conn *ct; 33 struct nf_conn *ct;
44 union nf_conntrack_nat_help help; 34 union nf_conntrack_nat_help help;
45#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ 35#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h
index 194c34794923..404324d1d0c4 100644
--- a/include/net/netfilter/nf_nat_helper.h
+++ b/include/net/netfilter/nf_nat_helper.h
@@ -39,28 +39,9 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
39 const char *rep_buffer, 39 const char *rep_buffer,
40 unsigned int rep_len); 40 unsigned int rep_len);
41 41
42extern void nf_nat_set_seq_adjust(struct nf_conn *ct,
43 enum ip_conntrack_info ctinfo,
44 __be32 seq, s32 off);
45extern int nf_nat_seq_adjust(struct sk_buff *skb,
46 struct nf_conn *ct,
47 enum ip_conntrack_info ctinfo,
48 unsigned int protoff);
49extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
50 struct nf_conn *ct,
51 enum ip_conntrack_info ctinfo,
52 unsigned int protoff);
53
54/* Setup NAT on this expected conntrack so it follows master, but goes 42/* Setup NAT on this expected conntrack so it follows master, but goes
55 * to port ct->master->saved_proto. */ 43 * to port ct->master->saved_proto. */
56extern void nf_nat_follow_master(struct nf_conn *ct, 44extern void nf_nat_follow_master(struct nf_conn *ct,
57 struct nf_conntrack_expect *this); 45 struct nf_conntrack_expect *this);
58 46
59extern s32 nf_nat_get_offset(const struct nf_conn *ct,
60 enum ip_conntrack_dir dir,
61 u32 seq);
62
63extern void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
64 u32 dir, s32 off);
65
66#endif 47#endif
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
index d69483fb3825..8dd803818ebe 100644
--- a/include/uapi/linux/netfilter/nf_conntrack_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -99,7 +99,8 @@ enum ip_conntrack_events {
99 IPCT_PROTOINFO, /* protocol information has changed */ 99 IPCT_PROTOINFO, /* protocol information has changed */
100 IPCT_HELPER, /* new helper has been set */ 100 IPCT_HELPER, /* new helper has been set */
101 IPCT_MARK, /* new mark has been set */ 101 IPCT_MARK, /* new mark has been set */
102 IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */ 102 IPCT_SEQADJ, /* sequence adjustment has changed */
103 IPCT_NATSEQADJ = IPCT_SEQADJ,
103 IPCT_SECMARK, /* new security mark has been set */ 104 IPCT_SECMARK, /* new security mark has been set */
104 IPCT_LABEL, /* new connlabel has been set */ 105 IPCT_LABEL, /* new connlabel has been set */
105}; 106};
diff --git a/include/uapi/linux/netfilter/nfnetlink_conntrack.h b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
index 08fabc6c93f3..acad6c52a652 100644
--- a/include/uapi/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/uapi/linux/netfilter/nfnetlink_conntrack.h
@@ -42,8 +42,10 @@ enum ctattr_type {
42 CTA_ID, 42 CTA_ID,
43 CTA_NAT_DST, 43 CTA_NAT_DST,
44 CTA_TUPLE_MASTER, 44 CTA_TUPLE_MASTER,
45 CTA_NAT_SEQ_ADJ_ORIG, 45 CTA_SEQ_ADJ_ORIG,
46 CTA_NAT_SEQ_ADJ_REPLY, 46 CTA_NAT_SEQ_ADJ_ORIG = CTA_SEQ_ADJ_ORIG,
47 CTA_SEQ_ADJ_REPLY,
48 CTA_NAT_SEQ_ADJ_REPLY = CTA_SEQ_ADJ_REPLY,
47 CTA_SECMARK, /* obsolete */ 49 CTA_SECMARK, /* obsolete */
48 CTA_ZONE, 50 CTA_ZONE,
49 CTA_SECCTX, 51 CTA_SECCTX,
@@ -165,6 +167,15 @@ enum ctattr_protonat {
165}; 167};
166#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1) 168#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1)
167 169
170enum ctattr_seqadj {
171 CTA_SEQADJ_UNSPEC,
172 CTA_SEQADJ_CORRECTION_POS,
173 CTA_SEQADJ_OFFSET_BEFORE,
174 CTA_SEQADJ_OFFSET_AFTER,
175 __CTA_SEQADJ_MAX
176};
177#define CTA_SEQADJ_MAX (__CTA_SEQADJ_MAX - 1)
178
168enum ctattr_natseq { 179enum ctattr_natseq {
169 CTA_NAT_SEQ_UNSPEC, 180 CTA_NAT_SEQ_UNSPEC,
170 CTA_NAT_SEQ_CORRECTION_POS, 181 CTA_NAT_SEQ_CORRECTION_POS,
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 0a2e0e3e95ba..86f5b34a4ed1 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -25,6 +25,7 @@
25#include <net/netfilter/nf_conntrack_l3proto.h> 25#include <net/netfilter/nf_conntrack_l3proto.h>
26#include <net/netfilter/nf_conntrack_zones.h> 26#include <net/netfilter/nf_conntrack_zones.h>
27#include <net/netfilter/nf_conntrack_core.h> 27#include <net/netfilter/nf_conntrack_core.h>
28#include <net/netfilter/nf_conntrack_seqadj.h>
28#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 29#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
29#include <net/netfilter/nf_nat_helper.h> 30#include <net/netfilter/nf_nat_helper.h>
30#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 31#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
@@ -136,11 +137,7 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
136 /* adjust seqs for loopback traffic only in outgoing direction */ 137 /* adjust seqs for loopback traffic only in outgoing direction */
137 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 138 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
138 !nf_is_loopback_packet(skb)) { 139 !nf_is_loopback_packet(skb)) {
139 typeof(nf_nat_seq_adjust_hook) seq_adjust; 140 if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
140
141 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
142 if (!seq_adjust ||
143 !seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
144 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 141 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
145 return NF_DROP; 142 return NF_DROP;
146 } 143 }
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index c9b6a6e6a1e8..d6e4dd8b58df 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -28,6 +28,7 @@
28#include <net/netfilter/nf_conntrack_l3proto.h> 28#include <net/netfilter/nf_conntrack_l3proto.h>
29#include <net/netfilter/nf_conntrack_core.h> 29#include <net/netfilter/nf_conntrack_core.h>
30#include <net/netfilter/nf_conntrack_zones.h> 30#include <net/netfilter/nf_conntrack_zones.h>
31#include <net/netfilter/nf_conntrack_seqadj.h>
31#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 32#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
32#include <net/netfilter/nf_nat_helper.h> 33#include <net/netfilter/nf_nat_helper.h>
33#include <net/netfilter/ipv6/nf_defrag_ipv6.h> 34#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
@@ -158,11 +159,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
158 /* adjust seqs for loopback traffic only in outgoing direction */ 159 /* adjust seqs for loopback traffic only in outgoing direction */
159 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 160 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
160 !nf_is_loopback_packet(skb)) { 161 !nf_is_loopback_packet(skb)) {
161 typeof(nf_nat_seq_adjust_hook) seq_adjust; 162 if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
162
163 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
164 if (!seq_adjust ||
165 !seq_adjust(skb, ct, ctinfo, protoff)) {
166 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 163 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
167 return NF_DROP; 164 return NF_DROP;
168 } 165 }
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index ebfa7dc747cd..89a9c1658f5e 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -1,6 +1,6 @@
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
2 2
3nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o 3nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o nf_conntrack_seqadj.o
4nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o 4nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
5nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o 5nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
6nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o 6nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index da6f1787a102..00a7a94d4132 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -39,6 +39,7 @@
39#include <net/netfilter/nf_conntrack_l4proto.h> 39#include <net/netfilter/nf_conntrack_l4proto.h>
40#include <net/netfilter/nf_conntrack_expect.h> 40#include <net/netfilter/nf_conntrack_expect.h>
41#include <net/netfilter/nf_conntrack_helper.h> 41#include <net/netfilter/nf_conntrack_helper.h>
42#include <net/netfilter/nf_conntrack_seqadj.h>
42#include <net/netfilter/nf_conntrack_core.h> 43#include <net/netfilter/nf_conntrack_core.h>
43#include <net/netfilter/nf_conntrack_extend.h> 44#include <net/netfilter/nf_conntrack_extend.h>
44#include <net/netfilter/nf_conntrack_acct.h> 45#include <net/netfilter/nf_conntrack_acct.h>
@@ -1326,6 +1327,7 @@ void nf_conntrack_cleanup_end(void)
1326 nf_ct_extend_unregister(&nf_ct_zone_extend); 1327 nf_ct_extend_unregister(&nf_ct_zone_extend);
1327#endif 1328#endif
1328 nf_conntrack_proto_fini(); 1329 nf_conntrack_proto_fini();
1330 nf_conntrack_seqadj_fini();
1329 nf_conntrack_labels_fini(); 1331 nf_conntrack_labels_fini();
1330 nf_conntrack_helper_fini(); 1332 nf_conntrack_helper_fini();
1331 nf_conntrack_timeout_fini(); 1333 nf_conntrack_timeout_fini();
@@ -1531,6 +1533,10 @@ int nf_conntrack_init_start(void)
1531 if (ret < 0) 1533 if (ret < 0)
1532 goto err_labels; 1534 goto err_labels;
1533 1535
1536 ret = nf_conntrack_seqadj_init();
1537 if (ret < 0)
1538 goto err_seqadj;
1539
1534#ifdef CONFIG_NF_CONNTRACK_ZONES 1540#ifdef CONFIG_NF_CONNTRACK_ZONES
1535 ret = nf_ct_extend_register(&nf_ct_zone_extend); 1541 ret = nf_ct_extend_register(&nf_ct_zone_extend);
1536 if (ret < 0) 1542 if (ret < 0)
@@ -1555,6 +1561,8 @@ err_proto:
1555 nf_ct_extend_unregister(&nf_ct_zone_extend); 1561 nf_ct_extend_unregister(&nf_ct_zone_extend);
1556err_extend: 1562err_extend:
1557#endif 1563#endif
1564 nf_conntrack_seqadj_fini();
1565err_seqadj:
1558 nf_conntrack_labels_fini(); 1566 nf_conntrack_labels_fini();
1559err_labels: 1567err_labels:
1560 nf_conntrack_helper_fini(); 1568 nf_conntrack_helper_fini();
@@ -1577,9 +1585,6 @@ void nf_conntrack_init_end(void)
1577 /* For use by REJECT target */ 1585 /* For use by REJECT target */
1578 RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); 1586 RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach);
1579 RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); 1587 RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack);
1580
1581 /* Howto get NAT offsets */
1582 RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
1583} 1588}
1584 1589
1585/* 1590/*
@@ -1666,8 +1671,3 @@ err_slabname:
1666err_stat: 1671err_stat:
1667 return ret; 1672 return ret;
1668} 1673}
1669
1670s32 (*nf_ct_nat_offset)(const struct nf_conn *ct,
1671 enum ip_conntrack_dir dir,
1672 u32 seq);
1673EXPORT_SYMBOL_GPL(nf_ct_nat_offset);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index fa61fea63234..7c55745ececf 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -37,6 +37,7 @@
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_expect.h>
39#include <net/netfilter/nf_conntrack_helper.h> 39#include <net/netfilter/nf_conntrack_helper.h>
40#include <net/netfilter/nf_conntrack_seqadj.h>
40#include <net/netfilter/nf_conntrack_l3proto.h> 41#include <net/netfilter/nf_conntrack_l3proto.h>
41#include <net/netfilter/nf_conntrack_l4proto.h> 42#include <net/netfilter/nf_conntrack_l4proto.h>
42#include <net/netfilter/nf_conntrack_tuple.h> 43#include <net/netfilter/nf_conntrack_tuple.h>
@@ -381,9 +382,8 @@ nla_put_failure:
381 return -1; 382 return -1;
382} 383}
383 384
384#ifdef CONFIG_NF_NAT_NEEDED
385static int 385static int
386dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type) 386dump_ct_seq_adj(struct sk_buff *skb, const struct nf_ct_seqadj *seq, int type)
387{ 387{
388 struct nlattr *nest_parms; 388 struct nlattr *nest_parms;
389 389
@@ -391,12 +391,12 @@ dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type)
391 if (!nest_parms) 391 if (!nest_parms)
392 goto nla_put_failure; 392 goto nla_put_failure;
393 393
394 if (nla_put_be32(skb, CTA_NAT_SEQ_CORRECTION_POS, 394 if (nla_put_be32(skb, CTA_SEQADJ_CORRECTION_POS,
395 htonl(natseq->correction_pos)) || 395 htonl(seq->correction_pos)) ||
396 nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_BEFORE, 396 nla_put_be32(skb, CTA_SEQADJ_OFFSET_BEFORE,
397 htonl(natseq->offset_before)) || 397 htonl(seq->offset_before)) ||
398 nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_AFTER, 398 nla_put_be32(skb, CTA_SEQADJ_OFFSET_AFTER,
399 htonl(natseq->offset_after))) 399 htonl(seq->offset_after)))
400 goto nla_put_failure; 400 goto nla_put_failure;
401 401
402 nla_nest_end(skb, nest_parms); 402 nla_nest_end(skb, nest_parms);
@@ -408,27 +408,24 @@ nla_put_failure:
408} 408}
409 409
410static inline int 410static inline int
411ctnetlink_dump_nat_seq_adj(struct sk_buff *skb, const struct nf_conn *ct) 411ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, const struct nf_conn *ct)
412{ 412{
413 struct nf_nat_seq *natseq; 413 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
414 struct nf_conn_nat *nat = nfct_nat(ct); 414 struct nf_ct_seqadj *seq;
415 415
416 if (!(ct->status & IPS_SEQ_ADJUST) || !nat) 416 if (!(ct->status & IPS_SEQ_ADJUST) || !seqadj)
417 return 0; 417 return 0;
418 418
419 natseq = &nat->seq[IP_CT_DIR_ORIGINAL]; 419 seq = &seqadj->seq[IP_CT_DIR_ORIGINAL];
420 if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_ORIG) == -1) 420 if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_ORIG) == -1)
421 return -1; 421 return -1;
422 422
423 natseq = &nat->seq[IP_CT_DIR_REPLY]; 423 seq = &seqadj->seq[IP_CT_DIR_REPLY];
424 if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_REPLY) == -1) 424 if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_REPLY) == -1)
425 return -1; 425 return -1;
426 426
427 return 0; 427 return 0;
428} 428}
429#else
430#define ctnetlink_dump_nat_seq_adj(a, b) (0)
431#endif
432 429
433static inline int 430static inline int
434ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) 431ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
@@ -502,7 +499,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
502 ctnetlink_dump_id(skb, ct) < 0 || 499 ctnetlink_dump_id(skb, ct) < 0 ||
503 ctnetlink_dump_use(skb, ct) < 0 || 500 ctnetlink_dump_use(skb, ct) < 0 ||
504 ctnetlink_dump_master(skb, ct) < 0 || 501 ctnetlink_dump_master(skb, ct) < 0 ||
505 ctnetlink_dump_nat_seq_adj(skb, ct) < 0) 502 ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
506 goto nla_put_failure; 503 goto nla_put_failure;
507 504
508 nlmsg_end(skb, nlh); 505 nlmsg_end(skb, nlh);
@@ -707,8 +704,8 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
707 ctnetlink_dump_master(skb, ct) < 0) 704 ctnetlink_dump_master(skb, ct) < 0)
708 goto nla_put_failure; 705 goto nla_put_failure;
709 706
710 if (events & (1 << IPCT_NATSEQADJ) && 707 if (events & (1 << IPCT_SEQADJ) &&
711 ctnetlink_dump_nat_seq_adj(skb, ct) < 0) 708 ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
712 goto nla_put_failure; 709 goto nla_put_failure;
713 } 710 }
714 711
@@ -1439,66 +1436,65 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, const struct nlattr * const cda[]
1439 return err; 1436 return err;
1440} 1437}
1441 1438
1442#ifdef CONFIG_NF_NAT_NEEDED 1439static const struct nla_policy seqadj_policy[CTA_SEQADJ_MAX+1] = {
1443static const struct nla_policy nat_seq_policy[CTA_NAT_SEQ_MAX+1] = { 1440 [CTA_SEQADJ_CORRECTION_POS] = { .type = NLA_U32 },
1444 [CTA_NAT_SEQ_CORRECTION_POS] = { .type = NLA_U32 }, 1441 [CTA_SEQADJ_OFFSET_BEFORE] = { .type = NLA_U32 },
1445 [CTA_NAT_SEQ_OFFSET_BEFORE] = { .type = NLA_U32 }, 1442 [CTA_SEQADJ_OFFSET_AFTER] = { .type = NLA_U32 },
1446 [CTA_NAT_SEQ_OFFSET_AFTER] = { .type = NLA_U32 },
1447}; 1443};
1448 1444
1449static inline int 1445static inline int
1450change_nat_seq_adj(struct nf_nat_seq *natseq, const struct nlattr * const attr) 1446change_seq_adj(struct nf_ct_seqadj *seq, const struct nlattr * const attr)
1451{ 1447{
1452 int err; 1448 int err;
1453 struct nlattr *cda[CTA_NAT_SEQ_MAX+1]; 1449 struct nlattr *cda[CTA_SEQADJ_MAX+1];
1454 1450
1455 err = nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, nat_seq_policy); 1451 err = nla_parse_nested(cda, CTA_SEQADJ_MAX, attr, seqadj_policy);
1456 if (err < 0) 1452 if (err < 0)
1457 return err; 1453 return err;
1458 1454
1459 if (!cda[CTA_NAT_SEQ_CORRECTION_POS]) 1455 if (!cda[CTA_SEQADJ_CORRECTION_POS])
1460 return -EINVAL; 1456 return -EINVAL;
1461 1457
1462 natseq->correction_pos = 1458 seq->correction_pos =
1463 ntohl(nla_get_be32(cda[CTA_NAT_SEQ_CORRECTION_POS])); 1459 ntohl(nla_get_be32(cda[CTA_SEQADJ_CORRECTION_POS]));
1464 1460
1465 if (!cda[CTA_NAT_SEQ_OFFSET_BEFORE]) 1461 if (!cda[CTA_SEQADJ_OFFSET_BEFORE])
1466 return -EINVAL; 1462 return -EINVAL;
1467 1463
1468 natseq->offset_before = 1464 seq->offset_before =
1469 ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_BEFORE])); 1465 ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_BEFORE]));
1470 1466
1471 if (!cda[CTA_NAT_SEQ_OFFSET_AFTER]) 1467 if (!cda[CTA_SEQADJ_OFFSET_AFTER])
1472 return -EINVAL; 1468 return -EINVAL;
1473 1469
1474 natseq->offset_after = 1470 seq->offset_after =
1475 ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_AFTER])); 1471 ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_AFTER]));
1476 1472
1477 return 0; 1473 return 0;
1478} 1474}
1479 1475
1480static int 1476static int
1481ctnetlink_change_nat_seq_adj(struct nf_conn *ct, 1477ctnetlink_change_seq_adj(struct nf_conn *ct,
1482 const struct nlattr * const cda[]) 1478 const struct nlattr * const cda[])
1483{ 1479{
1480 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
1484 int ret = 0; 1481 int ret = 0;
1485 struct nf_conn_nat *nat = nfct_nat(ct);
1486 1482
1487 if (!nat) 1483 if (!seqadj)
1488 return 0; 1484 return 0;
1489 1485
1490 if (cda[CTA_NAT_SEQ_ADJ_ORIG]) { 1486 if (cda[CTA_SEQ_ADJ_ORIG]) {
1491 ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_ORIGINAL], 1487 ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_ORIGINAL],
1492 cda[CTA_NAT_SEQ_ADJ_ORIG]); 1488 cda[CTA_SEQ_ADJ_ORIG]);
1493 if (ret < 0) 1489 if (ret < 0)
1494 return ret; 1490 return ret;
1495 1491
1496 ct->status |= IPS_SEQ_ADJUST; 1492 ct->status |= IPS_SEQ_ADJUST;
1497 } 1493 }
1498 1494
1499 if (cda[CTA_NAT_SEQ_ADJ_REPLY]) { 1495 if (cda[CTA_SEQ_ADJ_REPLY]) {
1500 ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_REPLY], 1496 ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_REPLY],
1501 cda[CTA_NAT_SEQ_ADJ_REPLY]); 1497 cda[CTA_SEQ_ADJ_REPLY]);
1502 if (ret < 0) 1498 if (ret < 0)
1503 return ret; 1499 return ret;
1504 1500
@@ -1507,7 +1503,6 @@ ctnetlink_change_nat_seq_adj(struct nf_conn *ct,
1507 1503
1508 return 0; 1504 return 0;
1509} 1505}
1510#endif
1511 1506
1512static int 1507static int
1513ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) 1508ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[])
@@ -1573,13 +1568,12 @@ ctnetlink_change_conntrack(struct nf_conn *ct,
1573 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); 1568 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
1574#endif 1569#endif
1575 1570
1576#ifdef CONFIG_NF_NAT_NEEDED 1571 if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) {
1577 if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { 1572 err = ctnetlink_change_seq_adj(ct, cda);
1578 err = ctnetlink_change_nat_seq_adj(ct, cda);
1579 if (err < 0) 1573 if (err < 0)
1580 return err; 1574 return err;
1581 } 1575 }
1582#endif 1576
1583 if (cda[CTA_LABELS]) { 1577 if (cda[CTA_LABELS]) {
1584 err = ctnetlink_attach_labels(ct, cda); 1578 err = ctnetlink_attach_labels(ct, cda);
1585 if (err < 0) 1579 if (err < 0)
@@ -1684,13 +1678,11 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
1684 goto err2; 1678 goto err2;
1685 } 1679 }
1686 1680
1687#ifdef CONFIG_NF_NAT_NEEDED 1681 if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) {
1688 if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { 1682 err = ctnetlink_change_seq_adj(ct, cda);
1689 err = ctnetlink_change_nat_seq_adj(ct, cda);
1690 if (err < 0) 1683 if (err < 0)
1691 goto err2; 1684 goto err2;
1692 } 1685 }
1693#endif
1694 1686
1695 memset(&ct->proto, 0, sizeof(ct->proto)); 1687 memset(&ct->proto, 0, sizeof(ct->proto));
1696 if (cda[CTA_PROTOINFO]) { 1688 if (cda[CTA_PROTOINFO]) {
@@ -1804,7 +1796,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1804 (1 << IPCT_ASSURED) | 1796 (1 << IPCT_ASSURED) |
1805 (1 << IPCT_HELPER) | 1797 (1 << IPCT_HELPER) |
1806 (1 << IPCT_PROTOINFO) | 1798 (1 << IPCT_PROTOINFO) |
1807 (1 << IPCT_NATSEQADJ) | 1799 (1 << IPCT_SEQADJ) |
1808 (1 << IPCT_MARK) | events, 1800 (1 << IPCT_MARK) | events,
1809 ct, NETLINK_CB(skb).portid, 1801 ct, NETLINK_CB(skb).portid,
1810 nlmsg_report(nlh)); 1802 nlmsg_report(nlh));
@@ -1827,7 +1819,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1827 (1 << IPCT_HELPER) | 1819 (1 << IPCT_HELPER) |
1828 (1 << IPCT_LABEL) | 1820 (1 << IPCT_LABEL) |
1829 (1 << IPCT_PROTOINFO) | 1821 (1 << IPCT_PROTOINFO) |
1830 (1 << IPCT_NATSEQADJ) | 1822 (1 << IPCT_SEQADJ) |
1831 (1 << IPCT_MARK), 1823 (1 << IPCT_MARK),
1832 ct, NETLINK_CB(skb).portid, 1824 ct, NETLINK_CB(skb).portid,
1833 nlmsg_report(nlh)); 1825 nlmsg_report(nlh));
@@ -2082,7 +2074,7 @@ ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
2082 goto nla_put_failure; 2074 goto nla_put_failure;
2083 2075
2084 if ((ct->status & IPS_SEQ_ADJUST) && 2076 if ((ct->status & IPS_SEQ_ADJUST) &&
2085 ctnetlink_dump_nat_seq_adj(skb, ct) < 0) 2077 ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
2086 goto nla_put_failure; 2078 goto nla_put_failure;
2087 2079
2088#ifdef CONFIG_NF_CONNTRACK_MARK 2080#ifdef CONFIG_NF_CONNTRACK_MARK
@@ -2211,6 +2203,7 @@ static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
2211 .build = ctnetlink_nfqueue_build, 2203 .build = ctnetlink_nfqueue_build,
2212 .parse = ctnetlink_nfqueue_parse, 2204 .parse = ctnetlink_nfqueue_parse,
2213 .attach_expect = ctnetlink_nfqueue_attach_expect, 2205 .attach_expect = ctnetlink_nfqueue_attach_expect,
2206 .seq_adjust = nf_ct_tcp_seqadj_set,
2214}; 2207};
2215#endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */ 2208#endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */
2216 2209
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index d224e001f14f..984a8d1a3359 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -27,6 +27,7 @@
27#include <net/netfilter/nf_conntrack.h> 27#include <net/netfilter/nf_conntrack.h>
28#include <net/netfilter/nf_conntrack_l4proto.h> 28#include <net/netfilter/nf_conntrack_l4proto.h>
29#include <net/netfilter/nf_conntrack_ecache.h> 29#include <net/netfilter/nf_conntrack_ecache.h>
30#include <net/netfilter/nf_conntrack_seqadj.h>
30#include <net/netfilter/nf_log.h> 31#include <net/netfilter/nf_log.h>
31#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 32#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
32#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 33#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
@@ -495,21 +496,6 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
495 } 496 }
496} 497}
497 498
498#ifdef CONFIG_NF_NAT_NEEDED
499static inline s32 nat_offset(const struct nf_conn *ct,
500 enum ip_conntrack_dir dir,
501 u32 seq)
502{
503 typeof(nf_ct_nat_offset) get_offset = rcu_dereference(nf_ct_nat_offset);
504
505 return get_offset != NULL ? get_offset(ct, dir, seq) : 0;
506}
507#define NAT_OFFSET(ct, dir, seq) \
508 (nat_offset(ct, dir, seq))
509#else
510#define NAT_OFFSET(ct, dir, seq) 0
511#endif
512
513static bool tcp_in_window(const struct nf_conn *ct, 499static bool tcp_in_window(const struct nf_conn *ct,
514 struct ip_ct_tcp *state, 500 struct ip_ct_tcp *state,
515 enum ip_conntrack_dir dir, 501 enum ip_conntrack_dir dir,
@@ -540,7 +526,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
540 tcp_sack(skb, dataoff, tcph, &sack); 526 tcp_sack(skb, dataoff, tcph, &sack);
541 527
542 /* Take into account NAT sequence number mangling */ 528 /* Take into account NAT sequence number mangling */
543 receiver_offset = NAT_OFFSET(ct, !dir, ack - 1); 529 receiver_offset = nf_ct_seq_offset(ct, !dir, ack - 1);
544 ack -= receiver_offset; 530 ack -= receiver_offset;
545 sack -= receiver_offset; 531 sack -= receiver_offset;
546 532
diff --git a/net/netfilter/nf_conntrack_seqadj.c b/net/netfilter/nf_conntrack_seqadj.c
new file mode 100644
index 000000000000..483eb9ce3216
--- /dev/null
+++ b/net/netfilter/nf_conntrack_seqadj.c
@@ -0,0 +1,218 @@
1#include <linux/types.h>
2#include <linux/netfilter.h>
3#include <net/tcp.h>
4
5#include <net/netfilter/nf_conntrack.h>
6#include <net/netfilter/nf_conntrack_extend.h>
7#include <net/netfilter/nf_conntrack_seqadj.h>
8
9int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
10 __be32 seq, s32 off)
11{
12 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
13 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
14 struct nf_ct_seqadj *this_way;
15
16 if (off == 0)
17 return 0;
18
19 set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
20
21 spin_lock_bh(&ct->lock);
22 this_way = &seqadj->seq[dir];
23 if (this_way->offset_before == this_way->offset_after ||
24 before(this_way->correction_pos, seq)) {
25 this_way->correction_pos = seq;
26 this_way->offset_before = this_way->offset_after;
27 this_way->offset_after += off;
28 }
29 spin_unlock_bh(&ct->lock);
30 return 0;
31}
32EXPORT_SYMBOL_GPL(nf_ct_seqadj_set);
33
34void nf_ct_tcp_seqadj_set(struct sk_buff *skb,
35 struct nf_conn *ct, enum ip_conntrack_info ctinfo,
36 s32 off)
37{
38 const struct tcphdr *th;
39
40 if (nf_ct_protonum(ct) != IPPROTO_TCP)
41 return;
42
43 th = (struct tcphdr *)(skb_network_header(skb) + ip_hdrlen(skb));
44 nf_ct_seqadj_set(ct, ctinfo, th->seq, off);
45}
46EXPORT_SYMBOL_GPL(nf_ct_tcp_seqadj_set);
47
48/* Adjust one found SACK option including checksum correction */
49static void nf_ct_sack_block_adjust(struct sk_buff *skb,
50 struct tcphdr *tcph,
51 unsigned int sackoff,
52 unsigned int sackend,
53 struct nf_ct_seqadj *seq)
54{
55 while (sackoff < sackend) {
56 struct tcp_sack_block_wire *sack;
57 __be32 new_start_seq, new_end_seq;
58
59 sack = (void *)skb->data + sackoff;
60 if (after(ntohl(sack->start_seq) - seq->offset_before,
61 seq->correction_pos))
62 new_start_seq = htonl(ntohl(sack->start_seq) -
63 seq->offset_after);
64 else
65 new_start_seq = htonl(ntohl(sack->start_seq) -
66 seq->offset_before);
67
68 if (after(ntohl(sack->end_seq) - seq->offset_before,
69 seq->correction_pos))
70 new_end_seq = htonl(ntohl(sack->end_seq) -
71 seq->offset_after);
72 else
73 new_end_seq = htonl(ntohl(sack->end_seq) -
74 seq->offset_before);
75
76 pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
77 ntohl(sack->start_seq), new_start_seq,
78 ntohl(sack->end_seq), new_end_seq);
79
80 inet_proto_csum_replace4(&tcph->check, skb,
81 sack->start_seq, new_start_seq, 0);
82 inet_proto_csum_replace4(&tcph->check, skb,
83 sack->end_seq, new_end_seq, 0);
84 sack->start_seq = new_start_seq;
85 sack->end_seq = new_end_seq;
86 sackoff += sizeof(*sack);
87 }
88}
89
90/* TCP SACK sequence number adjustment */
91static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
92 unsigned int protoff,
93 struct tcphdr *tcph,
94 struct nf_conn *ct,
95 enum ip_conntrack_info ctinfo)
96{
97 unsigned int dir, optoff, optend;
98 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
99
100 optoff = protoff + sizeof(struct tcphdr);
101 optend = protoff + tcph->doff * 4;
102
103 if (!skb_make_writable(skb, optend))
104 return 0;
105
106 dir = CTINFO2DIR(ctinfo);
107
108 while (optoff < optend) {
109 /* Usually: option, length. */
110 unsigned char *op = skb->data + optoff;
111
112 switch (op[0]) {
113 case TCPOPT_EOL:
114 return 1;
115 case TCPOPT_NOP:
116 optoff++;
117 continue;
118 default:
119 /* no partial options */
120 if (optoff + 1 == optend ||
121 optoff + op[1] > optend ||
122 op[1] < 2)
123 return 0;
124 if (op[0] == TCPOPT_SACK &&
125 op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
126 ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
127 nf_ct_sack_block_adjust(skb, tcph, optoff + 2,
128 optoff+op[1],
129 &seqadj->seq[!dir]);
130 optoff += op[1];
131 }
132 }
133 return 1;
134}
135
136/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
137int nf_ct_seq_adjust(struct sk_buff *skb,
138 struct nf_conn *ct, enum ip_conntrack_info ctinfo,
139 unsigned int protoff)
140{
141 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
142 struct tcphdr *tcph;
143 __be32 newseq, newack;
144 s32 seqoff, ackoff;
145 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
146 struct nf_ct_seqadj *this_way, *other_way;
147 int res;
148
149 this_way = &seqadj->seq[dir];
150 other_way = &seqadj->seq[!dir];
151
152 if (!skb_make_writable(skb, protoff + sizeof(*tcph)))
153 return 0;
154
155 tcph = (void *)skb->data + protoff;
156 spin_lock_bh(&ct->lock);
157 if (after(ntohl(tcph->seq), this_way->correction_pos))
158 seqoff = this_way->offset_after;
159 else
160 seqoff = this_way->offset_before;
161
162 if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
163 other_way->correction_pos))
164 ackoff = other_way->offset_after;
165 else
166 ackoff = other_way->offset_before;
167
168 newseq = htonl(ntohl(tcph->seq) + seqoff);
169 newack = htonl(ntohl(tcph->ack_seq) - ackoff);
170
171 inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
172 inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
173
174 pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
175 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
176 ntohl(newack));
177
178 tcph->seq = newseq;
179 tcph->ack_seq = newack;
180
181 res = nf_ct_sack_adjust(skb, protoff, tcph, ct, ctinfo);
182 spin_unlock_bh(&ct->lock);
183
184 return res;
185}
186EXPORT_SYMBOL_GPL(nf_ct_seq_adjust);
187
188s32 nf_ct_seq_offset(const struct nf_conn *ct,
189 enum ip_conntrack_dir dir,
190 u32 seq)
191{
192 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
193 struct nf_ct_seqadj *this_way;
194
195 if (!seqadj)
196 return 0;
197
198 this_way = &seqadj->seq[dir];
199 return after(seq, this_way->correction_pos) ?
200 this_way->offset_after : this_way->offset_before;
201}
202EXPORT_SYMBOL_GPL(nf_ct_seq_offset);
203
204static struct nf_ct_ext_type nf_ct_seqadj_extend __read_mostly = {
205 .len = sizeof(struct nf_conn_seqadj),
206 .align = __alignof__(struct nf_conn_seqadj),
207 .id = NF_CT_EXT_SEQADJ,
208};
209
210int nf_conntrack_seqadj_init(void)
211{
212 return nf_ct_extend_register(&nf_ct_seqadj_extend);
213}
214
215void nf_conntrack_seqadj_fini(void)
216{
217 nf_ct_extend_unregister(&nf_ct_seqadj_extend);
218}
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 6ff808375b5e..6f0f4f7f68a5 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -25,6 +25,7 @@
25#include <net/netfilter/nf_nat_core.h> 25#include <net/netfilter/nf_nat_core.h>
26#include <net/netfilter/nf_nat_helper.h> 26#include <net/netfilter/nf_nat_helper.h>
27#include <net/netfilter/nf_conntrack_helper.h> 27#include <net/netfilter/nf_conntrack_helper.h>
28#include <net/netfilter/nf_conntrack_seqadj.h>
28#include <net/netfilter/nf_conntrack_l3proto.h> 29#include <net/netfilter/nf_conntrack_l3proto.h>
29#include <net/netfilter/nf_conntrack_zones.h> 30#include <net/netfilter/nf_conntrack_zones.h>
30#include <linux/netfilter/nf_nat.h> 31#include <linux/netfilter/nf_nat.h>
@@ -402,6 +403,9 @@ nf_nat_setup_info(struct nf_conn *ct,
402 ct->status |= IPS_SRC_NAT; 403 ct->status |= IPS_SRC_NAT;
403 else 404 else
404 ct->status |= IPS_DST_NAT; 405 ct->status |= IPS_DST_NAT;
406
407 if (nfct_help(ct))
408 nfct_seqadj_ext_add(ct);
405 } 409 }
406 410
407 if (maniptype == NF_NAT_MANIP_SRC) { 411 if (maniptype == NF_NAT_MANIP_SRC) {
@@ -764,10 +768,6 @@ static struct nf_ct_helper_expectfn follow_master_nat = {
764 .expectfn = nf_nat_follow_master, 768 .expectfn = nf_nat_follow_master,
765}; 769};
766 770
767static struct nfq_ct_nat_hook nfq_ct_nat = {
768 .seq_adjust = nf_nat_tcp_seq_adjust,
769};
770
771static int __init nf_nat_init(void) 771static int __init nf_nat_init(void)
772{ 772{
773 int ret; 773 int ret;
@@ -787,14 +787,9 @@ static int __init nf_nat_init(void)
787 /* Initialize fake conntrack so that NAT will skip it */ 787 /* Initialize fake conntrack so that NAT will skip it */
788 nf_ct_untracked_status_or(IPS_NAT_DONE_MASK); 788 nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
789 789
790 BUG_ON(nf_nat_seq_adjust_hook != NULL);
791 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
792 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); 790 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
793 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, 791 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook,
794 nfnetlink_parse_nat_setup); 792 nfnetlink_parse_nat_setup);
795 BUG_ON(nf_ct_nat_offset != NULL);
796 RCU_INIT_POINTER(nf_ct_nat_offset, nf_nat_get_offset);
797 RCU_INIT_POINTER(nfq_ct_nat_hook, &nfq_ct_nat);
798#ifdef CONFIG_XFRM 793#ifdef CONFIG_XFRM
799 BUG_ON(nf_nat_decode_session_hook != NULL); 794 BUG_ON(nf_nat_decode_session_hook != NULL);
800 RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session); 795 RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session);
@@ -813,10 +808,7 @@ static void __exit nf_nat_cleanup(void)
813 unregister_pernet_subsys(&nf_nat_net_ops); 808 unregister_pernet_subsys(&nf_nat_net_ops);
814 nf_ct_extend_unregister(&nat_extend); 809 nf_ct_extend_unregister(&nat_extend);
815 nf_ct_helper_expectfn_unregister(&follow_master_nat); 810 nf_ct_helper_expectfn_unregister(&follow_master_nat);
816 RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL);
817 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); 811 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
818 RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
819 RCU_INIT_POINTER(nfq_ct_nat_hook, NULL);
820#ifdef CONFIG_XFRM 812#ifdef CONFIG_XFRM
821 RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); 813 RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL);
822#endif 814#endif
diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c
index 46b9baa845a6..2840abb5bb99 100644
--- a/net/netfilter/nf_nat_helper.c
+++ b/net/netfilter/nf_nat_helper.c
@@ -20,67 +20,13 @@
20#include <net/netfilter/nf_conntrack_helper.h> 20#include <net/netfilter/nf_conntrack_helper.h>
21#include <net/netfilter/nf_conntrack_ecache.h> 21#include <net/netfilter/nf_conntrack_ecache.h>
22#include <net/netfilter/nf_conntrack_expect.h> 22#include <net/netfilter/nf_conntrack_expect.h>
23#include <net/netfilter/nf_conntrack_seqadj.h>
23#include <net/netfilter/nf_nat.h> 24#include <net/netfilter/nf_nat.h>
24#include <net/netfilter/nf_nat_l3proto.h> 25#include <net/netfilter/nf_nat_l3proto.h>
25#include <net/netfilter/nf_nat_l4proto.h> 26#include <net/netfilter/nf_nat_l4proto.h>
26#include <net/netfilter/nf_nat_core.h> 27#include <net/netfilter/nf_nat_core.h>
27#include <net/netfilter/nf_nat_helper.h> 28#include <net/netfilter/nf_nat_helper.h>
28 29
29#define DUMP_OFFSET(x) \
30 pr_debug("offset_before=%d, offset_after=%d, correction_pos=%u\n", \
31 x->offset_before, x->offset_after, x->correction_pos);
32
33/* Setup TCP sequence correction given this change at this sequence */
34static inline void
35adjust_tcp_sequence(u32 seq,
36 int sizediff,
37 struct nf_conn *ct,
38 enum ip_conntrack_info ctinfo)
39{
40 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
41 struct nf_conn_nat *nat = nfct_nat(ct);
42 struct nf_nat_seq *this_way = &nat->seq[dir];
43
44 pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
45 seq, sizediff);
46
47 pr_debug("adjust_tcp_sequence: Seq_offset before: ");
48 DUMP_OFFSET(this_way);
49
50 spin_lock_bh(&ct->lock);
51
52 /* SYN adjust. If it's uninitialized, or this is after last
53 * correction, record it: we don't handle more than one
54 * adjustment in the window, but do deal with common case of a
55 * retransmit */
56 if (this_way->offset_before == this_way->offset_after ||
57 before(this_way->correction_pos, seq)) {
58 this_way->correction_pos = seq;
59 this_way->offset_before = this_way->offset_after;
60 this_way->offset_after += sizediff;
61 }
62 spin_unlock_bh(&ct->lock);
63
64 pr_debug("adjust_tcp_sequence: Seq_offset after: ");
65 DUMP_OFFSET(this_way);
66}
67
68/* Get the offset value, for conntrack. Caller must have the conntrack locked */
69s32 nf_nat_get_offset(const struct nf_conn *ct,
70 enum ip_conntrack_dir dir,
71 u32 seq)
72{
73 struct nf_conn_nat *nat = nfct_nat(ct);
74 struct nf_nat_seq *this_way;
75
76 if (!nat)
77 return 0;
78
79 this_way = &nat->seq[dir];
80 return after(seq, this_way->correction_pos)
81 ? this_way->offset_after : this_way->offset_before;
82}
83
84/* Frobs data inside this packet, which is linear. */ 30/* Frobs data inside this packet, which is linear. */
85static void mangle_contents(struct sk_buff *skb, 31static void mangle_contents(struct sk_buff *skb,
86 unsigned int dataoff, 32 unsigned int dataoff,
@@ -135,30 +81,6 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
135 return 1; 81 return 1;
136} 82}
137 83
138void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
139 __be32 seq, s32 off)
140{
141 if (!off)
142 return;
143 set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
144 adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo);
145 nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
146}
147EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
148
149void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
150 u32 ctinfo, int off)
151{
152 const struct tcphdr *th;
153
154 if (nf_ct_protonum(ct) != IPPROTO_TCP)
155 return;
156
157 th = (struct tcphdr *)(skb_network_header(skb)+ ip_hdrlen(skb));
158 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
159}
160EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust);
161
162/* Generic function for mangling variable-length address changes inside 84/* Generic function for mangling variable-length address changes inside
163 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX 85 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
164 * command in FTP). 86 * command in FTP).
@@ -203,8 +125,8 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
203 datalen, oldlen); 125 datalen, oldlen);
204 126
205 if (adjust && rep_len != match_len) 127 if (adjust && rep_len != match_len)
206 nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq, 128 nf_ct_seqadj_set(ct, ctinfo, tcph->seq,
207 (int)rep_len - (int)match_len); 129 (int)rep_len - (int)match_len);
208 130
209 return 1; 131 return 1;
210} 132}
@@ -264,150 +186,6 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
264} 186}
265EXPORT_SYMBOL(nf_nat_mangle_udp_packet); 187EXPORT_SYMBOL(nf_nat_mangle_udp_packet);
266 188
267/* Adjust one found SACK option including checksum correction */
268static void
269sack_adjust(struct sk_buff *skb,
270 struct tcphdr *tcph,
271 unsigned int sackoff,
272 unsigned int sackend,
273 struct nf_nat_seq *natseq)
274{
275 while (sackoff < sackend) {
276 struct tcp_sack_block_wire *sack;
277 __be32 new_start_seq, new_end_seq;
278
279 sack = (void *)skb->data + sackoff;
280 if (after(ntohl(sack->start_seq) - natseq->offset_before,
281 natseq->correction_pos))
282 new_start_seq = htonl(ntohl(sack->start_seq)
283 - natseq->offset_after);
284 else
285 new_start_seq = htonl(ntohl(sack->start_seq)
286 - natseq->offset_before);
287
288 if (after(ntohl(sack->end_seq) - natseq->offset_before,
289 natseq->correction_pos))
290 new_end_seq = htonl(ntohl(sack->end_seq)
291 - natseq->offset_after);
292 else
293 new_end_seq = htonl(ntohl(sack->end_seq)
294 - natseq->offset_before);
295
296 pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
297 ntohl(sack->start_seq), new_start_seq,
298 ntohl(sack->end_seq), new_end_seq);
299
300 inet_proto_csum_replace4(&tcph->check, skb,
301 sack->start_seq, new_start_seq, 0);
302 inet_proto_csum_replace4(&tcph->check, skb,
303 sack->end_seq, new_end_seq, 0);
304 sack->start_seq = new_start_seq;
305 sack->end_seq = new_end_seq;
306 sackoff += sizeof(*sack);
307 }
308}
309
310/* TCP SACK sequence number adjustment */
311static inline unsigned int
312nf_nat_sack_adjust(struct sk_buff *skb,
313 unsigned int protoff,
314 struct tcphdr *tcph,
315 struct nf_conn *ct,
316 enum ip_conntrack_info ctinfo)
317{
318 unsigned int dir, optoff, optend;
319 struct nf_conn_nat *nat = nfct_nat(ct);
320
321 optoff = protoff + sizeof(struct tcphdr);
322 optend = protoff + tcph->doff * 4;
323
324 if (!skb_make_writable(skb, optend))
325 return 0;
326
327 dir = CTINFO2DIR(ctinfo);
328
329 while (optoff < optend) {
330 /* Usually: option, length. */
331 unsigned char *op = skb->data + optoff;
332
333 switch (op[0]) {
334 case TCPOPT_EOL:
335 return 1;
336 case TCPOPT_NOP:
337 optoff++;
338 continue;
339 default:
340 /* no partial options */
341 if (optoff + 1 == optend ||
342 optoff + op[1] > optend ||
343 op[1] < 2)
344 return 0;
345 if (op[0] == TCPOPT_SACK &&
346 op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
347 ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
348 sack_adjust(skb, tcph, optoff+2,
349 optoff+op[1], &nat->seq[!dir]);
350 optoff += op[1];
351 }
352 }
353 return 1;
354}
355
356/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
357int
358nf_nat_seq_adjust(struct sk_buff *skb,
359 struct nf_conn *ct,
360 enum ip_conntrack_info ctinfo,
361 unsigned int protoff)
362{
363 struct tcphdr *tcph;
364 int dir;
365 __be32 newseq, newack;
366 s32 seqoff, ackoff;
367 struct nf_conn_nat *nat = nfct_nat(ct);
368 struct nf_nat_seq *this_way, *other_way;
369 int res;
370
371 dir = CTINFO2DIR(ctinfo);
372
373 this_way = &nat->seq[dir];
374 other_way = &nat->seq[!dir];
375
376 if (!skb_make_writable(skb, protoff + sizeof(*tcph)))
377 return 0;
378
379 tcph = (void *)skb->data + protoff;
380 spin_lock_bh(&ct->lock);
381 if (after(ntohl(tcph->seq), this_way->correction_pos))
382 seqoff = this_way->offset_after;
383 else
384 seqoff = this_way->offset_before;
385
386 if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
387 other_way->correction_pos))
388 ackoff = other_way->offset_after;
389 else
390 ackoff = other_way->offset_before;
391
392 newseq = htonl(ntohl(tcph->seq) + seqoff);
393 newack = htonl(ntohl(tcph->ack_seq) - ackoff);
394
395 inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
396 inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
397
398 pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
399 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
400 ntohl(newack));
401
402 tcph->seq = newseq;
403 tcph->ack_seq = newack;
404
405 res = nf_nat_sack_adjust(skb, protoff, tcph, ct, ctinfo);
406 spin_unlock_bh(&ct->lock);
407
408 return res;
409}
410
411/* Setup NAT on this expected conntrack so it follows master. */ 189/* Setup NAT on this expected conntrack so it follows master. */
412/* If we fail to get a free NAT slot, we'll get dropped on confirm */ 190/* If we fail to get a free NAT slot, we'll get dropped on confirm */
413void nf_nat_follow_master(struct nf_conn *ct, 191void nf_nat_follow_master(struct nf_conn *ct,
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c
index dac11f73868e..f9790405b7ff 100644
--- a/net/netfilter/nf_nat_sip.c
+++ b/net/netfilter/nf_nat_sip.c
@@ -20,6 +20,7 @@
20#include <net/netfilter/nf_nat_helper.h> 20#include <net/netfilter/nf_nat_helper.h>
21#include <net/netfilter/nf_conntrack_helper.h> 21#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_expect.h> 22#include <net/netfilter/nf_conntrack_expect.h>
23#include <net/netfilter/nf_conntrack_seqadj.h>
23#include <linux/netfilter/nf_conntrack_sip.h> 24#include <linux/netfilter/nf_conntrack_sip.h>
24 25
25MODULE_LICENSE("GPL"); 26MODULE_LICENSE("GPL");
@@ -308,7 +309,7 @@ static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff,
308 return; 309 return;
309 310
310 th = (struct tcphdr *)(skb->data + protoff); 311 th = (struct tcphdr *)(skb->data + protoff);
311 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); 312 nf_ct_seqadj_set(ct, ctinfo, th->seq, off);
312} 313}
313 314
314/* Handles expected signalling connections and media streams */ 315/* Handles expected signalling connections and media streams */
diff --git a/net/netfilter/nfnetlink_queue_ct.c b/net/netfilter/nfnetlink_queue_ct.c
index be893039966d..96cac50e0d12 100644
--- a/net/netfilter/nfnetlink_queue_ct.c
+++ b/net/netfilter/nfnetlink_queue_ct.c
@@ -87,14 +87,14 @@ nla_put_failure:
87void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, 87void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
88 enum ip_conntrack_info ctinfo, int diff) 88 enum ip_conntrack_info ctinfo, int diff)
89{ 89{
90 struct nfq_ct_nat_hook *nfq_nat_ct; 90 struct nfq_ct_hook *nfq_ct;
91 91
92 nfq_nat_ct = rcu_dereference(nfq_ct_nat_hook); 92 nfq_ct = rcu_dereference(nfq_ct_hook);
93 if (nfq_nat_ct == NULL) 93 if (nfq_ct == NULL)
94 return; 94 return;
95 95
96 if ((ct->status & IPS_NAT_MASK) && diff) 96 if ((ct->status & IPS_NAT_MASK) && diff)
97 nfq_nat_ct->seq_adjust(skb, ct, ctinfo, diff); 97 nfq_ct->seq_adjust(skb, ct, ctinfo, diff);
98} 98}
99 99
100int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr, 100int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,