netfilter: possible unaligned packet header in ip_route_me_harder
[linux-block.git] / include / net / netfilter / nf_conntrack_ecache.h
CommitLineData
f6180121
MJ
1/*
2 * connection tracking event cache.
3 */
4
5#ifndef _NF_CONNTRACK_ECACHE_H
6#define _NF_CONNTRACK_ECACHE_H
7#include <net/netfilter/nf_conntrack.h>
8
6058fa6b 9#include <net/net_namespace.h>
f6180121 10#include <net/netfilter/nf_conntrack_expect.h>
a0891aa6
PNA
11#include <linux/netfilter/nf_conntrack_common.h>
12#include <linux/netfilter/nf_conntrack_tuple_common.h>
13#include <net/netfilter/nf_conntrack_extend.h>
f6180121 14
a0891aa6 15struct nf_conntrack_ecache {
0cebe4b4
PM
16 unsigned long cache; /* bitops want long */
17 unsigned long missed; /* missed events */
18 u16 ctmask; /* bitmask of ct events to be delivered */
19 u16 expmask; /* bitmask of expect events to be delivered */
20 u32 pid; /* netlink pid of destroyer */
a0891aa6 21};
6bfea198 22
a0891aa6
PNA
23static inline struct nf_conntrack_ecache *
24nf_ct_ecache_find(const struct nf_conn *ct)
25{
e0e76c83 26#ifdef CONFIG_NF_CONNTRACK_EVENTS
a0891aa6 27 return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE);
e0e76c83
CG
28#else
29 return NULL;
30#endif
a0891aa6 31}
6bfea198 32
a0891aa6 33static inline struct nf_conntrack_ecache *
0cebe4b4 34nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
a0891aa6 35{
e0e76c83 36#ifdef CONFIG_NF_CONNTRACK_EVENTS
a0891aa6 37 struct net *net = nf_ct_net(ct);
0cebe4b4 38 struct nf_conntrack_ecache *e;
6bfea198 39
0cebe4b4
PM
40 if (!ctmask && !expmask && net->ct.sysctl_events) {
41 ctmask = ~0;
42 expmask = ~0;
43 }
44 if (!ctmask && !expmask)
a0891aa6 45 return NULL;
6bfea198 46
0cebe4b4
PM
47 e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
48 if (e) {
49 e->ctmask = ctmask;
50 e->expmask = expmask;
51 }
52 return e;
e0e76c83
CG
53#else
54 return NULL;
55#endif
6bfea198
PNA
56};
57
f6180121 58#ifdef CONFIG_NF_CONNTRACK_EVENTS
19abb7b0
PNA
59/* This structure is passed to event handler */
60struct nf_ct_event {
61 struct nf_conn *ct;
62 u32 pid;
63 int report;
64};
65
e34d5c1a
PNA
66struct nf_ct_event_notifier {
67 int (*fcn)(unsigned int events, struct nf_ct_event *item);
68};
69
0e60ebe0 70extern struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
e34d5c1a
PNA
71extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb);
72extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb);
f6180121 73
a0891aa6 74extern void nf_ct_deliver_cached_events(struct nf_conn *ct);
f6180121
MJ
75
76static inline void
a71996fc 77nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
f6180121 78{
a0891aa6
PNA
79 struct nf_conntrack_ecache *e;
80
81 if (nf_conntrack_event_cb == NULL)
82 return;
83
84 e = nf_ct_ecache_find(ct);
85 if (e == NULL)
86 return;
87
88 set_bit(event, &e->cache);
f6180121
MJ
89}
90
dd7669a9 91static inline int
a0891aa6
PNA
92nf_conntrack_eventmask_report(unsigned int eventmask,
93 struct nf_conn *ct,
94 u32 pid,
95 int report)
f6180121 96{
dd7669a9 97 int ret = 0;
e34d5c1a 98 struct nf_ct_event_notifier *notify;
dd7669a9 99 struct nf_conntrack_ecache *e;
e34d5c1a
PNA
100
101 rcu_read_lock();
102 notify = rcu_dereference(nf_conntrack_event_cb);
103 if (notify == NULL)
104 goto out_unlock;
105
dd7669a9
PNA
106 e = nf_ct_ecache_find(ct);
107 if (e == NULL)
108 goto out_unlock;
109
e34d5c1a
PNA
110 if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) {
111 struct nf_ct_event item = {
112 .ct = ct,
dd7669a9 113 .pid = e->pid ? e->pid : pid,
e34d5c1a
PNA
114 .report = report
115 };
dd7669a9
PNA
116 /* This is a resent of a destroy event? If so, skip missed */
117 unsigned long missed = e->pid ? 0 : e->missed;
118
0cebe4b4
PM
119 if (!((eventmask | missed) & e->ctmask))
120 goto out_unlock;
121
dd7669a9
PNA
122 ret = notify->fcn(eventmask | missed, &item);
123 if (unlikely(ret < 0 || missed)) {
124 spin_lock_bh(&ct->lock);
125 if (ret < 0) {
126 /* This is a destroy event that has been
127 * triggered by a process, we store the PID
128 * to include it in the retransmission. */
129 if (eventmask & (1 << IPCT_DESTROY) &&
130 e->pid == 0 && pid != 0)
131 e->pid = pid;
132 else
133 e->missed |= eventmask;
134 } else
135 e->missed &= ~missed;
136 spin_unlock_bh(&ct->lock);
137 }
e34d5c1a
PNA
138 }
139out_unlock:
140 rcu_read_unlock();
dd7669a9 141 return ret;
f6180121
MJ
142}
143
dd7669a9 144static inline int
a0891aa6
PNA
145nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
146 u32 pid, int report)
147{
dd7669a9 148 return nf_conntrack_eventmask_report(1 << event, ct, pid, report);
a0891aa6
PNA
149}
150
dd7669a9 151static inline int
19abb7b0
PNA
152nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
153{
dd7669a9 154 return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
19abb7b0
PNA
155}
156
157struct nf_exp_event {
158 struct nf_conntrack_expect *exp;
159 u32 pid;
160 int report;
161};
162
e34d5c1a
PNA
163struct nf_exp_event_notifier {
164 int (*fcn)(unsigned int events, struct nf_exp_event *item);
165};
166
0e60ebe0 167extern struct nf_exp_event_notifier __rcu *nf_expect_event_cb;
e34d5c1a
PNA
168extern int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *nb);
169extern void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *nb);
010c7d6f 170
19abb7b0
PNA
171static inline void
172nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
173 struct nf_conntrack_expect *exp,
174 u32 pid,
175 int report)
176{
e34d5c1a 177 struct nf_exp_event_notifier *notify;
0cebe4b4 178 struct nf_conntrack_ecache *e;
e34d5c1a
PNA
179
180 rcu_read_lock();
181 notify = rcu_dereference(nf_expect_event_cb);
182 if (notify == NULL)
183 goto out_unlock;
184
0cebe4b4
PM
185 e = nf_ct_ecache_find(exp->master);
186 if (e == NULL)
a0891aa6
PNA
187 goto out_unlock;
188
0cebe4b4 189 if (e->expmask & (1 << event)) {
e34d5c1a
PNA
190 struct nf_exp_event item = {
191 .exp = exp,
192 .pid = pid,
193 .report = report
194 };
a0891aa6 195 notify->fcn(1 << event, &item);
e34d5c1a
PNA
196 }
197out_unlock:
198 rcu_read_unlock();
19abb7b0
PNA
199}
200
f6180121 201static inline void
6823645d
PM
202nf_ct_expect_event(enum ip_conntrack_expect_events event,
203 struct nf_conntrack_expect *exp)
f6180121 204{
19abb7b0 205 nf_ct_expect_event_report(event, exp, 0, 0);
f6180121
MJ
206}
207
6058fa6b
AD
208extern int nf_conntrack_ecache_init(struct net *net);
209extern void nf_conntrack_ecache_fini(struct net *net);
210
f6180121
MJ
211#else /* CONFIG_NF_CONNTRACK_EVENTS */
212
213static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
64f1b653 214 struct nf_conn *ct) {}
dd7669a9
PNA
215static inline int nf_conntrack_eventmask_report(unsigned int eventmask,
216 struct nf_conn *ct,
217 u32 pid,
218 int report) { return 0; }
219static inline int nf_conntrack_event(enum ip_conntrack_events event,
220 struct nf_conn *ct) { return 0; }
221static inline int nf_conntrack_event_report(enum ip_conntrack_events event,
222 struct nf_conn *ct,
223 u32 pid,
224 int report) { return 0; }
f6180121 225static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
6823645d
PM
226static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
227 struct nf_conntrack_expect *exp) {}
19abb7b0
PNA
228static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e,
229 struct nf_conntrack_expect *exp,
230 u32 pid,
231 int report) {}
6058fa6b
AD
232
233static inline int nf_conntrack_ecache_init(struct net *net)
234{
235 return 0;
bb21c95e 236}
6058fa6b
AD
237
238static inline void nf_conntrack_ecache_fini(struct net *net)
239{
240}
f6180121
MJ
241#endif /* CONFIG_NF_CONNTRACK_EVENTS */
242
243#endif /*_NF_CONNTRACK_ECACHE_H*/
244