aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-07-21 15:39:35 -0400
committerDavid S. Miller <davem@davemloft.net>2011-07-21 15:39:35 -0400
commitf5caadbb3d8fc0b71533e880c684b2230bdb76ac (patch)
tree7a23a2b44f6e043d9cb6ad4245b78da4bd2e14b0 /net/netfilter
parent0ca87f05ba8bdc6791c14878464efc901ad71e99 (diff)
parent0f598f0b4c3b2259366cfa8adc01bd8e714c82d0 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c6
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c6
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c6
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c6
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c6
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c40
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c6
-rw-r--r--net/netfilter/nfnetlink.c40
-rw-r--r--net/netfilter/nfnetlink_queue.c170
-rw-r--r--net/netfilter/xt_AUDIT.c5
10 files changed, 215 insertions, 76 deletions
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index fa80bb9b9c81..f2d576e6b769 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -53,7 +53,8 @@ struct hash_ip4_telem {
53 53
54static inline bool 54static inline bool
55hash_ip4_data_equal(const struct hash_ip4_elem *ip1, 55hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
56 const struct hash_ip4_elem *ip2) 56 const struct hash_ip4_elem *ip2,
57 u32 *multi)
57{ 58{
58 return ip1->ip == ip2->ip; 59 return ip1->ip == ip2->ip;
59} 60}
@@ -225,7 +226,8 @@ struct hash_ip6_telem {
225 226
226static inline bool 227static inline bool
227hash_ip6_data_equal(const struct hash_ip6_elem *ip1, 228hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
228 const struct hash_ip6_elem *ip2) 229 const struct hash_ip6_elem *ip2,
230 u32 *multi)
229{ 231{
230 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0; 232 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
231} 233}
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index bbf51b67b170..6ee10f5d59bd 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -60,7 +60,8 @@ struct hash_ipport4_telem {
60 60
61static inline bool 61static inline bool
62hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1, 62hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
63 const struct hash_ipport4_elem *ip2) 63 const struct hash_ipport4_elem *ip2,
64 u32 *multi)
64{ 65{
65 return ip1->ip == ip2->ip && 66 return ip1->ip == ip2->ip &&
66 ip1->port == ip2->port && 67 ip1->port == ip2->port &&
@@ -276,7 +277,8 @@ struct hash_ipport6_telem {
276 277
277static inline bool 278static inline bool
278hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1, 279hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
279 const struct hash_ipport6_elem *ip2) 280 const struct hash_ipport6_elem *ip2,
281 u32 *multi)
280{ 282{
281 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && 283 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
282 ip1->port == ip2->port && 284 ip1->port == ip2->port &&
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 96525f529a54..fb90e344e907 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -62,7 +62,8 @@ struct hash_ipportip4_telem {
62 62
63static inline bool 63static inline bool
64hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, 64hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
65 const struct hash_ipportip4_elem *ip2) 65 const struct hash_ipportip4_elem *ip2,
66 u32 *multi)
66{ 67{
67 return ip1->ip == ip2->ip && 68 return ip1->ip == ip2->ip &&
68 ip1->ip2 == ip2->ip2 && 69 ip1->ip2 == ip2->ip2 &&
@@ -286,7 +287,8 @@ struct hash_ipportip6_telem {
286 287
287static inline bool 288static inline bool
288hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, 289hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
289 const struct hash_ipportip6_elem *ip2) 290 const struct hash_ipportip6_elem *ip2,
291 u32 *multi)
290{ 292{
291 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && 293 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
292 ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && 294 ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index d2d6ab89f087..deb3e3dfa5fc 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -62,7 +62,8 @@ struct hash_ipportnet4_telem {
62 62
63static inline bool 63static inline bool
64hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1, 64hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
65 const struct hash_ipportnet4_elem *ip2) 65 const struct hash_ipportnet4_elem *ip2,
66 u32 *multi)
66{ 67{
67 return ip1->ip == ip2->ip && 68 return ip1->ip == ip2->ip &&
68 ip1->ip2 == ip2->ip2 && 69 ip1->ip2 == ip2->ip2 &&
@@ -335,7 +336,8 @@ struct hash_ipportnet6_telem {
335 336
336static inline bool 337static inline bool
337hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1, 338hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
338 const struct hash_ipportnet6_elem *ip2) 339 const struct hash_ipportnet6_elem *ip2,
340 u32 *multi)
339{ 341{
340 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && 342 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
341 ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 && 343 ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
index 2d4b1f48e8c9..60d016541c58 100644
--- a/net/netfilter/ipset/ip_set_hash_net.c
+++ b/net/netfilter/ipset/ip_set_hash_net.c
@@ -58,7 +58,8 @@ struct hash_net4_telem {
58 58
59static inline bool 59static inline bool
60hash_net4_data_equal(const struct hash_net4_elem *ip1, 60hash_net4_data_equal(const struct hash_net4_elem *ip1,
61 const struct hash_net4_elem *ip2) 61 const struct hash_net4_elem *ip2,
62 u32 *multi)
62{ 63{
63 return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; 64 return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr;
64} 65}
@@ -249,7 +250,8 @@ struct hash_net6_telem {
249 250
250static inline bool 251static inline bool
251hash_net6_data_equal(const struct hash_net6_elem *ip1, 252hash_net6_data_equal(const struct hash_net6_elem *ip1,
252 const struct hash_net6_elem *ip2) 253 const struct hash_net6_elem *ip2,
254 u32 *multi)
253{ 255{
254 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && 256 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
255 ip1->cidr == ip2->cidr; 257 ip1->cidr == ip2->cidr;
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index 3d6c53b6211a..e13095deb50d 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -99,7 +99,7 @@ iface_test(struct rb_root *root, const char **iface)
99 99
100 while (n) { 100 while (n) {
101 const char *d = iface_data(n); 101 const char *d = iface_data(n);
102 int res = ifname_compare(*iface, d); 102 long res = ifname_compare(*iface, d);
103 103
104 if (res < 0) 104 if (res < 0)
105 n = n->rb_left; 105 n = n->rb_left;
@@ -121,7 +121,7 @@ iface_add(struct rb_root *root, const char **iface)
121 121
122 while (*n) { 122 while (*n) {
123 char *ifname = iface_data(*n); 123 char *ifname = iface_data(*n);
124 int res = ifname_compare(*iface, ifname); 124 long res = ifname_compare(*iface, ifname);
125 125
126 p = *n; 126 p = *n;
127 if (res < 0) 127 if (res < 0)
@@ -159,31 +159,42 @@ hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b);
159 159
160/* The type variant functions: IPv4 */ 160/* The type variant functions: IPv4 */
161 161
162struct hash_netiface4_elem_hashed {
163 __be32 ip;
164 u8 physdev;
165 u8 cidr;
166 u16 padding;
167};
168
169#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
170
162/* Member elements without timeout */ 171/* Member elements without timeout */
163struct hash_netiface4_elem { 172struct hash_netiface4_elem {
164 __be32 ip; 173 __be32 ip;
165 const char *iface;
166 u8 physdev; 174 u8 physdev;
167 u8 cidr; 175 u8 cidr;
168 u16 padding; 176 u16 padding;
177 const char *iface;
169}; 178};
170 179
171/* Member elements with timeout support */ 180/* Member elements with timeout support */
172struct hash_netiface4_telem { 181struct hash_netiface4_telem {
173 __be32 ip; 182 __be32 ip;
174 const char *iface;
175 u8 physdev; 183 u8 physdev;
176 u8 cidr; 184 u8 cidr;
177 u16 padding; 185 u16 padding;
186 const char *iface;
178 unsigned long timeout; 187 unsigned long timeout;
179}; 188};
180 189
181static inline bool 190static inline bool
182hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1, 191hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
183 const struct hash_netiface4_elem *ip2) 192 const struct hash_netiface4_elem *ip2,
193 u32 *multi)
184{ 194{
185 return ip1->ip == ip2->ip && 195 return ip1->ip == ip2->ip &&
186 ip1->cidr == ip2->cidr && 196 ip1->cidr == ip2->cidr &&
197 (++*multi) &&
187 ip1->physdev == ip2->physdev && 198 ip1->physdev == ip2->physdev &&
188 ip1->iface == ip2->iface; 199 ip1->iface == ip2->iface;
189} 200}
@@ -257,6 +268,7 @@ nla_put_failure:
257 268
258#define IP_SET_HASH_WITH_NETS 269#define IP_SET_HASH_WITH_NETS
259#define IP_SET_HASH_WITH_RBTREE 270#define IP_SET_HASH_WITH_RBTREE
271#define IP_SET_HASH_WITH_MULTI
260 272
261#define PF 4 273#define PF 4
262#define HOST_MASK 32 274#define HOST_MASK 32
@@ -424,29 +436,40 @@ hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b)
424 436
425/* The type variant functions: IPv6 */ 437/* The type variant functions: IPv6 */
426 438
439struct hash_netiface6_elem_hashed {
440 union nf_inet_addr ip;
441 u8 physdev;
442 u8 cidr;
443 u16 padding;
444};
445
446#define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
447
427struct hash_netiface6_elem { 448struct hash_netiface6_elem {
428 union nf_inet_addr ip; 449 union nf_inet_addr ip;
429 const char *iface;
430 u8 physdev; 450 u8 physdev;
431 u8 cidr; 451 u8 cidr;
432 u16 padding; 452 u16 padding;
453 const char *iface;
433}; 454};
434 455
435struct hash_netiface6_telem { 456struct hash_netiface6_telem {
436 union nf_inet_addr ip; 457 union nf_inet_addr ip;
437 const char *iface;
438 u8 physdev; 458 u8 physdev;
439 u8 cidr; 459 u8 cidr;
440 u16 padding; 460 u16 padding;
461 const char *iface;
441 unsigned long timeout; 462 unsigned long timeout;
442}; 463};
443 464
444static inline bool 465static inline bool
445hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1, 466hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
446 const struct hash_netiface6_elem *ip2) 467 const struct hash_netiface6_elem *ip2,
468 u32 *multi)
447{ 469{
448 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && 470 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
449 ip1->cidr == ip2->cidr && 471 ip1->cidr == ip2->cidr &&
472 (++*multi) &&
450 ip1->physdev == ip2->physdev && 473 ip1->physdev == ip2->physdev &&
451 ip1->iface == ip2->iface; 474 ip1->iface == ip2->iface;
452} 475}
@@ -681,6 +704,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
681 h->maxelem = maxelem; 704 h->maxelem = maxelem;
682 get_random_bytes(&h->initval, sizeof(h->initval)); 705 get_random_bytes(&h->initval, sizeof(h->initval));
683 h->timeout = IPSET_NO_TIMEOUT; 706 h->timeout = IPSET_NO_TIMEOUT;
707 h->ahash_max = AHASH_MAX_SIZE;
684 708
685 hbits = htable_bits(hashsize); 709 hbits = htable_bits(hashsize);
686 h->table = ip_set_alloc( 710 h->table = ip_set_alloc(
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index fe203d12f56b..8f9de7207ec9 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -59,7 +59,8 @@ struct hash_netport4_telem {
59 59
60static inline bool 60static inline bool
61hash_netport4_data_equal(const struct hash_netport4_elem *ip1, 61hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
62 const struct hash_netport4_elem *ip2) 62 const struct hash_netport4_elem *ip2,
63 u32 *multi)
63{ 64{
64 return ip1->ip == ip2->ip && 65 return ip1->ip == ip2->ip &&
65 ip1->port == ip2->port && 66 ip1->port == ip2->port &&
@@ -300,7 +301,8 @@ struct hash_netport6_telem {
300 301
301static inline bool 302static inline bool
302hash_netport6_data_equal(const struct hash_netport6_elem *ip1, 303hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
303 const struct hash_netport6_elem *ip2) 304 const struct hash_netport6_elem *ip2,
305 u32 *multi)
304{ 306{
305 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 && 307 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
306 ip1->port == ip2->port && 308 ip1->port == ip2->port &&
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index b4a4532823e8..1905976b5135 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -37,7 +37,7 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
37 37
38static char __initdata nfversion[] = "0.30"; 38static char __initdata nfversion[] = "0.30";
39 39
40static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; 40static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT];
41static DEFINE_MUTEX(nfnl_mutex); 41static DEFINE_MUTEX(nfnl_mutex);
42 42
43void nfnl_lock(void) 43void nfnl_lock(void)
@@ -59,7 +59,7 @@ int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
59 nfnl_unlock(); 59 nfnl_unlock();
60 return -EBUSY; 60 return -EBUSY;
61 } 61 }
62 subsys_table[n->subsys_id] = n; 62 rcu_assign_pointer(subsys_table[n->subsys_id], n);
63 nfnl_unlock(); 63 nfnl_unlock();
64 64
65 return 0; 65 return 0;
@@ -71,7 +71,7 @@ int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n)
71 nfnl_lock(); 71 nfnl_lock();
72 subsys_table[n->subsys_id] = NULL; 72 subsys_table[n->subsys_id] = NULL;
73 nfnl_unlock(); 73 nfnl_unlock();
74 74 synchronize_rcu();
75 return 0; 75 return 0;
76} 76}
77EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); 77EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
@@ -83,7 +83,7 @@ static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t t
83 if (subsys_id >= NFNL_SUBSYS_COUNT) 83 if (subsys_id >= NFNL_SUBSYS_COUNT)
84 return NULL; 84 return NULL;
85 85
86 return subsys_table[subsys_id]; 86 return rcu_dereference(subsys_table[subsys_id]);
87} 87}
88 88
89static inline const struct nfnl_callback * 89static inline const struct nfnl_callback *
@@ -139,21 +139,27 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
139 139
140 type = nlh->nlmsg_type; 140 type = nlh->nlmsg_type;
141replay: 141replay:
142 rcu_read_lock();
142 ss = nfnetlink_get_subsys(type); 143 ss = nfnetlink_get_subsys(type);
143 if (!ss) { 144 if (!ss) {
144#ifdef CONFIG_MODULES 145#ifdef CONFIG_MODULES
145 nfnl_unlock(); 146 rcu_read_unlock();
146 request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); 147 request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
147 nfnl_lock(); 148 rcu_read_lock();
148 ss = nfnetlink_get_subsys(type); 149 ss = nfnetlink_get_subsys(type);
149 if (!ss) 150 if (!ss)
150#endif 151#endif
152 {
153 rcu_read_unlock();
151 return -EINVAL; 154 return -EINVAL;
155 }
152 } 156 }
153 157
154 nc = nfnetlink_find_client(type, ss); 158 nc = nfnetlink_find_client(type, ss);
155 if (!nc) 159 if (!nc) {
160 rcu_read_unlock();
156 return -EINVAL; 161 return -EINVAL;
162 }
157 163
158 { 164 {
159 int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); 165 int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
@@ -167,7 +173,23 @@ replay:
167 if (err < 0) 173 if (err < 0)
168 return err; 174 return err;
169 175
170 err = nc->call(net->nfnl, skb, nlh, (const struct nlattr **)cda); 176 if (nc->call_rcu) {
177 err = nc->call_rcu(net->nfnl, skb, nlh,
178 (const struct nlattr **)cda);
179 rcu_read_unlock();
180 } else {
181 rcu_read_unlock();
182 nfnl_lock();
183 if (rcu_dereference_protected(
184 subsys_table[NFNL_SUBSYS_ID(type)],
185 lockdep_is_held(&nfnl_mutex)) != ss ||
186 nfnetlink_find_client(type, ss) != nc)
187 err = -EAGAIN;
188 else
189 err = nc->call(net->nfnl, skb, nlh,
190 (const struct nlattr **)cda);
191 nfnl_unlock();
192 }
171 if (err == -EAGAIN) 193 if (err == -EAGAIN)
172 goto replay; 194 goto replay;
173 return err; 195 return err;
@@ -176,9 +198,7 @@ replay:
176 198
177static void nfnetlink_rcv(struct sk_buff *skb) 199static void nfnetlink_rcv(struct sk_buff *skb)
178{ 200{
179 nfnl_lock();
180 netlink_rcv_skb(skb, &nfnetlink_rcv_msg); 201 netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
181 nfnl_unlock();
182} 202}
183 203
184static int __net_init nfnetlink_net_init(struct net *net) 204static int __net_init nfnetlink_net_init(struct net *net)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index fdd2fafe0a14..49132bddd73e 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -58,7 +58,7 @@ struct nfqnl_instance {
58 */ 58 */
59 spinlock_t lock; 59 spinlock_t lock;
60 unsigned int queue_total; 60 unsigned int queue_total;
61 atomic_t id_sequence; /* 'sequence' of pkt ids */ 61 unsigned int id_sequence; /* 'sequence' of pkt ids */
62 struct list_head queue_list; /* packets in queue */ 62 struct list_head queue_list; /* packets in queue */
63}; 63};
64 64
@@ -171,6 +171,13 @@ __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
171 queue->queue_total++; 171 queue->queue_total++;
172} 172}
173 173
174static void
175__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
176{
177 list_del(&entry->list);
178 queue->queue_total--;
179}
180
174static struct nf_queue_entry * 181static struct nf_queue_entry *
175find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) 182find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
176{ 183{
@@ -185,10 +192,8 @@ find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
185 } 192 }
186 } 193 }
187 194
188 if (entry) { 195 if (entry)
189 list_del(&entry->list); 196 __dequeue_entry(queue, entry);
190 queue->queue_total--;
191 }
192 197
193 spin_unlock_bh(&queue->lock); 198 spin_unlock_bh(&queue->lock);
194 199
@@ -213,13 +218,15 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
213 218
214static struct sk_buff * 219static struct sk_buff *
215nfqnl_build_packet_message(struct nfqnl_instance *queue, 220nfqnl_build_packet_message(struct nfqnl_instance *queue,
216 struct nf_queue_entry *entry) 221 struct nf_queue_entry *entry,
222 __be32 **packet_id_ptr)
217{ 223{
218 sk_buff_data_t old_tail; 224 sk_buff_data_t old_tail;
219 size_t size; 225 size_t size;
220 size_t data_len = 0; 226 size_t data_len = 0;
221 struct sk_buff *skb; 227 struct sk_buff *skb;
222 struct nfqnl_msg_packet_hdr pmsg; 228 struct nlattr *nla;
229 struct nfqnl_msg_packet_hdr *pmsg;
223 struct nlmsghdr *nlh; 230 struct nlmsghdr *nlh;
224 struct nfgenmsg *nfmsg; 231 struct nfgenmsg *nfmsg;
225 struct sk_buff *entskb = entry->skb; 232 struct sk_buff *entskb = entry->skb;
@@ -272,12 +279,11 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
272 nfmsg->version = NFNETLINK_V0; 279 nfmsg->version = NFNETLINK_V0;
273 nfmsg->res_id = htons(queue->queue_num); 280 nfmsg->res_id = htons(queue->queue_num);
274 281
275 entry->id = atomic_inc_return(&queue->id_sequence); 282 nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg));
276 pmsg.packet_id = htonl(entry->id); 283 pmsg = nla_data(nla);
277 pmsg.hw_protocol = entskb->protocol; 284 pmsg->hw_protocol = entskb->protocol;
278 pmsg.hook = entry->hook; 285 pmsg->hook = entry->hook;
279 286 *packet_id_ptr = &pmsg->packet_id;
280 NLA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg);
281 287
282 indev = entry->indev; 288 indev = entry->indev;
283 if (indev) { 289 if (indev) {
@@ -389,6 +395,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
389 struct sk_buff *nskb; 395 struct sk_buff *nskb;
390 struct nfqnl_instance *queue; 396 struct nfqnl_instance *queue;
391 int err = -ENOBUFS; 397 int err = -ENOBUFS;
398 __be32 *packet_id_ptr;
392 399
393 /* rcu_read_lock()ed by nf_hook_slow() */ 400 /* rcu_read_lock()ed by nf_hook_slow() */
394 queue = instance_lookup(queuenum); 401 queue = instance_lookup(queuenum);
@@ -402,7 +409,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
402 goto err_out; 409 goto err_out;
403 } 410 }
404 411
405 nskb = nfqnl_build_packet_message(queue, entry); 412 nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr);
406 if (nskb == NULL) { 413 if (nskb == NULL) {
407 err = -ENOMEM; 414 err = -ENOMEM;
408 goto err_out; 415 goto err_out;
@@ -421,6 +428,8 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
421 queue->queue_total); 428 queue->queue_total);
422 goto err_out_free_nskb; 429 goto err_out_free_nskb;
423 } 430 }
431 entry->id = ++queue->id_sequence;
432 *packet_id_ptr = htonl(entry->id);
424 433
425 /* nfnetlink_unicast will either free the nskb or add it to a socket */ 434 /* nfnetlink_unicast will either free the nskb or add it to a socket */
426 err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); 435 err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
@@ -608,6 +617,92 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
608 [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, 617 [NFQA_PAYLOAD] = { .type = NLA_UNSPEC },
609}; 618};
610 619
620static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
621 [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
622 [NFQA_MARK] = { .type = NLA_U32 },
623};
624
625static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid)
626{
627 struct nfqnl_instance *queue;
628
629 queue = instance_lookup(queue_num);
630 if (!queue)
631 return ERR_PTR(-ENODEV);
632
633 if (queue->peer_pid != nlpid)
634 return ERR_PTR(-EPERM);
635
636 return queue;
637}
638
639static struct nfqnl_msg_verdict_hdr*
640verdicthdr_get(const struct nlattr * const nfqa[])
641{
642 struct nfqnl_msg_verdict_hdr *vhdr;
643 unsigned int verdict;
644
645 if (!nfqa[NFQA_VERDICT_HDR])
646 return NULL;
647
648 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
649 verdict = ntohl(vhdr->verdict);
650 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)
651 return NULL;
652 return vhdr;
653}
654
655static int nfq_id_after(unsigned int id, unsigned int max)
656{
657 return (int)(id - max) > 0;
658}
659
660static int
661nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
662 const struct nlmsghdr *nlh,
663 const struct nlattr * const nfqa[])
664{
665 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
666 struct nf_queue_entry *entry, *tmp;
667 unsigned int verdict, maxid;
668 struct nfqnl_msg_verdict_hdr *vhdr;
669 struct nfqnl_instance *queue;
670 LIST_HEAD(batch_list);
671 u16 queue_num = ntohs(nfmsg->res_id);
672
673 queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
674 if (IS_ERR(queue))
675 return PTR_ERR(queue);
676
677 vhdr = verdicthdr_get(nfqa);
678 if (!vhdr)
679 return -EINVAL;
680
681 verdict = ntohl(vhdr->verdict);
682 maxid = ntohl(vhdr->id);
683
684 spin_lock_bh(&queue->lock);
685
686 list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) {
687 if (nfq_id_after(entry->id, maxid))
688 break;
689 __dequeue_entry(queue, entry);
690 list_add_tail(&entry->list, &batch_list);
691 }
692
693 spin_unlock_bh(&queue->lock);
694
695 if (list_empty(&batch_list))
696 return -ENOENT;
697
698 list_for_each_entry_safe(entry, tmp, &batch_list, list) {
699 if (nfqa[NFQA_MARK])
700 entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
701 nf_reinject(entry, verdict);
702 }
703 return 0;
704}
705
611static int 706static int
612nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, 707nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
613 const struct nlmsghdr *nlh, 708 const struct nlmsghdr *nlh,
@@ -620,39 +715,23 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
620 struct nfqnl_instance *queue; 715 struct nfqnl_instance *queue;
621 unsigned int verdict; 716 unsigned int verdict;
622 struct nf_queue_entry *entry; 717 struct nf_queue_entry *entry;
623 int err;
624 718
625 rcu_read_lock();
626 queue = instance_lookup(queue_num); 719 queue = instance_lookup(queue_num);
627 if (!queue) { 720 if (!queue)
628 err = -ENODEV;
629 goto err_out_unlock;
630 }
631 721
632 if (queue->peer_pid != NETLINK_CB(skb).pid) { 722 queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
633 err = -EPERM; 723 if (IS_ERR(queue))
634 goto err_out_unlock; 724 return PTR_ERR(queue);
635 }
636 725
637 if (!nfqa[NFQA_VERDICT_HDR]) { 726 vhdr = verdicthdr_get(nfqa);
638 err = -EINVAL; 727 if (!vhdr)
639 goto err_out_unlock; 728 return -EINVAL;
640 }
641 729
642 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
643 verdict = ntohl(vhdr->verdict); 730 verdict = ntohl(vhdr->verdict);
644 731
645 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) {
646 err = -EINVAL;
647 goto err_out_unlock;
648 }
649
650 entry = find_dequeue_entry(queue, ntohl(vhdr->id)); 732 entry = find_dequeue_entry(queue, ntohl(vhdr->id));
651 if (entry == NULL) { 733 if (entry == NULL)
652 err = -ENOENT; 734 return -ENOENT;
653 goto err_out_unlock;
654 }
655 rcu_read_unlock();
656 735
657 if (nfqa[NFQA_PAYLOAD]) { 736 if (nfqa[NFQA_PAYLOAD]) {
658 if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), 737 if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
@@ -665,10 +744,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
665 744
666 nf_reinject(entry, verdict); 745 nf_reinject(entry, verdict);
667 return 0; 746 return 0;
668
669err_out_unlock:
670 rcu_read_unlock();
671 return err;
672} 747}
673 748
674static int 749static int
@@ -781,14 +856,17 @@ err_out_unlock:
781} 856}
782 857
783static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { 858static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
784 [NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp, 859 [NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp,
785 .attr_count = NFQA_MAX, }, 860 .attr_count = NFQA_MAX, },
786 [NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict, 861 [NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict,
787 .attr_count = NFQA_MAX, 862 .attr_count = NFQA_MAX,
788 .policy = nfqa_verdict_policy }, 863 .policy = nfqa_verdict_policy },
789 [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, 864 [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
790 .attr_count = NFQA_CFG_MAX, 865 .attr_count = NFQA_CFG_MAX,
791 .policy = nfqa_cfg_policy }, 866 .policy = nfqa_cfg_policy },
867 [NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
868 .attr_count = NFQA_MAX,
869 .policy = nfqa_verdict_batch_policy },
792}; 870};
793 871
794static const struct nfnetlink_subsystem nfqnl_subsys = { 872static const struct nfnetlink_subsystem nfqnl_subsys = {
@@ -870,7 +948,7 @@ static int seq_show(struct seq_file *s, void *v)
870 inst->peer_pid, inst->queue_total, 948 inst->peer_pid, inst->queue_total,
871 inst->copy_mode, inst->copy_range, 949 inst->copy_mode, inst->copy_range,
872 inst->queue_dropped, inst->queue_user_dropped, 950 inst->queue_dropped, inst->queue_user_dropped,
873 atomic_read(&inst->id_sequence), 1); 951 inst->id_sequence, 1);
874} 952}
875 953
876static const struct seq_operations nfqnl_seq_ops = { 954static const struct seq_operations nfqnl_seq_ops = {
diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c
index 363a99ec0637..4bca15a0c385 100644
--- a/net/netfilter/xt_AUDIT.c
+++ b/net/netfilter/xt_AUDIT.c
@@ -163,6 +163,11 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par)
163 break; 163 break;
164 } 164 }
165 165
166#ifdef CONFIG_NETWORK_SECMARK
167 if (skb->secmark)
168 audit_log_secctx(ab, skb->secmark);
169#endif
170
166 audit_log_end(ab); 171 audit_log_end(ab);
167 172
168errout: 173errout: