All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2 v3] netfilter: nfnetlink_queue: get rid of nfnetlink_queue_ct.c
@ 2015-10-01 18:43 Pablo Neira Ayuso
  2015-10-01 18:43 ` [PATCH 2/2 v3] netfilter: rename nfnetlink_queue_core.c to nfnetlink_queue.c Pablo Neira Ayuso
  0 siblings, 1 reply; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-01 18:43 UTC (permalink / raw)
  To: netfilter-devel; +Cc: chamaken

The original intention was to avoid dependencies between nfnetlink_queue and
conntrack without ifdef pollution. However, we can achieve this by moving the
conntrack dependent code into ctnetlink and keep some glue code to access the
nfq_ct indirection from nfqueue.

After this patch, the nfq_ct indirection is always compiled in the netfilter
core to avoid polluting nfqueue with ifdefs. Thus, if nf_conntrack is not
compiled this results in only 8-bytes of memory waste in x86_64.

This patch also adds ctnetlink_nfqueue_seqadj() to avoid that the nf_conn
structure layout if exposed to nf_queue, which creates another dependency with
nf_conntrack at compilation time.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v3: fix typo when rebasing without the patch to consolidate the netlink message
    size calculation.

 include/linux/netfilter.h               |  12 ++--
 include/net/netfilter/nfnetlink_queue.h |  51 --------------
 net/netfilter/Makefile                  |   1 -
 net/netfilter/core.c                    |   9 ++-
 net/netfilter/nf_conntrack_netlink.c    |  52 ++++++++++++++-
 net/netfilter/nfnetlink_queue_core.c    |  52 +++++++++++----
 net/netfilter/nfnetlink_queue_ct.c      | 113 --------------------------------
 7 files changed, 103 insertions(+), 187 deletions(-)
 delete mode 100644 include/net/netfilter/nfnetlink_queue.h
 delete mode 100644 net/netfilter/nfnetlink_queue_ct.c

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 165ab2d..3e5e8f2 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -369,14 +369,21 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
 extern void (*ip_ct_attach)(struct sk_buff *, const struct sk_buff *) __rcu;
 void nf_ct_attach(struct sk_buff *, const struct sk_buff *);
 extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu;
+#else
+static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
+#endif
 
 struct nf_conn;
 enum ip_conntrack_info;
 struct nlattr;
 
 struct nfq_ct_hook {
+	struct nf_conn *(*get_ct)(struct sk_buff *skb,
+				  enum ip_conntrack_info *ctinfo);
 	size_t (*build_size)(const struct nf_conn *ct);
-	int (*build)(struct sk_buff *skb, struct nf_conn *ct);
+	int (*build)(struct sk_buff *skb, struct nf_conn *ct,
+		     enum ip_conntrack_info ctinfo,
+		     u_int16_t ct_attr, u_int16_t ct_info_attr);
 	int (*parse)(const struct nlattr *attr, struct nf_conn *ct);
 	int (*attach_expect)(const struct nlattr *attr, struct nf_conn *ct,
 			     u32 portid, u32 report);
@@ -384,9 +391,6 @@ struct nfq_ct_hook {
 			   enum ip_conntrack_info ctinfo, s32 off);
 };
 extern struct nfq_ct_hook __rcu *nfq_ct_hook;
-#else
-static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
-#endif
 
 /**
  * nf_skb_duplicated - TEE target has sent a packet
diff --git a/include/net/netfilter/nfnetlink_queue.h b/include/net/netfilter/nfnetlink_queue.h
deleted file mode 100644
index aff88ba..0000000
--- a/include/net/netfilter/nfnetlink_queue.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _NET_NFNL_QUEUE_H_
-#define _NET_NFNL_QUEUE_H_
-
-#include <linux/netfilter/nf_conntrack_common.h>
-
-struct nf_conn;
-
-#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
-struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size,
-			     enum ip_conntrack_info *ctinfo);
-struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb,
-			       const struct nlattr *attr,
-			       enum ip_conntrack_info *ctinfo);
-int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
-		 enum ip_conntrack_info ctinfo);
-void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
-			 enum ip_conntrack_info ctinfo, int diff);
-int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
-			u32 portid, u32 report);
-#else
-inline struct nf_conn *
-nfqnl_ct_get(struct sk_buff *entskb, size_t *size, enum ip_conntrack_info *ctinfo)
-{
-	return NULL;
-}
-
-inline struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb,
-				      const struct nlattr *attr,
-				      enum ip_conntrack_info *ctinfo)
-{
-	return NULL;
-}
-
-inline int
-nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo)
-{
-	return 0;
-}
-
-inline void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
-				enum ip_conntrack_info ctinfo, int diff)
-{
-}
-
-inline int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
-			       u32 portid, u32 report)
-{
-	return 0;
-}
-#endif /* NF_CONNTRACK */
-#endif
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 70d026d..4d68e72 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_NETFILTER) = netfilter.o
 obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
 obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o
 nfnetlink_queue-y := nfnetlink_queue_core.o
-nfnetlink_queue-$(CONFIG_NETFILTER_NETLINK_QUEUE_CT) += nfnetlink_queue_ct.o
 obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
 obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
 
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 2e90733..1412e36 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -348,6 +348,12 @@ int skb_make_writable(struct sk_buff *skb, unsigned int writable_len)
 }
 EXPORT_SYMBOL(skb_make_writable);
 
+/* This needs to be compiled in any case to avoid dependencies between the
+ * nfnetlink_queue code and nf_conntrack.
+ */
+struct nfq_ct_hook __rcu *nfq_ct_hook __read_mostly;
+EXPORT_SYMBOL_GPL(nfq_ct_hook);
+
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
 /* This does not belong here, but locally generated errors need it if connection
    tracking in use: without this, connection may not be in hash table, and hence
@@ -385,9 +391,6 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct)
 }
 EXPORT_SYMBOL(nf_conntrack_destroy);
 
-struct nfq_ct_hook __rcu *nfq_ct_hook __read_mostly;
-EXPORT_SYMBOL_GPL(nfq_ct_hook);
-
 /* Built-in default zone used e.g. by modules. */
 const struct nf_conntrack_zone nf_ct_zone_dflt = {
 	.id	= NF_CT_DEFAULT_ZONE_ID,
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 94a6654..eb67bf8 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2162,8 +2162,19 @@ ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
 	       ;
 }
 
-static int
-ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
+static struct nf_conn *ctnetlink_nfqueue_get_ct(struct sk_buff *skb,
+						enum ip_conntrack_info *ctinfo)
+{
+	struct nf_conn *ct;
+
+	ct = nf_ct_get(skb, ctinfo);
+	if (ct && nf_ct_is_untracked(ct))
+		ct = NULL;
+
+	return ct;
+}
+
+static int __ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
 {
 	const struct nf_conntrack_zone *zone;
 	struct nlattr *nest_parms;
@@ -2236,6 +2247,31 @@ nla_put_failure:
 }
 
 static int
+ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct,
+			enum ip_conntrack_info ctinfo,
+			u_int16_t ct_attr, u_int16_t ct_info_attr)
+{
+	struct nlattr *nest_parms;
+
+	nest_parms = nla_nest_start(skb, ct_attr | NLA_F_NESTED);
+	if (!nest_parms)
+		goto nla_put_failure;
+
+	if (__ctnetlink_nfqueue_build(skb, ct) < 0)
+		goto nla_put_failure;
+
+	nla_nest_end(skb, nest_parms);
+
+	if (nla_put_be32(skb, ct_info_attr, htonl(ctinfo)))
+		goto nla_put_failure;
+
+	return 0;
+
+nla_put_failure:
+	return -ENOSPC;
+}
+
+static int
 ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
 {
 	int err;
@@ -2350,12 +2386,22 @@ ctnetlink_nfqueue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
 	return 0;
 }
 
+static void ctnetlink_nfqueue_seqadj(struct sk_buff *skb, struct nf_conn *ct,
+				     enum ip_conntrack_info ctinfo, int diff)
+{
+	if (!(ct->status & IPS_NAT_MASK))
+		return;
+
+	nf_ct_tcp_seqadj_set(skb, ct, ctinfo, diff);
+}
+
 static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
+	.get_ct		= ctnetlink_nfqueue_get_ct,
 	.build_size	= ctnetlink_nfqueue_build_size,
 	.build		= ctnetlink_nfqueue_build,
 	.parse		= ctnetlink_nfqueue_parse,
 	.attach_expect	= ctnetlink_nfqueue_attach_expect,
-	.seq_adjust	= nf_ct_tcp_seqadj_set,
+	.seq_adjust	= ctnetlink_nfqueue_seqadj,
 };
 #endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */
 
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 41583e3..b1f1c74 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -28,12 +28,12 @@
 #include <linux/netfilter_bridge.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_queue.h>
+#include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/list.h>
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <net/netfilter/nf_queue.h>
 #include <net/netns/generic.h>
-#include <net/netfilter/nfnetlink_queue.h>
 
 #include <linux/atomic.h>
 
@@ -313,6 +313,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 	struct net_device *outdev;
 	struct nf_conn *ct = NULL;
 	enum ip_conntrack_info uninitialized_var(ctinfo);
+	struct nfq_ct_hook *nfq_ct;
 	bool csum_verify;
 	char *secdata = NULL;
 	u32 seclen = 0;
@@ -364,8 +365,14 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 		break;
 	}
 
-	if (queue->flags & NFQA_CFG_F_CONNTRACK)
-		ct = nfqnl_ct_get(entskb, &size, &ctinfo);
+	if (queue->flags & NFQA_CFG_F_CONNTRACK) {
+		nfq_ct = rcu_dereference(nfq_ct_hook);
+		if (nfq_ct != NULL) {
+			ct = nfq_ct->get_ct(entskb, &ctinfo);
+			if (ct != NULL)
+				size += nfq_ct->build_size(ct);
+		}
+	}
 
 	if (queue->flags & NFQA_CFG_F_UID_GID) {
 		size +=  (nla_total_size(sizeof(u_int32_t))	/* uid */
@@ -508,7 +515,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 	if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata))
 		goto nla_put_failure;
 
-	if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
+	if (ct && nfq_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
 		goto nla_put_failure;
 
 	if (cap_len > data_len &&
@@ -1001,6 +1008,28 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
 	return 0;
 }
 
+static struct nf_conn *nfqnl_ct_parse(struct nfq_ct_hook *nfq_ct,
+				      const struct nlmsghdr *nlh,
+				      const struct nlattr * const nfqa[],
+				      struct nf_queue_entry *entry,
+				      enum ip_conntrack_info *ctinfo)
+{
+	struct nf_conn *ct;
+
+	ct = nfq_ct->get_ct(entry->skb, ctinfo);
+	if (ct == NULL)
+		return NULL;
+
+	if (nfq_ct->parse(nfqa[NFQA_CT], ct) < 0)
+		return NULL;
+
+	if (nfqa[NFQA_EXP])
+		nfq_ct->attach_expect(nfqa[NFQA_EXP], ct,
+				      NETLINK_CB(entry->skb).portid,
+				      nlmsg_report(nlh));
+	return ct;
+}
+
 static int
 nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
 		   const struct nlmsghdr *nlh,
@@ -1014,6 +1043,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
 	unsigned int verdict;
 	struct nf_queue_entry *entry;
 	enum ip_conntrack_info uninitialized_var(ctinfo);
+	struct nfq_ct_hook *nfq_ct;
 	struct nf_conn *ct = NULL;
 
 	struct net *net = sock_net(ctnl);
@@ -1037,12 +1067,10 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
 		return -ENOENT;
 
 	if (nfqa[NFQA_CT]) {
-		ct = nfqnl_ct_parse(entry->skb, nfqa[NFQA_CT], &ctinfo);
-		if (ct && nfqa[NFQA_EXP]) {
-			nfqnl_attach_expect(ct, nfqa[NFQA_EXP],
-					    NETLINK_CB(skb).portid,
-					    nlmsg_report(nlh));
-		}
+		/* rcu lock already held from nfnl->call_rcu. */
+		nfq_ct = rcu_dereference(nfq_ct_hook);
+		if (nfq_ct != NULL)
+			ct = nfqnl_ct_parse(nfq_ct, nlh, nfqa, entry, &ctinfo);
 	}
 
 	if (nfqa[NFQA_PAYLOAD]) {
@@ -1053,8 +1081,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
 				 payload_len, entry, diff) < 0)
 			verdict = NF_DROP;
 
-		if (ct)
-			nfqnl_ct_seq_adjust(entry->skb, ct, ctinfo, diff);
+		if (ct && diff)
+			nfq_ct->seq_adjust(entry->skb, ct, ctinfo, diff);
 	}
 
 	if (nfqa[NFQA_MARK])
diff --git a/net/netfilter/nfnetlink_queue_ct.c b/net/netfilter/nfnetlink_queue_ct.c
deleted file mode 100644
index 96cac50..0000000
--- a/net/netfilter/nfnetlink_queue_ct.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/skbuff.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nfnetlink_queue.h>
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nfnetlink_queue.h>
-
-struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size,
-			     enum ip_conntrack_info *ctinfo)
-{
-	struct nfq_ct_hook *nfq_ct;
-	struct nf_conn *ct;
-
-	/* rcu_read_lock()ed by __nf_queue already. */
-	nfq_ct = rcu_dereference(nfq_ct_hook);
-	if (nfq_ct == NULL)
-		return NULL;
-
-	ct = nf_ct_get(entskb, ctinfo);
-	if (ct) {
-		if (!nf_ct_is_untracked(ct))
-			*size += nfq_ct->build_size(ct);
-		else
-			ct = NULL;
-	}
-	return ct;
-}
-
-struct nf_conn *
-nfqnl_ct_parse(const struct sk_buff *skb, const struct nlattr *attr,
-	       enum ip_conntrack_info *ctinfo)
-{
-	struct nfq_ct_hook *nfq_ct;
-	struct nf_conn *ct;
-
-	/* rcu_read_lock()ed by __nf_queue already. */
-	nfq_ct = rcu_dereference(nfq_ct_hook);
-	if (nfq_ct == NULL)
-		return NULL;
-
-	ct = nf_ct_get(skb, ctinfo);
-	if (ct && !nf_ct_is_untracked(ct))
-		nfq_ct->parse(attr, ct);
-
-	return ct;
-}
-
-int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
-		 enum ip_conntrack_info ctinfo)
-{
-	struct nfq_ct_hook *nfq_ct;
-	struct nlattr *nest_parms;
-	u_int32_t tmp;
-
-	nfq_ct = rcu_dereference(nfq_ct_hook);
-	if (nfq_ct == NULL)
-		return 0;
-
-	nest_parms = nla_nest_start(skb, NFQA_CT | NLA_F_NESTED);
-	if (!nest_parms)
-		goto nla_put_failure;
-
-	if (nfq_ct->build(skb, ct) < 0)
-		goto nla_put_failure;
-
-	nla_nest_end(skb, nest_parms);
-
-	tmp = ctinfo;
-	if (nla_put_be32(skb, NFQA_CT_INFO, htonl(tmp)))
-		goto nla_put_failure;
-
-	return 0;
-
-nla_put_failure:
-	return -1;
-}
-
-void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
-			 enum ip_conntrack_info ctinfo, int diff)
-{
-	struct nfq_ct_hook *nfq_ct;
-
-	nfq_ct = rcu_dereference(nfq_ct_hook);
-	if (nfq_ct == NULL)
-		return;
-
-	if ((ct->status & IPS_NAT_MASK) && diff)
-		nfq_ct->seq_adjust(skb, ct, ctinfo, diff);
-}
-
-int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
-			u32 portid, u32 report)
-{
-	struct nfq_ct_hook *nfq_ct;
-
-	if (nf_ct_is_untracked(ct))
-		return 0;
-
-	nfq_ct = rcu_dereference(nfq_ct_hook);
-	if (nfq_ct == NULL)
-		return -EOPNOTSUPP;
-
-	return nfq_ct->attach_expect(attr, ct, portid, report);
-}
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH 2/2 v3] netfilter: rename nfnetlink_queue_core.c to nfnetlink_queue.c
  2015-10-01 18:43 [PATCH 1/2 v3] netfilter: nfnetlink_queue: get rid of nfnetlink_queue_ct.c Pablo Neira Ayuso
@ 2015-10-01 18:43 ` Pablo Neira Ayuso
  2015-10-05  2:44   ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Ken-ichirou MATSUZAWA
  0 siblings, 1 reply; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-01 18:43 UTC (permalink / raw)
  To: netfilter-devel; +Cc: chamaken

Now that we have integrated the ct glue code into nfnetlink_queue without
introducing dependencies with the conntrack code.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v3: no changes

 net/netfilter/Makefile               |    1 -
 net/netfilter/nfnetlink_queue.c      | 1443 ++++++++++++++++++++++++++++++++++
 net/netfilter/nfnetlink_queue_core.c | 1443 ----------------------------------
 3 files changed, 1443 insertions(+), 1444 deletions(-)
 create mode 100644 net/netfilter/nfnetlink_queue.c
 delete mode 100644 net/netfilter/nfnetlink_queue_core.c

diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 4d68e72..7638c36 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_NETFILTER) = netfilter.o
 
 obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
 obj-$(CONFIG_NETFILTER_NETLINK_ACCT) += nfnetlink_acct.o
-nfnetlink_queue-y := nfnetlink_queue_core.o
 obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
 obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
 
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
new file mode 100644
index 0000000..b1f1c74
--- /dev/null
+++ b/net/netfilter/nfnetlink_queue.c
@@ -0,0 +1,1443 @@
+/*
+ * This is a module which is used for queueing packets and communicating with
+ * userspace via nfnetlink.
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ * (C) 2007 by Patrick McHardy <kaber@trash.net>
+ *
+ * Based on the old ipv4-only ip_queue.c:
+ * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
+ * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/proc_fs.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_bridge.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/netfilter/nf_queue.h>
+#include <net/netns/generic.h>
+
+#include <linux/atomic.h>
+
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+#include "../bridge/br_private.h"
+#endif
+
+#define NFQNL_QMAX_DEFAULT 1024
+
+/* We're using struct nlattr which has 16bit nla_len. Note that nla_len
+ * includes the header length. Thus, the maximum packet length that we
+ * support is 65531 bytes. We send truncated packets if the specified length
+ * is larger than that.  Userspace can check for presence of NFQA_CAP_LEN
+ * attribute to detect truncation.
+ */
+#define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN)
+
+struct nfqnl_instance {
+	struct hlist_node hlist;		/* global list of queues */
+	struct rcu_head rcu;
+
+	u32 peer_portid;
+	unsigned int queue_maxlen;
+	unsigned int copy_range;
+	unsigned int queue_dropped;
+	unsigned int queue_user_dropped;
+
+
+	u_int16_t queue_num;			/* number of this queue */
+	u_int8_t copy_mode;
+	u_int32_t flags;			/* Set using NFQA_CFG_FLAGS */
+/*
+ * Following fields are dirtied for each queued packet,
+ * keep them in same cache line if possible.
+ */
+	spinlock_t	lock;
+	unsigned int	queue_total;
+	unsigned int	id_sequence;		/* 'sequence' of pkt ids */
+	struct list_head queue_list;		/* packets in queue */
+};
+
+typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
+
+static int nfnl_queue_net_id __read_mostly;
+
+#define INSTANCE_BUCKETS	16
+struct nfnl_queue_net {
+	spinlock_t instances_lock;
+	struct hlist_head instance_table[INSTANCE_BUCKETS];
+};
+
+static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net)
+{
+	return net_generic(net, nfnl_queue_net_id);
+}
+
+static inline u_int8_t instance_hashfn(u_int16_t queue_num)
+{
+	return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;
+}
+
+static struct nfqnl_instance *
+instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num)
+{
+	struct hlist_head *head;
+	struct nfqnl_instance *inst;
+
+	head = &q->instance_table[instance_hashfn(queue_num)];
+	hlist_for_each_entry_rcu(inst, head, hlist) {
+		if (inst->queue_num == queue_num)
+			return inst;
+	}
+	return NULL;
+}
+
+static struct nfqnl_instance *
+instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
+{
+	struct nfqnl_instance *inst;
+	unsigned int h;
+	int err;
+
+	spin_lock(&q->instances_lock);
+	if (instance_lookup(q, queue_num)) {
+		err = -EEXIST;
+		goto out_unlock;
+	}
+
+	inst = kzalloc(sizeof(*inst), GFP_ATOMIC);
+	if (!inst) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+
+	inst->queue_num = queue_num;
+	inst->peer_portid = portid;
+	inst->queue_maxlen = NFQNL_QMAX_DEFAULT;
+	inst->copy_range = NFQNL_MAX_COPY_RANGE;
+	inst->copy_mode = NFQNL_COPY_NONE;
+	spin_lock_init(&inst->lock);
+	INIT_LIST_HEAD(&inst->queue_list);
+
+	if (!try_module_get(THIS_MODULE)) {
+		err = -EAGAIN;
+		goto out_free;
+	}
+
+	h = instance_hashfn(queue_num);
+	hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]);
+
+	spin_unlock(&q->instances_lock);
+
+	return inst;
+
+out_free:
+	kfree(inst);
+out_unlock:
+	spin_unlock(&q->instances_lock);
+	return ERR_PTR(err);
+}
+
+static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
+			unsigned long data);
+
+static void
+instance_destroy_rcu(struct rcu_head *head)
+{
+	struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance,
+						   rcu);
+
+	nfqnl_flush(inst, NULL, 0);
+	kfree(inst);
+	module_put(THIS_MODULE);
+}
+
+static void
+__instance_destroy(struct nfqnl_instance *inst)
+{
+	hlist_del_rcu(&inst->hlist);
+	call_rcu(&inst->rcu, instance_destroy_rcu);
+}
+
+static void
+instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst)
+{
+	spin_lock(&q->instances_lock);
+	__instance_destroy(inst);
+	spin_unlock(&q->instances_lock);
+}
+
+static inline void
+__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
+{
+       list_add_tail(&entry->list, &queue->queue_list);
+       queue->queue_total++;
+}
+
+static void
+__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
+{
+	list_del(&entry->list);
+	queue->queue_total--;
+}
+
+static struct nf_queue_entry *
+find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
+{
+	struct nf_queue_entry *entry = NULL, *i;
+
+	spin_lock_bh(&queue->lock);
+
+	list_for_each_entry(i, &queue->queue_list, list) {
+		if (i->id == id) {
+			entry = i;
+			break;
+		}
+	}
+
+	if (entry)
+		__dequeue_entry(queue, entry);
+
+	spin_unlock_bh(&queue->lock);
+
+	return entry;
+}
+
+static void
+nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
+{
+	struct nf_queue_entry *entry, *next;
+
+	spin_lock_bh(&queue->lock);
+	list_for_each_entry_safe(entry, next, &queue->queue_list, list) {
+		if (!cmpfn || cmpfn(entry, data)) {
+			list_del(&entry->list);
+			queue->queue_total--;
+			nf_reinject(entry, NF_DROP);
+		}
+	}
+	spin_unlock_bh(&queue->lock);
+}
+
+static int
+nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
+		      bool csum_verify)
+{
+	__u32 flags = 0;
+
+	if (packet->ip_summed == CHECKSUM_PARTIAL)
+		flags = NFQA_SKB_CSUMNOTREADY;
+	else if (csum_verify)
+		flags = NFQA_SKB_CSUM_NOTVERIFIED;
+
+	if (skb_is_gso(packet))
+		flags |= NFQA_SKB_GSO;
+
+	return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0;
+}
+
+static int nfqnl_put_sk_uidgid(struct sk_buff *skb, struct sock *sk)
+{
+	const struct cred *cred;
+
+	if (!sk_fullsock(sk))
+		return 0;
+
+	read_lock_bh(&sk->sk_callback_lock);
+	if (sk->sk_socket && sk->sk_socket->file) {
+		cred = sk->sk_socket->file->f_cred;
+		if (nla_put_be32(skb, NFQA_UID,
+		    htonl(from_kuid_munged(&init_user_ns, cred->fsuid))))
+			goto nla_put_failure;
+		if (nla_put_be32(skb, NFQA_GID,
+		    htonl(from_kgid_munged(&init_user_ns, cred->fsgid))))
+			goto nla_put_failure;
+	}
+	read_unlock_bh(&sk->sk_callback_lock);
+	return 0;
+
+nla_put_failure:
+	read_unlock_bh(&sk->sk_callback_lock);
+	return -1;
+}
+
+static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
+{
+	u32 seclen = 0;
+#if IS_ENABLED(CONFIG_NETWORK_SECMARK)
+	if (!skb || !sk_fullsock(skb->sk))
+		return 0;
+
+	read_lock_bh(&skb->sk->sk_callback_lock);
+
+	if (skb->secmark)
+		security_secid_to_secctx(skb->secmark, secdata, &seclen);
+
+	read_unlock_bh(&skb->sk->sk_callback_lock);
+#endif
+	return seclen;
+}
+
+static struct sk_buff *
+nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
+			   struct nf_queue_entry *entry,
+			   __be32 **packet_id_ptr)
+{
+	size_t size;
+	size_t data_len = 0, cap_len = 0, rem_len = 0;
+	unsigned int hlen = 0;
+	struct sk_buff *skb;
+	struct nlattr *nla;
+	struct nfqnl_msg_packet_hdr *pmsg;
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfmsg;
+	struct sk_buff *entskb = entry->skb;
+	struct net_device *indev;
+	struct net_device *outdev;
+	struct nf_conn *ct = NULL;
+	enum ip_conntrack_info uninitialized_var(ctinfo);
+	struct nfq_ct_hook *nfq_ct;
+	bool csum_verify;
+	char *secdata = NULL;
+	u32 seclen = 0;
+
+	size =    nlmsg_total_size(sizeof(struct nfgenmsg))
+		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr))
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
+#endif
+		+ nla_total_size(sizeof(u_int32_t))	/* mark */
+		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
+		+ nla_total_size(sizeof(u_int32_t))	/* skbinfo */
+		+ nla_total_size(sizeof(u_int32_t));	/* cap_len */
+
+	if (entskb->tstamp.tv64)
+		size += nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp));
+
+	if (entry->state.hook <= NF_INET_FORWARD ||
+	   (entry->state.hook == NF_INET_POST_ROUTING && entskb->sk == NULL))
+		csum_verify = !skb_csum_unnecessary(entskb);
+	else
+		csum_verify = false;
+
+	outdev = entry->state.out;
+
+	switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) {
+	case NFQNL_COPY_META:
+	case NFQNL_COPY_NONE:
+		break;
+
+	case NFQNL_COPY_PACKET:
+		if (!(queue->flags & NFQA_CFG_F_GSO) &&
+		    entskb->ip_summed == CHECKSUM_PARTIAL &&
+		    skb_checksum_help(entskb))
+			return NULL;
+
+		data_len = ACCESS_ONCE(queue->copy_range);
+		if (data_len > entskb->len)
+			data_len = entskb->len;
+
+		hlen = skb_zerocopy_headlen(entskb);
+		hlen = min_t(unsigned int, hlen, data_len);
+		size += sizeof(struct nlattr) + hlen;
+		cap_len = entskb->len;
+		rem_len = data_len - hlen;
+		break;
+	}
+
+	if (queue->flags & NFQA_CFG_F_CONNTRACK) {
+		nfq_ct = rcu_dereference(nfq_ct_hook);
+		if (nfq_ct != NULL) {
+			ct = nfq_ct->get_ct(entskb, &ctinfo);
+			if (ct != NULL)
+				size += nfq_ct->build_size(ct);
+		}
+	}
+
+	if (queue->flags & NFQA_CFG_F_UID_GID) {
+		size +=  (nla_total_size(sizeof(u_int32_t))	/* uid */
+			+ nla_total_size(sizeof(u_int32_t)));	/* gid */
+	}
+
+	if ((queue->flags & NFQA_CFG_F_SECCTX) && entskb->sk) {
+		seclen = nfqnl_get_sk_secctx(entskb, &secdata);
+		if (seclen)
+			size += nla_total_size(seclen);
+	}
+
+	skb = __netlink_alloc_skb(net->nfnl, size, rem_len, queue->peer_portid,
+				  GFP_ATOMIC);
+	if (!skb) {
+		skb_tx_error(entskb);
+		return NULL;
+	}
+
+	nlh = nlmsg_put(skb, 0, 0,
+			NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
+			sizeof(struct nfgenmsg), 0);
+	if (!nlh) {
+		skb_tx_error(entskb);
+		kfree_skb(skb);
+		return NULL;
+	}
+	nfmsg = nlmsg_data(nlh);
+	nfmsg->nfgen_family = entry->state.pf;
+	nfmsg->version = NFNETLINK_V0;
+	nfmsg->res_id = htons(queue->queue_num);
+
+	nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg));
+	pmsg = nla_data(nla);
+	pmsg->hw_protocol	= entskb->protocol;
+	pmsg->hook		= entry->state.hook;
+	*packet_id_ptr		= &pmsg->packet_id;
+
+	indev = entry->state.in;
+	if (indev) {
+#if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+		if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex)))
+			goto nla_put_failure;
+#else
+		if (entry->state.pf == PF_BRIDGE) {
+			/* Case 1: indev is physical input device, we need to
+			 * look for bridge group (when called from
+			 * netfilter_bridge) */
+			if (nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
+					 htonl(indev->ifindex)) ||
+			/* this is the bridge group "brX" */
+			/* rcu_read_lock()ed by __nf_queue */
+			    nla_put_be32(skb, NFQA_IFINDEX_INDEV,
+					 htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
+				goto nla_put_failure;
+		} else {
+			int physinif;
+
+			/* Case 2: indev is bridge group, we need to look for
+			 * physical device (when called from ipv4) */
+			if (nla_put_be32(skb, NFQA_IFINDEX_INDEV,
+					 htonl(indev->ifindex)))
+				goto nla_put_failure;
+
+			physinif = nf_bridge_get_physinif(entskb);
+			if (physinif &&
+			    nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
+					 htonl(physinif)))
+				goto nla_put_failure;
+		}
+#endif
+	}
+
+	if (outdev) {
+#if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+		if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex)))
+			goto nla_put_failure;
+#else
+		if (entry->state.pf == PF_BRIDGE) {
+			/* Case 1: outdev is physical output device, we need to
+			 * look for bridge group (when called from
+			 * netfilter_bridge) */
+			if (nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
+					 htonl(outdev->ifindex)) ||
+			/* this is the bridge group "brX" */
+			/* rcu_read_lock()ed by __nf_queue */
+			    nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
+					 htonl(br_port_get_rcu(outdev)->br->dev->ifindex)))
+				goto nla_put_failure;
+		} else {
+			int physoutif;
+
+			/* Case 2: outdev is bridge group, we need to look for
+			 * physical output device (when called from ipv4) */
+			if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
+					 htonl(outdev->ifindex)))
+				goto nla_put_failure;
+
+			physoutif = nf_bridge_get_physoutif(entskb);
+			if (physoutif &&
+			    nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
+					 htonl(physoutif)))
+				goto nla_put_failure;
+		}
+#endif
+	}
+
+	if (entskb->mark &&
+	    nla_put_be32(skb, NFQA_MARK, htonl(entskb->mark)))
+		goto nla_put_failure;
+
+	if (indev && entskb->dev &&
+	    entskb->mac_header != entskb->network_header) {
+		struct nfqnl_msg_packet_hw phw;
+		int len;
+
+		memset(&phw, 0, sizeof(phw));
+		len = dev_parse_header(entskb, phw.hw_addr);
+		if (len) {
+			phw.hw_addrlen = htons(len);
+			if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw))
+				goto nla_put_failure;
+		}
+	}
+
+	if (entskb->tstamp.tv64) {
+		struct nfqnl_msg_packet_timestamp ts;
+		struct timeval tv = ktime_to_timeval(entskb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
+
+		if (nla_put(skb, NFQA_TIMESTAMP, sizeof(ts), &ts))
+			goto nla_put_failure;
+	}
+
+	if ((queue->flags & NFQA_CFG_F_UID_GID) && entskb->sk &&
+	    nfqnl_put_sk_uidgid(skb, entskb->sk) < 0)
+		goto nla_put_failure;
+
+	if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata))
+		goto nla_put_failure;
+
+	if (ct && nfq_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
+		goto nla_put_failure;
+
+	if (cap_len > data_len &&
+	    nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
+		goto nla_put_failure;
+
+	if (nfqnl_put_packet_info(skb, entskb, csum_verify))
+		goto nla_put_failure;
+
+	if (data_len) {
+		struct nlattr *nla;
+
+		if (skb_tailroom(skb) < sizeof(*nla) + hlen)
+			goto nla_put_failure;
+
+		nla = (struct nlattr *)skb_put(skb, sizeof(*nla));
+		nla->nla_type = NFQA_PAYLOAD;
+		nla->nla_len = nla_attr_size(data_len);
+
+		if (skb_zerocopy(skb, entskb, data_len, hlen))
+			goto nla_put_failure;
+	}
+
+	nlh->nlmsg_len = skb->len;
+	return skb;
+
+nla_put_failure:
+	skb_tx_error(entskb);
+	kfree_skb(skb);
+	net_err_ratelimited("nf_queue: error creating packet message\n");
+	return NULL;
+}
+
+static int
+__nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
+			struct nf_queue_entry *entry)
+{
+	struct sk_buff *nskb;
+	int err = -ENOBUFS;
+	__be32 *packet_id_ptr;
+	int failopen = 0;
+
+	nskb = nfqnl_build_packet_message(net, queue, entry, &packet_id_ptr);
+	if (nskb == NULL) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	spin_lock_bh(&queue->lock);
+
+	if (queue->queue_total >= queue->queue_maxlen) {
+		if (queue->flags & NFQA_CFG_F_FAIL_OPEN) {
+			failopen = 1;
+			err = 0;
+		} else {
+			queue->queue_dropped++;
+			net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n",
+					     queue->queue_total);
+		}
+		goto err_out_free_nskb;
+	}
+	entry->id = ++queue->id_sequence;
+	*packet_id_ptr = htonl(entry->id);
+
+	/* nfnetlink_unicast will either free the nskb or add it to a socket */
+	err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT);
+	if (err < 0) {
+		queue->queue_user_dropped++;
+		goto err_out_unlock;
+	}
+
+	__enqueue_entry(queue, entry);
+
+	spin_unlock_bh(&queue->lock);
+	return 0;
+
+err_out_free_nskb:
+	kfree_skb(nskb);
+err_out_unlock:
+	spin_unlock_bh(&queue->lock);
+	if (failopen)
+		nf_reinject(entry, NF_ACCEPT);
+err_out:
+	return err;
+}
+
+static struct nf_queue_entry *
+nf_queue_entry_dup(struct nf_queue_entry *e)
+{
+	struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
+	if (entry) {
+		if (nf_queue_entry_get_refs(entry))
+			return entry;
+		kfree(entry);
+	}
+	return NULL;
+}
+
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+/* When called from bridge netfilter, skb->data must point to MAC header
+ * before calling skb_gso_segment(). Else, original MAC header is lost
+ * and segmented skbs will be sent to wrong destination.
+ */
+static void nf_bridge_adjust_skb_data(struct sk_buff *skb)
+{
+	if (skb->nf_bridge)
+		__skb_push(skb, skb->network_header - skb->mac_header);
+}
+
+static void nf_bridge_adjust_segmented_data(struct sk_buff *skb)
+{
+	if (skb->nf_bridge)
+		__skb_pull(skb, skb->network_header - skb->mac_header);
+}
+#else
+#define nf_bridge_adjust_skb_data(s) do {} while (0)
+#define nf_bridge_adjust_segmented_data(s) do {} while (0)
+#endif
+
+static void free_entry(struct nf_queue_entry *entry)
+{
+	nf_queue_entry_release_refs(entry);
+	kfree(entry);
+}
+
+static int
+__nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue,
+			   struct sk_buff *skb, struct nf_queue_entry *entry)
+{
+	int ret = -ENOMEM;
+	struct nf_queue_entry *entry_seg;
+
+	nf_bridge_adjust_segmented_data(skb);
+
+	if (skb->next == NULL) { /* last packet, no need to copy entry */
+		struct sk_buff *gso_skb = entry->skb;
+		entry->skb = skb;
+		ret = __nfqnl_enqueue_packet(net, queue, entry);
+		if (ret)
+			entry->skb = gso_skb;
+		return ret;
+	}
+
+	skb->next = NULL;
+
+	entry_seg = nf_queue_entry_dup(entry);
+	if (entry_seg) {
+		entry_seg->skb = skb;
+		ret = __nfqnl_enqueue_packet(net, queue, entry_seg);
+		if (ret)
+			free_entry(entry_seg);
+	}
+	return ret;
+}
+
+static int
+nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+{
+	unsigned int queued;
+	struct nfqnl_instance *queue;
+	struct sk_buff *skb, *segs;
+	int err = -ENOBUFS;
+	struct net *net = entry->state.net;
+	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
+	/* rcu_read_lock()ed by nf_hook_slow() */
+	queue = instance_lookup(q, queuenum);
+	if (!queue)
+		return -ESRCH;
+
+	if (queue->copy_mode == NFQNL_COPY_NONE)
+		return -EINVAL;
+
+	skb = entry->skb;
+
+	switch (entry->state.pf) {
+	case NFPROTO_IPV4:
+		skb->protocol = htons(ETH_P_IP);
+		break;
+	case NFPROTO_IPV6:
+		skb->protocol = htons(ETH_P_IPV6);
+		break;
+	}
+
+	if ((queue->flags & NFQA_CFG_F_GSO) || !skb_is_gso(skb))
+		return __nfqnl_enqueue_packet(net, queue, entry);
+
+	nf_bridge_adjust_skb_data(skb);
+	segs = skb_gso_segment(skb, 0);
+	/* Does not use PTR_ERR to limit the number of error codes that can be
+	 * returned by nf_queue.  For instance, callers rely on -ECANCELED to
+	 * mean 'ignore this hook'.
+	 */
+	if (IS_ERR_OR_NULL(segs))
+		goto out_err;
+	queued = 0;
+	err = 0;
+	do {
+		struct sk_buff *nskb = segs->next;
+		if (err == 0)
+			err = __nfqnl_enqueue_packet_gso(net, queue,
+							segs, entry);
+		if (err == 0)
+			queued++;
+		else
+			kfree_skb(segs);
+		segs = nskb;
+	} while (segs);
+
+	if (queued) {
+		if (err) /* some segments are already queued */
+			free_entry(entry);
+		kfree_skb(skb);
+		return 0;
+	}
+ out_err:
+	nf_bridge_adjust_segmented_data(skb);
+	return err;
+}
+
+static int
+nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
+{
+	struct sk_buff *nskb;
+
+	if (diff < 0) {
+		if (pskb_trim(e->skb, data_len))
+			return -ENOMEM;
+	} else if (diff > 0) {
+		if (data_len > 0xFFFF)
+			return -EINVAL;
+		if (diff > skb_tailroom(e->skb)) {
+			nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
+					       diff, GFP_ATOMIC);
+			if (!nskb) {
+				printk(KERN_WARNING "nf_queue: OOM "
+				      "in mangle, dropping packet\n");
+				return -ENOMEM;
+			}
+			kfree_skb(e->skb);
+			e->skb = nskb;
+		}
+		skb_put(e->skb, diff);
+	}
+	if (!skb_make_writable(e->skb, data_len))
+		return -ENOMEM;
+	skb_copy_to_linear_data(e->skb, data, data_len);
+	e->skb->ip_summed = CHECKSUM_NONE;
+	return 0;
+}
+
+static int
+nfqnl_set_mode(struct nfqnl_instance *queue,
+	       unsigned char mode, unsigned int range)
+{
+	int status = 0;
+
+	spin_lock_bh(&queue->lock);
+	switch (mode) {
+	case NFQNL_COPY_NONE:
+	case NFQNL_COPY_META:
+		queue->copy_mode = mode;
+		queue->copy_range = 0;
+		break;
+
+	case NFQNL_COPY_PACKET:
+		queue->copy_mode = mode;
+		if (range == 0 || range > NFQNL_MAX_COPY_RANGE)
+			queue->copy_range = NFQNL_MAX_COPY_RANGE;
+		else
+			queue->copy_range = range;
+		break;
+
+	default:
+		status = -EINVAL;
+
+	}
+	spin_unlock_bh(&queue->lock);
+
+	return status;
+}
+
+static int
+dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
+{
+	if (entry->state.in)
+		if (entry->state.in->ifindex == ifindex)
+			return 1;
+	if (entry->state.out)
+		if (entry->state.out->ifindex == ifindex)
+			return 1;
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+	if (entry->skb->nf_bridge) {
+		int physinif, physoutif;
+
+		physinif = nf_bridge_get_physinif(entry->skb);
+		physoutif = nf_bridge_get_physoutif(entry->skb);
+
+		if (physinif == ifindex || physoutif == ifindex)
+			return 1;
+	}
+#endif
+	return 0;
+}
+
+/* drop all packets with either indev or outdev == ifindex from all queue
+ * instances */
+static void
+nfqnl_dev_drop(struct net *net, int ifindex)
+{
+	int i;
+	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
+	rcu_read_lock();
+
+	for (i = 0; i < INSTANCE_BUCKETS; i++) {
+		struct nfqnl_instance *inst;
+		struct hlist_head *head = &q->instance_table[i];
+
+		hlist_for_each_entry_rcu(inst, head, hlist)
+			nfqnl_flush(inst, dev_cmp, ifindex);
+	}
+
+	rcu_read_unlock();
+}
+
+static int
+nfqnl_rcv_dev_event(struct notifier_block *this,
+		    unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+	/* Drop any packets associated with the downed device */
+	if (event == NETDEV_DOWN)
+		nfqnl_dev_drop(dev_net(dev), dev->ifindex);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nfqnl_dev_notifier = {
+	.notifier_call	= nfqnl_rcv_dev_event,
+};
+
+static int nf_hook_cmp(struct nf_queue_entry *entry, unsigned long ops_ptr)
+{
+	return entry->elem == (struct nf_hook_ops *)ops_ptr;
+}
+
+static void nfqnl_nf_hook_drop(struct net *net, struct nf_hook_ops *hook)
+{
+	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+	int i;
+
+	rcu_read_lock();
+	for (i = 0; i < INSTANCE_BUCKETS; i++) {
+		struct nfqnl_instance *inst;
+		struct hlist_head *head = &q->instance_table[i];
+
+		hlist_for_each_entry_rcu(inst, head, hlist)
+			nfqnl_flush(inst, nf_hook_cmp, (unsigned long)hook);
+	}
+	rcu_read_unlock();
+}
+
+static int
+nfqnl_rcv_nl_event(struct notifier_block *this,
+		   unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+	struct nfnl_queue_net *q = nfnl_queue_pernet(n->net);
+
+	if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
+		int i;
+
+		/* destroy all instances for this portid */
+		spin_lock(&q->instances_lock);
+		for (i = 0; i < INSTANCE_BUCKETS; i++) {
+			struct hlist_node *t2;
+			struct nfqnl_instance *inst;
+			struct hlist_head *head = &q->instance_table[i];
+
+			hlist_for_each_entry_safe(inst, t2, head, hlist) {
+				if (n->portid == inst->peer_portid)
+					__instance_destroy(inst);
+			}
+		}
+		spin_unlock(&q->instances_lock);
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nfqnl_rtnl_notifier = {
+	.notifier_call	= nfqnl_rcv_nl_event,
+};
+
+static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
+	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
+	[NFQA_MARK]		= { .type = NLA_U32 },
+	[NFQA_PAYLOAD]		= { .type = NLA_UNSPEC },
+	[NFQA_CT]		= { .type = NLA_UNSPEC },
+	[NFQA_EXP]		= { .type = NLA_UNSPEC },
+};
+
+static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
+	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
+	[NFQA_MARK]		= { .type = NLA_U32 },
+};
+
+static struct nfqnl_instance *
+verdict_instance_lookup(struct nfnl_queue_net *q, u16 queue_num, u32 nlportid)
+{
+	struct nfqnl_instance *queue;
+
+	queue = instance_lookup(q, queue_num);
+	if (!queue)
+		return ERR_PTR(-ENODEV);
+
+	if (queue->peer_portid != nlportid)
+		return ERR_PTR(-EPERM);
+
+	return queue;
+}
+
+static struct nfqnl_msg_verdict_hdr*
+verdicthdr_get(const struct nlattr * const nfqa[])
+{
+	struct nfqnl_msg_verdict_hdr *vhdr;
+	unsigned int verdict;
+
+	if (!nfqa[NFQA_VERDICT_HDR])
+		return NULL;
+
+	vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
+	verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK;
+	if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN)
+		return NULL;
+	return vhdr;
+}
+
+static int nfq_id_after(unsigned int id, unsigned int max)
+{
+	return (int)(id - max) > 0;
+}
+
+static int
+nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
+		   const struct nlmsghdr *nlh,
+		   const struct nlattr * const nfqa[])
+{
+	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+	struct nf_queue_entry *entry, *tmp;
+	unsigned int verdict, maxid;
+	struct nfqnl_msg_verdict_hdr *vhdr;
+	struct nfqnl_instance *queue;
+	LIST_HEAD(batch_list);
+	u16 queue_num = ntohs(nfmsg->res_id);
+
+	struct net *net = sock_net(ctnl);
+	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
+	queue = verdict_instance_lookup(q, queue_num,
+					NETLINK_CB(skb).portid);
+	if (IS_ERR(queue))
+		return PTR_ERR(queue);
+
+	vhdr = verdicthdr_get(nfqa);
+	if (!vhdr)
+		return -EINVAL;
+
+	verdict = ntohl(vhdr->verdict);
+	maxid = ntohl(vhdr->id);
+
+	spin_lock_bh(&queue->lock);
+
+	list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) {
+		if (nfq_id_after(entry->id, maxid))
+			break;
+		__dequeue_entry(queue, entry);
+		list_add_tail(&entry->list, &batch_list);
+	}
+
+	spin_unlock_bh(&queue->lock);
+
+	if (list_empty(&batch_list))
+		return -ENOENT;
+
+	list_for_each_entry_safe(entry, tmp, &batch_list, list) {
+		if (nfqa[NFQA_MARK])
+			entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
+		nf_reinject(entry, verdict);
+	}
+	return 0;
+}
+
+static struct nf_conn *nfqnl_ct_parse(struct nfq_ct_hook *nfq_ct,
+				      const struct nlmsghdr *nlh,
+				      const struct nlattr * const nfqa[],
+				      struct nf_queue_entry *entry,
+				      enum ip_conntrack_info *ctinfo)
+{
+	struct nf_conn *ct;
+
+	ct = nfq_ct->get_ct(entry->skb, ctinfo);
+	if (ct == NULL)
+		return NULL;
+
+	if (nfq_ct->parse(nfqa[NFQA_CT], ct) < 0)
+		return NULL;
+
+	if (nfqa[NFQA_EXP])
+		nfq_ct->attach_expect(nfqa[NFQA_EXP], ct,
+				      NETLINK_CB(entry->skb).portid,
+				      nlmsg_report(nlh));
+	return ct;
+}
+
+static int
+nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
+		   const struct nlmsghdr *nlh,
+		   const struct nlattr * const nfqa[])
+{
+	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+	u_int16_t queue_num = ntohs(nfmsg->res_id);
+
+	struct nfqnl_msg_verdict_hdr *vhdr;
+	struct nfqnl_instance *queue;
+	unsigned int verdict;
+	struct nf_queue_entry *entry;
+	enum ip_conntrack_info uninitialized_var(ctinfo);
+	struct nfq_ct_hook *nfq_ct;
+	struct nf_conn *ct = NULL;
+
+	struct net *net = sock_net(ctnl);
+	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
+	queue = instance_lookup(q, queue_num);
+	if (!queue)
+		queue = verdict_instance_lookup(q, queue_num,
+						NETLINK_CB(skb).portid);
+	if (IS_ERR(queue))
+		return PTR_ERR(queue);
+
+	vhdr = verdicthdr_get(nfqa);
+	if (!vhdr)
+		return -EINVAL;
+
+	verdict = ntohl(vhdr->verdict);
+
+	entry = find_dequeue_entry(queue, ntohl(vhdr->id));
+	if (entry == NULL)
+		return -ENOENT;
+
+	if (nfqa[NFQA_CT]) {
+		/* rcu lock already held from nfnl->call_rcu. */
+		nfq_ct = rcu_dereference(nfq_ct_hook);
+		if (nfq_ct != NULL)
+			ct = nfqnl_ct_parse(nfq_ct, nlh, nfqa, entry, &ctinfo);
+	}
+
+	if (nfqa[NFQA_PAYLOAD]) {
+		u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]);
+		int diff = payload_len - entry->skb->len;
+
+		if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
+				 payload_len, entry, diff) < 0)
+			verdict = NF_DROP;
+
+		if (ct && diff)
+			nfq_ct->seq_adjust(entry->skb, ct, ctinfo, diff);
+	}
+
+	if (nfqa[NFQA_MARK])
+		entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
+
+	nf_reinject(entry, verdict);
+	return 0;
+}
+
+static int
+nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
+		  const struct nlmsghdr *nlh,
+		  const struct nlattr * const nfqa[])
+{
+	return -ENOTSUPP;
+}
+
+static const struct nla_policy nfqa_cfg_policy[NFQA_CFG_MAX+1] = {
+	[NFQA_CFG_CMD]		= { .len = sizeof(struct nfqnl_msg_config_cmd) },
+	[NFQA_CFG_PARAMS]	= { .len = sizeof(struct nfqnl_msg_config_params) },
+};
+
+static const struct nf_queue_handler nfqh = {
+	.outfn		= &nfqnl_enqueue_packet,
+	.nf_hook_drop	= &nfqnl_nf_hook_drop,
+};
+
+static int
+nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
+		  const struct nlmsghdr *nlh,
+		  const struct nlattr * const nfqa[])
+{
+	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+	u_int16_t queue_num = ntohs(nfmsg->res_id);
+	struct nfqnl_instance *queue;
+	struct nfqnl_msg_config_cmd *cmd = NULL;
+	struct net *net = sock_net(ctnl);
+	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+	int ret = 0;
+
+	if (nfqa[NFQA_CFG_CMD]) {
+		cmd = nla_data(nfqa[NFQA_CFG_CMD]);
+
+		/* Obsolete commands without queue context */
+		switch (cmd->command) {
+		case NFQNL_CFG_CMD_PF_BIND: return 0;
+		case NFQNL_CFG_CMD_PF_UNBIND: return 0;
+		}
+	}
+
+	rcu_read_lock();
+	queue = instance_lookup(q, queue_num);
+	if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
+		ret = -EPERM;
+		goto err_out_unlock;
+	}
+
+	if (cmd != NULL) {
+		switch (cmd->command) {
+		case NFQNL_CFG_CMD_BIND:
+			if (queue) {
+				ret = -EBUSY;
+				goto err_out_unlock;
+			}
+			queue = instance_create(q, queue_num,
+						NETLINK_CB(skb).portid);
+			if (IS_ERR(queue)) {
+				ret = PTR_ERR(queue);
+				goto err_out_unlock;
+			}
+			break;
+		case NFQNL_CFG_CMD_UNBIND:
+			if (!queue) {
+				ret = -ENODEV;
+				goto err_out_unlock;
+			}
+			instance_destroy(q, queue);
+			break;
+		case NFQNL_CFG_CMD_PF_BIND:
+		case NFQNL_CFG_CMD_PF_UNBIND:
+			break;
+		default:
+			ret = -ENOTSUPP;
+			break;
+		}
+	}
+
+	if (nfqa[NFQA_CFG_PARAMS]) {
+		struct nfqnl_msg_config_params *params;
+
+		if (!queue) {
+			ret = -ENODEV;
+			goto err_out_unlock;
+		}
+		params = nla_data(nfqa[NFQA_CFG_PARAMS]);
+		nfqnl_set_mode(queue, params->copy_mode,
+				ntohl(params->copy_range));
+	}
+
+	if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
+		__be32 *queue_maxlen;
+
+		if (!queue) {
+			ret = -ENODEV;
+			goto err_out_unlock;
+		}
+		queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
+		spin_lock_bh(&queue->lock);
+		queue->queue_maxlen = ntohl(*queue_maxlen);
+		spin_unlock_bh(&queue->lock);
+	}
+
+	if (nfqa[NFQA_CFG_FLAGS]) {
+		__u32 flags, mask;
+
+		if (!queue) {
+			ret = -ENODEV;
+			goto err_out_unlock;
+		}
+
+		if (!nfqa[NFQA_CFG_MASK]) {
+			/* A mask is needed to specify which flags are being
+			 * changed.
+			 */
+			ret = -EINVAL;
+			goto err_out_unlock;
+		}
+
+		flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
+		mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
+
+		if (flags >= NFQA_CFG_F_MAX) {
+			ret = -EOPNOTSUPP;
+			goto err_out_unlock;
+		}
+#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
+		if (flags & mask & NFQA_CFG_F_SECCTX) {
+			ret = -EOPNOTSUPP;
+			goto err_out_unlock;
+		}
+#endif
+		spin_lock_bh(&queue->lock);
+		queue->flags &= ~mask;
+		queue->flags |= flags & mask;
+		spin_unlock_bh(&queue->lock);
+	}
+
+err_out_unlock:
+	rcu_read_unlock();
+	return ret;
+}
+
+static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
+	[NFQNL_MSG_PACKET]	= { .call_rcu = nfqnl_recv_unsupp,
+				    .attr_count = NFQA_MAX, },
+	[NFQNL_MSG_VERDICT]	= { .call_rcu = nfqnl_recv_verdict,
+				    .attr_count = NFQA_MAX,
+				    .policy = nfqa_verdict_policy },
+	[NFQNL_MSG_CONFIG]	= { .call = nfqnl_recv_config,
+				    .attr_count = NFQA_CFG_MAX,
+				    .policy = nfqa_cfg_policy },
+	[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
+				    .attr_count = NFQA_MAX,
+				    .policy = nfqa_verdict_batch_policy },
+};
+
+static const struct nfnetlink_subsystem nfqnl_subsys = {
+	.name		= "nf_queue",
+	.subsys_id	= NFNL_SUBSYS_QUEUE,
+	.cb_count	= NFQNL_MSG_MAX,
+	.cb		= nfqnl_cb,
+};
+
+#ifdef CONFIG_PROC_FS
+struct iter_state {
+	struct seq_net_private p;
+	unsigned int bucket;
+};
+
+static struct hlist_node *get_first(struct seq_file *seq)
+{
+	struct iter_state *st = seq->private;
+	struct net *net;
+	struct nfnl_queue_net *q;
+
+	if (!st)
+		return NULL;
+
+	net = seq_file_net(seq);
+	q = nfnl_queue_pernet(net);
+	for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
+		if (!hlist_empty(&q->instance_table[st->bucket]))
+			return q->instance_table[st->bucket].first;
+	}
+	return NULL;
+}
+
+static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+{
+	struct iter_state *st = seq->private;
+	struct net *net = seq_file_net(seq);
+
+	h = h->next;
+	while (!h) {
+		struct nfnl_queue_net *q;
+
+		if (++st->bucket >= INSTANCE_BUCKETS)
+			return NULL;
+
+		q = nfnl_queue_pernet(net);
+		h = q->instance_table[st->bucket].first;
+	}
+	return h;
+}
+
+static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct hlist_node *head;
+	head = get_first(seq);
+
+	if (head)
+		while (pos && (head = get_next(seq, head)))
+			pos--;
+	return pos ? NULL : head;
+}
+
+static void *seq_start(struct seq_file *s, loff_t *pos)
+	__acquires(nfnl_queue_pernet(seq_file_net(s))->instances_lock)
+{
+	spin_lock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock);
+	return get_idx(s, *pos);
+}
+
+static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	(*pos)++;
+	return get_next(s, v);
+}
+
+static void seq_stop(struct seq_file *s, void *v)
+	__releases(nfnl_queue_pernet(seq_file_net(s))->instances_lock)
+{
+	spin_unlock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock);
+}
+
+static int seq_show(struct seq_file *s, void *v)
+{
+	const struct nfqnl_instance *inst = v;
+
+	seq_printf(s, "%5u %6u %5u %1u %5u %5u %5u %8u %2d\n",
+		   inst->queue_num,
+		   inst->peer_portid, inst->queue_total,
+		   inst->copy_mode, inst->copy_range,
+		   inst->queue_dropped, inst->queue_user_dropped,
+		   inst->id_sequence, 1);
+	return 0;
+}
+
+static const struct seq_operations nfqnl_seq_ops = {
+	.start	= seq_start,
+	.next	= seq_next,
+	.stop	= seq_stop,
+	.show	= seq_show,
+};
+
+static int nfqnl_open(struct inode *inode, struct file *file)
+{
+	return seq_open_net(inode, file, &nfqnl_seq_ops,
+			sizeof(struct iter_state));
+}
+
+static const struct file_operations nfqnl_file_ops = {
+	.owner	 = THIS_MODULE,
+	.open	 = nfqnl_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release_net,
+};
+
+#endif /* PROC_FS */
+
+static int __net_init nfnl_queue_net_init(struct net *net)
+{
+	unsigned int i;
+	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
+	for (i = 0; i < INSTANCE_BUCKETS; i++)
+		INIT_HLIST_HEAD(&q->instance_table[i]);
+
+	spin_lock_init(&q->instances_lock);
+
+#ifdef CONFIG_PROC_FS
+	if (!proc_create("nfnetlink_queue", 0440,
+			 net->nf.proc_netfilter, &nfqnl_file_ops))
+		return -ENOMEM;
+#endif
+	return 0;
+}
+
+static void __net_exit nfnl_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnl_queue_net_ops = {
+	.init	= nfnl_queue_net_init,
+	.exit	= nfnl_queue_net_exit,
+	.id	= &nfnl_queue_net_id,
+	.size	= sizeof(struct nfnl_queue_net),
+};
+
+static int __init nfnetlink_queue_init(void)
+{
+	int status;
+
+	status = register_pernet_subsys(&nfnl_queue_net_ops);
+	if (status < 0) {
+		pr_err("nf_queue: failed to register pernet ops\n");
+		goto out;
+	}
+
+	netlink_register_notifier(&nfqnl_rtnl_notifier);
+	status = nfnetlink_subsys_register(&nfqnl_subsys);
+	if (status < 0) {
+		pr_err("nf_queue: failed to create netlink socket\n");
+		goto cleanup_netlink_notifier;
+	}
+
+	register_netdevice_notifier(&nfqnl_dev_notifier);
+	nf_register_queue_handler(&nfqh);
+	return status;
+
+cleanup_netlink_notifier:
+	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+out:
+	return status;
+}
+
+static void __exit nfnetlink_queue_fini(void)
+{
+	nf_unregister_queue_handler();
+	unregister_netdevice_notifier(&nfqnl_dev_notifier);
+	nfnetlink_subsys_unregister(&nfqnl_subsys);
+	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+	unregister_pernet_subsys(&nfnl_queue_net_ops);
+
+	rcu_barrier(); /* Wait for completion of call_rcu()'s */
+}
+
+MODULE_DESCRIPTION("netfilter packet queue handler");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE);
+
+module_init(nfnetlink_queue_init);
+module_exit(nfnetlink_queue_fini);
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
deleted file mode 100644
index b1f1c74..0000000
--- a/net/netfilter/nfnetlink_queue_core.c
+++ /dev/null
@@ -1,1443 +0,0 @@
-/*
- * This is a module which is used for queueing packets and communicating with
- * userspace via nfnetlink.
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.org>
- * (C) 2007 by Patrick McHardy <kaber@trash.net>
- *
- * Based on the old ipv4-only ip_queue.c:
- * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
- * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/netdevice.h>
-#include <linux/netfilter.h>
-#include <linux/proc_fs.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv6.h>
-#include <linux/netfilter_bridge.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nfnetlink_queue.h>
-#include <linux/netfilter/nf_conntrack_common.h>
-#include <linux/list.h>
-#include <net/sock.h>
-#include <net/tcp_states.h>
-#include <net/netfilter/nf_queue.h>
-#include <net/netns/generic.h>
-
-#include <linux/atomic.h>
-
-#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-#include "../bridge/br_private.h"
-#endif
-
-#define NFQNL_QMAX_DEFAULT 1024
-
-/* We're using struct nlattr which has 16bit nla_len. Note that nla_len
- * includes the header length. Thus, the maximum packet length that we
- * support is 65531 bytes. We send truncated packets if the specified length
- * is larger than that.  Userspace can check for presence of NFQA_CAP_LEN
- * attribute to detect truncation.
- */
-#define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN)
-
-struct nfqnl_instance {
-	struct hlist_node hlist;		/* global list of queues */
-	struct rcu_head rcu;
-
-	u32 peer_portid;
-	unsigned int queue_maxlen;
-	unsigned int copy_range;
-	unsigned int queue_dropped;
-	unsigned int queue_user_dropped;
-
-
-	u_int16_t queue_num;			/* number of this queue */
-	u_int8_t copy_mode;
-	u_int32_t flags;			/* Set using NFQA_CFG_FLAGS */
-/*
- * Following fields are dirtied for each queued packet,
- * keep them in same cache line if possible.
- */
-	spinlock_t	lock;
-	unsigned int	queue_total;
-	unsigned int	id_sequence;		/* 'sequence' of pkt ids */
-	struct list_head queue_list;		/* packets in queue */
-};
-
-typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
-
-static int nfnl_queue_net_id __read_mostly;
-
-#define INSTANCE_BUCKETS	16
-struct nfnl_queue_net {
-	spinlock_t instances_lock;
-	struct hlist_head instance_table[INSTANCE_BUCKETS];
-};
-
-static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net)
-{
-	return net_generic(net, nfnl_queue_net_id);
-}
-
-static inline u_int8_t instance_hashfn(u_int16_t queue_num)
-{
-	return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;
-}
-
-static struct nfqnl_instance *
-instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num)
-{
-	struct hlist_head *head;
-	struct nfqnl_instance *inst;
-
-	head = &q->instance_table[instance_hashfn(queue_num)];
-	hlist_for_each_entry_rcu(inst, head, hlist) {
-		if (inst->queue_num == queue_num)
-			return inst;
-	}
-	return NULL;
-}
-
-static struct nfqnl_instance *
-instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
-{
-	struct nfqnl_instance *inst;
-	unsigned int h;
-	int err;
-
-	spin_lock(&q->instances_lock);
-	if (instance_lookup(q, queue_num)) {
-		err = -EEXIST;
-		goto out_unlock;
-	}
-
-	inst = kzalloc(sizeof(*inst), GFP_ATOMIC);
-	if (!inst) {
-		err = -ENOMEM;
-		goto out_unlock;
-	}
-
-	inst->queue_num = queue_num;
-	inst->peer_portid = portid;
-	inst->queue_maxlen = NFQNL_QMAX_DEFAULT;
-	inst->copy_range = NFQNL_MAX_COPY_RANGE;
-	inst->copy_mode = NFQNL_COPY_NONE;
-	spin_lock_init(&inst->lock);
-	INIT_LIST_HEAD(&inst->queue_list);
-
-	if (!try_module_get(THIS_MODULE)) {
-		err = -EAGAIN;
-		goto out_free;
-	}
-
-	h = instance_hashfn(queue_num);
-	hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]);
-
-	spin_unlock(&q->instances_lock);
-
-	return inst;
-
-out_free:
-	kfree(inst);
-out_unlock:
-	spin_unlock(&q->instances_lock);
-	return ERR_PTR(err);
-}
-
-static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
-			unsigned long data);
-
-static void
-instance_destroy_rcu(struct rcu_head *head)
-{
-	struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance,
-						   rcu);
-
-	nfqnl_flush(inst, NULL, 0);
-	kfree(inst);
-	module_put(THIS_MODULE);
-}
-
-static void
-__instance_destroy(struct nfqnl_instance *inst)
-{
-	hlist_del_rcu(&inst->hlist);
-	call_rcu(&inst->rcu, instance_destroy_rcu);
-}
-
-static void
-instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst)
-{
-	spin_lock(&q->instances_lock);
-	__instance_destroy(inst);
-	spin_unlock(&q->instances_lock);
-}
-
-static inline void
-__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
-{
-       list_add_tail(&entry->list, &queue->queue_list);
-       queue->queue_total++;
-}
-
-static void
-__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
-{
-	list_del(&entry->list);
-	queue->queue_total--;
-}
-
-static struct nf_queue_entry *
-find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
-{
-	struct nf_queue_entry *entry = NULL, *i;
-
-	spin_lock_bh(&queue->lock);
-
-	list_for_each_entry(i, &queue->queue_list, list) {
-		if (i->id == id) {
-			entry = i;
-			break;
-		}
-	}
-
-	if (entry)
-		__dequeue_entry(queue, entry);
-
-	spin_unlock_bh(&queue->lock);
-
-	return entry;
-}
-
-static void
-nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
-{
-	struct nf_queue_entry *entry, *next;
-
-	spin_lock_bh(&queue->lock);
-	list_for_each_entry_safe(entry, next, &queue->queue_list, list) {
-		if (!cmpfn || cmpfn(entry, data)) {
-			list_del(&entry->list);
-			queue->queue_total--;
-			nf_reinject(entry, NF_DROP);
-		}
-	}
-	spin_unlock_bh(&queue->lock);
-}
-
-static int
-nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
-		      bool csum_verify)
-{
-	__u32 flags = 0;
-
-	if (packet->ip_summed == CHECKSUM_PARTIAL)
-		flags = NFQA_SKB_CSUMNOTREADY;
-	else if (csum_verify)
-		flags = NFQA_SKB_CSUM_NOTVERIFIED;
-
-	if (skb_is_gso(packet))
-		flags |= NFQA_SKB_GSO;
-
-	return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0;
-}
-
-static int nfqnl_put_sk_uidgid(struct sk_buff *skb, struct sock *sk)
-{
-	const struct cred *cred;
-
-	if (!sk_fullsock(sk))
-		return 0;
-
-	read_lock_bh(&sk->sk_callback_lock);
-	if (sk->sk_socket && sk->sk_socket->file) {
-		cred = sk->sk_socket->file->f_cred;
-		if (nla_put_be32(skb, NFQA_UID,
-		    htonl(from_kuid_munged(&init_user_ns, cred->fsuid))))
-			goto nla_put_failure;
-		if (nla_put_be32(skb, NFQA_GID,
-		    htonl(from_kgid_munged(&init_user_ns, cred->fsgid))))
-			goto nla_put_failure;
-	}
-	read_unlock_bh(&sk->sk_callback_lock);
-	return 0;
-
-nla_put_failure:
-	read_unlock_bh(&sk->sk_callback_lock);
-	return -1;
-}
-
-static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
-{
-	u32 seclen = 0;
-#if IS_ENABLED(CONFIG_NETWORK_SECMARK)
-	if (!skb || !sk_fullsock(skb->sk))
-		return 0;
-
-	read_lock_bh(&skb->sk->sk_callback_lock);
-
-	if (skb->secmark)
-		security_secid_to_secctx(skb->secmark, secdata, &seclen);
-
-	read_unlock_bh(&skb->sk->sk_callback_lock);
-#endif
-	return seclen;
-}
-
-static struct sk_buff *
-nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
-			   struct nf_queue_entry *entry,
-			   __be32 **packet_id_ptr)
-{
-	size_t size;
-	size_t data_len = 0, cap_len = 0, rem_len = 0;
-	unsigned int hlen = 0;
-	struct sk_buff *skb;
-	struct nlattr *nla;
-	struct nfqnl_msg_packet_hdr *pmsg;
-	struct nlmsghdr *nlh;
-	struct nfgenmsg *nfmsg;
-	struct sk_buff *entskb = entry->skb;
-	struct net_device *indev;
-	struct net_device *outdev;
-	struct nf_conn *ct = NULL;
-	enum ip_conntrack_info uninitialized_var(ctinfo);
-	struct nfq_ct_hook *nfq_ct;
-	bool csum_verify;
-	char *secdata = NULL;
-	u32 seclen = 0;
-
-	size =    nlmsg_total_size(sizeof(struct nfgenmsg))
-		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr))
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-		+ nla_total_size(sizeof(u_int32_t))	/* ifindex */
-#endif
-		+ nla_total_size(sizeof(u_int32_t))	/* mark */
-		+ nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
-		+ nla_total_size(sizeof(u_int32_t))	/* skbinfo */
-		+ nla_total_size(sizeof(u_int32_t));	/* cap_len */
-
-	if (entskb->tstamp.tv64)
-		size += nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp));
-
-	if (entry->state.hook <= NF_INET_FORWARD ||
-	   (entry->state.hook == NF_INET_POST_ROUTING && entskb->sk == NULL))
-		csum_verify = !skb_csum_unnecessary(entskb);
-	else
-		csum_verify = false;
-
-	outdev = entry->state.out;
-
-	switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) {
-	case NFQNL_COPY_META:
-	case NFQNL_COPY_NONE:
-		break;
-
-	case NFQNL_COPY_PACKET:
-		if (!(queue->flags & NFQA_CFG_F_GSO) &&
-		    entskb->ip_summed == CHECKSUM_PARTIAL &&
-		    skb_checksum_help(entskb))
-			return NULL;
-
-		data_len = ACCESS_ONCE(queue->copy_range);
-		if (data_len > entskb->len)
-			data_len = entskb->len;
-
-		hlen = skb_zerocopy_headlen(entskb);
-		hlen = min_t(unsigned int, hlen, data_len);
-		size += sizeof(struct nlattr) + hlen;
-		cap_len = entskb->len;
-		rem_len = data_len - hlen;
-		break;
-	}
-
-	if (queue->flags & NFQA_CFG_F_CONNTRACK) {
-		nfq_ct = rcu_dereference(nfq_ct_hook);
-		if (nfq_ct != NULL) {
-			ct = nfq_ct->get_ct(entskb, &ctinfo);
-			if (ct != NULL)
-				size += nfq_ct->build_size(ct);
-		}
-	}
-
-	if (queue->flags & NFQA_CFG_F_UID_GID) {
-		size +=  (nla_total_size(sizeof(u_int32_t))	/* uid */
-			+ nla_total_size(sizeof(u_int32_t)));	/* gid */
-	}
-
-	if ((queue->flags & NFQA_CFG_F_SECCTX) && entskb->sk) {
-		seclen = nfqnl_get_sk_secctx(entskb, &secdata);
-		if (seclen)
-			size += nla_total_size(seclen);
-	}
-
-	skb = __netlink_alloc_skb(net->nfnl, size, rem_len, queue->peer_portid,
-				  GFP_ATOMIC);
-	if (!skb) {
-		skb_tx_error(entskb);
-		return NULL;
-	}
-
-	nlh = nlmsg_put(skb, 0, 0,
-			NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
-			sizeof(struct nfgenmsg), 0);
-	if (!nlh) {
-		skb_tx_error(entskb);
-		kfree_skb(skb);
-		return NULL;
-	}
-	nfmsg = nlmsg_data(nlh);
-	nfmsg->nfgen_family = entry->state.pf;
-	nfmsg->version = NFNETLINK_V0;
-	nfmsg->res_id = htons(queue->queue_num);
-
-	nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg));
-	pmsg = nla_data(nla);
-	pmsg->hw_protocol	= entskb->protocol;
-	pmsg->hook		= entry->state.hook;
-	*packet_id_ptr		= &pmsg->packet_id;
-
-	indev = entry->state.in;
-	if (indev) {
-#if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-		if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex)))
-			goto nla_put_failure;
-#else
-		if (entry->state.pf == PF_BRIDGE) {
-			/* Case 1: indev is physical input device, we need to
-			 * look for bridge group (when called from
-			 * netfilter_bridge) */
-			if (nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
-					 htonl(indev->ifindex)) ||
-			/* this is the bridge group "brX" */
-			/* rcu_read_lock()ed by __nf_queue */
-			    nla_put_be32(skb, NFQA_IFINDEX_INDEV,
-					 htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
-				goto nla_put_failure;
-		} else {
-			int physinif;
-
-			/* Case 2: indev is bridge group, we need to look for
-			 * physical device (when called from ipv4) */
-			if (nla_put_be32(skb, NFQA_IFINDEX_INDEV,
-					 htonl(indev->ifindex)))
-				goto nla_put_failure;
-
-			physinif = nf_bridge_get_physinif(entskb);
-			if (physinif &&
-			    nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
-					 htonl(physinif)))
-				goto nla_put_failure;
-		}
-#endif
-	}
-
-	if (outdev) {
-#if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-		if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex)))
-			goto nla_put_failure;
-#else
-		if (entry->state.pf == PF_BRIDGE) {
-			/* Case 1: outdev is physical output device, we need to
-			 * look for bridge group (when called from
-			 * netfilter_bridge) */
-			if (nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
-					 htonl(outdev->ifindex)) ||
-			/* this is the bridge group "brX" */
-			/* rcu_read_lock()ed by __nf_queue */
-			    nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
-					 htonl(br_port_get_rcu(outdev)->br->dev->ifindex)))
-				goto nla_put_failure;
-		} else {
-			int physoutif;
-
-			/* Case 2: outdev is bridge group, we need to look for
-			 * physical output device (when called from ipv4) */
-			if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
-					 htonl(outdev->ifindex)))
-				goto nla_put_failure;
-
-			physoutif = nf_bridge_get_physoutif(entskb);
-			if (physoutif &&
-			    nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
-					 htonl(physoutif)))
-				goto nla_put_failure;
-		}
-#endif
-	}
-
-	if (entskb->mark &&
-	    nla_put_be32(skb, NFQA_MARK, htonl(entskb->mark)))
-		goto nla_put_failure;
-
-	if (indev && entskb->dev &&
-	    entskb->mac_header != entskb->network_header) {
-		struct nfqnl_msg_packet_hw phw;
-		int len;
-
-		memset(&phw, 0, sizeof(phw));
-		len = dev_parse_header(entskb, phw.hw_addr);
-		if (len) {
-			phw.hw_addrlen = htons(len);
-			if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw))
-				goto nla_put_failure;
-		}
-	}
-
-	if (entskb->tstamp.tv64) {
-		struct nfqnl_msg_packet_timestamp ts;
-		struct timeval tv = ktime_to_timeval(entskb->tstamp);
-		ts.sec = cpu_to_be64(tv.tv_sec);
-		ts.usec = cpu_to_be64(tv.tv_usec);
-
-		if (nla_put(skb, NFQA_TIMESTAMP, sizeof(ts), &ts))
-			goto nla_put_failure;
-	}
-
-	if ((queue->flags & NFQA_CFG_F_UID_GID) && entskb->sk &&
-	    nfqnl_put_sk_uidgid(skb, entskb->sk) < 0)
-		goto nla_put_failure;
-
-	if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata))
-		goto nla_put_failure;
-
-	if (ct && nfq_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
-		goto nla_put_failure;
-
-	if (cap_len > data_len &&
-	    nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
-		goto nla_put_failure;
-
-	if (nfqnl_put_packet_info(skb, entskb, csum_verify))
-		goto nla_put_failure;
-
-	if (data_len) {
-		struct nlattr *nla;
-
-		if (skb_tailroom(skb) < sizeof(*nla) + hlen)
-			goto nla_put_failure;
-
-		nla = (struct nlattr *)skb_put(skb, sizeof(*nla));
-		nla->nla_type = NFQA_PAYLOAD;
-		nla->nla_len = nla_attr_size(data_len);
-
-		if (skb_zerocopy(skb, entskb, data_len, hlen))
-			goto nla_put_failure;
-	}
-
-	nlh->nlmsg_len = skb->len;
-	return skb;
-
-nla_put_failure:
-	skb_tx_error(entskb);
-	kfree_skb(skb);
-	net_err_ratelimited("nf_queue: error creating packet message\n");
-	return NULL;
-}
-
-static int
-__nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
-			struct nf_queue_entry *entry)
-{
-	struct sk_buff *nskb;
-	int err = -ENOBUFS;
-	__be32 *packet_id_ptr;
-	int failopen = 0;
-
-	nskb = nfqnl_build_packet_message(net, queue, entry, &packet_id_ptr);
-	if (nskb == NULL) {
-		err = -ENOMEM;
-		goto err_out;
-	}
-	spin_lock_bh(&queue->lock);
-
-	if (queue->queue_total >= queue->queue_maxlen) {
-		if (queue->flags & NFQA_CFG_F_FAIL_OPEN) {
-			failopen = 1;
-			err = 0;
-		} else {
-			queue->queue_dropped++;
-			net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n",
-					     queue->queue_total);
-		}
-		goto err_out_free_nskb;
-	}
-	entry->id = ++queue->id_sequence;
-	*packet_id_ptr = htonl(entry->id);
-
-	/* nfnetlink_unicast will either free the nskb or add it to a socket */
-	err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT);
-	if (err < 0) {
-		queue->queue_user_dropped++;
-		goto err_out_unlock;
-	}
-
-	__enqueue_entry(queue, entry);
-
-	spin_unlock_bh(&queue->lock);
-	return 0;
-
-err_out_free_nskb:
-	kfree_skb(nskb);
-err_out_unlock:
-	spin_unlock_bh(&queue->lock);
-	if (failopen)
-		nf_reinject(entry, NF_ACCEPT);
-err_out:
-	return err;
-}
-
-static struct nf_queue_entry *
-nf_queue_entry_dup(struct nf_queue_entry *e)
-{
-	struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
-	if (entry) {
-		if (nf_queue_entry_get_refs(entry))
-			return entry;
-		kfree(entry);
-	}
-	return NULL;
-}
-
-#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-/* When called from bridge netfilter, skb->data must point to MAC header
- * before calling skb_gso_segment(). Else, original MAC header is lost
- * and segmented skbs will be sent to wrong destination.
- */
-static void nf_bridge_adjust_skb_data(struct sk_buff *skb)
-{
-	if (skb->nf_bridge)
-		__skb_push(skb, skb->network_header - skb->mac_header);
-}
-
-static void nf_bridge_adjust_segmented_data(struct sk_buff *skb)
-{
-	if (skb->nf_bridge)
-		__skb_pull(skb, skb->network_header - skb->mac_header);
-}
-#else
-#define nf_bridge_adjust_skb_data(s) do {} while (0)
-#define nf_bridge_adjust_segmented_data(s) do {} while (0)
-#endif
-
-static void free_entry(struct nf_queue_entry *entry)
-{
-	nf_queue_entry_release_refs(entry);
-	kfree(entry);
-}
-
-static int
-__nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue,
-			   struct sk_buff *skb, struct nf_queue_entry *entry)
-{
-	int ret = -ENOMEM;
-	struct nf_queue_entry *entry_seg;
-
-	nf_bridge_adjust_segmented_data(skb);
-
-	if (skb->next == NULL) { /* last packet, no need to copy entry */
-		struct sk_buff *gso_skb = entry->skb;
-		entry->skb = skb;
-		ret = __nfqnl_enqueue_packet(net, queue, entry);
-		if (ret)
-			entry->skb = gso_skb;
-		return ret;
-	}
-
-	skb->next = NULL;
-
-	entry_seg = nf_queue_entry_dup(entry);
-	if (entry_seg) {
-		entry_seg->skb = skb;
-		ret = __nfqnl_enqueue_packet(net, queue, entry_seg);
-		if (ret)
-			free_entry(entry_seg);
-	}
-	return ret;
-}
-
-static int
-nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
-{
-	unsigned int queued;
-	struct nfqnl_instance *queue;
-	struct sk_buff *skb, *segs;
-	int err = -ENOBUFS;
-	struct net *net = entry->state.net;
-	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
-
-	/* rcu_read_lock()ed by nf_hook_slow() */
-	queue = instance_lookup(q, queuenum);
-	if (!queue)
-		return -ESRCH;
-
-	if (queue->copy_mode == NFQNL_COPY_NONE)
-		return -EINVAL;
-
-	skb = entry->skb;
-
-	switch (entry->state.pf) {
-	case NFPROTO_IPV4:
-		skb->protocol = htons(ETH_P_IP);
-		break;
-	case NFPROTO_IPV6:
-		skb->protocol = htons(ETH_P_IPV6);
-		break;
-	}
-
-	if ((queue->flags & NFQA_CFG_F_GSO) || !skb_is_gso(skb))
-		return __nfqnl_enqueue_packet(net, queue, entry);
-
-	nf_bridge_adjust_skb_data(skb);
-	segs = skb_gso_segment(skb, 0);
-	/* Does not use PTR_ERR to limit the number of error codes that can be
-	 * returned by nf_queue.  For instance, callers rely on -ECANCELED to
-	 * mean 'ignore this hook'.
-	 */
-	if (IS_ERR_OR_NULL(segs))
-		goto out_err;
-	queued = 0;
-	err = 0;
-	do {
-		struct sk_buff *nskb = segs->next;
-		if (err == 0)
-			err = __nfqnl_enqueue_packet_gso(net, queue,
-							segs, entry);
-		if (err == 0)
-			queued++;
-		else
-			kfree_skb(segs);
-		segs = nskb;
-	} while (segs);
-
-	if (queued) {
-		if (err) /* some segments are already queued */
-			free_entry(entry);
-		kfree_skb(skb);
-		return 0;
-	}
- out_err:
-	nf_bridge_adjust_segmented_data(skb);
-	return err;
-}
-
-static int
-nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
-{
-	struct sk_buff *nskb;
-
-	if (diff < 0) {
-		if (pskb_trim(e->skb, data_len))
-			return -ENOMEM;
-	} else if (diff > 0) {
-		if (data_len > 0xFFFF)
-			return -EINVAL;
-		if (diff > skb_tailroom(e->skb)) {
-			nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
-					       diff, GFP_ATOMIC);
-			if (!nskb) {
-				printk(KERN_WARNING "nf_queue: OOM "
-				      "in mangle, dropping packet\n");
-				return -ENOMEM;
-			}
-			kfree_skb(e->skb);
-			e->skb = nskb;
-		}
-		skb_put(e->skb, diff);
-	}
-	if (!skb_make_writable(e->skb, data_len))
-		return -ENOMEM;
-	skb_copy_to_linear_data(e->skb, data, data_len);
-	e->skb->ip_summed = CHECKSUM_NONE;
-	return 0;
-}
-
-static int
-nfqnl_set_mode(struct nfqnl_instance *queue,
-	       unsigned char mode, unsigned int range)
-{
-	int status = 0;
-
-	spin_lock_bh(&queue->lock);
-	switch (mode) {
-	case NFQNL_COPY_NONE:
-	case NFQNL_COPY_META:
-		queue->copy_mode = mode;
-		queue->copy_range = 0;
-		break;
-
-	case NFQNL_COPY_PACKET:
-		queue->copy_mode = mode;
-		if (range == 0 || range > NFQNL_MAX_COPY_RANGE)
-			queue->copy_range = NFQNL_MAX_COPY_RANGE;
-		else
-			queue->copy_range = range;
-		break;
-
-	default:
-		status = -EINVAL;
-
-	}
-	spin_unlock_bh(&queue->lock);
-
-	return status;
-}
-
-static int
-dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
-{
-	if (entry->state.in)
-		if (entry->state.in->ifindex == ifindex)
-			return 1;
-	if (entry->state.out)
-		if (entry->state.out->ifindex == ifindex)
-			return 1;
-#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-	if (entry->skb->nf_bridge) {
-		int physinif, physoutif;
-
-		physinif = nf_bridge_get_physinif(entry->skb);
-		physoutif = nf_bridge_get_physoutif(entry->skb);
-
-		if (physinif == ifindex || physoutif == ifindex)
-			return 1;
-	}
-#endif
-	return 0;
-}
-
-/* drop all packets with either indev or outdev == ifindex from all queue
- * instances */
-static void
-nfqnl_dev_drop(struct net *net, int ifindex)
-{
-	int i;
-	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
-
-	rcu_read_lock();
-
-	for (i = 0; i < INSTANCE_BUCKETS; i++) {
-		struct nfqnl_instance *inst;
-		struct hlist_head *head = &q->instance_table[i];
-
-		hlist_for_each_entry_rcu(inst, head, hlist)
-			nfqnl_flush(inst, dev_cmp, ifindex);
-	}
-
-	rcu_read_unlock();
-}
-
-static int
-nfqnl_rcv_dev_event(struct notifier_block *this,
-		    unsigned long event, void *ptr)
-{
-	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
-	/* Drop any packets associated with the downed device */
-	if (event == NETDEV_DOWN)
-		nfqnl_dev_drop(dev_net(dev), dev->ifindex);
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block nfqnl_dev_notifier = {
-	.notifier_call	= nfqnl_rcv_dev_event,
-};
-
-static int nf_hook_cmp(struct nf_queue_entry *entry, unsigned long ops_ptr)
-{
-	return entry->elem == (struct nf_hook_ops *)ops_ptr;
-}
-
-static void nfqnl_nf_hook_drop(struct net *net, struct nf_hook_ops *hook)
-{
-	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
-	int i;
-
-	rcu_read_lock();
-	for (i = 0; i < INSTANCE_BUCKETS; i++) {
-		struct nfqnl_instance *inst;
-		struct hlist_head *head = &q->instance_table[i];
-
-		hlist_for_each_entry_rcu(inst, head, hlist)
-			nfqnl_flush(inst, nf_hook_cmp, (unsigned long)hook);
-	}
-	rcu_read_unlock();
-}
-
-static int
-nfqnl_rcv_nl_event(struct notifier_block *this,
-		   unsigned long event, void *ptr)
-{
-	struct netlink_notify *n = ptr;
-	struct nfnl_queue_net *q = nfnl_queue_pernet(n->net);
-
-	if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
-		int i;
-
-		/* destroy all instances for this portid */
-		spin_lock(&q->instances_lock);
-		for (i = 0; i < INSTANCE_BUCKETS; i++) {
-			struct hlist_node *t2;
-			struct nfqnl_instance *inst;
-			struct hlist_head *head = &q->instance_table[i];
-
-			hlist_for_each_entry_safe(inst, t2, head, hlist) {
-				if (n->portid == inst->peer_portid)
-					__instance_destroy(inst);
-			}
-		}
-		spin_unlock(&q->instances_lock);
-	}
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block nfqnl_rtnl_notifier = {
-	.notifier_call	= nfqnl_rcv_nl_event,
-};
-
-static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
-	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
-	[NFQA_MARK]		= { .type = NLA_U32 },
-	[NFQA_PAYLOAD]		= { .type = NLA_UNSPEC },
-	[NFQA_CT]		= { .type = NLA_UNSPEC },
-	[NFQA_EXP]		= { .type = NLA_UNSPEC },
-};
-
-static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
-	[NFQA_VERDICT_HDR]	= { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
-	[NFQA_MARK]		= { .type = NLA_U32 },
-};
-
-static struct nfqnl_instance *
-verdict_instance_lookup(struct nfnl_queue_net *q, u16 queue_num, u32 nlportid)
-{
-	struct nfqnl_instance *queue;
-
-	queue = instance_lookup(q, queue_num);
-	if (!queue)
-		return ERR_PTR(-ENODEV);
-
-	if (queue->peer_portid != nlportid)
-		return ERR_PTR(-EPERM);
-
-	return queue;
-}
-
-static struct nfqnl_msg_verdict_hdr*
-verdicthdr_get(const struct nlattr * const nfqa[])
-{
-	struct nfqnl_msg_verdict_hdr *vhdr;
-	unsigned int verdict;
-
-	if (!nfqa[NFQA_VERDICT_HDR])
-		return NULL;
-
-	vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
-	verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK;
-	if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN)
-		return NULL;
-	return vhdr;
-}
-
-static int nfq_id_after(unsigned int id, unsigned int max)
-{
-	return (int)(id - max) > 0;
-}
-
-static int
-nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
-		   const struct nlmsghdr *nlh,
-		   const struct nlattr * const nfqa[])
-{
-	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-	struct nf_queue_entry *entry, *tmp;
-	unsigned int verdict, maxid;
-	struct nfqnl_msg_verdict_hdr *vhdr;
-	struct nfqnl_instance *queue;
-	LIST_HEAD(batch_list);
-	u16 queue_num = ntohs(nfmsg->res_id);
-
-	struct net *net = sock_net(ctnl);
-	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
-
-	queue = verdict_instance_lookup(q, queue_num,
-					NETLINK_CB(skb).portid);
-	if (IS_ERR(queue))
-		return PTR_ERR(queue);
-
-	vhdr = verdicthdr_get(nfqa);
-	if (!vhdr)
-		return -EINVAL;
-
-	verdict = ntohl(vhdr->verdict);
-	maxid = ntohl(vhdr->id);
-
-	spin_lock_bh(&queue->lock);
-
-	list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) {
-		if (nfq_id_after(entry->id, maxid))
-			break;
-		__dequeue_entry(queue, entry);
-		list_add_tail(&entry->list, &batch_list);
-	}
-
-	spin_unlock_bh(&queue->lock);
-
-	if (list_empty(&batch_list))
-		return -ENOENT;
-
-	list_for_each_entry_safe(entry, tmp, &batch_list, list) {
-		if (nfqa[NFQA_MARK])
-			entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
-		nf_reinject(entry, verdict);
-	}
-	return 0;
-}
-
-static struct nf_conn *nfqnl_ct_parse(struct nfq_ct_hook *nfq_ct,
-				      const struct nlmsghdr *nlh,
-				      const struct nlattr * const nfqa[],
-				      struct nf_queue_entry *entry,
-				      enum ip_conntrack_info *ctinfo)
-{
-	struct nf_conn *ct;
-
-	ct = nfq_ct->get_ct(entry->skb, ctinfo);
-	if (ct == NULL)
-		return NULL;
-
-	if (nfq_ct->parse(nfqa[NFQA_CT], ct) < 0)
-		return NULL;
-
-	if (nfqa[NFQA_EXP])
-		nfq_ct->attach_expect(nfqa[NFQA_EXP], ct,
-				      NETLINK_CB(entry->skb).portid,
-				      nlmsg_report(nlh));
-	return ct;
-}
-
-static int
-nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
-		   const struct nlmsghdr *nlh,
-		   const struct nlattr * const nfqa[])
-{
-	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-	u_int16_t queue_num = ntohs(nfmsg->res_id);
-
-	struct nfqnl_msg_verdict_hdr *vhdr;
-	struct nfqnl_instance *queue;
-	unsigned int verdict;
-	struct nf_queue_entry *entry;
-	enum ip_conntrack_info uninitialized_var(ctinfo);
-	struct nfq_ct_hook *nfq_ct;
-	struct nf_conn *ct = NULL;
-
-	struct net *net = sock_net(ctnl);
-	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
-
-	queue = instance_lookup(q, queue_num);
-	if (!queue)
-		queue = verdict_instance_lookup(q, queue_num,
-						NETLINK_CB(skb).portid);
-	if (IS_ERR(queue))
-		return PTR_ERR(queue);
-
-	vhdr = verdicthdr_get(nfqa);
-	if (!vhdr)
-		return -EINVAL;
-
-	verdict = ntohl(vhdr->verdict);
-
-	entry = find_dequeue_entry(queue, ntohl(vhdr->id));
-	if (entry == NULL)
-		return -ENOENT;
-
-	if (nfqa[NFQA_CT]) {
-		/* rcu lock already held from nfnl->call_rcu. */
-		nfq_ct = rcu_dereference(nfq_ct_hook);
-		if (nfq_ct != NULL)
-			ct = nfqnl_ct_parse(nfq_ct, nlh, nfqa, entry, &ctinfo);
-	}
-
-	if (nfqa[NFQA_PAYLOAD]) {
-		u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]);
-		int diff = payload_len - entry->skb->len;
-
-		if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
-				 payload_len, entry, diff) < 0)
-			verdict = NF_DROP;
-
-		if (ct && diff)
-			nfq_ct->seq_adjust(entry->skb, ct, ctinfo, diff);
-	}
-
-	if (nfqa[NFQA_MARK])
-		entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
-
-	nf_reinject(entry, verdict);
-	return 0;
-}
-
-static int
-nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
-		  const struct nlmsghdr *nlh,
-		  const struct nlattr * const nfqa[])
-{
-	return -ENOTSUPP;
-}
-
-static const struct nla_policy nfqa_cfg_policy[NFQA_CFG_MAX+1] = {
-	[NFQA_CFG_CMD]		= { .len = sizeof(struct nfqnl_msg_config_cmd) },
-	[NFQA_CFG_PARAMS]	= { .len = sizeof(struct nfqnl_msg_config_params) },
-};
-
-static const struct nf_queue_handler nfqh = {
-	.outfn		= &nfqnl_enqueue_packet,
-	.nf_hook_drop	= &nfqnl_nf_hook_drop,
-};
-
-static int
-nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
-		  const struct nlmsghdr *nlh,
-		  const struct nlattr * const nfqa[])
-{
-	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-	u_int16_t queue_num = ntohs(nfmsg->res_id);
-	struct nfqnl_instance *queue;
-	struct nfqnl_msg_config_cmd *cmd = NULL;
-	struct net *net = sock_net(ctnl);
-	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
-	int ret = 0;
-
-	if (nfqa[NFQA_CFG_CMD]) {
-		cmd = nla_data(nfqa[NFQA_CFG_CMD]);
-
-		/* Obsolete commands without queue context */
-		switch (cmd->command) {
-		case NFQNL_CFG_CMD_PF_BIND: return 0;
-		case NFQNL_CFG_CMD_PF_UNBIND: return 0;
-		}
-	}
-
-	rcu_read_lock();
-	queue = instance_lookup(q, queue_num);
-	if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
-		ret = -EPERM;
-		goto err_out_unlock;
-	}
-
-	if (cmd != NULL) {
-		switch (cmd->command) {
-		case NFQNL_CFG_CMD_BIND:
-			if (queue) {
-				ret = -EBUSY;
-				goto err_out_unlock;
-			}
-			queue = instance_create(q, queue_num,
-						NETLINK_CB(skb).portid);
-			if (IS_ERR(queue)) {
-				ret = PTR_ERR(queue);
-				goto err_out_unlock;
-			}
-			break;
-		case NFQNL_CFG_CMD_UNBIND:
-			if (!queue) {
-				ret = -ENODEV;
-				goto err_out_unlock;
-			}
-			instance_destroy(q, queue);
-			break;
-		case NFQNL_CFG_CMD_PF_BIND:
-		case NFQNL_CFG_CMD_PF_UNBIND:
-			break;
-		default:
-			ret = -ENOTSUPP;
-			break;
-		}
-	}
-
-	if (nfqa[NFQA_CFG_PARAMS]) {
-		struct nfqnl_msg_config_params *params;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		params = nla_data(nfqa[NFQA_CFG_PARAMS]);
-		nfqnl_set_mode(queue, params->copy_mode,
-				ntohl(params->copy_range));
-	}
-
-	if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
-		__be32 *queue_maxlen;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
-		spin_lock_bh(&queue->lock);
-		queue->queue_maxlen = ntohl(*queue_maxlen);
-		spin_unlock_bh(&queue->lock);
-	}
-
-	if (nfqa[NFQA_CFG_FLAGS]) {
-		__u32 flags, mask;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-
-		if (!nfqa[NFQA_CFG_MASK]) {
-			/* A mask is needed to specify which flags are being
-			 * changed.
-			 */
-			ret = -EINVAL;
-			goto err_out_unlock;
-		}
-
-		flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
-		mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
-
-		if (flags >= NFQA_CFG_F_MAX) {
-			ret = -EOPNOTSUPP;
-			goto err_out_unlock;
-		}
-#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
-		if (flags & mask & NFQA_CFG_F_SECCTX) {
-			ret = -EOPNOTSUPP;
-			goto err_out_unlock;
-		}
-#endif
-		spin_lock_bh(&queue->lock);
-		queue->flags &= ~mask;
-		queue->flags |= flags & mask;
-		spin_unlock_bh(&queue->lock);
-	}
-
-err_out_unlock:
-	rcu_read_unlock();
-	return ret;
-}
-
-static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
-	[NFQNL_MSG_PACKET]	= { .call_rcu = nfqnl_recv_unsupp,
-				    .attr_count = NFQA_MAX, },
-	[NFQNL_MSG_VERDICT]	= { .call_rcu = nfqnl_recv_verdict,
-				    .attr_count = NFQA_MAX,
-				    .policy = nfqa_verdict_policy },
-	[NFQNL_MSG_CONFIG]	= { .call = nfqnl_recv_config,
-				    .attr_count = NFQA_CFG_MAX,
-				    .policy = nfqa_cfg_policy },
-	[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
-				    .attr_count = NFQA_MAX,
-				    .policy = nfqa_verdict_batch_policy },
-};
-
-static const struct nfnetlink_subsystem nfqnl_subsys = {
-	.name		= "nf_queue",
-	.subsys_id	= NFNL_SUBSYS_QUEUE,
-	.cb_count	= NFQNL_MSG_MAX,
-	.cb		= nfqnl_cb,
-};
-
-#ifdef CONFIG_PROC_FS
-struct iter_state {
-	struct seq_net_private p;
-	unsigned int bucket;
-};
-
-static struct hlist_node *get_first(struct seq_file *seq)
-{
-	struct iter_state *st = seq->private;
-	struct net *net;
-	struct nfnl_queue_net *q;
-
-	if (!st)
-		return NULL;
-
-	net = seq_file_net(seq);
-	q = nfnl_queue_pernet(net);
-	for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
-		if (!hlist_empty(&q->instance_table[st->bucket]))
-			return q->instance_table[st->bucket].first;
-	}
-	return NULL;
-}
-
-static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
-{
-	struct iter_state *st = seq->private;
-	struct net *net = seq_file_net(seq);
-
-	h = h->next;
-	while (!h) {
-		struct nfnl_queue_net *q;
-
-		if (++st->bucket >= INSTANCE_BUCKETS)
-			return NULL;
-
-		q = nfnl_queue_pernet(net);
-		h = q->instance_table[st->bucket].first;
-	}
-	return h;
-}
-
-static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
-{
-	struct hlist_node *head;
-	head = get_first(seq);
-
-	if (head)
-		while (pos && (head = get_next(seq, head)))
-			pos--;
-	return pos ? NULL : head;
-}
-
-static void *seq_start(struct seq_file *s, loff_t *pos)
-	__acquires(nfnl_queue_pernet(seq_file_net(s))->instances_lock)
-{
-	spin_lock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock);
-	return get_idx(s, *pos);
-}
-
-static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
-{
-	(*pos)++;
-	return get_next(s, v);
-}
-
-static void seq_stop(struct seq_file *s, void *v)
-	__releases(nfnl_queue_pernet(seq_file_net(s))->instances_lock)
-{
-	spin_unlock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock);
-}
-
-static int seq_show(struct seq_file *s, void *v)
-{
-	const struct nfqnl_instance *inst = v;
-
-	seq_printf(s, "%5u %6u %5u %1u %5u %5u %5u %8u %2d\n",
-		   inst->queue_num,
-		   inst->peer_portid, inst->queue_total,
-		   inst->copy_mode, inst->copy_range,
-		   inst->queue_dropped, inst->queue_user_dropped,
-		   inst->id_sequence, 1);
-	return 0;
-}
-
-static const struct seq_operations nfqnl_seq_ops = {
-	.start	= seq_start,
-	.next	= seq_next,
-	.stop	= seq_stop,
-	.show	= seq_show,
-};
-
-static int nfqnl_open(struct inode *inode, struct file *file)
-{
-	return seq_open_net(inode, file, &nfqnl_seq_ops,
-			sizeof(struct iter_state));
-}
-
-static const struct file_operations nfqnl_file_ops = {
-	.owner	 = THIS_MODULE,
-	.open	 = nfqnl_open,
-	.read	 = seq_read,
-	.llseek	 = seq_lseek,
-	.release = seq_release_net,
-};
-
-#endif /* PROC_FS */
-
-static int __net_init nfnl_queue_net_init(struct net *net)
-{
-	unsigned int i;
-	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
-
-	for (i = 0; i < INSTANCE_BUCKETS; i++)
-		INIT_HLIST_HEAD(&q->instance_table[i]);
-
-	spin_lock_init(&q->instances_lock);
-
-#ifdef CONFIG_PROC_FS
-	if (!proc_create("nfnetlink_queue", 0440,
-			 net->nf.proc_netfilter, &nfqnl_file_ops))
-		return -ENOMEM;
-#endif
-	return 0;
-}
-
-static void __net_exit nfnl_queue_net_exit(struct net *net)
-{
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
-#endif
-}
-
-static struct pernet_operations nfnl_queue_net_ops = {
-	.init	= nfnl_queue_net_init,
-	.exit	= nfnl_queue_net_exit,
-	.id	= &nfnl_queue_net_id,
-	.size	= sizeof(struct nfnl_queue_net),
-};
-
-static int __init nfnetlink_queue_init(void)
-{
-	int status;
-
-	status = register_pernet_subsys(&nfnl_queue_net_ops);
-	if (status < 0) {
-		pr_err("nf_queue: failed to register pernet ops\n");
-		goto out;
-	}
-
-	netlink_register_notifier(&nfqnl_rtnl_notifier);
-	status = nfnetlink_subsys_register(&nfqnl_subsys);
-	if (status < 0) {
-		pr_err("nf_queue: failed to create netlink socket\n");
-		goto cleanup_netlink_notifier;
-	}
-
-	register_netdevice_notifier(&nfqnl_dev_notifier);
-	nf_register_queue_handler(&nfqh);
-	return status;
-
-cleanup_netlink_notifier:
-	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
-out:
-	return status;
-}
-
-static void __exit nfnetlink_queue_fini(void)
-{
-	nf_unregister_queue_handler();
-	unregister_netdevice_notifier(&nfqnl_dev_notifier);
-	nfnetlink_subsys_unregister(&nfqnl_subsys);
-	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
-	unregister_pernet_subsys(&nfnl_queue_net_ops);
-
-	rcu_barrier(); /* Wait for completion of call_rcu()'s */
-}
-
-MODULE_DESCRIPTION("netfilter packet queue handler");
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE);
-
-module_init(nfnetlink_queue_init);
-module_exit(nfnetlink_queue_fini);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information
  2015-10-01 18:43 ` [PATCH 2/2 v3] netfilter: rename nfnetlink_queue_core.c to nfnetlink_queue.c Pablo Neira Ayuso
@ 2015-10-05  2:44   ` Ken-ichirou MATSUZAWA
  2015-10-05  2:47     ` [PATCHv2 nf-next 1/4] netfilter: nfnetlink_queue: rename related to nfqueue attaching conntrack info Ken-ichirou MATSUZAWA
                       ` (4 more replies)
  0 siblings, 5 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-05  2:44 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

 Hi Pablo,

I rebased on top of your patches, would you review these?

You suggested it might be better to divide ct attaching Kconfig to
each of nfqueue and nflog, but I think it makes less sense now
because of your rework. is it right?

Thanks,

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCHv2 nf-next 1/4] netfilter: nfnetlink_queue: rename related to nfqueue attaching conntrack info
  2015-10-05  2:44   ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Ken-ichirou MATSUZAWA
@ 2015-10-05  2:47     ` Ken-ichirou MATSUZAWA
  2015-10-05  2:48     ` [PATCHv2 nf-next 2/4] netfilter: Kconfig rename QUEUE_CT to GLUE_CT Ken-ichirou MATSUZAWA
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-05  2:47 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

The idea of this series of patch is to attach conntrack information to
nflog like nfqueue has already done. nfqueue conntrack info attaching
basis is generic, rename those names to generic one, glue.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 include/linux/netfilter.h            |    4 +--
 net/netfilter/core.c                 |    4 +--
 net/netfilter/nf_conntrack_netlink.c |   60 +++++++++++++++++-----------------
 net/netfilter/nfnetlink_queue.c      |   30 ++++++++---------
 4 files changed, 49 insertions(+), 49 deletions(-)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 3e5e8f2..27747de 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -377,7 +377,7 @@ struct nf_conn;
 enum ip_conntrack_info;
 struct nlattr;
 
-struct nfq_ct_hook {
+struct nfnl_ct_hook {
 	struct nf_conn *(*get_ct)(struct sk_buff *skb,
 				  enum ip_conntrack_info *ctinfo);
 	size_t (*build_size)(const struct nf_conn *ct);
@@ -390,7 +390,7 @@ struct nfq_ct_hook {
 	void (*seq_adjust)(struct sk_buff *skb, struct nf_conn *ct,
 			   enum ip_conntrack_info ctinfo, s32 off);
 };
-extern struct nfq_ct_hook __rcu *nfq_ct_hook;
+extern struct nfnl_ct_hook __rcu *nfnl_ct_hook;
 
 /**
  * nf_skb_duplicated - TEE target has sent a packet
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 1412e36..32a2894 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -351,8 +351,8 @@ EXPORT_SYMBOL(skb_make_writable);
 /* This needs to be compiled in any case to avoid dependencies between the
  * nfnetlink_queue code and nf_conntrack.
  */
-struct nfq_ct_hook __rcu *nfq_ct_hook __read_mostly;
-EXPORT_SYMBOL_GPL(nfq_ct_hook);
+struct nfnl_ct_hook __rcu *nfnl_ct_hook __read_mostly;
+EXPORT_SYMBOL_GPL(nfnl_ct_hook);
 
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
 /* This does not belong here, but locally generated errors need it if connection
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index eb67bf8..704f29b 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2135,7 +2135,7 @@ ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
 
 #ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
 static size_t
-ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
+ctnetlink_glue_build_size(const struct nf_conn *ct)
 {
 	return 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */
 	       + 3 * nla_total_size(0) /* CTA_TUPLE_IP */
@@ -2162,8 +2162,8 @@ ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
 	       ;
 }
 
-static struct nf_conn *ctnetlink_nfqueue_get_ct(struct sk_buff *skb,
-						enum ip_conntrack_info *ctinfo)
+static struct nf_conn *ctnetlink_glue_get_ct(struct sk_buff *skb,
+					     enum ip_conntrack_info *ctinfo)
 {
 	struct nf_conn *ct;
 
@@ -2174,7 +2174,7 @@ static struct nf_conn *ctnetlink_nfqueue_get_ct(struct sk_buff *skb,
 	return ct;
 }
 
-static int __ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
+static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
 {
 	const struct nf_conntrack_zone *zone;
 	struct nlattr *nest_parms;
@@ -2247,9 +2247,9 @@ nla_put_failure:
 }
 
 static int
-ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct,
-			enum ip_conntrack_info ctinfo,
-			u_int16_t ct_attr, u_int16_t ct_info_attr)
+ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct,
+		     enum ip_conntrack_info ctinfo,
+		     u_int16_t ct_attr, u_int16_t ct_info_attr)
 {
 	struct nlattr *nest_parms;
 
@@ -2257,7 +2257,7 @@ ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct,
 	if (!nest_parms)
 		goto nla_put_failure;
 
-	if (__ctnetlink_nfqueue_build(skb, ct) < 0)
+	if (__ctnetlink_glue_build(skb, ct) < 0)
 		goto nla_put_failure;
 
 	nla_nest_end(skb, nest_parms);
@@ -2272,7 +2272,7 @@ nla_put_failure:
 }
 
 static int
-ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
+ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
 {
 	int err;
 
@@ -2312,7 +2312,7 @@ ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
 }
 
 static int
-ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
+ctnetlink_glue_parse(const struct nlattr *attr, struct nf_conn *ct)
 {
 	struct nlattr *cda[CTA_MAX+1];
 	int ret;
@@ -2322,16 +2322,16 @@ ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
 		return ret;
 
 	spin_lock_bh(&nf_conntrack_expect_lock);
-	ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
+	ret = ctnetlink_glue_parse_ct((const struct nlattr **)cda, ct);
 	spin_unlock_bh(&nf_conntrack_expect_lock);
 
 	return ret;
 }
 
-static int ctnetlink_nfqueue_exp_parse(const struct nlattr * const *cda,
-				       const struct nf_conn *ct,
-				       struct nf_conntrack_tuple *tuple,
-				       struct nf_conntrack_tuple *mask)
+static int ctnetlink_glue_exp_parse(const struct nlattr * const *cda,
+				    const struct nf_conn *ct,
+				    struct nf_conntrack_tuple *tuple,
+				    struct nf_conntrack_tuple *mask)
 {
 	int err;
 
@@ -2345,8 +2345,8 @@ static int ctnetlink_nfqueue_exp_parse(const struct nlattr * const *cda,
 }
 
 static int
-ctnetlink_nfqueue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
-				u32 portid, u32 report)
+ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
+			     u32 portid, u32 report)
 {
 	struct nlattr *cda[CTA_EXPECT_MAX+1];
 	struct nf_conntrack_tuple tuple, mask;
@@ -2358,8 +2358,8 @@ ctnetlink_nfqueue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
 	if (err < 0)
 		return err;
 
-	err = ctnetlink_nfqueue_exp_parse((const struct nlattr * const *)cda,
-					  ct, &tuple, &mask);
+	err = ctnetlink_glue_exp_parse((const struct nlattr * const *)cda,
+				       ct, &tuple, &mask);
 	if (err < 0)
 		return err;
 
@@ -2386,8 +2386,8 @@ ctnetlink_nfqueue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
 	return 0;
 }
 
