1/*
2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/skbuff.h>
11#include <linux/netfilter.h>
12#include <linux/netfilter/nfnetlink.h>
13#include <linux/netfilter/nfnetlink_queue.h>
14#include <net/netfilter/nf_conntrack.h>
15#include <net/netfilter/nfnetlink_queue.h>
16
17struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size,
18			     enum ip_conntrack_info *ctinfo)
19{
20	struct nfq_ct_hook *nfq_ct;
21	struct nf_conn *ct;
22
23	/* rcu_read_lock()ed by __nf_queue already. */
24	nfq_ct = rcu_dereference(nfq_ct_hook);
25	if (nfq_ct == NULL)
26		return NULL;
27
28	ct = nf_ct_get(entskb, ctinfo);
29	if (ct) {
30		if (!nf_ct_is_untracked(ct))
31			*size += nfq_ct->build_size(ct);
32		else
33			ct = NULL;
34	}
35	return ct;
36}
37
38struct nf_conn *
39nfqnl_ct_parse(const struct sk_buff *skb, const struct nlattr *attr,
40	       enum ip_conntrack_info *ctinfo)
41{
42	struct nfq_ct_hook *nfq_ct;
43	struct nf_conn *ct;
44
45	/* rcu_read_lock()ed by __nf_queue already. */
46	nfq_ct = rcu_dereference(nfq_ct_hook);
47	if (nfq_ct == NULL)
48		return NULL;
49
50	ct = nf_ct_get(skb, ctinfo);
51	if (ct && !nf_ct_is_untracked(ct))
52		nfq_ct->parse(attr, ct);
53
54	return ct;
55}
56
57int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct,
58		 enum ip_conntrack_info ctinfo)
59{
60	struct nfq_ct_hook *nfq_ct;
61	struct nlattr *nest_parms;
62	u_int32_t tmp;
63
64	nfq_ct = rcu_dereference(nfq_ct_hook);
65	if (nfq_ct == NULL)
66		return 0;
67
68	nest_parms = nla_nest_start(skb, NFQA_CT | NLA_F_NESTED);
69	if (!nest_parms)
70		goto nla_put_failure;
71
72	if (nfq_ct->build(skb, ct) < 0)
73		goto nla_put_failure;
74
75	nla_nest_end(skb, nest_parms);
76
77	tmp = ctinfo;
78	if (nla_put_be32(skb, NFQA_CT_INFO, htonl(tmp)))
79		goto nla_put_failure;
80
81	return 0;
82
83nla_put_failure:
84	return -1;
85}
86
87void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct,
88			 enum ip_conntrack_info ctinfo, int diff)
89{
90	struct nfq_ct_hook *nfq_ct;
91
92	nfq_ct = rcu_dereference(nfq_ct_hook);
93	if (nfq_ct == NULL)
94		return;
95
96	if ((ct->status & IPS_NAT_MASK) && diff)
97		nfq_ct->seq_adjust(skb, ct, ctinfo, diff);
98}
99
100int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,
101			u32 portid, u32 report)
102{
103	struct nfq_ct_hook *nfq_ct;
104
105	if (nf_ct_is_untracked(ct))
106		return 0;
107
108	nfq_ct = rcu_dereference(nfq_ct_hook);
109	if (nfq_ct == NULL)
110		return -EOPNOTSUPP;
111
112	return nfq_ct->attach_expect(attr, ct, portid, report);
113}
114