diff options
33 files changed, 416 insertions, 210 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index adbc50a20ec2..7b1a652066c0 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
@@ -437,6 +437,29 @@ extern void xt_free_table_info(struct xt_table_info *info); | |||
437 | extern void xt_table_entry_swap_rcu(struct xt_table_info *old, | 437 | extern void xt_table_entry_swap_rcu(struct xt_table_info *old, |
438 | struct xt_table_info *new); | 438 | struct xt_table_info *new); |
439 | 439 | ||
440 | /* | ||
441 | * This helper is performance critical and must be inlined | ||
442 | */ | ||
443 | static inline unsigned long ifname_compare_aligned(const char *_a, | ||
444 | const char *_b, | ||
445 | const char *_mask) | ||
446 | { | ||
447 | const unsigned long *a = (const unsigned long *)_a; | ||
448 | const unsigned long *b = (const unsigned long *)_b; | ||
449 | const unsigned long *mask = (const unsigned long *)_mask; | ||
450 | unsigned long ret; | ||
451 | |||
452 | ret = (a[0] ^ b[0]) & mask[0]; | ||
453 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
454 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
455 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
456 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
457 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
458 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
459 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
460 | return ret; | ||
461 | } | ||
462 | |||
440 | #ifdef CONFIG_COMPAT | 463 | #ifdef CONFIG_COMPAT |
441 | #include <net/compat.h> | 464 | #include <net/compat.h> |
442 | 465 | ||
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 4dfb793c3f15..6c3f964de9e1 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -91,8 +91,7 @@ struct nf_conn_help { | |||
91 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 91 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
92 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 92 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
93 | 93 | ||
94 | struct nf_conn | 94 | struct nf_conn { |
95 | { | ||
96 | /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, | 95 | /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, |
97 | plus 1 for any connection(s) we are `master' for */ | 96 | plus 1 for any connection(s) we are `master' for */ |
98 | struct nf_conntrack ct_general; | 97 | struct nf_conntrack ct_general; |
@@ -126,7 +125,6 @@ struct nf_conn | |||
126 | #ifdef CONFIG_NET_NS | 125 | #ifdef CONFIG_NET_NS |
127 | struct net *ct_net; | 126 | struct net *ct_net; |
128 | #endif | 127 | #endif |
129 | struct rcu_head rcu; | ||
130 | }; | 128 | }; |
131 | 129 | ||
132 | static inline struct nf_conn * | 130 | static inline struct nf_conn * |
@@ -190,9 +188,13 @@ static inline void nf_ct_put(struct nf_conn *ct) | |||
190 | extern int nf_ct_l3proto_try_module_get(unsigned short l3proto); | 188 | extern int nf_ct_l3proto_try_module_get(unsigned short l3proto); |
191 | extern void nf_ct_l3proto_module_put(unsigned short l3proto); | 189 | extern void nf_ct_l3proto_module_put(unsigned short l3proto); |
192 | 190 | ||
193 | extern struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced); | 191 | /* |
194 | extern void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, | 192 | * Allocate a hashtable of hlist_head (if nulls == 0), |
195 | unsigned int size); | 193 | * or hlist_nulls_head (if nulls == 1) |
194 | */ | ||
195 | extern void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls); | ||
196 | |||
197 | extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size); | ||
196 | 198 | ||
197 | extern struct nf_conntrack_tuple_hash * | 199 | extern struct nf_conntrack_tuple_hash * |
198 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); | 200 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); |
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index 66d65a7caa39..ee2a4b369a04 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h | |||
@@ -14,6 +14,8 @@ | |||
14 | 14 | ||
15 | struct module; | 15 | struct module; |
16 | 16 | ||
17 | #define NF_CT_HELPER_NAME_LEN 16 | ||
18 | |||
17 | struct nf_conntrack_helper | 19 | struct nf_conntrack_helper |
18 | { | 20 | { |
19 | struct hlist_node hnode; /* Internal use. */ | 21 | struct hlist_node hnode; /* Internal use. */ |
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index 0378676c3dd8..9f99d36d5de9 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h | |||
@@ -53,10 +53,17 @@ struct nf_conntrack_l3proto | |||
53 | int (*tuple_to_nlattr)(struct sk_buff *skb, | 53 | int (*tuple_to_nlattr)(struct sk_buff *skb, |
54 | const struct nf_conntrack_tuple *t); | 54 | const struct nf_conntrack_tuple *t); |
55 | 55 | ||
56 | /* | ||
57 | * Calculate size of tuple nlattr | ||
58 | */ | ||
59 | int (*nlattr_tuple_size)(void); | ||
60 | |||
56 | int (*nlattr_to_tuple)(struct nlattr *tb[], | 61 | int (*nlattr_to_tuple)(struct nlattr *tb[], |
57 | struct nf_conntrack_tuple *t); | 62 | struct nf_conntrack_tuple *t); |
58 | const struct nla_policy *nla_policy; | 63 | const struct nla_policy *nla_policy; |
59 | 64 | ||
65 | size_t nla_size; | ||
66 | |||
60 | #ifdef CONFIG_SYSCTL | 67 | #ifdef CONFIG_SYSCTL |
61 | struct ctl_table_header *ctl_table_header; | 68 | struct ctl_table_header *ctl_table_header; |
62 | struct ctl_path *ctl_table_path; | 69 | struct ctl_path *ctl_table_path; |
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index b01070bf2f84..ba32ed7bdabe 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h | |||
@@ -64,16 +64,22 @@ struct nf_conntrack_l4proto | |||
64 | /* convert protoinfo to nfnetink attributes */ | 64 | /* convert protoinfo to nfnetink attributes */ |
65 | int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, | 65 | int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, |
66 | const struct nf_conn *ct); | 66 | const struct nf_conn *ct); |
67 | /* Calculate protoinfo nlattr size */ | ||
68 | int (*nlattr_size)(void); | ||
67 | 69 | ||
68 | /* convert nfnetlink attributes to protoinfo */ | 70 | /* convert nfnetlink attributes to protoinfo */ |
69 | int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); | 71 | int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); |
70 | 72 | ||
71 | int (*tuple_to_nlattr)(struct sk_buff *skb, | 73 | int (*tuple_to_nlattr)(struct sk_buff *skb, |
72 | const struct nf_conntrack_tuple *t); | 74 | const struct nf_conntrack_tuple *t); |
75 | /* Calculate tuple nlattr size */ | ||
76 | int (*nlattr_tuple_size)(void); | ||
73 | int (*nlattr_to_tuple)(struct nlattr *tb[], | 77 | int (*nlattr_to_tuple)(struct nlattr *tb[], |
74 | struct nf_conntrack_tuple *t); | 78 | struct nf_conntrack_tuple *t); |
75 | const struct nla_policy *nla_policy; | 79 | const struct nla_policy *nla_policy; |
76 | 80 | ||
81 | size_t nla_size; | ||
82 | |||
77 | #ifdef CONFIG_SYSCTL | 83 | #ifdef CONFIG_SYSCTL |
78 | struct ctl_table_header **ctl_table_header; | 84 | struct ctl_table_header **ctl_table_header; |
79 | struct ctl_table *ctl_table; | 85 | struct ctl_table *ctl_table; |
@@ -107,6 +113,7 @@ extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, | |||
107 | const struct nf_conntrack_tuple *tuple); | 113 | const struct nf_conntrack_tuple *tuple); |
108 | extern int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], | 114 | extern int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], |
109 | struct nf_conntrack_tuple *t); | 115 | struct nf_conntrack_tuple *t); |
116 | extern int nf_ct_port_nlattr_tuple_size(void); | ||
110 | extern const struct nla_policy nf_ct_port_nla_policy[]; | 117 | extern const struct nla_policy nf_ct_port_nla_policy[]; |
111 | 118 | ||
112 | #ifdef CONFIG_SYSCTL | 119 | #ifdef CONFIG_SYSCTL |
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index f2f6aa73dc10..2628c154d40e 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/netfilter/x_tables.h> | 13 | #include <linux/netfilter/x_tables.h> |
14 | #include <linux/netfilter/nf_conntrack_tuple_common.h> | 14 | #include <linux/netfilter/nf_conntrack_tuple_common.h> |
15 | #include <linux/list_nulls.h> | ||
15 | 16 | ||
16 | /* A `tuple' is a structure containing the information to uniquely | 17 | /* A `tuple' is a structure containing the information to uniquely |
17 | identify a connection. ie. if two packets have the same tuple, they | 18 | identify a connection. ie. if two packets have the same tuple, they |
@@ -146,9 +147,8 @@ static inline void nf_ct_dump_tuple(const struct nf_conntrack_tuple *t) | |||
146 | ((enum ip_conntrack_dir)(h)->tuple.dst.dir) | 147 | ((enum ip_conntrack_dir)(h)->tuple.dst.dir) |
147 | 148 | ||
148 | /* Connections have two entries in the hash table: one for each way */ | 149 | /* Connections have two entries in the hash table: one for each way */ |
149 | struct nf_conntrack_tuple_hash | 150 | struct nf_conntrack_tuple_hash { |
150 | { | 151 | struct hlist_nulls_node hnnode; |
151 | struct hlist_node hnode; | ||
152 | struct nf_conntrack_tuple tuple; | 152 | struct nf_conntrack_tuple tuple; |
153 | }; | 153 | }; |
154 | 154 | ||
diff --git a/include/net/netlink.h b/include/net/netlink.h index 8a6150a3f4c7..eddb50289d6d 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h | |||
@@ -230,6 +230,7 @@ extern int nla_validate(struct nlattr *head, int len, int maxtype, | |||
230 | extern int nla_parse(struct nlattr *tb[], int maxtype, | 230 | extern int nla_parse(struct nlattr *tb[], int maxtype, |
231 | struct nlattr *head, int len, | 231 | struct nlattr *head, int len, |
232 | const struct nla_policy *policy); | 232 | const struct nla_policy *policy); |
233 | extern int nla_policy_len(const struct nla_policy *, int); | ||
233 | extern struct nlattr * nla_find(struct nlattr *head, int len, int attrtype); | 234 | extern struct nlattr * nla_find(struct nlattr *head, int len, int attrtype); |
234 | extern size_t nla_strlcpy(char *dst, const struct nlattr *nla, | 235 | extern size_t nla_strlcpy(char *dst, const struct nlattr *nla, |
235 | size_t dstsize); | 236 | size_t dstsize); |
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index f4498a62881b..9dc58402bc09 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __NETNS_CONNTRACK_H | 2 | #define __NETNS_CONNTRACK_H |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <linux/list_nulls.h> | ||
5 | #include <asm/atomic.h> | 6 | #include <asm/atomic.h> |
6 | 7 | ||
7 | struct ctl_table_header; | 8 | struct ctl_table_header; |
@@ -10,9 +11,9 @@ struct nf_conntrack_ecache; | |||
10 | struct netns_ct { | 11 | struct netns_ct { |
11 | atomic_t count; | 12 | atomic_t count; |
12 | unsigned int expect_count; | 13 | unsigned int expect_count; |
13 | struct hlist_head *hash; | 14 | struct hlist_nulls_head *hash; |
14 | struct hlist_head *expect_hash; | 15 | struct hlist_head *expect_hash; |
15 | struct hlist_head unconfirmed; | 16 | struct hlist_nulls_head unconfirmed; |
16 | struct ip_conntrack_stat *stat; | 17 | struct ip_conntrack_stat *stat; |
17 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 18 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
18 | struct nf_conntrack_ecache *ecache; | 19 | struct nf_conntrack_ecache *ecache; |
diff --git a/lib/nlattr.c b/lib/nlattr.c index 80009a24e21d..c4706eb98d3d 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c | |||
@@ -133,6 +133,32 @@ errout: | |||
133 | } | 133 | } |
134 | 134 | ||
135 | /** | 135 | /** |
136 | * nla_policy_len - Determin the max. length of a policy | ||
137 | * @policy: policy to use | ||
138 | * @n: number of policies | ||
139 | * | ||
140 | * Determines the max. length of the policy. It is currently used | ||
141 | * to allocated Netlink buffers roughly the size of the actual | ||
142 | * message. | ||
143 | * | ||
144 | * Returns 0 on success or a negative error code. | ||
145 | */ | ||
146 | int | ||
147 | nla_policy_len(const struct nla_policy *p, int n) | ||
148 | { | ||
149 | int i, len = 0; | ||
150 | |||
151 | for (i = 0; i < n; i++) { | ||
152 | if (p->len) | ||
153 | len += nla_total_size(p->len); | ||
154 | else if (nla_attr_minlen[p->type]) | ||
155 | len += nla_total_size(nla_attr_minlen[p->type]); | ||
156 | } | ||
157 | |||
158 | return len; | ||
159 | } | ||
160 | |||
161 | /** | ||
136 | * nla_parse - Parse a stream of attributes into a tb buffer | 162 | * nla_parse - Parse a stream of attributes into a tb buffer |
137 | * @tb: destination array with maxtype+1 elements | 163 | * @tb: destination array with maxtype+1 elements |
138 | * @maxtype: maximum attribute type to be expected | 164 | * @maxtype: maximum attribute type to be expected |
@@ -467,6 +493,7 @@ EXPORT_SYMBOL(nla_append); | |||
467 | #endif | 493 | #endif |
468 | 494 | ||
469 | EXPORT_SYMBOL(nla_validate); | 495 | EXPORT_SYMBOL(nla_validate); |
496 | EXPORT_SYMBOL(nla_policy_len); | ||
470 | EXPORT_SYMBOL(nla_parse); | 497 | EXPORT_SYMBOL(nla_parse); |
471 | EXPORT_SYMBOL(nla_find); | 498 | EXPORT_SYMBOL(nla_find); |
472 | EXPORT_SYMBOL(nla_strlcpy); | 499 | EXPORT_SYMBOL(nla_strlcpy); |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 84b9c179df51..35c5f6a5cb7c 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -81,19 +81,7 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, | |||
81 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | 81 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) |
82 | { | 82 | { |
83 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 83 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
84 | const unsigned long *a = (const unsigned long *)_a; | 84 | unsigned long ret = ifname_compare_aligned(_a, _b, _mask); |
85 | const unsigned long *b = (const unsigned long *)_b; | ||
86 | const unsigned long *mask = (const unsigned long *)_mask; | ||
87 | unsigned long ret; | ||
88 | |||
89 | ret = (a[0] ^ b[0]) & mask[0]; | ||
90 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
91 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
92 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
93 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
94 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
95 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
96 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
97 | #else | 85 | #else |
98 | unsigned long ret = 0; | 86 | unsigned long ret = 0; |
99 | const u16 *a = (const u16 *)_a; | 87 | const u16 *a = (const u16 *)_a; |
@@ -404,7 +392,9 @@ static int mark_source_chains(struct xt_table_info *newinfo, | |||
404 | && unconditional(&e->arp)) || visited) { | 392 | && unconditional(&e->arp)) || visited) { |
405 | unsigned int oldpos, size; | 393 | unsigned int oldpos, size; |
406 | 394 | ||
407 | if (t->verdict < -NF_MAX_VERDICT - 1) { | 395 | if ((strcmp(t->target.u.user.name, |
396 | ARPT_STANDARD_TARGET) == 0) && | ||
397 | t->verdict < -NF_MAX_VERDICT - 1) { | ||
408 | duprintf("mark_source_chains: bad " | 398 | duprintf("mark_source_chains: bad " |
409 | "negative verdict (%i)\n", | 399 | "negative verdict (%i)\n", |
410 | t->verdict); | 400 | t->verdict); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index e5294aec967d..82ee7c9049ff 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -74,25 +74,6 @@ do { \ | |||
74 | 74 | ||
75 | Hence the start of any table is given by get_table() below. */ | 75 | Hence the start of any table is given by get_table() below. */ |
76 | 76 | ||
77 | static unsigned long ifname_compare(const char *_a, const char *_b, | ||
78 | const unsigned char *_mask) | ||
79 | { | ||
80 | const unsigned long *a = (const unsigned long *)_a; | ||
81 | const unsigned long *b = (const unsigned long *)_b; | ||
82 | const unsigned long *mask = (const unsigned long *)_mask; | ||
83 | unsigned long ret; | ||
84 | |||
85 | ret = (a[0] ^ b[0]) & mask[0]; | ||
86 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
87 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
88 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
89 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
90 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
91 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
92 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | /* Returns whether matches rule or not. */ | 77 | /* Returns whether matches rule or not. */ |
97 | /* Performance critical - called for every packet */ | 78 | /* Performance critical - called for every packet */ |
98 | static inline bool | 79 | static inline bool |
@@ -121,7 +102,7 @@ ip_packet_match(const struct iphdr *ip, | |||
121 | return false; | 102 | return false; |
122 | } | 103 | } |
123 | 104 | ||
124 | ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask); | 105 | ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask); |
125 | 106 | ||
126 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { | 107 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { |
127 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 108 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -130,7 +111,7 @@ ip_packet_match(const struct iphdr *ip, | |||
130 | return false; | 111 | return false; |
131 | } | 112 | } |
132 | 113 | ||
133 | ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask); | 114 | ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask); |
134 | 115 | ||
135 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { | 116 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { |
136 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 117 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
@@ -507,7 +488,9 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
507 | && unconditional(&e->ip)) || visited) { | 488 | && unconditional(&e->ip)) || visited) { |
508 | unsigned int oldpos, size; | 489 | unsigned int oldpos, size; |
509 | 490 | ||
510 | if (t->verdict < -NF_MAX_VERDICT - 1) { | 491 | if ((strcmp(t->target.u.user.name, |
492 | IPT_STANDARD_TARGET) == 0) && | ||
493 | t->verdict < -NF_MAX_VERDICT - 1) { | ||
511 | duprintf("mark_source_chains: bad " | 494 | duprintf("mark_source_chains: bad " |
512 | "negative verdict (%i)\n", | 495 | "negative verdict (%i)\n", |
513 | t->verdict); | 496 | t->verdict); |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 8b681f24e271..7d2ead7228ac 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -328,6 +328,11 @@ static int ipv4_nlattr_to_tuple(struct nlattr *tb[], | |||
328 | 328 | ||
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | |||
332 | static int ipv4_nlattr_tuple_size(void) | ||
333 | { | ||
334 | return nla_policy_len(ipv4_nla_policy, CTA_IP_MAX + 1); | ||
335 | } | ||
331 | #endif | 336 | #endif |
332 | 337 | ||
333 | static struct nf_sockopt_ops so_getorigdst = { | 338 | static struct nf_sockopt_ops so_getorigdst = { |
@@ -347,6 +352,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = { | |||
347 | .get_l4proto = ipv4_get_l4proto, | 352 | .get_l4proto = ipv4_get_l4proto, |
348 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 353 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
349 | .tuple_to_nlattr = ipv4_tuple_to_nlattr, | 354 | .tuple_to_nlattr = ipv4_tuple_to_nlattr, |
355 | .nlattr_tuple_size = ipv4_nlattr_tuple_size, | ||
350 | .nlattr_to_tuple = ipv4_nlattr_to_tuple, | 356 | .nlattr_to_tuple = ipv4_nlattr_to_tuple, |
351 | .nla_policy = ipv4_nla_policy, | 357 | .nla_policy = ipv4_nla_policy, |
352 | #endif | 358 | #endif |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index 6ba5c557690c..8668a3defda6 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | |||
@@ -25,40 +25,42 @@ struct ct_iter_state { | |||
25 | unsigned int bucket; | 25 | unsigned int bucket; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | static struct hlist_node *ct_get_first(struct seq_file *seq) | 28 | static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) |
29 | { | 29 | { |
30 | struct net *net = seq_file_net(seq); | 30 | struct net *net = seq_file_net(seq); |
31 | struct ct_iter_state *st = seq->private; | 31 | struct ct_iter_state *st = seq->private; |
32 | struct hlist_node *n; | 32 | struct hlist_nulls_node *n; |
33 | 33 | ||
34 | for (st->bucket = 0; | 34 | for (st->bucket = 0; |
35 | st->bucket < nf_conntrack_htable_size; | 35 | st->bucket < nf_conntrack_htable_size; |
36 | st->bucket++) { | 36 | st->bucket++) { |
37 | n = rcu_dereference(net->ct.hash[st->bucket].first); | 37 | n = rcu_dereference(net->ct.hash[st->bucket].first); |
38 | if (n) | 38 | if (!is_a_nulls(n)) |
39 | return n; | 39 | return n; |
40 | } | 40 | } |
41 | return NULL; | 41 | return NULL; |
42 | } | 42 | } |
43 | 43 | ||
44 | static struct hlist_node *ct_get_next(struct seq_file *seq, | 44 | static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, |
45 | struct hlist_node *head) | 45 | struct hlist_nulls_node *head) |
46 | { | 46 | { |
47 | struct net *net = seq_file_net(seq); | 47 | struct net *net = seq_file_net(seq); |
48 | struct ct_iter_state *st = seq->private; | 48 | struct ct_iter_state *st = seq->private; |
49 | 49 | ||
50 | head = rcu_dereference(head->next); | 50 | head = rcu_dereference(head->next); |
51 | while (head == NULL) { | 51 | while (is_a_nulls(head)) { |
52 | if (++st->bucket >= nf_conntrack_htable_size) | 52 | if (likely(get_nulls_value(head) == st->bucket)) { |
53 | return NULL; | 53 | if (++st->bucket >= nf_conntrack_htable_size) |
54 | return NULL; | ||
55 | } | ||
54 | head = rcu_dereference(net->ct.hash[st->bucket].first); | 56 | head = rcu_dereference(net->ct.hash[st->bucket].first); |
55 | } | 57 | } |
56 | return head; | 58 | return head; |
57 | } | 59 | } |
58 | 60 | ||
59 | static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos) | 61 | static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) |
60 | { | 62 | { |
61 | struct hlist_node *head = ct_get_first(seq); | 63 | struct hlist_nulls_node *head = ct_get_first(seq); |
62 | 64 | ||
63 | if (head) | 65 | if (head) |
64 | while (pos && (head = ct_get_next(seq, head))) | 66 | while (pos && (head = ct_get_next(seq, head))) |
@@ -87,69 +89,76 @@ static void ct_seq_stop(struct seq_file *s, void *v) | |||
87 | 89 | ||
88 | static int ct_seq_show(struct seq_file *s, void *v) | 90 | static int ct_seq_show(struct seq_file *s, void *v) |
89 | { | 91 | { |
90 | const struct nf_conntrack_tuple_hash *hash = v; | 92 | struct nf_conntrack_tuple_hash *hash = v; |
91 | const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | 93 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); |
92 | const struct nf_conntrack_l3proto *l3proto; | 94 | const struct nf_conntrack_l3proto *l3proto; |
93 | const struct nf_conntrack_l4proto *l4proto; | 95 | const struct nf_conntrack_l4proto *l4proto; |
96 | int ret = 0; | ||
94 | 97 | ||
95 | NF_CT_ASSERT(ct); | 98 | NF_CT_ASSERT(ct); |
99 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | ||
100 | return 0; | ||
101 | |||
96 | 102 | ||
97 | /* we only want to print DIR_ORIGINAL */ | 103 | /* we only want to print DIR_ORIGINAL */ |
98 | if (NF_CT_DIRECTION(hash)) | 104 | if (NF_CT_DIRECTION(hash)) |
99 | return 0; | 105 | goto release; |
100 | if (nf_ct_l3num(ct) != AF_INET) | 106 | if (nf_ct_l3num(ct) != AF_INET) |
101 | return 0; | 107 | goto release; |
102 | 108 | ||
103 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); | 109 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); |
104 | NF_CT_ASSERT(l3proto); | 110 | NF_CT_ASSERT(l3proto); |
105 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); | 111 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); |
106 | NF_CT_ASSERT(l4proto); | 112 | NF_CT_ASSERT(l4proto); |
107 | 113 | ||
114 | ret = -ENOSPC; | ||
108 | if (seq_printf(s, "%-8s %u %ld ", | 115 | if (seq_printf(s, "%-8s %u %ld ", |
109 | l4proto->name, nf_ct_protonum(ct), | 116 | l4proto->name, nf_ct_protonum(ct), |
110 | timer_pending(&ct->timeout) | 117 | timer_pending(&ct->timeout) |
111 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) | 118 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) |
112 | return -ENOSPC; | 119 | goto release; |
113 | 120 | ||
114 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) | 121 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) |
115 | return -ENOSPC; | 122 | goto release; |
116 | 123 | ||
117 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 124 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
118 | l3proto, l4proto)) | 125 | l3proto, l4proto)) |
119 | return -ENOSPC; | 126 | goto release; |
120 | 127 | ||
121 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) | 128 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) |
122 | return -ENOSPC; | 129 | goto release; |
123 | 130 | ||
124 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) | 131 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
125 | if (seq_printf(s, "[UNREPLIED] ")) | 132 | if (seq_printf(s, "[UNREPLIED] ")) |
126 | return -ENOSPC; | 133 | goto release; |
127 | 134 | ||
128 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, | 135 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
129 | l3proto, l4proto)) | 136 | l3proto, l4proto)) |
130 | return -ENOSPC; | 137 | goto release; |
131 | 138 | ||
132 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) | 139 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) |
133 | return -ENOSPC; | 140 | goto release; |
134 | 141 | ||
135 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) | 142 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) |
136 | if (seq_printf(s, "[ASSURED] ")) | 143 | if (seq_printf(s, "[ASSURED] ")) |
137 | return -ENOSPC; | 144 | goto release; |
138 | 145 | ||
139 | #ifdef CONFIG_NF_CONNTRACK_MARK | 146 | #ifdef CONFIG_NF_CONNTRACK_MARK |
140 | if (seq_printf(s, "mark=%u ", ct->mark)) | 147 | if (seq_printf(s, "mark=%u ", ct->mark)) |
141 | return -ENOSPC; | 148 | goto release; |
142 | #endif | 149 | #endif |
143 | 150 | ||
144 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | 151 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
145 | if (seq_printf(s, "secmark=%u ", ct->secmark)) | 152 | if (seq_printf(s, "secmark=%u ", ct->secmark)) |
146 | return -ENOSPC; | 153 | goto release; |
147 | #endif | 154 | #endif |
148 | 155 | ||
149 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) | 156 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) |
150 | return -ENOSPC; | 157 | goto release; |
151 | 158 | ret = 0; | |
152 | return 0; | 159 | release: |
160 | nf_ct_put(ct); | ||
161 | return ret; | ||
153 | } | 162 | } |
154 | 163 | ||
155 | static const struct seq_operations ct_seq_ops = { | 164 | static const struct seq_operations ct_seq_ops = { |
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 2a8bee26f43d..23b2c2ee869a 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -262,6 +262,11 @@ static int icmp_nlattr_to_tuple(struct nlattr *tb[], | |||
262 | 262 | ||
263 | return 0; | 263 | return 0; |
264 | } | 264 | } |
265 | |||
266 | static int icmp_nlattr_tuple_size(void) | ||
267 | { | ||
268 | return nla_policy_len(icmp_nla_policy, CTA_PROTO_MAX + 1); | ||
269 | } | ||
265 | #endif | 270 | #endif |
266 | 271 | ||
267 | #ifdef CONFIG_SYSCTL | 272 | #ifdef CONFIG_SYSCTL |
@@ -309,6 +314,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = | |||
309 | .me = NULL, | 314 | .me = NULL, |
310 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 315 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
311 | .tuple_to_nlattr = icmp_tuple_to_nlattr, | 316 | .tuple_to_nlattr = icmp_tuple_to_nlattr, |
317 | .nlattr_tuple_size = icmp_nlattr_tuple_size, | ||
312 | .nlattr_to_tuple = icmp_nlattr_to_tuple, | 318 | .nlattr_to_tuple = icmp_nlattr_to_tuple, |
313 | .nla_policy = icmp_nla_policy, | 319 | .nla_policy = icmp_nla_policy, |
314 | #endif | 320 | #endif |
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index a65cf692359f..fe65187810f0 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
@@ -679,7 +679,7 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct, | |||
679 | static int __net_init nf_nat_net_init(struct net *net) | 679 | static int __net_init nf_nat_net_init(struct net *net) |
680 | { | 680 | { |
681 | net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, | 681 | net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, |
682 | &net->ipv4.nat_vmalloced); | 682 | &net->ipv4.nat_vmalloced, 0); |
683 | if (!net->ipv4.nat_bysource) | 683 | if (!net->ipv4.nat_bysource) |
684 | return -ENOMEM; | 684 | return -ENOMEM; |
685 | return 0; | 685 | return 0; |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 34af7bb8df5f..e89cfa3a8f25 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -89,25 +89,6 @@ ip6t_ext_hdr(u8 nexthdr) | |||
89 | (nexthdr == IPPROTO_DSTOPTS) ); | 89 | (nexthdr == IPPROTO_DSTOPTS) ); |
90 | } | 90 | } |
91 | 91 | ||
92 | static unsigned long ifname_compare(const char *_a, const char *_b, | ||
93 | const unsigned char *_mask) | ||
94 | { | ||
95 | const unsigned long *a = (const unsigned long *)_a; | ||
96 | const unsigned long *b = (const unsigned long *)_b; | ||
97 | const unsigned long *mask = (const unsigned long *)_mask; | ||
98 | unsigned long ret; | ||
99 | |||
100 | ret = (a[0] ^ b[0]) & mask[0]; | ||
101 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
102 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
103 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
104 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
105 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
106 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
107 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | /* Returns whether matches rule or not. */ | 92 | /* Returns whether matches rule or not. */ |
112 | /* Performance critical - called for every packet */ | 93 | /* Performance critical - called for every packet */ |
113 | static inline bool | 94 | static inline bool |
@@ -138,7 +119,7 @@ ip6_packet_match(const struct sk_buff *skb, | |||
138 | return false; | 119 | return false; |
139 | } | 120 | } |
140 | 121 | ||
141 | ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask); | 122 | ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask); |
142 | 123 | ||
143 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { | 124 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { |
144 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 125 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -147,7 +128,7 @@ ip6_packet_match(const struct sk_buff *skb, | |||
147 | return false; | 128 | return false; |
148 | } | 129 | } |
149 | 130 | ||
150 | ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask); | 131 | ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask); |
151 | 132 | ||
152 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { | 133 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { |
153 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 134 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
@@ -536,7 +517,9 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
536 | && unconditional(&e->ipv6)) || visited) { | 517 | && unconditional(&e->ipv6)) || visited) { |
537 | unsigned int oldpos, size; | 518 | unsigned int oldpos, size; |
538 | 519 | ||
539 | if (t->verdict < -NF_MAX_VERDICT - 1) { | 520 | if ((strcmp(t->target.u.user.name, |
521 | IP6T_STANDARD_TARGET) == 0) && | ||
522 | t->verdict < -NF_MAX_VERDICT - 1) { | ||
540 | duprintf("mark_source_chains: bad " | 523 | duprintf("mark_source_chains: bad " |
541 | "negative verdict (%i)\n", | 524 | "negative verdict (%i)\n", |
542 | t->verdict); | 525 | t->verdict); |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index e6852f617217..2a15c2d66c69 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -342,6 +342,11 @@ static int ipv6_nlattr_to_tuple(struct nlattr *tb[], | |||
342 | 342 | ||
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | |||
346 | static int ipv6_nlattr_tuple_size(void) | ||
347 | { | ||
348 | return nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1); | ||
349 | } | ||
345 | #endif | 350 | #endif |
346 | 351 | ||
347 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { | 352 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { |
@@ -353,6 +358,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { | |||
353 | .get_l4proto = ipv6_get_l4proto, | 358 | .get_l4proto = ipv6_get_l4proto, |
354 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 359 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
355 | .tuple_to_nlattr = ipv6_tuple_to_nlattr, | 360 | .tuple_to_nlattr = ipv6_tuple_to_nlattr, |
361 | .nlattr_tuple_size = ipv6_nlattr_tuple_size, | ||
356 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, | 362 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, |
357 | .nla_policy = ipv6_nla_policy, | 363 | .nla_policy = ipv6_nla_policy, |
358 | #endif | 364 | #endif |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 41b8a956e1be..9903227bf37c 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -269,6 +269,11 @@ static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], | |||
269 | 269 | ||
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | |||
273 | static int icmpv6_nlattr_tuple_size(void) | ||
274 | { | ||
275 | return nla_policy_len(icmpv6_nla_policy, CTA_PROTO_MAX + 1); | ||
276 | } | ||
272 | #endif | 277 | #endif |
273 | 278 | ||
274 | #ifdef CONFIG_SYSCTL | 279 | #ifdef CONFIG_SYSCTL |
@@ -300,6 +305,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = | |||
300 | .error = icmpv6_error, | 305 | .error = icmpv6_error, |
301 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 306 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
302 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, | 307 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, |
308 | .nlattr_tuple_size = icmpv6_nlattr_tuple_size, | ||
303 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, | 309 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
304 | .nla_policy = icmpv6_nla_policy, | 310 | .nla_policy = icmpv6_nla_policy, |
305 | #endif | 311 | #endif |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 2562d05dbaf5..2c967e4f706c 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -374,7 +374,7 @@ config NETFILTER_XT_TARGET_HL | |||
374 | 374 | ||
375 | config NETFILTER_XT_TARGET_LED | 375 | config NETFILTER_XT_TARGET_LED |
376 | tristate '"LED" target support' | 376 | tristate '"LED" target support' |
377 | depends on LEDS_CLASS | 377 | depends on LEDS_CLASS && LED_TRIGGERS |
378 | depends on NETFILTER_ADVANCED | 378 | depends on NETFILTER_ADVANCED |
379 | help | 379 | help |
380 | This option adds a `LED' target, which allows you to blink LEDs in | 380 | This option adds a `LED' target, which allows you to blink LEDs in |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index dfb447b584da..8020db6274b8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
30 | #include <linux/socket.h> | 30 | #include <linux/socket.h> |
31 | #include <linux/mm.h> | 31 | #include <linux/mm.h> |
32 | #include <linux/rculist_nulls.h> | ||
32 | 33 | ||
33 | #include <net/netfilter/nf_conntrack.h> | 34 | #include <net/netfilter/nf_conntrack.h> |
34 | #include <net/netfilter/nf_conntrack_l3proto.h> | 35 | #include <net/netfilter/nf_conntrack_l3proto.h> |
@@ -163,8 +164,8 @@ static void | |||
163 | clean_from_lists(struct nf_conn *ct) | 164 | clean_from_lists(struct nf_conn *ct) |
164 | { | 165 | { |
165 | pr_debug("clean_from_lists(%p)\n", ct); | 166 | pr_debug("clean_from_lists(%p)\n", ct); |
166 | hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | 167 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); |
167 | hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode); | 168 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); |
168 | 169 | ||
169 | /* Destroy all pending expectations */ | 170 | /* Destroy all pending expectations */ |
170 | nf_ct_remove_expectations(ct); | 171 | nf_ct_remove_expectations(ct); |
@@ -204,8 +205,8 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
204 | 205 | ||
205 | /* We overload first tuple to link into unconfirmed list. */ | 206 | /* We overload first tuple to link into unconfirmed list. */ |
206 | if (!nf_ct_is_confirmed(ct)) { | 207 | if (!nf_ct_is_confirmed(ct)) { |
207 | BUG_ON(hlist_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode)); | 208 | BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); |
208 | hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | 209 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); |
209 | } | 210 | } |
210 | 211 | ||
211 | NF_CT_STAT_INC(net, delete); | 212 | NF_CT_STAT_INC(net, delete); |
@@ -242,18 +243,26 @@ static void death_by_timeout(unsigned long ul_conntrack) | |||
242 | nf_ct_put(ct); | 243 | nf_ct_put(ct); |
243 | } | 244 | } |
244 | 245 | ||
246 | /* | ||
247 | * Warning : | ||
248 | * - Caller must take a reference on returned object | ||
249 | * and recheck nf_ct_tuple_equal(tuple, &h->tuple) | ||
250 | * OR | ||
251 | * - Caller must lock nf_conntrack_lock before calling this function | ||
252 | */ | ||
245 | struct nf_conntrack_tuple_hash * | 253 | struct nf_conntrack_tuple_hash * |
246 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) | 254 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) |
247 | { | 255 | { |
248 | struct nf_conntrack_tuple_hash *h; | 256 | struct nf_conntrack_tuple_hash *h; |
249 | struct hlist_node *n; | 257 | struct hlist_nulls_node *n; |
250 | unsigned int hash = hash_conntrack(tuple); | 258 | unsigned int hash = hash_conntrack(tuple); |
251 | 259 | ||
252 | /* Disable BHs the entire time since we normally need to disable them | 260 | /* Disable BHs the entire time since we normally need to disable them |
253 | * at least once for the stats anyway. | 261 | * at least once for the stats anyway. |
254 | */ | 262 | */ |
255 | local_bh_disable(); | 263 | local_bh_disable(); |
256 | hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) { | 264 | begin: |
265 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { | ||
257 | if (nf_ct_tuple_equal(tuple, &h->tuple)) { | 266 | if (nf_ct_tuple_equal(tuple, &h->tuple)) { |
258 | NF_CT_STAT_INC(net, found); | 267 | NF_CT_STAT_INC(net, found); |
259 | local_bh_enable(); | 268 | local_bh_enable(); |
@@ -261,6 +270,13 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) | |||
261 | } | 270 | } |
262 | NF_CT_STAT_INC(net, searched); | 271 | NF_CT_STAT_INC(net, searched); |
263 | } | 272 | } |
273 | /* | ||
274 | * if the nulls value we got at the end of this lookup is | ||
275 | * not the expected one, we must restart lookup. | ||
276 | * We probably met an item that was moved to another chain. | ||
277 | */ | ||
278 | if (get_nulls_value(n) != hash) | ||
279 | goto begin; | ||
264 | local_bh_enable(); | 280 | local_bh_enable(); |
265 | 281 | ||
266 | return NULL; | 282 | return NULL; |
@@ -275,11 +291,18 @@ nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) | |||
275 | struct nf_conn *ct; | 291 | struct nf_conn *ct; |
276 | 292 | ||
277 | rcu_read_lock(); | 293 | rcu_read_lock(); |
294 | begin: | ||
278 | h = __nf_conntrack_find(net, tuple); | 295 | h = __nf_conntrack_find(net, tuple); |
279 | if (h) { | 296 | if (h) { |
280 | ct = nf_ct_tuplehash_to_ctrack(h); | 297 | ct = nf_ct_tuplehash_to_ctrack(h); |
281 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | 298 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) |
282 | h = NULL; | 299 | h = NULL; |
300 | else { | ||
301 | if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) { | ||
302 | nf_ct_put(ct); | ||
303 | goto begin; | ||
304 | } | ||
305 | } | ||
283 | } | 306 | } |
284 | rcu_read_unlock(); | 307 | rcu_read_unlock(); |
285 | 308 | ||
@@ -293,9 +316,9 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct, | |||
293 | { | 316 | { |
294 | struct net *net = nf_ct_net(ct); | 317 | struct net *net = nf_ct_net(ct); |
295 | 318 | ||
296 | hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, | 319 | hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, |
297 | &net->ct.hash[hash]); | 320 | &net->ct.hash[hash]); |
298 | hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode, | 321 | hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, |
299 | &net->ct.hash[repl_hash]); | 322 | &net->ct.hash[repl_hash]); |
300 | } | 323 | } |
301 | 324 | ||
@@ -318,7 +341,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
318 | struct nf_conntrack_tuple_hash *h; | 341 | struct nf_conntrack_tuple_hash *h; |
319 | struct nf_conn *ct; | 342 | struct nf_conn *ct; |
320 | struct nf_conn_help *help; | 343 | struct nf_conn_help *help; |
321 | struct hlist_node *n; | 344 | struct hlist_nulls_node *n; |
322 | enum ip_conntrack_info ctinfo; | 345 | enum ip_conntrack_info ctinfo; |
323 | struct net *net; | 346 | struct net *net; |
324 | 347 | ||
@@ -350,17 +373,17 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
350 | /* See if there's one in the list already, including reverse: | 373 | /* See if there's one in the list already, including reverse: |
351 | NAT could have grabbed it without realizing, since we're | 374 | NAT could have grabbed it without realizing, since we're |
352 | not in the hash. If there is, we lost race. */ | 375 | not in the hash. If there is, we lost race. */ |
353 | hlist_for_each_entry(h, n, &net->ct.hash[hash], hnode) | 376 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) |
354 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 377 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
355 | &h->tuple)) | 378 | &h->tuple)) |
356 | goto out; | 379 | goto out; |
357 | hlist_for_each_entry(h, n, &net->ct.hash[repl_hash], hnode) | 380 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) |
358 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, | 381 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
359 | &h->tuple)) | 382 | &h->tuple)) |
360 | goto out; | 383 | goto out; |
361 | 384 | ||
362 | /* Remove from unconfirmed list */ | 385 | /* Remove from unconfirmed list */ |
363 | hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | 386 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); |
364 | 387 | ||
365 | __nf_conntrack_hash_insert(ct, hash, repl_hash); | 388 | __nf_conntrack_hash_insert(ct, hash, repl_hash); |
366 | /* Timer relative to confirmation time, not original | 389 | /* Timer relative to confirmation time, not original |
@@ -399,14 +422,14 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, | |||
399 | { | 422 | { |
400 | struct net *net = nf_ct_net(ignored_conntrack); | 423 | struct net *net = nf_ct_net(ignored_conntrack); |
401 | struct nf_conntrack_tuple_hash *h; | 424 | struct nf_conntrack_tuple_hash *h; |
402 | struct hlist_node *n; | 425 | struct hlist_nulls_node *n; |
403 | unsigned int hash = hash_conntrack(tuple); | 426 | unsigned int hash = hash_conntrack(tuple); |
404 | 427 | ||
405 | /* Disable BHs the entire time since we need to disable them at | 428 | /* Disable BHs the entire time since we need to disable them at |
406 | * least once for the stats anyway. | 429 | * least once for the stats anyway. |
407 | */ | 430 | */ |
408 | rcu_read_lock_bh(); | 431 | rcu_read_lock_bh(); |
409 | hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) { | 432 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { |
410 | if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && | 433 | if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && |
411 | nf_ct_tuple_equal(tuple, &h->tuple)) { | 434 | nf_ct_tuple_equal(tuple, &h->tuple)) { |
412 | NF_CT_STAT_INC(net, found); | 435 | NF_CT_STAT_INC(net, found); |
@@ -430,14 +453,14 @@ static noinline int early_drop(struct net *net, unsigned int hash) | |||
430 | /* Use oldest entry, which is roughly LRU */ | 453 | /* Use oldest entry, which is roughly LRU */ |
431 | struct nf_conntrack_tuple_hash *h; | 454 | struct nf_conntrack_tuple_hash *h; |
432 | struct nf_conn *ct = NULL, *tmp; | 455 | struct nf_conn *ct = NULL, *tmp; |
433 | struct hlist_node *n; | 456 | struct hlist_nulls_node *n; |
434 | unsigned int i, cnt = 0; | 457 | unsigned int i, cnt = 0; |
435 | int dropped = 0; | 458 | int dropped = 0; |
436 | 459 | ||
437 | rcu_read_lock(); | 460 | rcu_read_lock(); |
438 | for (i = 0; i < nf_conntrack_htable_size; i++) { | 461 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
439 | hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], | 462 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], |
440 | hnode) { | 463 | hnnode) { |
441 | tmp = nf_ct_tuplehash_to_ctrack(h); | 464 | tmp = nf_ct_tuplehash_to_ctrack(h); |
442 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) | 465 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) |
443 | ct = tmp; | 466 | ct = tmp; |
@@ -508,27 +531,19 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, | |||
508 | #ifdef CONFIG_NET_NS | 531 | #ifdef CONFIG_NET_NS |
509 | ct->ct_net = net; | 532 | ct->ct_net = net; |
510 | #endif | 533 | #endif |
511 | INIT_RCU_HEAD(&ct->rcu); | ||
512 | 534 | ||
513 | return ct; | 535 | return ct; |
514 | } | 536 | } |
515 | EXPORT_SYMBOL_GPL(nf_conntrack_alloc); | 537 | EXPORT_SYMBOL_GPL(nf_conntrack_alloc); |
516 | 538 | ||
517 | static void nf_conntrack_free_rcu(struct rcu_head *head) | ||
518 | { | ||
519 | struct nf_conn *ct = container_of(head, struct nf_conn, rcu); | ||
520 | |||
521 | nf_ct_ext_free(ct); | ||
522 | kmem_cache_free(nf_conntrack_cachep, ct); | ||
523 | } | ||
524 | |||
525 | void nf_conntrack_free(struct nf_conn *ct) | 539 | void nf_conntrack_free(struct nf_conn *ct) |
526 | { | 540 | { |
527 | struct net *net = nf_ct_net(ct); | 541 | struct net *net = nf_ct_net(ct); |
528 | 542 | ||
529 | nf_ct_ext_destroy(ct); | 543 | nf_ct_ext_destroy(ct); |
530 | atomic_dec(&net->ct.count); | 544 | atomic_dec(&net->ct.count); |
531 | call_rcu(&ct->rcu, nf_conntrack_free_rcu); | 545 | nf_ct_ext_free(ct); |
546 | kmem_cache_free(nf_conntrack_cachep, ct); | ||
532 | } | 547 | } |
533 | EXPORT_SYMBOL_GPL(nf_conntrack_free); | 548 | EXPORT_SYMBOL_GPL(nf_conntrack_free); |
534 | 549 | ||
@@ -594,7 +609,7 @@ init_conntrack(struct net *net, | |||
594 | } | 609 | } |
595 | 610 | ||
596 | /* Overload tuple linked list to put us in unconfirmed list. */ | 611 | /* Overload tuple linked list to put us in unconfirmed list. */ |
597 | hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, | 612 | hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, |
598 | &net->ct.unconfirmed); | 613 | &net->ct.unconfirmed); |
599 | 614 | ||
600 | spin_unlock_bh(&nf_conntrack_lock); | 615 | spin_unlock_bh(&nf_conntrack_lock); |
@@ -906,6 +921,12 @@ int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], | |||
906 | return 0; | 921 | return 0; |
907 | } | 922 | } |
908 | EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple); | 923 | EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple); |
924 | |||
925 | int nf_ct_port_nlattr_tuple_size(void) | ||
926 | { | ||
927 | return nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); | ||
928 | } | ||
929 | EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_tuple_size); | ||
909 | #endif | 930 | #endif |
910 | 931 | ||
911 | /* Used by ipt_REJECT and ip6t_REJECT. */ | 932 | /* Used by ipt_REJECT and ip6t_REJECT. */ |
@@ -934,17 +955,17 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), | |||
934 | { | 955 | { |
935 | struct nf_conntrack_tuple_hash *h; | 956 | struct nf_conntrack_tuple_hash *h; |
936 | struct nf_conn *ct; | 957 | struct nf_conn *ct; |
937 | struct hlist_node *n; | 958 | struct hlist_nulls_node *n; |
938 | 959 | ||
939 | spin_lock_bh(&nf_conntrack_lock); | 960 | spin_lock_bh(&nf_conntrack_lock); |
940 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { | 961 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { |
941 | hlist_for_each_entry(h, n, &net->ct.hash[*bucket], hnode) { | 962 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) { |
942 | ct = nf_ct_tuplehash_to_ctrack(h); | 963 | ct = nf_ct_tuplehash_to_ctrack(h); |
943 | if (iter(ct, data)) | 964 | if (iter(ct, data)) |
944 | goto found; | 965 | goto found; |
945 | } | 966 | } |
946 | } | 967 | } |
947 | hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode) { | 968 | hlist_nulls_for_each_entry(h, n, &net->ct.unconfirmed, hnnode) { |
948 | ct = nf_ct_tuplehash_to_ctrack(h); | 969 | ct = nf_ct_tuplehash_to_ctrack(h); |
949 | if (iter(ct, data)) | 970 | if (iter(ct, data)) |
950 | set_bit(IPS_DYING_BIT, &ct->status); | 971 | set_bit(IPS_DYING_BIT, &ct->status); |
@@ -992,7 +1013,7 @@ static int kill_all(struct nf_conn *i, void *data) | |||
992 | return 1; | 1013 | return 1; |
993 | } | 1014 | } |
994 | 1015 | ||
995 | void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int size) | 1016 | void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size) |
996 | { | 1017 | { |
997 | if (vmalloced) | 1018 | if (vmalloced) |
998 | vfree(hash); | 1019 | vfree(hash); |
@@ -1060,26 +1081,28 @@ void nf_conntrack_cleanup(struct net *net) | |||
1060 | } | 1081 | } |
1061 | } | 1082 | } |
1062 | 1083 | ||
1063 | struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced) | 1084 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls) |
1064 | { | 1085 | { |
1065 | struct hlist_head *hash; | 1086 | struct hlist_nulls_head *hash; |
1066 | unsigned int size, i; | 1087 | unsigned int nr_slots, i; |
1088 | size_t sz; | ||
1067 | 1089 | ||
1068 | *vmalloced = 0; | 1090 | *vmalloced = 0; |
1069 | 1091 | ||
1070 | size = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_head)); | 1092 | BUILD_BUG_ON(sizeof(struct hlist_nulls_head) != sizeof(struct hlist_head)); |
1071 | hash = (void*)__get_free_pages(GFP_KERNEL|__GFP_NOWARN, | 1093 | nr_slots = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_nulls_head)); |
1072 | get_order(sizeof(struct hlist_head) | 1094 | sz = nr_slots * sizeof(struct hlist_nulls_head); |
1073 | * size)); | 1095 | hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, |
1096 | get_order(sz)); | ||
1074 | if (!hash) { | 1097 | if (!hash) { |
1075 | *vmalloced = 1; | 1098 | *vmalloced = 1; |
1076 | printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); | 1099 | printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); |
1077 | hash = vmalloc(sizeof(struct hlist_head) * size); | 1100 | hash = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); |
1078 | } | 1101 | } |
1079 | 1102 | ||
1080 | if (hash) | 1103 | if (hash && nulls) |
1081 | for (i = 0; i < size; i++) | 1104 | for (i = 0; i < nr_slots; i++) |
1082 | INIT_HLIST_HEAD(&hash[i]); | 1105 | INIT_HLIST_NULLS_HEAD(&hash[i], i); |
1083 | 1106 | ||
1084 | return hash; | 1107 | return hash; |
1085 | } | 1108 | } |
@@ -1090,7 +1113,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) | |||
1090 | int i, bucket, vmalloced, old_vmalloced; | 1113 | int i, bucket, vmalloced, old_vmalloced; |
1091 | unsigned int hashsize, old_size; | 1114 | unsigned int hashsize, old_size; |
1092 | int rnd; | 1115 | int rnd; |
1093 | struct hlist_head *hash, *old_hash; | 1116 | struct hlist_nulls_head *hash, *old_hash; |
1094 | struct nf_conntrack_tuple_hash *h; | 1117 | struct nf_conntrack_tuple_hash *h; |
1095 | 1118 | ||
1096 | /* On boot, we can set this without any fancy locking. */ | 1119 | /* On boot, we can set this without any fancy locking. */ |
@@ -1101,7 +1124,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) | |||
1101 | if (!hashsize) | 1124 | if (!hashsize) |
1102 | return -EINVAL; | 1125 | return -EINVAL; |
1103 | 1126 | ||
1104 | hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced); | 1127 | hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced, 1); |
1105 | if (!hash) | 1128 | if (!hash) |
1106 | return -ENOMEM; | 1129 | return -ENOMEM; |
1107 | 1130 | ||
@@ -1116,12 +1139,12 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) | |||
1116 | */ | 1139 | */ |
1117 | spin_lock_bh(&nf_conntrack_lock); | 1140 | spin_lock_bh(&nf_conntrack_lock); |
1118 | for (i = 0; i < nf_conntrack_htable_size; i++) { | 1141 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
1119 | while (!hlist_empty(&init_net.ct.hash[i])) { | 1142 | while (!hlist_nulls_empty(&init_net.ct.hash[i])) { |
1120 | h = hlist_entry(init_net.ct.hash[i].first, | 1143 | h = hlist_nulls_entry(init_net.ct.hash[i].first, |
1121 | struct nf_conntrack_tuple_hash, hnode); | 1144 | struct nf_conntrack_tuple_hash, hnnode); |
1122 | hlist_del_rcu(&h->hnode); | 1145 | hlist_nulls_del_rcu(&h->hnnode); |
1123 | bucket = __hash_conntrack(&h->tuple, hashsize, rnd); | 1146 | bucket = __hash_conntrack(&h->tuple, hashsize, rnd); |
1124 | hlist_add_head(&h->hnode, &hash[bucket]); | 1147 | hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]); |
1125 | } | 1148 | } |
1126 | } | 1149 | } |
1127 | old_size = nf_conntrack_htable_size; | 1150 | old_size = nf_conntrack_htable_size; |
@@ -1172,7 +1195,7 @@ static int nf_conntrack_init_init_net(void) | |||
1172 | 1195 | ||
1173 | nf_conntrack_cachep = kmem_cache_create("nf_conntrack", | 1196 | nf_conntrack_cachep = kmem_cache_create("nf_conntrack", |
1174 | sizeof(struct nf_conn), | 1197 | sizeof(struct nf_conn), |
1175 | 0, 0, NULL); | 1198 | 0, SLAB_DESTROY_BY_RCU, NULL); |
1176 | if (!nf_conntrack_cachep) { | 1199 | if (!nf_conntrack_cachep) { |
1177 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); | 1200 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); |
1178 | ret = -ENOMEM; | 1201 | ret = -ENOMEM; |
@@ -1202,7 +1225,7 @@ static int nf_conntrack_init_net(struct net *net) | |||
1202 | int ret; | 1225 | int ret; |
1203 | 1226 | ||
1204 | atomic_set(&net->ct.count, 0); | 1227 | atomic_set(&net->ct.count, 0); |
1205 | INIT_HLIST_HEAD(&net->ct.unconfirmed); | 1228 | INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); |
1206 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); | 1229 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); |
1207 | if (!net->ct.stat) { | 1230 | if (!net->ct.stat) { |
1208 | ret = -ENOMEM; | 1231 | ret = -ENOMEM; |
@@ -1212,7 +1235,7 @@ static int nf_conntrack_init_net(struct net *net) | |||
1212 | if (ret < 0) | 1235 | if (ret < 0) |
1213 | goto err_ecache; | 1236 | goto err_ecache; |
1214 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, | 1237 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, |
1215 | &net->ct.hash_vmalloc); | 1238 | &net->ct.hash_vmalloc, 1); |
1216 | if (!net->ct.hash) { | 1239 | if (!net->ct.hash) { |
1217 | ret = -ENOMEM; | 1240 | ret = -ENOMEM; |
1218 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); | 1241 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 357ba39d4c8d..3940f996a2e4 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -604,7 +604,7 @@ int nf_conntrack_expect_init(struct net *net) | |||
604 | 604 | ||
605 | net->ct.expect_count = 0; | 605 | net->ct.expect_count = 0; |
606 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, | 606 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, |
607 | &net->ct.expect_vmalloc); | 607 | &net->ct.expect_vmalloc, 0); |
608 | if (net->ct.expect_hash == NULL) | 608 | if (net->ct.expect_hash == NULL) |
609 | goto err1; | 609 | goto err1; |
610 | 610 | ||
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index a51bdac9f3a0..30b8e9009f99 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -142,6 +142,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | |||
142 | 142 | ||
143 | BUG_ON(me->expect_policy == NULL); | 143 | BUG_ON(me->expect_policy == NULL); |
144 | BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); | 144 | BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); |
145 | BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1); | ||
145 | 146 | ||
146 | mutex_lock(&nf_ct_helper_mutex); | 147 | mutex_lock(&nf_ct_helper_mutex); |
147 | hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); | 148 | hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); |
@@ -158,6 +159,7 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, | |||
158 | struct nf_conntrack_tuple_hash *h; | 159 | struct nf_conntrack_tuple_hash *h; |
159 | struct nf_conntrack_expect *exp; | 160 | struct nf_conntrack_expect *exp; |
160 | const struct hlist_node *n, *next; | 161 | const struct hlist_node *n, *next; |
162 | const struct hlist_nulls_node *nn; | ||
161 | unsigned int i; | 163 | unsigned int i; |
162 | 164 | ||
163 | /* Get rid of expectations */ | 165 | /* Get rid of expectations */ |
@@ -174,10 +176,10 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, | |||
174 | } | 176 | } |
175 | 177 | ||
176 | /* Get rid of expecteds, set helpers to NULL. */ | 178 | /* Get rid of expecteds, set helpers to NULL. */ |
177 | hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode) | 179 | hlist_for_each_entry(h, nn, &net->ct.unconfirmed, hnnode) |
178 | unhelp(h, me); | 180 | unhelp(h, me); |
179 | for (i = 0; i < nf_conntrack_htable_size; i++) { | 181 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
180 | hlist_for_each_entry(h, n, &net->ct.hash[i], hnode) | 182 | hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode) |
181 | unhelp(h, me); | 183 | unhelp(h, me); |
182 | } | 184 | } |
183 | } | 185 | } |
@@ -217,7 +219,7 @@ int nf_conntrack_helper_init(void) | |||
217 | 219 | ||
218 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ | 220 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ |
219 | nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, | 221 | nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, |
220 | &nf_ct_helper_vmalloc); | 222 | &nf_ct_helper_vmalloc, 0); |
221 | if (!nf_ct_helper_hash) | 223 | if (!nf_ct_helper_hash) |
222 | return -ENOMEM; | 224 | return -ENOMEM; |
223 | 225 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 7a16bd462f82..c6439c77953c 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/rculist.h> | 21 | #include <linux/rculist.h> |
22 | #include <linux/rculist_nulls.h> | ||
22 | #include <linux/types.h> | 23 | #include <linux/types.h> |
23 | #include <linux/timer.h> | 24 | #include <linux/timer.h> |
24 | #include <linux/skbuff.h> | 25 | #include <linux/skbuff.h> |
@@ -404,6 +405,78 @@ nla_put_failure: | |||
404 | } | 405 | } |
405 | 406 | ||
406 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 407 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
408 | /* | ||
409 | * The general structure of a ctnetlink event is | ||
410 | * | ||
411 | * CTA_TUPLE_ORIG | ||
412 | * <l3/l4-proto-attributes> | ||
413 | * CTA_TUPLE_REPLY | ||
414 | * <l3/l4-proto-attributes> | ||
415 | * CTA_ID | ||
416 | * ... | ||
417 | * CTA_PROTOINFO | ||
418 | * <l4-proto-attributes> | ||
419 | * CTA_TUPLE_MASTER | ||
420 | * <l3/l4-proto-attributes> | ||
421 | * | ||
422 | * Therefore the formular is | ||
423 | * | ||
424 | * size = sizeof(headers) + sizeof(generic_nlas) + 3 * sizeof(tuple_nlas) | ||
425 | * + sizeof(protoinfo_nlas) | ||
426 | */ | ||
427 | static struct sk_buff * | ||
428 | ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp) | ||
429 | { | ||
430 | struct nf_conntrack_l3proto *l3proto; | ||
431 | struct nf_conntrack_l4proto *l4proto; | ||
432 | int len; | ||
433 | |||
434 | #define NLA_TYPE_SIZE(type) nla_total_size(sizeof(type)) | ||
435 | |||
436 | /* proto independant part */ | ||
437 | len = NLMSG_SPACE(sizeof(struct nfgenmsg)) | ||
438 | + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ | ||
439 | + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ | ||
440 | + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ | ||
441 | + 3 * NLA_TYPE_SIZE(u_int8_t) /* CTA_PROTO_NUM */ | ||
442 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_ID */ | ||
443 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_STATUS */ | ||
444 | #ifdef CONFIG_NF_CT_ACCT | ||
445 | + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ | ||
446 | + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_PACKETS */ | ||
447 | + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_BYTES */ | ||
448 | #endif | ||
449 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_TIMEOUT */ | ||
450 | + nla_total_size(0) /* CTA_PROTOINFO */ | ||
451 | + nla_total_size(0) /* CTA_HELP */ | ||
452 | + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */ | ||
453 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | ||
454 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_SECMARK */ | ||
455 | #endif | ||
456 | #ifdef CONFIG_NF_NAT_NEEDED | ||
457 | + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */ | ||
458 | + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_POS */ | ||
459 | + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_BEFORE */ | ||
460 | + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_AFTER */ | ||
461 | #endif | ||
462 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
463 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_MARK */ | ||
464 | #endif | ||
465 | ; | ||
466 | |||
467 | #undef NLA_TYPE_SIZE | ||
468 | |||
469 | rcu_read_lock(); | ||
470 | l3proto = __nf_ct_l3proto_find(tuple->src.l3num); | ||
471 | len += l3proto->nla_size; | ||
472 | |||
473 | l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); | ||
474 | len += l4proto->nla_size; | ||
475 | rcu_read_unlock(); | ||
476 | |||
477 | return alloc_skb(len, gfp); | ||
478 | } | ||
479 | |||
407 | static int ctnetlink_conntrack_event(struct notifier_block *this, | 480 | static int ctnetlink_conntrack_event(struct notifier_block *this, |
408 | unsigned long events, void *ptr) | 481 | unsigned long events, void *ptr) |
409 | { | 482 | { |
@@ -437,7 +510,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
437 | if (!item->report && !nfnetlink_has_listeners(group)) | 510 | if (!item->report && !nfnetlink_has_listeners(group)) |
438 | return NOTIFY_DONE; | 511 | return NOTIFY_DONE; |
439 | 512 | ||
440 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 513 | skb = ctnetlink_alloc_skb(tuple(ct, IP_CT_DIR_ORIGINAL), GFP_ATOMIC); |
441 | if (!skb) | 514 | if (!skb) |
442 | return NOTIFY_DONE; | 515 | return NOTIFY_DONE; |
443 | 516 | ||
@@ -536,7 +609,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
536 | { | 609 | { |
537 | struct nf_conn *ct, *last; | 610 | struct nf_conn *ct, *last; |
538 | struct nf_conntrack_tuple_hash *h; | 611 | struct nf_conntrack_tuple_hash *h; |
539 | struct hlist_node *n; | 612 | struct hlist_nulls_node *n; |
540 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | 613 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); |
541 | u_int8_t l3proto = nfmsg->nfgen_family; | 614 | u_int8_t l3proto = nfmsg->nfgen_family; |
542 | 615 | ||
@@ -544,27 +617,27 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
544 | last = (struct nf_conn *)cb->args[1]; | 617 | last = (struct nf_conn *)cb->args[1]; |
545 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { | 618 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { |
546 | restart: | 619 | restart: |
547 | hlist_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]], | 620 | hlist_nulls_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]], |
548 | hnode) { | 621 | hnnode) { |
549 | if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) | 622 | if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) |
550 | continue; | 623 | continue; |
551 | ct = nf_ct_tuplehash_to_ctrack(h); | 624 | ct = nf_ct_tuplehash_to_ctrack(h); |
625 | if (!atomic_inc_not_zero(&ct->ct_general.use)) | ||
626 | continue; | ||
552 | /* Dump entries of a given L3 protocol number. | 627 | /* Dump entries of a given L3 protocol number. |
553 | * If it is not specified, ie. l3proto == 0, | 628 | * If it is not specified, ie. l3proto == 0, |
554 | * then dump everything. */ | 629 | * then dump everything. */ |
555 | if (l3proto && nf_ct_l3num(ct) != l3proto) | 630 | if (l3proto && nf_ct_l3num(ct) != l3proto) |
556 | continue; | 631 | goto releasect; |
557 | if (cb->args[1]) { | 632 | if (cb->args[1]) { |
558 | if (ct != last) | 633 | if (ct != last) |
559 | continue; | 634 | goto releasect; |
560 | cb->args[1] = 0; | 635 | cb->args[1] = 0; |
561 | } | 636 | } |
562 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | 637 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
563 | cb->nlh->nlmsg_seq, | 638 | cb->nlh->nlmsg_seq, |
564 | IPCTNL_MSG_CT_NEW, | 639 | IPCTNL_MSG_CT_NEW, |
565 | 1, ct) < 0) { | 640 | 1, ct) < 0) { |
566 | if (!atomic_inc_not_zero(&ct->ct_general.use)) | ||
567 | continue; | ||
568 | cb->args[1] = (unsigned long)ct; | 641 | cb->args[1] = (unsigned long)ct; |
569 | goto out; | 642 | goto out; |
570 | } | 643 | } |
@@ -577,6 +650,8 @@ restart: | |||
577 | if (acct) | 650 | if (acct) |
578 | memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX])); | 651 | memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX])); |
579 | } | 652 | } |
653 | releasect: | ||
654 | nf_ct_put(ct); | ||
580 | } | 655 | } |
581 | if (cb->args[1]) { | 656 | if (cb->args[1]) { |
582 | cb->args[1] = 0; | 657 | cb->args[1] = 0; |
@@ -1242,13 +1317,12 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1242 | if (err < 0) | 1317 | if (err < 0) |
1243 | goto err2; | 1318 | goto err2; |
1244 | 1319 | ||
1245 | master_h = __nf_conntrack_find(&init_net, &master); | 1320 | master_h = nf_conntrack_find_get(&init_net, &master); |
1246 | if (master_h == NULL) { | 1321 | if (master_h == NULL) { |
1247 | err = -ENOENT; | 1322 | err = -ENOENT; |
1248 | goto err2; | 1323 | goto err2; |
1249 | } | 1324 | } |
1250 | master_ct = nf_ct_tuplehash_to_ctrack(master_h); | 1325 | master_ct = nf_ct_tuplehash_to_ctrack(master_h); |
1251 | nf_conntrack_get(&master_ct->ct_general); | ||
1252 | __set_bit(IPS_EXPECTED_BIT, &ct->status); | 1326 | __set_bit(IPS_EXPECTED_BIT, &ct->status); |
1253 | ct->master = master_ct; | 1327 | ct->master = master_ct; |
1254 | } | 1328 | } |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 9a62b4efa0e1..1a4568bf7ea5 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -167,6 +167,9 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
167 | if (proto->l3proto >= AF_MAX) | 167 | if (proto->l3proto >= AF_MAX) |
168 | return -EBUSY; | 168 | return -EBUSY; |
169 | 169 | ||
170 | if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size) | ||
171 | return -EINVAL; | ||
172 | |||
170 | mutex_lock(&nf_ct_proto_mutex); | 173 | mutex_lock(&nf_ct_proto_mutex); |
171 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { | 174 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { |
172 | ret = -EBUSY; | 175 | ret = -EBUSY; |
@@ -177,6 +180,9 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
177 | if (ret < 0) | 180 | if (ret < 0) |
178 | goto out_unlock; | 181 | goto out_unlock; |
179 | 182 | ||
183 | if (proto->nlattr_tuple_size) | ||
184 | proto->nla_size = 3 * proto->nlattr_tuple_size(); | ||
185 | |||
180 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); | 186 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); |
181 | 187 | ||
182 | out_unlock: | 188 | out_unlock: |
@@ -263,6 +269,10 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) | |||
263 | if (l4proto->l3proto >= PF_MAX) | 269 | if (l4proto->l3proto >= PF_MAX) |
264 | return -EBUSY; | 270 | return -EBUSY; |
265 | 271 | ||
272 | if ((l4proto->to_nlattr && !l4proto->nlattr_size) | ||
273 | || (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) | ||
274 | return -EINVAL; | ||
275 | |||
266 | mutex_lock(&nf_ct_proto_mutex); | 276 | mutex_lock(&nf_ct_proto_mutex); |
267 | if (!nf_ct_protos[l4proto->l3proto]) { | 277 | if (!nf_ct_protos[l4proto->l3proto]) { |
268 | /* l3proto may be loaded latter. */ | 278 | /* l3proto may be loaded latter. */ |
@@ -290,6 +300,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) | |||
290 | if (ret < 0) | 300 | if (ret < 0) |
291 | goto out_unlock; | 301 | goto out_unlock; |
292 | 302 | ||
303 | l4proto->nla_size = 0; | ||
304 | if (l4proto->nlattr_size) | ||
305 | l4proto->nla_size += l4proto->nlattr_size(); | ||
306 | if (l4proto->nlattr_tuple_size) | ||
307 | l4proto->nla_size += 3 * l4proto->nlattr_tuple_size(); | ||
308 | |||
293 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], | 309 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], |
294 | l4proto); | 310 | l4proto); |
295 | 311 | ||
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index d3d5a7fd73ce..50dac8dbe7d8 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
@@ -669,6 +669,12 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) | |||
669 | write_unlock_bh(&dccp_lock); | 669 | write_unlock_bh(&dccp_lock); |
670 | return 0; | 670 | return 0; |
671 | } | 671 | } |
672 | |||
673 | static int dccp_nlattr_size(void) | ||
674 | { | ||
675 | return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ | ||
676 | + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); | ||
677 | } | ||
672 | #endif | 678 | #endif |
673 | 679 | ||
674 | #ifdef CONFIG_SYSCTL | 680 | #ifdef CONFIG_SYSCTL |
@@ -749,8 +755,10 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { | |||
749 | .print_conntrack = dccp_print_conntrack, | 755 | .print_conntrack = dccp_print_conntrack, |
750 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 756 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
751 | .to_nlattr = dccp_to_nlattr, | 757 | .to_nlattr = dccp_to_nlattr, |
758 | .nlattr_size = dccp_nlattr_size, | ||
752 | .from_nlattr = nlattr_to_dccp, | 759 | .from_nlattr = nlattr_to_dccp, |
753 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 760 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
761 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
754 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 762 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
755 | .nla_policy = nf_ct_port_nla_policy, | 763 | .nla_policy = nf_ct_port_nla_policy, |
756 | #endif | 764 | #endif |
@@ -771,6 +779,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
771 | .to_nlattr = dccp_to_nlattr, | 779 | .to_nlattr = dccp_to_nlattr, |
772 | .from_nlattr = nlattr_to_dccp, | 780 | .from_nlattr = nlattr_to_dccp, |
773 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 781 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
782 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
774 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 783 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
775 | .nla_policy = nf_ct_port_nla_policy, | 784 | .nla_policy = nf_ct_port_nla_policy, |
776 | #endif | 785 | #endif |
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 1b279f9d6bf3..117b80112fcb 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c | |||
@@ -293,6 +293,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | |||
293 | .me = THIS_MODULE, | 293 | .me = THIS_MODULE, |
294 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 294 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
295 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 295 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
296 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
296 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 297 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
297 | .nla_policy = nf_ct_port_nla_policy, | 298 | .nla_policy = nf_ct_port_nla_policy, |
298 | #endif | 299 | #endif |
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 74e037901199..101b4ad9e817 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c | |||
@@ -537,6 +537,12 @@ static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) | |||
537 | 537 | ||
538 | return 0; | 538 | return 0; |
539 | } | 539 | } |
540 | |||
541 | static int sctp_nlattr_size(void) | ||
542 | { | ||
543 | return nla_total_size(0) /* CTA_PROTOINFO_SCTP */ | ||
544 | + nla_policy_len(sctp_nla_policy, CTA_PROTOINFO_SCTP_MAX + 1); | ||
545 | } | ||
540 | #endif | 546 | #endif |
541 | 547 | ||
542 | #ifdef CONFIG_SYSCTL | 548 | #ifdef CONFIG_SYSCTL |
@@ -668,8 +674,10 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { | |||
668 | .me = THIS_MODULE, | 674 | .me = THIS_MODULE, |
669 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 675 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
670 | .to_nlattr = sctp_to_nlattr, | 676 | .to_nlattr = sctp_to_nlattr, |
677 | .nlattr_size = sctp_nlattr_size, | ||
671 | .from_nlattr = nlattr_to_sctp, | 678 | .from_nlattr = nlattr_to_sctp, |
672 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 679 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
680 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
673 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 681 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
674 | .nla_policy = nf_ct_port_nla_policy, | 682 | .nla_policy = nf_ct_port_nla_policy, |
675 | #endif | 683 | #endif |
@@ -696,8 +704,10 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { | |||
696 | .me = THIS_MODULE, | 704 | .me = THIS_MODULE, |
697 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 705 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
698 | .to_nlattr = sctp_to_nlattr, | 706 | .to_nlattr = sctp_to_nlattr, |
707 | .nlattr_size = sctp_nlattr_size, | ||
699 | .from_nlattr = nlattr_to_sctp, | 708 | .from_nlattr = nlattr_to_sctp, |
700 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 709 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
710 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
701 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 711 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
702 | .nla_policy = nf_ct_port_nla_policy, | 712 | .nla_policy = nf_ct_port_nla_policy, |
703 | #endif | 713 | #endif |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 0aeb8b09a1f7..b5ccf2b4b2e7 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -1184,6 +1184,17 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) | |||
1184 | 1184 | ||
1185 | return 0; | 1185 | return 0; |
1186 | } | 1186 | } |
1187 | |||
1188 | static int tcp_nlattr_size(void) | ||
1189 | { | ||
1190 | return nla_total_size(0) /* CTA_PROTOINFO_TCP */ | ||
1191 | + nla_policy_len(tcp_nla_policy, CTA_PROTOINFO_TCP_MAX + 1); | ||
1192 | } | ||
1193 | |||
1194 | static int tcp_nlattr_tuple_size(void) | ||
1195 | { | ||
1196 | return nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); | ||
1197 | } | ||
1187 | #endif | 1198 | #endif |
1188 | 1199 | ||
1189 | #ifdef CONFIG_SYSCTL | 1200 | #ifdef CONFIG_SYSCTL |
@@ -1399,9 +1410,11 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = | |||
1399 | .error = tcp_error, | 1410 | .error = tcp_error, |
1400 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 1411 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
1401 | .to_nlattr = tcp_to_nlattr, | 1412 | .to_nlattr = tcp_to_nlattr, |
1413 | .nlattr_size = tcp_nlattr_size, | ||
1402 | .from_nlattr = nlattr_to_tcp, | 1414 | .from_nlattr = nlattr_to_tcp, |
1403 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 1415 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1404 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 1416 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1417 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | ||
1405 | .nla_policy = nf_ct_port_nla_policy, | 1418 | .nla_policy = nf_ct_port_nla_policy, |
1406 | #endif | 1419 | #endif |
1407 | #ifdef CONFIG_SYSCTL | 1420 | #ifdef CONFIG_SYSCTL |
@@ -1429,9 +1442,11 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = | |||
1429 | .error = tcp_error, | 1442 | .error = tcp_error, |
1430 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 1443 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
1431 | .to_nlattr = tcp_to_nlattr, | 1444 | .to_nlattr = tcp_to_nlattr, |
1445 | .nlattr_size = tcp_nlattr_size, | ||
1432 | .from_nlattr = nlattr_to_tcp, | 1446 | .from_nlattr = nlattr_to_tcp, |
1433 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 1447 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1434 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 1448 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1449 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | ||
1435 | .nla_policy = nf_ct_port_nla_policy, | 1450 | .nla_policy = nf_ct_port_nla_policy, |
1436 | #endif | 1451 | #endif |
1437 | #ifdef CONFIG_SYSCTL | 1452 | #ifdef CONFIG_SYSCTL |
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index d4021179e24e..70809d117b91 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -195,6 +195,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = | |||
195 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 195 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
196 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 196 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
197 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 197 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
198 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
198 | .nla_policy = nf_ct_port_nla_policy, | 199 | .nla_policy = nf_ct_port_nla_policy, |
199 | #endif | 200 | #endif |
200 | #ifdef CONFIG_SYSCTL | 201 | #ifdef CONFIG_SYSCTL |
@@ -222,6 +223,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = | |||
222 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 223 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
223 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 224 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
224 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 225 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
226 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
225 | .nla_policy = nf_ct_port_nla_policy, | 227 | .nla_policy = nf_ct_port_nla_policy, |
226 | #endif | 228 | #endif |
227 | #ifdef CONFIG_SYSCTL | 229 | #ifdef CONFIG_SYSCTL |
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 4579d8de13b1..4614696c1b88 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c | |||
@@ -180,6 +180,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = | |||
180 | .error = udplite_error, | 180 | .error = udplite_error, |
181 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 181 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
182 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 182 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
183 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
183 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 184 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
184 | .nla_policy = nf_ct_port_nla_policy, | 185 | .nla_policy = nf_ct_port_nla_policy, |
185 | #endif | 186 | #endif |
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 4da54b0b9233..193515381970 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -44,40 +44,42 @@ struct ct_iter_state { | |||
44 | unsigned int bucket; | 44 | unsigned int bucket; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | static struct hlist_node *ct_get_first(struct seq_file *seq) | 47 | static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) |
48 | { | 48 | { |
49 | struct net *net = seq_file_net(seq); | 49 | struct net *net = seq_file_net(seq); |
50 | struct ct_iter_state *st = seq->private; | 50 | struct ct_iter_state *st = seq->private; |
51 | struct hlist_node *n; | 51 | struct hlist_nulls_node *n; |
52 | 52 | ||
53 | for (st->bucket = 0; | 53 | for (st->bucket = 0; |
54 | st->bucket < nf_conntrack_htable_size; | 54 | st->bucket < nf_conntrack_htable_size; |
55 | st->bucket++) { | 55 | st->bucket++) { |
56 | n = rcu_dereference(net->ct.hash[st->bucket].first); | 56 | n = rcu_dereference(net->ct.hash[st->bucket].first); |
57 | if (n) | 57 | if (!is_a_nulls(n)) |
58 | return n; | 58 | return n; |
59 | } | 59 | } |
60 | return NULL; | 60 | return NULL; |
61 | } | 61 | } |
62 | 62 | ||
63 | static struct hlist_node *ct_get_next(struct seq_file *seq, | 63 | static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, |
64 | struct hlist_node *head) | 64 | struct hlist_nulls_node *head) |
65 | { | 65 | { |
66 | struct net *net = seq_file_net(seq); | 66 | struct net *net = seq_file_net(seq); |
67 | struct ct_iter_state *st = seq->private; | 67 | struct ct_iter_state *st = seq->private; |
68 | 68 | ||
69 | head = rcu_dereference(head->next); | 69 | head = rcu_dereference(head->next); |
70 | while (head == NULL) { | 70 | while (is_a_nulls(head)) { |
71 | if (++st->bucket >= nf_conntrack_htable_size) | 71 | if (likely(get_nulls_value(head) == st->bucket)) { |
72 | return NULL; | 72 | if (++st->bucket >= nf_conntrack_htable_size) |
73 | return NULL; | ||
74 | } | ||
73 | head = rcu_dereference(net->ct.hash[st->bucket].first); | 75 | head = rcu_dereference(net->ct.hash[st->bucket].first); |
74 | } | 76 | } |
75 | return head; | 77 | return head; |
76 | } | 78 | } |
77 | 79 | ||
78 | static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos) | 80 | static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) |
79 | { | 81 | { |
80 | struct hlist_node *head = ct_get_first(seq); | 82 | struct hlist_nulls_node *head = ct_get_first(seq); |
81 | 83 | ||
82 | if (head) | 84 | if (head) |
83 | while (pos && (head = ct_get_next(seq, head))) | 85 | while (pos && (head = ct_get_next(seq, head))) |
@@ -107,67 +109,74 @@ static void ct_seq_stop(struct seq_file *s, void *v) | |||
107 | /* return 0 on success, 1 in case of error */ | 109 | /* return 0 on success, 1 in case of error */ |
108 | static int ct_seq_show(struct seq_file *s, void *v) | 110 | static int ct_seq_show(struct seq_file *s, void *v) |
109 | { | 111 | { |
110 | const struct nf_conntrack_tuple_hash *hash = v; | 112 | struct nf_conntrack_tuple_hash *hash = v; |
111 | const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | 113 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); |
112 | const struct nf_conntrack_l3proto *l3proto; | 114 | const struct nf_conntrack_l3proto *l3proto; |
113 | const struct nf_conntrack_l4proto *l4proto; | 115 | const struct nf_conntrack_l4proto *l4proto; |
116 | int ret = 0; | ||
114 | 117 | ||
115 | NF_CT_ASSERT(ct); | 118 | NF_CT_ASSERT(ct); |
119 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | ||
120 | return 0; | ||
116 | 121 | ||
117 | /* we only want to print DIR_ORIGINAL */ | 122 | /* we only want to print DIR_ORIGINAL */ |
118 | if (NF_CT_DIRECTION(hash)) | 123 | if (NF_CT_DIRECTION(hash)) |
119 | return 0; | 124 | goto release; |
120 | 125 | ||
121 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); | 126 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); |
122 | NF_CT_ASSERT(l3proto); | 127 | NF_CT_ASSERT(l3proto); |
123 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); | 128 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); |
124 | NF_CT_ASSERT(l4proto); | 129 | NF_CT_ASSERT(l4proto); |
125 | 130 | ||
131 | ret = -ENOSPC; | ||
126 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", | 132 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", |
127 | l3proto->name, nf_ct_l3num(ct), | 133 | l3proto->name, nf_ct_l3num(ct), |
128 | l4proto->name, nf_ct_protonum(ct), | 134 | l4proto->name, nf_ct_protonum(ct), |
129 | timer_pending(&ct->timeout) | 135 | timer_pending(&ct->timeout) |
130 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) | 136 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) |
131 | return -ENOSPC; | 137 | goto release; |
132 | 138 | ||
133 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) | 139 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) |
134 | return -ENOSPC; | 140 | goto release; |
135 | 141 | ||
136 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 142 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
137 | l3proto, l4proto)) | 143 | l3proto, l4proto)) |
138 | return -ENOSPC; | 144 | goto release; |
139 | 145 | ||
140 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) | 146 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) |
141 | return -ENOSPC; | 147 | goto release; |
142 | 148 | ||
143 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) | 149 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
144 | if (seq_printf(s, "[UNREPLIED] ")) | 150 | if (seq_printf(s, "[UNREPLIED] ")) |
145 | return -ENOSPC; | 151 | goto release; |
146 | 152 | ||
147 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, | 153 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
148 | l3proto, l4proto)) | 154 | l3proto, l4proto)) |
149 | return -ENOSPC; | 155 | goto release; |
150 | 156 | ||
151 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) | 157 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) |
152 | return -ENOSPC; | 158 | goto release; |
153 | 159 | ||
154 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) | 160 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) |
155 | if (seq_printf(s, "[ASSURED] ")) | 161 | if (seq_printf(s, "[ASSURED] ")) |
156 | return -ENOSPC; | 162 | goto release; |
157 | 163 | ||
158 | #if defined(CONFIG_NF_CONNTRACK_MARK) | 164 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
159 | if (seq_printf(s, "mark=%u ", ct->mark)) | 165 | if (seq_printf(s, "mark=%u ", ct->mark)) |
160 | return -ENOSPC; | 166 | goto release; |
161 | #endif | 167 | #endif |
162 | 168 | ||
163 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | 169 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
164 | if (seq_printf(s, "secmark=%u ", ct->secmark)) | 170 | if (seq_printf(s, "secmark=%u ", ct->secmark)) |
165 | return -ENOSPC; | 171 | goto release; |
166 | #endif | 172 | #endif |
167 | 173 | ||
168 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) | 174 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) |
169 | return -ENOSPC; | 175 | goto release; |
170 | 176 | ||
177 | ret = 0; | ||
178 | release: | ||
179 | nf_ct_put(ct); | ||
171 | return 0; | 180 | return 0; |
172 | } | 181 | } |
173 | 182 | ||
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 7f404cc64c83..680980954395 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c | |||
@@ -108,7 +108,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
108 | const struct nf_conntrack_tuple_hash *found; | 108 | const struct nf_conntrack_tuple_hash *found; |
109 | struct xt_connlimit_conn *conn; | 109 | struct xt_connlimit_conn *conn; |
110 | struct xt_connlimit_conn *tmp; | 110 | struct xt_connlimit_conn *tmp; |
111 | const struct nf_conn *found_ct; | 111 | struct nf_conn *found_ct; |
112 | struct list_head *hash; | 112 | struct list_head *hash; |
113 | bool addit = true; | 113 | bool addit = true; |
114 | int matches = 0; | 114 | int matches = 0; |
@@ -123,7 +123,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
123 | 123 | ||
124 | /* check the saved connections */ | 124 | /* check the saved connections */ |
125 | list_for_each_entry_safe(conn, tmp, hash, list) { | 125 | list_for_each_entry_safe(conn, tmp, hash, list) { |
126 | found = __nf_conntrack_find(&init_net, &conn->tuple); | 126 | found = nf_conntrack_find_get(&init_net, &conn->tuple); |
127 | found_ct = NULL; | 127 | found_ct = NULL; |
128 | 128 | ||
129 | if (found != NULL) | 129 | if (found != NULL) |
@@ -151,6 +151,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
151 | * we do not care about connections which are | 151 | * we do not care about connections which are |
152 | * closed already -> ditch it | 152 | * closed already -> ditch it |
153 | */ | 153 | */ |
154 | nf_ct_put(found_ct); | ||
154 | list_del(&conn->list); | 155 | list_del(&conn->list); |
155 | kfree(conn); | 156 | kfree(conn); |
156 | continue; | 157 | continue; |
@@ -160,6 +161,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
160 | match->family)) | 161 | match->family)) |
161 | /* same source network -> be counted! */ | 162 | /* same source network -> be counted! */ |
162 | ++matches; | 163 | ++matches; |
164 | nf_ct_put(found_ct); | ||
163 | } | 165 | } |
164 | 166 | ||
165 | rcu_read_unlock(); | 167 | rcu_read_unlock(); |
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index 44a234ef4439..8d28ca5848bc 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c | |||
@@ -20,23 +20,6 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match"); | |||
20 | MODULE_ALIAS("ipt_physdev"); | 20 | MODULE_ALIAS("ipt_physdev"); |
21 | MODULE_ALIAS("ip6t_physdev"); | 21 | MODULE_ALIAS("ip6t_physdev"); |
22 | 22 | ||
23 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | ||
24 | { | ||
25 | const unsigned long *a = (const unsigned long *)_a; | ||
26 | const unsigned long *b = (const unsigned long *)_b; | ||
27 | const unsigned long *mask = (const unsigned long *)_mask; | ||
28 | unsigned long ret; | ||
29 | |||
30 | ret = (a[0] ^ b[0]) & mask[0]; | ||
31 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
32 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
33 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
34 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
35 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
36 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
37 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
38 | return ret; | ||
39 | } | ||
40 | 23 | ||
41 | static bool | 24 | static bool |
42 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 25 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
@@ -85,7 +68,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |||
85 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) | 68 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) |
86 | goto match_outdev; | 69 | goto match_outdev; |
87 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; | 70 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; |
88 | ret = ifname_compare(indev, info->physindev, info->in_mask); | 71 | ret = ifname_compare_aligned(indev, info->physindev, info->in_mask); |
89 | 72 | ||
90 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) | 73 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) |
91 | return false; | 74 | return false; |
@@ -95,7 +78,7 @@ match_outdev: | |||
95 | return true; | 78 | return true; |
96 | outdev = nf_bridge->physoutdev ? | 79 | outdev = nf_bridge->physoutdev ? |
97 | nf_bridge->physoutdev->name : nulldevname; | 80 | nf_bridge->physoutdev->name : nulldevname; |
98 | ret = ifname_compare(outdev, info->physoutdev, info->out_mask); | 81 | ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask); |
99 | 82 | ||
100 | return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); | 83 | return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); |
101 | } | 84 | } |