-static void ctnetlink_nfqueue_seqadj(struct sk_buff *skb, struct nf_conn *ct,
-				     enum ip_conntrack_info ctinfo, int diff)
+static void ctnetlink_glue_seqadj(struct sk_buff *skb, struct nf_conn *ct,
+				  enum ip_conntrack_info ctinfo, int diff)
 {
 	if (!(ct->status & IPS_NAT_MASK))
 		return;
@@ -2395,13 +2395,13 @@ static void ctnetlink_nfqueue_seqadj(struct sk_buff *skb, struct nf_conn *ct,
 	nf_ct_tcp_seqadj_set(skb, ct, ctinfo, diff);
 }
 
-static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
-	.get_ct		= ctnetlink_nfqueue_get_ct,
-	.build_size	= ctnetlink_nfqueue_build_size,
-	.build		= ctnetlink_nfqueue_build,
-	.parse		= ctnetlink_nfqueue_parse,
-	.attach_expect	= ctnetlink_nfqueue_attach_expect,
-	.seq_adjust	= ctnetlink_nfqueue_seqadj,
+static struct nfnl_ct_hook ctnetlink_glue_hook = {
+	.get_ct		= ctnetlink_glue_get_ct,
+	.build_size	= ctnetlink_glue_build_size,
+	.build		= ctnetlink_glue_build,
+	.parse		= ctnetlink_glue_parse,
+	.attach_expect	= ctnetlink_glue_attach_expect,
+	.seq_adjust	= ctnetlink_glue_seqadj,
 };
 #endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */
 
@@ -3389,7 +3389,7 @@ static int __init ctnetlink_init(void)
 	}
 #ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
 	/* setup interaction between nf_queue and nf_conntrack_netlink. */
-	RCU_INIT_POINTER(nfq_ct_hook, &ctnetlink_nfqueue_hook);
+	RCU_INIT_POINTER(nfnl_ct_hook, &ctnetlink_glue_hook);
 #endif
 	return 0;
 
@@ -3409,7 +3409,7 @@ static void __exit ctnetlink_exit(void)
 	nfnetlink_subsys_unregister(&ctnl_exp_subsys);
 	nfnetlink_subsys_unregister(&ctnl_subsys);
 #ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
-	RCU_INIT_POINTER(nfq_ct_hook, NULL);
+	RCU_INIT_POINTER(nfnl_ct_hook, NULL);
 #endif
 }
 
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b1f1c74..789a738 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -313,7 +313,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 	struct net_device *outdev;
 	struct nf_conn *ct = NULL;
 	enum ip_conntrack_info uninitialized_var(ctinfo);
-	struct nfq_ct_hook *nfq_ct;
+	struct nfnl_ct_hook *nfnl_ct;
 	bool csum_verify;
 	char *secdata = NULL;
 	u32 seclen = 0;
@@ -366,11 +366,11 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 	}
 
 	if (queue->flags & NFQA_CFG_F_CONNTRACK) {
-		nfq_ct = rcu_dereference(nfq_ct_hook);
-		if (nfq_ct != NULL) {
-			ct = nfq_ct->get_ct(entskb, &ctinfo);
+		nfnl_ct = rcu_dereference(nfnl_ct_hook);
+		if (nfnl_ct != NULL) {
+			ct = nfnl_ct->get_ct(entskb, &ctinfo);
 			if (ct != NULL)
-				size += nfq_ct->build_size(ct);
+				size += nfnl_ct->build_size(ct);
 		}
 	}
 
@@ -515,7 +515,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 	if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata))
 		goto nla_put_failure;
 
-	if (ct && nfq_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
+	if (ct && nfnl_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
 		goto nla_put_failure;
 
 	if (cap_len > data_len &&
@@ -1008,7 +1008,7 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
 	return 0;
 }
 
-static struct nf_conn *nfqnl_ct_parse(struct nfq_ct_hook *nfq_ct,
+static struct nf_conn *nfqnl_ct_parse(struct nfnl_ct_hook *nfnl_ct,
 				      const struct nlmsghdr *nlh,
 				      const struct nlattr * const nfqa[],
 				      struct nf_queue_entry *entry,
@@ -1016,15 +1016,15 @@ static struct nf_conn *nfqnl_ct_parse(struct nfq_ct_hook *nfq_ct,
 {
 	struct nf_conn *ct;
 
-	ct = nfq_ct->get_ct(entry->skb, ctinfo);
+	ct = nfnl_ct->get_ct(entry->skb, ctinfo);
 	if (ct == NULL)
 		return NULL;
 
-	if (nfq_ct->parse(nfqa[NFQA_CT], ct) < 0)
+	if (nfnl_ct->parse(nfqa[NFQA_CT], ct) < 0)
 		return NULL;
 
 	if (nfqa[NFQA_EXP])
-		nfq_ct->attach_expect(nfqa[NFQA_EXP], ct,
+		nfnl_ct->attach_expect(nfqa[NFQA_EXP], ct,
 				      NETLINK_CB(entry->skb).portid,
 				      nlmsg_report(nlh));
 	return ct;
@@ -1043,7 +1043,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
 	unsigned int verdict;
 	struct nf_queue_entry *entry;
 	enum ip_conntrack_info uninitialized_var(ctinfo);
-	struct nfq_ct_hook *nfq_ct;
+	struct nfnl_ct_hook *nfnl_ct;
 	struct nf_conn *ct = NULL;
 
 	struct net *net = sock_net(ctnl);
@@ -1068,9 +1068,9 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
 
 	if (nfqa[NFQA_CT]) {
 		/* rcu lock already held from nfnl->call_rcu. */
-		nfq_ct = rcu_dereference(nfq_ct_hook);
-		if (nfq_ct != NULL)
-			ct = nfqnl_ct_parse(nfq_ct, nlh, nfqa, entry, &ctinfo);
+		nfnl_ct = rcu_dereference(nfnl_ct_hook);
+		if (nfnl_ct != NULL)
+			ct = nfqnl_ct_parse(nfnl_ct, nlh, nfqa, entry, &ctinfo);
 	}
 
 	if (nfqa[NFQA_PAYLOAD]) {
@@ -1082,7 +1082,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
 			verdict = NF_DROP;
 
 		if (ct && diff)
-			nfq_ct->seq_adjust(entry->skb, ct, ctinfo, diff);
+			nfnl_ct->seq_adjust(entry->skb, ct, ctinfo, diff);
 	}
 
 	if (nfqa[NFQA_MARK])
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCHv2 nf-next 2/4] netfilter: Kconfig rename QUEUE_CT to GLUE_CT
  2015-10-05  2:44   ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Ken-ichirou MATSUZAWA
  2015-10-05  2:47     ` [PATCHv2 nf-next 1/4] netfilter: nfnetlink_queue: rename related to nfqueue attaching conntrack info Ken-ichirou MATSUZAWA
@ 2015-10-05  2:48     ` Ken-ichirou MATSUZAWA
  2015-10-05  2:49     ` [PATCHv2 nf-next 3/4] netfilter: nf_conntrack_netlink: add const qualifier to nfnl_hook.get_ct Ken-ichirou MATSUZAWA
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-05  2:48 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Conntrack information attaching infrastructure is now generic and
update it's name to use `glue' in previous patch. This patch updates
Kconfig symbol name and adding NF_CT_NETLINK dependency.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/Kconfig                |   10 +++++-----
 net/netfilter/nf_conntrack_netlink.c |    8 ++++----
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 3e1b4ab..d287818 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -354,7 +354,7 @@ config NF_CT_NETLINK_HELPER
 	select NETFILTER_NETLINK
 	depends on NF_CT_NETLINK
 	depends on NETFILTER_NETLINK_QUEUE
-	depends on NETFILTER_NETLINK_QUEUE_CT
+	depends on NETFILTER_NETLINK_GLUE_CT
 	depends on NETFILTER_ADVANCED
 	help
 	  This option enables the user-space connection tracking helpers
@@ -362,10 +362,10 @@ config NF_CT_NETLINK_HELPER
 
 	  If unsure, say `N'.
 
-config NETFILTER_NETLINK_QUEUE_CT
-        bool "NFQUEUE integration with Connection Tracking"
-        default n
-        depends on NETFILTER_NETLINK_QUEUE
+config NETFILTER_NETLINK_GLUE_CT
+	bool "NFQUEUE integration with Connection Tracking"
+	default n
+	depends on NETFILTER_NETLINK_QUEUE && NF_CT_NETLINK
 	help
 	  If this option is enabled, NFQUEUE can include Connection Tracking
 	  information together with the packet is the enqueued via NFNETLINK.
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 704f29b..71d6ada 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2133,7 +2133,7 @@ ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
 		       struct nf_conntrack_tuple *tuple,
 		       struct nf_conntrack_tuple *mask);
 
-#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
+#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
 static size_t
 ctnetlink_glue_build_size(const struct nf_conn *ct)
 {
@@ -2403,7 +2403,7 @@ static struct nfnl_ct_hook ctnetlink_glue_hook = {
 	.attach_expect	= ctnetlink_glue_attach_expect,
 	.seq_adjust	= ctnetlink_glue_seqadj,
 };
-#endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */
+#endif /* CONFIG_NETFILTER_NETLINK_GLUE_CT */
 
 /***********************************************************************
  * EXPECT
@@ -3387,7 +3387,7 @@ static int __init ctnetlink_init(void)
 		pr_err("ctnetlink_init: cannot register pernet operations\n");
 		goto err_unreg_exp_subsys;
 	}
-#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
+#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
 	/* setup interaction between nf_queue and nf_conntrack_netlink. */
 	RCU_INIT_POINTER(nfnl_ct_hook, &ctnetlink_glue_hook);
 #endif
@@ -3408,7 +3408,7 @@ static void __exit ctnetlink_exit(void)
 	unregister_pernet_subsys(&ctnetlink_net_ops);
 	nfnetlink_subsys_unregister(&ctnl_exp_subsys);
 	nfnetlink_subsys_unregister(&ctnl_subsys);
-#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT
+#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
 	RCU_INIT_POINTER(nfnl_ct_hook, NULL);
 #endif
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCHv2 nf-next 3/4] netfilter: nf_conntrack_netlink: add const qualifier to nfnl_hook.get_ct
  2015-10-05  2:44   ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Ken-ichirou MATSUZAWA
  2015-10-05  2:47     ` [PATCHv2 nf-next 1/4] netfilter: nfnetlink_queue: rename related to nfqueue attaching conntrack info Ken-ichirou MATSUZAWA
  2015-10-05  2:48     ` [PATCHv2 nf-next 2/4] netfilter: Kconfig rename QUEUE_CT to GLUE_CT Ken-ichirou MATSUZAWA
@ 2015-10-05  2:49     ` Ken-ichirou MATSUZAWA
  2015-10-05  2:50     ` [PATCHv2 nf-next 4/4] netfilter: nfnetlink_log: allow to attach conntrack Ken-ichirou MATSUZAWA
  2015-10-05 15:33     ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Pablo Neira Ayuso
  4 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-05  2:49 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

get_ct as is and will not update its skb argument, and users of
nfnl_ct_hook is currently only nfqueue, we can add const qualifier.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 include/linux/netfilter.h            |    2 +-
 net/netfilter/nf_conntrack_netlink.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 27747de..edb3dc3 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -378,7 +378,7 @@ enum ip_conntrack_info;
 struct nlattr;
 
 struct nfnl_ct_hook {
-	struct nf_conn *(*get_ct)(struct sk_buff *skb,
+	struct nf_conn *(*get_ct)(const struct sk_buff *skb,
 				  enum ip_conntrack_info *ctinfo);
 	size_t (*build_size)(const struct nf_conn *ct);
 	int (*build)(struct sk_buff *skb, struct nf_conn *ct,
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 71d6ada..9f52729 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2162,7 +2162,7 @@ ctnetlink_glue_build_size(const struct nf_conn *ct)
 	       ;
 }
 
-static struct nf_conn *ctnetlink_glue_get_ct(struct sk_buff *skb,
+static struct nf_conn *ctnetlink_glue_get_ct(const struct sk_buff *skb,
 					     enum ip_conntrack_info *ctinfo)
 {
 	struct nf_conn *ct;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCHv2 nf-next 4/4] netfilter: nfnetlink_log: allow to attach conntrack
  2015-10-05  2:44   ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Ken-ichirou MATSUZAWA
                       ` (2 preceding siblings ...)
  2015-10-05  2:49     ` [PATCHv2 nf-next 3/4] netfilter: nf_conntrack_netlink: add const qualifier to nfnl_hook.get_ct Ken-ichirou MATSUZAWA
@ 2015-10-05  2:50     ` Ken-ichirou MATSUZAWA
  2015-10-05 15:23       ` Pablo Neira Ayuso
  2015-10-05 15:33     ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Pablo Neira Ayuso
  4 siblings, 1 reply; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-05  2:50 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch enables to include the conntrack information together
with the packet that is sent to user-space via NFLOG, then a
user-space program can acquire NATed information by this NFULA_CT
attribute.

Including the conntrack information is optional, you can set it
via NFULNL_CFG_F_CONNTRACK flag with the NFULA_CFG_FLAGS attribute
like NFQUEUE.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 include/uapi/linux/netfilter/nfnetlink_log.h |    3 ++
 net/netfilter/Kconfig                        |    9 +++---
 net/netfilter/nfnetlink_log.c                |   40 ++++++++++++++++++++++----
 3 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/include/uapi/linux/netfilter/nfnetlink_log.h b/include/uapi/linux/netfilter/nfnetlink_log.h
index 90c2c95..fb21f0c 100644
--- a/include/uapi/linux/netfilter/nfnetlink_log.h
+++ b/include/uapi/linux/netfilter/nfnetlink_log.h
@@ -51,6 +51,8 @@ enum nfulnl_attr_type {
 	NFULA_HWTYPE,			/* hardware type */
 	NFULA_HWHEADER,			/* hardware header */
 	NFULA_HWLEN,			/* hardware header length */
+	NFULA_CT,                       /* nf_conntrack_netlink.h */
+	NFULA_CT_INFO,                  /* enum ip_conntrack_info */
 
 	__NFULA_MAX
 };
@@ -93,5 +95,6 @@ enum nfulnl_attr_config {
 
 #define NFULNL_CFG_F_SEQ	0x0001
 #define NFULNL_CFG_F_SEQ_GLOBAL	0x0002
+#define NFULNL_CFG_F_CONNTRACK	0x0004
 
 #endif /* _NFNETLINK_LOG_H */
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index d287818..e22349e 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -363,12 +363,13 @@ config NF_CT_NETLINK_HELPER
 	  If unsure, say `N'.
 
 config NETFILTER_NETLINK_GLUE_CT
-	bool "NFQUEUE integration with Connection Tracking"
+	bool "NFQUEUE and NFLOG integration with Connection Tracking"
 	default n
-	depends on NETFILTER_NETLINK_QUEUE && NF_CT_NETLINK
+	depends on (NETFILTER_NETLINK_QUEUE || NETFILTER_NETLINK_LOG) && NF_CT_NETLINK
 	help
-	  If this option is enabled, NFQUEUE can include Connection Tracking
-	  information together with the packet is the enqueued via NFNETLINK.
+	  If this option is enabled, NFQUEUE and NFLOG can include
+	  Connection Tracking information together with the packet is
+	  the enqueued via NFNETLINK.
 
 config NF_NAT
 	tristate
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 4670821..d4b6947 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -27,6 +27,7 @@
 #include <net/netlink.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_log.h>
+#include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/spinlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
@@ -401,7 +402,9 @@ __build_packet_message(struct nfnl_log_net *log,
 			unsigned int hooknum,
 			const struct net_device *indev,
 			const struct net_device *outdev,
-			const char *prefix, unsigned int plen)
+			const char *prefix, unsigned int plen,
+			const struct nfnl_ct_hook *nfnl_ct,
+			struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 {
 	struct nfulnl_msg_packet_hdr pmsg;
 	struct nlmsghdr *nlh;
@@ -575,6 +578,10 @@ __build_packet_message(struct nfnl_log_net *log,
 			 htonl(atomic_inc_return(&log->global_seq))))
 		goto nla_put_failure;
 
+	if (ct && nfnl_ct->build(inst->skb, ct, ctinfo,
+				 NFULA_CT, NFULA_CT_INFO) < 0)
+			goto nla_put_failure;
+	
 	if (data_len) {
 		struct nlattr *nla;
 		int size = nla_attr_size(data_len);
@@ -620,12 +627,16 @@ nfulnl_log_packet(struct net *net,
 		  const struct nf_loginfo *li_user,
 		  const char *prefix)
 {
-	unsigned int size, data_len;
+	size_t size;
+	unsigned int data_len;
 	struct nfulnl_instance *inst;
 	const struct nf_loginfo *li;
 	unsigned int qthreshold;
 	unsigned int plen;
 	struct nfnl_log_net *log = nfnl_log_pernet(net);
+	const struct nfnl_ct_hook *nfnl_ct = NULL;
+	struct nf_conn *ct = NULL;
+	enum ip_conntrack_info uninitialized_var(ctinfo);
 
 	if (li_user && li_user->type == NF_LOG_TYPE_ULOG)
 		li = li_user;
@@ -671,7 +682,15 @@ nfulnl_log_packet(struct net *net,
 		size += nla_total_size(sizeof(u_int32_t));
 	if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL)
 		size += nla_total_size(sizeof(u_int32_t));
-
+	if (inst->flags & NFULNL_CFG_F_CONNTRACK) {
+		nfnl_ct = rcu_dereference(nfnl_ct_hook);
+		if (nfnl_ct != NULL) {
+			ct = nfnl_ct->get_ct(skb, &ctinfo);
+			if (ct != NULL)
+				size += nfnl_ct->build_size(ct);
+		}
+	}
+	
 	qthreshold = inst->qthreshold;
 	/* per-rule qthreshold overrides per-instance */
 	if (li->u.ulog.qthreshold)
@@ -715,7 +734,8 @@ nfulnl_log_packet(struct net *net,
 	inst->qlen++;
 
 	__build_packet_message(log, inst, skb, data_len, pf,
-				hooknum, in, out, prefix, plen);
+				hooknum, in, out, prefix, plen,
+				nfnl_ct, ct, ctinfo);
 
 	if (inst->qlen >= qthreshold)
 		__nfulnl_flush(inst);
@@ -899,13 +919,21 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 	}
 
 	if (nfula[NFULA_CFG_FLAGS]) {
-		__be16 flags = nla_get_be16(nfula[NFULA_CFG_FLAGS]);
+		u16 flags = ntohs(nla_get_be16(nfula[NFULA_CFG_FLAGS]));
 
 		if (!inst) {
 			ret = -ENODEV;
 			goto out;
 		}
-		nfulnl_set_flags(inst, ntohs(flags));
+
+		if (flags & NFULNL_CFG_F_CONNTRACK &&
+		    rcu_dereference(nfnl_ct_hook) == NULL) {
+			ret = -EOPNOTSUPP;
+			goto out;
+
+		}
+
+		nfulnl_set_flags(inst, flags);
 	}
 
 out_put:
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCHv2 nf-next 4/4] netfilter: nfnetlink_log: allow to attach conntrack
  2015-10-05  2:50     ` [PATCHv2 nf-next 4/4] netfilter: nfnetlink_log: allow to attach conntrack Ken-ichirou MATSUZAWA
@ 2015-10-05 15:23       ` Pablo Neira Ayuso
  2015-10-06  2:10         ` [PATCHv2 nf-next 0/1] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
  0 siblings, 1 reply; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-05 15:23 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Mon, Oct 05, 2015 at 11:50:46AM +0900, Ken-ichirou MATSUZAWA wrote:
> This patch enables to include the conntrack information together
> with the packet that is sent to user-space via NFLOG, then a
> user-space program can acquire NATed information by this NFULA_CT
> attribute.

WARNING: suspect code indent for conditional statements (8, 24)
#99: FILE: net/netfilter/nfnetlink_log.c:581:
+       if (ct && nfnl_ct->build(inst->skb, ct, ctinfo,
[...]
+                       goto nla_put_failure;

Please, make sure you use tabs next time.

ERROR: trailing whitespace
#102: FILE: net/netfilter/nfnetlink_log.c:584:

ERROR: trailing whitespace
#137: FILE: net/netfilter/nfnetlink_log.c:693:

Please, run checkpatch.pl on your patches next time to address
whitespace errors and wrong indent.

And regarding this:

        ...
        rcu_dereference(nfnl_ct_hook) == NULL) {

it should be:

        rcu_access_pointer(nfnl_ct_hook) == NULL) {

I have fixed these issues here this time, no need to resend.

But, would you please resubmit this:

http://patchwork.ozlabs.org/patch/516185/

but using rcu_access_pointer() instead?

BTW, another thing that would be good to investigate is to autoload
nf_conntrack_netlink if the process passes the _F_CONNTRACK flag is
set. Would you have a look into that?

Thanks.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information
  2015-10-05  2:44   ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Ken-ichirou MATSUZAWA
                       ` (3 preceding siblings ...)
  2015-10-05  2:50     ` [PATCHv2 nf-next 4/4] netfilter: nfnetlink_log: allow to attach conntrack Ken-ichirou MATSUZAWA
@ 2015-10-05 15:33     ` Pablo Neira Ayuso
  4 siblings, 0 replies; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-05 15:33 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Mon, Oct 05, 2015 at 11:44:54AM +0900, Ken-ichirou MATSUZAWA wrote:
> Hi Pablo,
> 
> I rebased on top of your patches, would you review these?
> 
> You suggested it might be better to divide ct attaching Kconfig to
> each of nfqueue and nflog, but I think it makes less sense now
> because of your rework. is it right?

Series applied, thanks for your patience.

Please, follow up with fixes in case of problems.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCHv2 nf-next 0/1] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag
  2015-10-05 15:23       ` Pablo Neira Ayuso
@ 2015-10-06  2:10         ` Ken-ichirou MATSUZAWA
  2015-10-06  2:12           ` [PATCHv2 nf-next 1/1] " Ken-ichirou MATSUZAWA
  0 siblings, 1 reply; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-06  2:10 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

 Thank you for advices.

I try to fix rcu_dereference() and to autoload not only
nf_conntrack_netlink but also l3ct module if nfgen family is
specified. Is it unnecessary?

I will make same thing to nfnetlink_log after this round.

Thanks,

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCHv2 nf-next 1/1] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag
  2015-10-06  2:10         ` [PATCHv2 nf-next 0/1] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
@ 2015-10-06  2:12           ` Ken-ichirou MATSUZAWA
  2015-10-06 10:07             ` Pablo Neira Ayuso
  0 siblings, 1 reply; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-06  2:12 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch enables to check GLUE_CT is enabled or not when
NFQA_CFG_F_CONNTRACK config flag is received. And try to load
nf_conntrack_netlink module, and l3proto module if family is
specified. Then returns error either case is failed.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a659e57..99c9c8c 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -34,6 +34,7 @@
 #include <net/tcp_states.h>
 #include <net/netfilter/nf_queue.h>
 #include <net/netns/generic.h>
+#include <net/netfilter/nf_conntrack.h>
 
 #include <linux/atomic.h>
 
@@ -1225,6 +1226,24 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 			goto err_out_unlock;
 		}
 #endif
+		if (flags & mask & NFQA_CFG_F_CONNTRACK) {
+			if (!rcu_access_pointer(nfnl_ct_hook))
+#ifdef CONFIG_MODULES
+				if (request_module("ip_conntrack_netlink") ||
+				    !rcu_access_pointer(nfnl_ct_hook))
+#endif
+				{
+					ret = -EOPNOTSUPP;
+					goto err_out_unlock;
+				}
+
+			if (nfmsg->nfgen_family &&
+			    nf_ct_l3proto_try_module_get(nfmsg->nfgen_family)) {
+				ret = -EPROTONOSUPPORT;
+				goto err_out_unlock;
+			}
+		}
+
 		spin_lock_bh(&queue->lock);
 		queue->flags &= ~mask;
 		queue->flags |= flags & mask;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCHv2 nf-next 1/1] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag
  2015-10-06  2:12           ` [PATCHv2 nf-next 1/1] " Ken-ichirou MATSUZAWA
@ 2015-10-06 10:07             ` Pablo Neira Ayuso
  2015-10-07  4:20               ` Ken-ichirou MATSUZAWA
  0 siblings, 1 reply; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-06 10:07 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Tue, Oct 06, 2015 at 11:12:46AM +0900, Ken-ichirou MATSUZAWA wrote:
> This patch enables to check GLUE_CT is enabled or not when
> NFQA_CFG_F_CONNTRACK config flag is received. And try to load
> nf_conntrack_netlink module, and l3proto module if family is
> specified. Then returns error either case is failed.
> 
> Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
> ---
>  net/netfilter/nfnetlink_queue.c |   19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
> index a659e57..99c9c8c 100644
> --- a/net/netfilter/nfnetlink_queue.c
> +++ b/net/netfilter/nfnetlink_queue.c
> @@ -34,6 +34,7 @@
>  #include <net/tcp_states.h>
>  #include <net/netfilter/nf_queue.h>
>  #include <net/netns/generic.h>
> +#include <net/netfilter/nf_conntrack.h>
>  
>  #include <linux/atomic.h>
>  
> @@ -1225,6 +1226,24 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
>  			goto err_out_unlock;
>  		}
>  #endif
> +		if (flags & mask & NFQA_CFG_F_CONNTRACK) {
> +			if (!rcu_access_pointer(nfnl_ct_hook))
> +#ifdef CONFIG_MODULES
> +				if (request_module("ip_conntrack_netlink") ||

nfnl_lock is held while requesting a module, which is something that
we should avoid. Please, abort the operation and return -EAGAIN to
retry, this is the usual procedure when requesting other modules.

> +				    !rcu_access_pointer(nfnl_ct_hook))
> +#endif
> +				{
> +					ret = -EOPNOTSUPP;
> +					goto err_out_unlock;
> +				}
> +
> +			if (nfmsg->nfgen_family &&



> +			    nf_ct_l3proto_try_module_get(nfmsg->nfgen_family)) {
> +				ret = -EPROTONOSUPPORT;
> +				goto err_out_unlock;

I think this chunk belongs to nf_conntrack_netlink, the
nf_conntrack_{ipv4,ipv6} modules gets loaded when the user tries to
create a conntrack/expectation.

Otherwise we create a hard dependency between nfnetlink_queue and
nf_conntrack, which is what we're trying to avoid ;-)

> +			}
> +		}
> +
>  		spin_lock_bh(&queue->lock);
>  		queue->flags &= ~mask;
>  		queue->flags |= flags & mask;
> -- 
> 1.7.10.4
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCHv2 nf-next 1/1] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag
  2015-10-06 10:07             ` Pablo Neira Ayuso
@ 2015-10-07  4:20               ` Ken-ichirou MATSUZAWA
  2015-10-07  4:23                 ` [PATCHv3 nf-next] " Ken-ichirou MATSUZAWA
                                   ` (3 more replies)
  0 siblings, 4 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-07  4:20 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

On Tue, Oct 06, 2015 at 12:07:28PM +0200, Pablo Neira Ayuso wrote:
> On Tue, Oct 06, 2015 at 11:12:46AM +0900, Ken-ichirou MATSUZAWA wrote:
> > +		if (flags & mask & NFQA_CFG_F_CONNTRACK) {
> > +			if (!rcu_access_pointer(nfnl_ct_hook))
> > +#ifdef CONFIG_MODULES
> > +				if (request_module("ip_conntrack_netlink") ||
> 
> nfnl_lock is held while requesting a module, which is something that
> we should avoid. Please, abort the operation and return -EAGAIN to
> retry, this is the usual procedure when requesting other modules.

Thank you as always.

I read another request_module() part and I think I can understand,
would you review it again? I changed rcu_access_pointer() since
rcu_read_lock() is called in nfqnl_recv_config().

I think a few fix seems to be needed at that time, and try to fix
it in the following patches. Would you confirm these too?

Thanks,

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCHv3 nf-next] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag
  2015-10-07  4:20               ` Ken-ichirou MATSUZAWA
@ 2015-10-07  4:23                 ` Ken-ichirou MATSUZAWA
  2015-10-07  4:25                 ` [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module " Ken-ichirou MATSUZAWA
                                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-07  4:23 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch enables to check if GLUE_CT is enabled and try to load
dependent, nf_conntrack_netlink module when NFQA_CFG_F_CONNTRACK
config flag is received. Then returns error either case is failed.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a659e57..583a7a0 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1225,6 +1225,23 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 			goto err_out_unlock;
 		}
 #endif
+		if (flags & mask & NFQA_CFG_F_CONNTRACK &&
+		    !rcu_dereference(nfnl_ct_hook)) {
+#ifdef CONFIG_MODULES
+			rcu_read_unlock();
+			nfnl_unlock(NFNL_SUBSYS_QUEUE);
+			request_module("ip_conntrack_netlink");
+			nfnl_lock(NFNL_SUBSYS_QUEUE);
+			rcu_read_lock();
+			if (rcu_dereference(nfnl_ct_hook)) {
+				ret = -EAGAIN;
+				goto err_out_unlock;
+			}
+#endif
+			ret = -EOPNOTSUPP;
+			goto err_out_unlock;
+		}
+
 		spin_lock_bh(&queue->lock);
 		queue->flags &= ~mask;
 		queue->flags |= flags & mask;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag
  2015-10-07  4:20               ` Ken-ichirou MATSUZAWA
  2015-10-07  4:23                 ` [PATCHv3 nf-next] " Ken-ichirou MATSUZAWA
@ 2015-10-07  4:25                 ` Ken-ichirou MATSUZAWA
  2015-10-12 17:13                   ` Pablo Neira Ayuso
  2015-10-16 17:05                   ` Pablo Neira Ayuso
  2015-10-07  4:27                 ` [PATCH nf-next] netfilter: nf_conntrack_netlink: fix nf-nat module loaded checking Ken-ichirou MATSUZAWA
  2015-10-07  4:30                 ` [PATCH nf-next] netfilter: nf_conntrack_netlink: fix locks around helper module loading Ken-ichirou MATSUZAWA
  3 siblings, 2 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-07  4:25 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch enables to load nf_conntrack_netlink module if
NFULNL_CFG_F_CONNTRACK config flag is specified.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_log.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index e1d1187..f8d9bd8 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -927,7 +927,16 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 		}
 
 		if (flags & NFULNL_CFG_F_CONNTRACK &&
-		    rcu_access_pointer(nfnl_ct_hook) == NULL) {
+		    !rcu_access_pointer(nfnl_ct_hook)) {
+#ifdef CONFIG_MODULES
+			nfnl_unlock(NFNL_SUBSYS_ULOG);
+			request_module("ip_conntrack_netlink");
+			nfnl_lock(NFNL_SUBSYS_ULOG);
+			if (rcu_access_pointer(nfnl_ct_hook)) {
+				ret = -EAGAIN;
+				goto out;
+			}
+#endif
 			ret = -EOPNOTSUPP;
 			goto out;
 		}
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next] netfilter: nf_conntrack_netlink: fix nf-nat module loaded checking
  2015-10-07  4:20               ` Ken-ichirou MATSUZAWA
  2015-10-07  4:23                 ` [PATCHv3 nf-next] " Ken-ichirou MATSUZAWA
  2015-10-07  4:25                 ` [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module " Ken-ichirou MATSUZAWA
@ 2015-10-07  4:27                 ` Ken-ichirou MATSUZAWA
  2015-10-07  4:30                 ` [PATCH nf-next] netfilter: nf_conntrack_netlink: fix locks around helper module loading Ken-ichirou MATSUZAWA
  3 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-07  4:27 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nf_conntrack_netlink.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 9f52729..dd13596 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1389,7 +1389,7 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
 		}
 		nfnl_lock(NFNL_SUBSYS_CTNETLINK);
 		rcu_read_lock();
-		if (nfnetlink_parse_nat_setup_hook)
+		if (rcu_dereference(nfnetlink_parse_nat_setup_hook))
 			return -EAGAIN;
 #endif
 		return -EOPNOTSUPP;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next] netfilter: nf_conntrack_netlink: fix locks around helper module loading
  2015-10-07  4:20               ` Ken-ichirou MATSUZAWA
                                   ` (2 preceding siblings ...)
  2015-10-07  4:27                 ` [PATCH nf-next] netfilter: nf_conntrack_netlink: fix nf-nat module loaded checking Ken-ichirou MATSUZAWA
@ 2015-10-07  4:30                 ` Ken-ichirou MATSUZAWA
  3 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-10-07  4:30 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

There are two paths for calling ctnetlink_change_helper which may
call request_module() which requires nfnl lock, and may also call
__nf_conntrack_helper_find() which needs rcu read lock.

    - nfqnl_cb[NFQNL_MSG_VERDICT].call_rcu / nfqnl_recv_verdict()
    - ctnl_cb[IPCTNL_MSG_CT_NEW].call / ctnetlink_new_conntrack()

These uses different lock mechanism, it seems we need to adjust it.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nf_conntrack_netlink.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index dd13596..9121226 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1497,12 +1497,17 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
 	if (helper == NULL) {
 #ifdef CONFIG_MODULES
 		spin_unlock_bh(&nf_conntrack_expect_lock);
-
+		rcu_read_unlock();
+		nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
 		if (request_module("nfct-helper-%s", helpname) < 0) {
+			nfnl_lock(NFNL_SUBSYS_CTNETLINK);
+			rcu_read_lock();
 			spin_lock_bh(&nf_conntrack_expect_lock);
 			return -EOPNOTSUPP;
 		}
 
+		nfnl_lock(NFNL_SUBSYS_CTNETLINK);
+		rcu_read_lock();
 		spin_lock_bh(&nf_conntrack_expect_lock);
 		helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
 						    nf_ct_protonum(ct));
@@ -1943,9 +1948,11 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
 	err = -EEXIST;
 	ct = nf_ct_tuplehash_to_ctrack(h);
 	if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
+		rcu_read_lock();
 		spin_lock_bh(&nf_conntrack_expect_lock);
 		err = ctnetlink_change_conntrack(ct, cda);
 		spin_unlock_bh(&nf_conntrack_expect_lock);
+		rcu_read_unlock();
 		if (err == 0) {
 			nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
 						      (1 << IPCT_ASSURED) |
@@ -2287,7 +2294,9 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
 			return err;
 	}
 	if (cda[CTA_HELP]) {
+		nfnl_lock(NFNL_SUBSYS_CTNETLINK);
 		err = ctnetlink_change_helper(ct, cda);
+		nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
 		if (err < 0)
 			return err;
 	}
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag
  2015-10-07  4:25                 ` [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module " Ken-ichirou MATSUZAWA
@ 2015-10-12 17:13                   ` Pablo Neira Ayuso
  2015-10-12 20:10                     ` Pablo Neira Ayuso
  2015-10-16 17:05                   ` Pablo Neira Ayuso
  1 sibling, 1 reply; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-12 17:13 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Wed, Oct 07, 2015 at 01:25:50PM +0900, Ken-ichirou MATSUZAWA wrote:
> This patch enables to load nf_conntrack_netlink module if
> NFULNL_CFG_F_CONNTRACK config flag is specified.

Applied, thanks.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag
  2015-10-12 17:13                   ` Pablo Neira Ayuso
@ 2015-10-12 20:10                     ` Pablo Neira Ayuso
  0 siblings, 0 replies; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-12 20:10 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Mon, Oct 12, 2015 at 07:13:52PM +0200, Pablo Neira Ayuso wrote:
> On Wed, Oct 07, 2015 at 01:25:50PM +0900, Ken-ichirou MATSUZAWA wrote:
> > This patch enables to load nf_conntrack_netlink module if
> > NFULNL_CFG_F_CONNTRACK config flag is specified.
> 
> Applied, thanks.

I just noticed we're breaking atomicity when configuring things.

I mean, if we fail to configure the flags, we return an error but it's
too late, we just create the instance and we have configured
everything.

I quickly made a couple of patches here, we'll be posting them
tomorrow.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag
  2015-10-07  4:25                 ` [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module " Ken-ichirou MATSUZAWA
  2015-10-12 17:13                   ` Pablo Neira Ayuso
@ 2015-10-16 17:05                   ` Pablo Neira Ayuso
  2015-11-06  0:46                     ` Ken-ichirou MATSUZAWA
  1 sibling, 1 reply; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-10-16 17:05 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Wed, Oct 07, 2015 at 01:25:50PM +0900, Ken-ichirou MATSUZAWA wrote:
> This patch enables to load nf_conntrack_netlink module if
> NFULNL_CFG_F_CONNTRACK config flag is specified.
> 
> Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
> ---
>  net/netfilter/nfnetlink_log.c |   11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
> index e1d1187..f8d9bd8 100644
> --- a/net/netfilter/nfnetlink_log.c
> +++ b/net/netfilter/nfnetlink_log.c
> @@ -927,7 +927,16 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
>  		}
>  
>  		if (flags & NFULNL_CFG_F_CONNTRACK &&
> -		    rcu_access_pointer(nfnl_ct_hook) == NULL) {
> +		    !rcu_access_pointer(nfnl_ct_hook)) {
> +#ifdef CONFIG_MODULES
> +			nfnl_unlock(NFNL_SUBSYS_ULOG);
> +			request_module("ip_conntrack_netlink");
> +			nfnl_lock(NFNL_SUBSYS_ULOG);
> +			if (rcu_access_pointer(nfnl_ct_hook)) {
> +				ret = -EAGAIN;
> +				goto out;
> +			}
> +#endif

I know this is not your fault, but could you have a look to see if we
can get resolved the broken atomicity problems in first place when
applying configuration updates to nfnetlink_queue in a similar way to
what I did for nfnetlink_log?

I mean, move code that check for things right up the beginning of the
functions, then we pass the preparation phase and we're good, we apply
the configuration changes.

Again not your fault, but there's another nasty thing in that code: We
can destroy a queue in NFQNL_CFG_CMD_UNBIND, then we can keep going on
configuring it when it is actually destroyed. This is working only by
luck because we're using call_rcu so the object is still there, but
this is sloppy and it should be fixed.

After having that resolved, we can go back to adding module autoload.

Let me know,
Thanks.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag
  2015-10-16 17:05                   ` Pablo Neira Ayuso
@ 2015-11-06  0:46                     ` Ken-ichirou MATSUZAWA
  2015-11-06  0:49                       ` [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling Ken-ichirou MATSUZAWA
                                         ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-11-06  0:46 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

 Sorry for being late.
 
On Fri, Oct 16, 2015 at 07:05:32PM +0200, Pablo Neira Ayuso wrote:
> can get resolved the broken atomicity problems in first place when
> applying configuration updates to nfnetlink_queue in a similar way to
> what I did for nfnetlink_log?

I tried it, would you review the following patches?

> can destroy a queue in NFQNL_CFG_CMD_UNBIND, then we can keep going on
> configuring it when it is actually destroyed. This is working only by

I'm wondering how we handle obsolete commands
NFQNL_CFG_CMD_PF_BIND / UNBIND, especially with a valid queue_num
and configurations. These patches follows current behavior, do
nothing, ignores another nlas and just returns success. Should I
update patches to handle configuraion nlas with obsolute commands?

Thanks,

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling
  2015-11-06  0:46                     ` Ken-ichirou MATSUZAWA
@ 2015-11-06  0:49                       ` Ken-ichirou MATSUZAWA
  2015-11-08 22:14                         ` Pablo Neira Ayuso
  2015-11-06  0:56                       ` [PATCH nf-next 2/3] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity Ken-ichirou MATSUZAWA
  2015-11-06  0:58                       ` [PATCH nf-next 3/3] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
  2 siblings, 1 reply; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-11-06  0:49 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |   18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 7d81d28..f85a3d3 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1116,21 +1116,10 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
 	u_int16_t queue_num = ntohs(nfmsg->res_id);
 	struct nfqnl_instance *queue;
-	struct nfqnl_msg_config_cmd *cmd = NULL;
 	struct net *net = sock_net(ctnl);
 	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
 	int ret = 0;
 
-	if (nfqa[NFQA_CFG_CMD]) {
-		cmd = nla_data(nfqa[NFQA_CFG_CMD]);
-
-		/* Obsolete commands without queue context */
-		switch (cmd->command) {
-		case NFQNL_CFG_CMD_PF_BIND: return 0;
-		case NFQNL_CFG_CMD_PF_UNBIND: return 0;
-		}
-	}
-
 	rcu_read_lock();
 	queue = instance_lookup(q, queue_num);
 	if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
@@ -1138,7 +1127,9 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 		goto err_out_unlock;
 	}
 
-	if (cmd != NULL) {
+	if (nfqa[NFQA_CFG_CMD]) {
+		struct nfqnl_msg_config_cmd *cmd = nla_data(nfqa[NFQA_CFG_CMD]);
+
 		switch (cmd->command) {
 		case NFQNL_CFG_CMD_BIND:
 			if (queue) {
@@ -1161,7 +1152,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 			break;
 		case NFQNL_CFG_CMD_PF_BIND:
 		case NFQNL_CFG_CMD_PF_UNBIND:
-			break;
+			/* Obsolete commands without queue context */
+			goto err_out_unlock;
 		default:
 			ret = -ENOTSUPP;
 			break;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next 2/3] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity
  2015-11-06  0:46                     ` Ken-ichirou MATSUZAWA
  2015-11-06  0:49                       ` [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling Ken-ichirou MATSUZAWA
@ 2015-11-06  0:56                       ` Ken-ichirou MATSUZAWA
  2015-11-06  0:58                       ` [PATCH nf-next 3/3] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
  2 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-11-06  0:56 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Check that dependencies are fulfilled before updating the queue
instance, otherwise we can leave things in intermediate state on errors
in nfqnl_recv_config(). This patch also fixes unknown and destroy
command handling.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |   74 +++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 42 deletions(-)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index f85a3d3..98c9edc 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1118,8 +1118,30 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 	struct nfqnl_instance *queue;
 	struct net *net = sock_net(ctnl);
 	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+	__u32 flags, mask;
 	int ret = 0;
 
+	/* Check if we support these flags in first place, dependencies should
+	 * be there too not to break atomicity.
+	 */
+	if (nfqa[NFQA_CFG_FLAGS]) {
+		if (!nfqa[NFQA_CFG_MASK])
+			/* A mask is needed to specify which flags are being
+			 * changed.
+			 */
+			return -EINVAL;
+
+		flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
+		mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
+
+		if (flags >= NFQA_CFG_F_MAX)
+			return -EOPNOTSUPP;
+#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
+		if (flags & mask & NFQA_CFG_F_SECCTX)
+			return -EOPNOTSUPP;
+#endif
+	}
+
 	rcu_read_lock();
 	queue = instance_lookup(q, queue_num);
 	if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
@@ -1149,71 +1171,39 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 				goto err_out_unlock;
 			}
 			instance_destroy(q, queue);
-			break;
+			goto err_out_unlock;
 		case NFQNL_CFG_CMD_PF_BIND:
 		case NFQNL_CFG_CMD_PF_UNBIND:
 			/* Obsolete commands without queue context */
 			goto err_out_unlock;
 		default:
 			ret = -ENOTSUPP;
-			break;
+			goto err_out_unlock;
 		}
 	}
 
+	if (!queue) {
+		ret = -ENODEV;
+		goto err_out_unlock;
+	}
+
 	if (nfqa[NFQA_CFG_PARAMS]) {
-		struct nfqnl_msg_config_params *params;
+		struct nfqnl_msg_config_params *params
+			= nla_data(nfqa[NFQA_CFG_PARAMS]);
 
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		params = nla_data(nfqa[NFQA_CFG_PARAMS]);
 		nfqnl_set_mode(queue, params->copy_mode,
 				ntohl(params->copy_range));
 	}
 
 	if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
-		__be32 *queue_maxlen;
+		__be32 *queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
 
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
 		spin_lock_bh(&queue->lock);
 		queue->queue_maxlen = ntohl(*queue_maxlen);
 		spin_unlock_bh(&queue->lock);
 	}
 
 	if (nfqa[NFQA_CFG_FLAGS]) {
-		__u32 flags, mask;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-
-		if (!nfqa[NFQA_CFG_MASK]) {
-			/* A mask is needed to specify which flags are being
-			 * changed.
-			 */
-			ret = -EINVAL;
-			goto err_out_unlock;
-		}
-
-		flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
-		mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
-
-		if (flags >= NFQA_CFG_F_MAX) {
-			ret = -EOPNOTSUPP;
-			goto err_out_unlock;
-		}
-#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
-		if (flags & mask & NFQA_CFG_F_SECCTX) {
-			ret = -EOPNOTSUPP;
-			goto err_out_unlock;
-		}
-#endif
 		spin_lock_bh(&queue->lock);
 		queue->flags &= ~mask;
 		queue->flags |= flags & mask;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next 3/3] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag
  2015-11-06  0:46                     ` Ken-ichirou MATSUZAWA
  2015-11-06  0:49                       ` [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling Ken-ichirou MATSUZAWA
  2015-11-06  0:56                       ` [PATCH nf-next 2/3] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity Ken-ichirou MATSUZAWA
@ 2015-11-06  0:58                       ` Ken-ichirou MATSUZAWA
  2 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2015-11-06  0:58 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch enables to load nf_conntrack_netlink module if
NFQA_CFG_F_CONNTRACK config flag is specified.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 98c9edc..d990c81 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1140,6 +1140,17 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 		if (flags & mask & NFQA_CFG_F_SECCTX)
 			return -EOPNOTSUPP;
 #endif
+		if ((flags & mask & NFQA_CFG_F_CONNTRACK) &&
+		    !rcu_access_pointer(nfnl_ct_hook)) {
+#ifdef CONFIG_MODULES
+			nfnl_unlock(NFNL_SUBSYS_QUEUE);
+			request_module("ip_conntrack_netlink");
+			nfnl_lock(NFNL_SUBSYS_QUEUE);
+			if (rcu_access_pointer(nfnl_ct_hook))
+				return -EAGAIN;
+#endif
+			return -EOPNOTSUPP;
+		}
 	}
 
 	rcu_read_lock();
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling
  2015-11-06  0:49                       ` [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling Ken-ichirou MATSUZAWA
@ 2015-11-08 22:14                         ` Pablo Neira Ayuso
  2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
  0 siblings, 1 reply; 32+ messages in thread
From: Pablo Neira Ayuso @ 2015-11-08 22:14 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Fri, Nov 06, 2015 at 09:49:47AM +0900, Ken-ichirou MATSUZAWA wrote:
> Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
> ---
>  net/netfilter/nfnetlink_queue.c |   18 +++++-------------
>  1 file changed, 5 insertions(+), 13 deletions(-)
> 
> diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
> index 7d81d28..f85a3d3 100644
> --- a/net/netfilter/nfnetlink_queue.c
> +++ b/net/netfilter/nfnetlink_queue.c
> @@ -1116,21 +1116,10 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
>  	struct nfgenmsg *nfmsg = nlmsg_data(nlh);
>  	u_int16_t queue_num = ntohs(nfmsg->res_id);
>  	struct nfqnl_instance *queue;
> -	struct nfqnl_msg_config_cmd *cmd = NULL;
>  	struct net *net = sock_net(ctnl);
>  	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
>  	int ret = 0;
>  
> -	if (nfqa[NFQA_CFG_CMD]) {
> -		cmd = nla_data(nfqa[NFQA_CFG_CMD]);
> -
> -		/* Obsolete commands without queue context */
> -		switch (cmd->command) {
> -		case NFQNL_CFG_CMD_PF_BIND: return 0;
> -		case NFQNL_CFG_CMD_PF_UNBIND: return 0;
> -		}
> -	}
> -

Thanks for following up on this Ken-ichirou.

However, I suspect this is wrong:

commit 0360ae412d09bc6f4864c801effcb20bfd84520e
Author: Florian Westphal <fw@strlen.de>
Date:   Fri Nov 23 06:22:21 2012 +0000

    netfilter: kill support for per-af queue backends

The former behaviour before Florian's patch is that
NFQNL_CFG_CMD_PF_BIND and NFQNL_CFG_CMD_PF_UNBIND are terminal.

This code is there not to break backward compatibility, ie. old
userspace that rely on these commands.

After this patch, we inspect if there is an existing queue for this,
which was not happening before.

As I said, my concerns go in the direction of possible breakage of old
code, we shouldn't break backward.

Let me know, thanks.

>  	rcu_read_lock();
>  	queue = instance_lookup(q, queue_num);
>  	if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling
  2015-11-08 22:14                         ` Pablo Neira Ayuso
@ 2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
  2016-01-05  0:28                             ` [PATCH nf-next 1/5] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity Ken-ichirou MATSUZAWA
                                               ` (4 more replies)
  0 siblings, 5 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2016-01-05  0:24 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Sorry for being late often.

On Sun, Nov 08, 2015 at 11:14:54PM +0100, Pablo Neira Ayuso wrote:
> commit 0360ae412d09bc6f4864c801effcb20bfd84520e
> Author: Florian Westphal <fw@strlen.de>
> Date:   Fri Nov 23 06:22:21 2012 +0000
> 
>     netfilter: kill support for per-af queue backends
> 
> The former behaviour before Florian's patch is that
> NFQNL_CFG_CMD_PF_BIND and NFQNL_CFG_CMD_PF_UNBIND are terminal.
> 
> This code is there not to break backward compatibility, ie. old
> userspace that rely on these commands.
> 
> After this patch, we inspect if there is an existing queue for this,
> which was not happening before.

I tried to follow your advice, would you see again?

> As I said, my concerns go in the direction of possible breakage of old
> code, we shouldn't break backward.

I'm worry about appended patches 3/5 and 5/5 may not follow it.
After these patches applied, userspace can not update instance's
options with invalid command. is it acceptable?

Thanks,


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH nf-next 1/5] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity
  2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
@ 2016-01-05  0:28                             ` Ken-ichirou MATSUZAWA
  2016-01-05  0:29                             ` [PATCH nf-next 2/5] netfilter: nfnetlink_queue: not handle options after unbind Ken-ichirou MATSUZAWA
                                               ` (3 subsequent siblings)
  4 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2016-01-05  0:28 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Check that dependencies are fulfilled before updating the queue
instance, otherwise we can leave things in intermediate state on errors
in nfqnl_recv_config().

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |   74 +++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 42 deletions(-)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 3d1f16c..a4ae731 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1113,6 +1113,7 @@ static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
 	struct nfqnl_instance *queue;
 	struct nfqnl_msg_config_cmd *cmd = NULL;
 	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+	__u32 flags = 0, mask = 0;
 	int ret = 0;
 
 	if (nfqa[NFQA_CFG_CMD]) {
@@ -1125,6 +1126,29 @@ static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
 		}
 	}
 
+	/* Check if we support these flags in first place, dependencies should
+	 * be there too not to break atomicity.
+	 */
+	if (nfqa[NFQA_CFG_FLAGS]) {
+		if (!nfqa[NFQA_CFG_MASK]) {
+			/* A mask is needed to specify which flags are being
+			 * changed.
+			 */
+			return -EINVAL;
+		}
+
+		flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
+		mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
+
+		if (flags >= NFQA_CFG_F_MAX)
+			return -EOPNOTSUPP;
+
+#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
+		if (flags & mask & NFQA_CFG_F_SECCTX)
+			return -EOPNOTSUPP;
+#endif
+	}
+
 	rcu_read_lock();
 	queue = instance_lookup(q, queue_num);
 	if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
@@ -1162,60 +1186,26 @@ static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
 		}
 	}
 
-	if (nfqa[NFQA_CFG_PARAMS]) {
-		struct nfqnl_msg_config_params *params;
+	if (!queue) {
+		ret = -ENODEV;
+		goto err_out_unlock;
+	}
 
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		params = nla_data(nfqa[NFQA_CFG_PARAMS]);
+	if (nfqa[NFQA_CFG_PARAMS]) {
+		struct nfqnl_msg_config_params *params
+			= nla_data(nfqa[NFQA_CFG_PARAMS]);
 		nfqnl_set_mode(queue, params->copy_mode,
 				ntohl(params->copy_range));
 	}
 
 	if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) {
-		__be32 *queue_maxlen;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-		queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
+		__be32 *queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]);
 		spin_lock_bh(&queue->lock);
 		queue->queue_maxlen = ntohl(*queue_maxlen);
 		spin_unlock_bh(&queue->lock);
 	}
 
 	if (nfqa[NFQA_CFG_FLAGS]) {
-		__u32 flags, mask;
-
-		if (!queue) {
-			ret = -ENODEV;
-			goto err_out_unlock;
-		}
-
-		if (!nfqa[NFQA_CFG_MASK]) {
-			/* A mask is needed to specify which flags are being
-			 * changed.
-			 */
-			ret = -EINVAL;
-			goto err_out_unlock;
-		}
-
-		flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
-		mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
-
-		if (flags >= NFQA_CFG_F_MAX) {
-			ret = -EOPNOTSUPP;
-			goto err_out_unlock;
-		}
-#if !IS_ENABLED(CONFIG_NETWORK_SECMARK)
-		if (flags & mask & NFQA_CFG_F_SECCTX) {
-			ret = -EOPNOTSUPP;
-			goto err_out_unlock;
-		}
-#endif
 		spin_lock_bh(&queue->lock);
 		queue->flags &= ~mask;
 		queue->flags |= flags & mask;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next 2/5] netfilter: nfnetlink_queue: not handle options after unbind
  2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
  2016-01-05  0:28                             ` [PATCH nf-next 1/5] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity Ken-ichirou MATSUZAWA
@ 2016-01-05  0:29                             ` Ken-ichirou MATSUZAWA
  2016-01-05  0:31                             ` [PATCH nf-next 3/5] netfilter: nfnetlink_queue: just returns error for unknown command Ken-ichirou MATSUZAWA
                                               ` (2 subsequent siblings)
  4 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2016-01-05  0:29 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch stops processing after destroying a queue instance.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a4ae731..ca00a98 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1176,7 +1176,7 @@ static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
 				goto err_out_unlock;
 			}
 			instance_destroy(q, queue);
-			break;
+			goto err_out_unlock;
 		case NFQNL_CFG_CMD_PF_BIND:
 		case NFQNL_CFG_CMD_PF_UNBIND:
 			break;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next 3/5] netfilter: nfnetlink_queue: just returns error for unknown command
  2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
  2016-01-05  0:28                             ` [PATCH nf-next 1/5] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity Ken-ichirou MATSUZAWA
  2016-01-05  0:29                             ` [PATCH nf-next 2/5] netfilter: nfnetlink_queue: not handle options after unbind Ken-ichirou MATSUZAWA
@ 2016-01-05  0:31                             ` Ken-ichirou MATSUZAWA
  2016-01-05  0:32                             ` [PATCH nf-next 4/5] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
  2016-01-05  0:34                             ` [PATCH nf-next 5/5] netfilter: nfnetlink_log: just returns error for unknown command Ken-ichirou MATSUZAWA
  4 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2016-01-05  0:31 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch stops processing options for unknown command.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index ca00a98..c5cd50c 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1182,7 +1182,7 @@ static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
 			break;
 		default:
 			ret = -ENOTSUPP;
-			break;
+			goto err_out_unlock;
 		}
 	}
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next 4/5] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag
  2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
                                               ` (2 preceding siblings ...)
  2016-01-05  0:31                             ` [PATCH nf-next 3/5] netfilter: nfnetlink_queue: just returns error for unknown command Ken-ichirou MATSUZAWA
@ 2016-01-05  0:32                             ` Ken-ichirou MATSUZAWA
  2016-01-05  0:34                             ` [PATCH nf-next 5/5] netfilter: nfnetlink_log: just returns error for unknown command Ken-ichirou MATSUZAWA
  4 siblings, 0 replies; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2016-01-05  0:32 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch enables to load nf_conntrack_netlink module if
NFQA_CFG_F_CONNTRACK config flag is specified.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_queue.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index c5cd50c..6168984 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1147,6 +1147,17 @@ static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
 		if (flags & mask & NFQA_CFG_F_SECCTX)
 			return -EOPNOTSUPP;
 #endif
+		if ((flags & mask & NFQA_CFG_F_CONNTRACK) &&
+		    !rcu_access_pointer(nfnl_ct_hook)) {
+#ifdef CONFIG_MODULES
+			nfnl_unlock(NFNL_SUBSYS_QUEUE);
+			request_module("ip_conntrack_netlink");
+			nfnl_lock(NFNL_SUBSYS_QUEUE);
+			if (rcu_access_pointer(nfnl_ct_hook))
+				return -EAGAIN;
+#endif
+			return -EOPNOTSUPP;
+		}
 	}
 
 	rcu_read_lock();
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH nf-next 5/5] netfilter: nfnetlink_log: just returns error for unknown command
  2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
                                               ` (3 preceding siblings ...)
  2016-01-05  0:32                             ` [PATCH nf-next 4/5] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
@ 2016-01-05  0:34                             ` Ken-ichirou MATSUZAWA
  2016-01-05 11:03                               ` Pablo Neira Ayuso
  4 siblings, 1 reply; 32+ messages in thread
From: Ken-ichirou MATSUZAWA @ 2016-01-05  0:34 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch stops processing options for unknown command.

Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
---
 net/netfilter/nfnetlink_log.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 6a57f10..643c2d3 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -888,7 +888,9 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
 			goto out_put;
 		default:
 			ret = -ENOTSUPP;
-			break;
+			if (inst)
+				goto out_put;
+			goto out;
 		}
 	} else if (!inst) {
 		ret = -ENODEV;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH nf-next 5/5] netfilter: nfnetlink_log: just returns error for unknown command
  2016-01-05  0:34                             ` [PATCH nf-next 5/5] netfilter: nfnetlink_log: just returns error for unknown command Ken-ichirou MATSUZAWA
@ 2016-01-05 11:03                               ` Pablo Neira Ayuso
  0 siblings, 0 replies; 32+ messages in thread
From: Pablo Neira Ayuso @ 2016-01-05 11:03 UTC (permalink / raw)
  To: Ken-ichirou MATSUZAWA; +Cc: netfilter-devel

On Tue, Jan 05, 2016 at 09:34:34AM +0900, Ken-ichirou MATSUZAWA wrote:
> This patch stops processing options for unknown command.
> 
> Signed-off-by: Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
> ---
>  net/netfilter/nfnetlink_log.c |    4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
> index 6a57f10..643c2d3 100644
> --- a/net/netfilter/nfnetlink_log.c
> +++ b/net/netfilter/nfnetlink_log.c
> @@ -888,7 +888,9 @@ static int nfulnl_recv_config(struct net *net, struct sock *ctnl,
>  			goto out_put;
>  		default:
>  			ret = -ENOTSUPP;
> -			break;
> +			if (inst)
> +				goto out_put;
> +			goto out;

We can simplify this to:

                        goto out_put;

since instance_put() already checks if inst is non-null.

No need to resend, I'll fix this here.

Thanks a lot for following up on this series Ken-ichirou :-).

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2016-01-05 11:04 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-01 18:43 [PATCH 1/2 v3] netfilter: nfnetlink_queue: get rid of nfnetlink_queue_ct.c Pablo Neira Ayuso
2015-10-01 18:43 ` [PATCH 2/2 v3] netfilter: rename nfnetlink_queue_core.c to nfnetlink_queue.c Pablo Neira Ayuso
2015-10-05  2:44   ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Ken-ichirou MATSUZAWA
2015-10-05  2:47     ` [PATCHv2 nf-next 1/4] netfilter: nfnetlink_queue: rename related to nfqueue attaching conntrack info Ken-ichirou MATSUZAWA
2015-10-05  2:48     ` [PATCHv2 nf-next 2/4] netfilter: Kconfig rename QUEUE_CT to GLUE_CT Ken-ichirou MATSUZAWA
2015-10-05  2:49     ` [PATCHv2 nf-next 3/4] netfilter: nf_conntrack_netlink: add const qualifier to nfnl_hook.get_ct Ken-ichirou MATSUZAWA
2015-10-05  2:50     ` [PATCHv2 nf-next 4/4] netfilter: nfnetlink_log: allow to attach conntrack Ken-ichirou MATSUZAWA
2015-10-05 15:23       ` Pablo Neira Ayuso
2015-10-06  2:10         ` [PATCHv2 nf-next 0/1] netfilter: nfnetlink_queue: check NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
2015-10-06  2:12           ` [PATCHv2 nf-next 1/1] " Ken-ichirou MATSUZAWA
2015-10-06 10:07             ` Pablo Neira Ayuso
2015-10-07  4:20               ` Ken-ichirou MATSUZAWA
2015-10-07  4:23                 ` [PATCHv3 nf-next] " Ken-ichirou MATSUZAWA
2015-10-07  4:25                 ` [PATCH nf-next] netfilter: nfnetlink_log: autoload nf_conntrack_netlink module " Ken-ichirou MATSUZAWA
2015-10-12 17:13                   ` Pablo Neira Ayuso
2015-10-12 20:10                     ` Pablo Neira Ayuso
2015-10-16 17:05                   ` Pablo Neira Ayuso
2015-11-06  0:46                     ` Ken-ichirou MATSUZAWA
2015-11-06  0:49                       ` [PATCH nf-next 1/3] netfilter: nfnetlink_queue: remove duplicated obsolete commands handling Ken-ichirou MATSUZAWA
2015-11-08 22:14                         ` Pablo Neira Ayuso
2016-01-05  0:24                           ` Ken-ichirou MATSUZAWA
2016-01-05  0:28                             ` [PATCH nf-next 1/5] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity Ken-ichirou MATSUZAWA
2016-01-05  0:29                             ` [PATCH nf-next 2/5] netfilter: nfnetlink_queue: not handle options after unbind Ken-ichirou MATSUZAWA
2016-01-05  0:31                             ` [PATCH nf-next 3/5] netfilter: nfnetlink_queue: just returns error for unknown command Ken-ichirou MATSUZAWA
2016-01-05  0:32                             ` [PATCH nf-next 4/5] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
2016-01-05  0:34                             ` [PATCH nf-next 5/5] netfilter: nfnetlink_log: just returns error for unknown command Ken-ichirou MATSUZAWA
2016-01-05 11:03                               ` Pablo Neira Ayuso
2015-11-06  0:56                       ` [PATCH nf-next 2/3] netfilter: nfnetlink_queue: validate dependencies to avoid breaking atomicity Ken-ichirou MATSUZAWA
2015-11-06  0:58                       ` [PATCH nf-next 3/3] netfilter: nfnetlink_queue: autoload nf_conntrack_netlink module NFQA_CFG_F_CONNTRACK config flag Ken-ichirou MATSUZAWA
2015-10-07  4:27                 ` [PATCH nf-next] netfilter: nf_conntrack_netlink: fix nf-nat module loaded checking Ken-ichirou MATSUZAWA
2015-10-07  4:30                 ` [PATCH nf-next] netfilter: nf_conntrack_netlink: fix locks around helper module loading Ken-ichirou MATSUZAWA
2015-10-05 15:33     ` [PATCHv2 nf-next 0/4] netfilter: nfnetlink_log attach conntrack information Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.