1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * xfrm_state.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Changes:
6*4882a593Smuzhiyun * Mitsuru KANDA @USAGI
7*4882a593Smuzhiyun * Kazunori MIYAZAWA @USAGI
8*4882a593Smuzhiyun * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
9*4882a593Smuzhiyun * IPv6 support
10*4882a593Smuzhiyun * YOSHIFUJI Hideaki @USAGI
11*4882a593Smuzhiyun * Split up af-specific functions
12*4882a593Smuzhiyun * Derek Atkins <derek@ihtfp.com>
13*4882a593Smuzhiyun * Add UDP Encapsulation
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/workqueue.h>
18*4882a593Smuzhiyun #include <net/xfrm.h>
19*4882a593Smuzhiyun #include <linux/pfkeyv2.h>
20*4882a593Smuzhiyun #include <linux/ipsec.h>
21*4882a593Smuzhiyun #include <linux/module.h>
22*4882a593Smuzhiyun #include <linux/cache.h>
23*4882a593Smuzhiyun #include <linux/audit.h>
24*4882a593Smuzhiyun #include <linux/uaccess.h>
25*4882a593Smuzhiyun #include <linux/ktime.h>
26*4882a593Smuzhiyun #include <linux/slab.h>
27*4882a593Smuzhiyun #include <linux/interrupt.h>
28*4882a593Smuzhiyun #include <linux/kernel.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include <crypto/aead.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include "xfrm_hash.h"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define xfrm_state_deref_prot(table, net) \
35*4882a593Smuzhiyun rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock))
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static void xfrm_state_gc_task(struct work_struct *work);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /* Each xfrm_state may be linked to two tables:
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
42*4882a593Smuzhiyun 2. Hash table by (daddr,family,reqid) to find what SAs exist for given
43*4882a593Smuzhiyun destination/tunnel endpoint. (output)
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
47*4882a593Smuzhiyun static struct kmem_cache *xfrm_state_cache __ro_after_init;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task);
50*4882a593Smuzhiyun static HLIST_HEAD(xfrm_state_gc_list);
51*4882a593Smuzhiyun
xfrm_state_hold_rcu(struct xfrm_state __rcu * x)52*4882a593Smuzhiyun static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun return refcount_inc_not_zero(&x->refcnt);
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
xfrm_dst_hash(struct net * net,const xfrm_address_t * daddr,const xfrm_address_t * saddr,u32 reqid,unsigned short family)57*4882a593Smuzhiyun static inline unsigned int xfrm_dst_hash(struct net *net,
58*4882a593Smuzhiyun const xfrm_address_t *daddr,
59*4882a593Smuzhiyun const xfrm_address_t *saddr,
60*4882a593Smuzhiyun u32 reqid,
61*4882a593Smuzhiyun unsigned short family)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
xfrm_src_hash(struct net * net,const xfrm_address_t * daddr,const xfrm_address_t * saddr,unsigned short family)66*4882a593Smuzhiyun static inline unsigned int xfrm_src_hash(struct net *net,
67*4882a593Smuzhiyun const xfrm_address_t *daddr,
68*4882a593Smuzhiyun const xfrm_address_t *saddr,
69*4882a593Smuzhiyun unsigned short family)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun static inline unsigned int
xfrm_spi_hash(struct net * net,const xfrm_address_t * daddr,__be32 spi,u8 proto,unsigned short family)75*4882a593Smuzhiyun xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr,
76*4882a593Smuzhiyun __be32 spi, u8 proto, unsigned short family)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
xfrm_hash_transfer(struct hlist_head * list,struct hlist_head * ndsttable,struct hlist_head * nsrctable,struct hlist_head * nspitable,unsigned int nhashmask)81*4882a593Smuzhiyun static void xfrm_hash_transfer(struct hlist_head *list,
82*4882a593Smuzhiyun struct hlist_head *ndsttable,
83*4882a593Smuzhiyun struct hlist_head *nsrctable,
84*4882a593Smuzhiyun struct hlist_head *nspitable,
85*4882a593Smuzhiyun unsigned int nhashmask)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun struct hlist_node *tmp;
88*4882a593Smuzhiyun struct xfrm_state *x;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun hlist_for_each_entry_safe(x, tmp, list, bydst) {
91*4882a593Smuzhiyun unsigned int h;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
94*4882a593Smuzhiyun x->props.reqid, x->props.family,
95*4882a593Smuzhiyun nhashmask);
96*4882a593Smuzhiyun hlist_add_head_rcu(&x->bydst, ndsttable + h);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
99*4882a593Smuzhiyun x->props.family,
100*4882a593Smuzhiyun nhashmask);
101*4882a593Smuzhiyun hlist_add_head_rcu(&x->bysrc, nsrctable + h);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (x->id.spi) {
104*4882a593Smuzhiyun h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
105*4882a593Smuzhiyun x->id.proto, x->props.family,
106*4882a593Smuzhiyun nhashmask);
107*4882a593Smuzhiyun hlist_add_head_rcu(&x->byspi, nspitable + h);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
xfrm_hash_new_size(unsigned int state_hmask)112*4882a593Smuzhiyun static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
xfrm_hash_resize(struct work_struct * work)117*4882a593Smuzhiyun static void xfrm_hash_resize(struct work_struct *work)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun struct net *net = container_of(work, struct net, xfrm.state_hash_work);
120*4882a593Smuzhiyun struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi;
121*4882a593Smuzhiyun unsigned long nsize, osize;
122*4882a593Smuzhiyun unsigned int nhashmask, ohashmask;
123*4882a593Smuzhiyun int i;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
126*4882a593Smuzhiyun ndst = xfrm_hash_alloc(nsize);
127*4882a593Smuzhiyun if (!ndst)
128*4882a593Smuzhiyun return;
129*4882a593Smuzhiyun nsrc = xfrm_hash_alloc(nsize);
130*4882a593Smuzhiyun if (!nsrc) {
131*4882a593Smuzhiyun xfrm_hash_free(ndst, nsize);
132*4882a593Smuzhiyun return;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun nspi = xfrm_hash_alloc(nsize);
135*4882a593Smuzhiyun if (!nspi) {
136*4882a593Smuzhiyun xfrm_hash_free(ndst, nsize);
137*4882a593Smuzhiyun xfrm_hash_free(nsrc, nsize);
138*4882a593Smuzhiyun return;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
142*4882a593Smuzhiyun write_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun nhashmask = (nsize / sizeof(struct hlist_head)) - 1U;
145*4882a593Smuzhiyun odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net);
146*4882a593Smuzhiyun for (i = net->xfrm.state_hmask; i >= 0; i--)
147*4882a593Smuzhiyun xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nhashmask);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net);
150*4882a593Smuzhiyun ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net);
151*4882a593Smuzhiyun ohashmask = net->xfrm.state_hmask;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun rcu_assign_pointer(net->xfrm.state_bydst, ndst);
154*4882a593Smuzhiyun rcu_assign_pointer(net->xfrm.state_bysrc, nsrc);
155*4882a593Smuzhiyun rcu_assign_pointer(net->xfrm.state_byspi, nspi);
156*4882a593Smuzhiyun net->xfrm.state_hmask = nhashmask;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun write_seqcount_end(&net->xfrm.xfrm_state_hash_generation);
159*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun osize = (ohashmask + 1) * sizeof(struct hlist_head);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun synchronize_rcu();
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun xfrm_hash_free(odst, osize);
166*4882a593Smuzhiyun xfrm_hash_free(osrc, osize);
167*4882a593Smuzhiyun xfrm_hash_free(ospi, osize);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
171*4882a593Smuzhiyun static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun static DEFINE_SPINLOCK(xfrm_state_gc_lock);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun int __xfrm_state_delete(struct xfrm_state *x);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
178*4882a593Smuzhiyun static bool km_is_alive(const struct km_event *c);
179*4882a593Smuzhiyun void km_state_expired(struct xfrm_state *x, int hard, u32 portid);
180*4882a593Smuzhiyun
xfrm_register_type(const struct xfrm_type * type,unsigned short family)181*4882a593Smuzhiyun int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
184*4882a593Smuzhiyun int err = 0;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun if (!afinfo)
187*4882a593Smuzhiyun return -EAFNOSUPPORT;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun #define X(afi, T, name) do { \
190*4882a593Smuzhiyun WARN_ON((afi)->type_ ## name); \
191*4882a593Smuzhiyun (afi)->type_ ## name = (T); \
192*4882a593Smuzhiyun } while (0)
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun switch (type->proto) {
195*4882a593Smuzhiyun case IPPROTO_COMP:
196*4882a593Smuzhiyun X(afinfo, type, comp);
197*4882a593Smuzhiyun break;
198*4882a593Smuzhiyun case IPPROTO_AH:
199*4882a593Smuzhiyun X(afinfo, type, ah);
200*4882a593Smuzhiyun break;
201*4882a593Smuzhiyun case IPPROTO_ESP:
202*4882a593Smuzhiyun X(afinfo, type, esp);
203*4882a593Smuzhiyun break;
204*4882a593Smuzhiyun case IPPROTO_IPIP:
205*4882a593Smuzhiyun X(afinfo, type, ipip);
206*4882a593Smuzhiyun break;
207*4882a593Smuzhiyun case IPPROTO_DSTOPTS:
208*4882a593Smuzhiyun X(afinfo, type, dstopts);
209*4882a593Smuzhiyun break;
210*4882a593Smuzhiyun case IPPROTO_ROUTING:
211*4882a593Smuzhiyun X(afinfo, type, routing);
212*4882a593Smuzhiyun break;
213*4882a593Smuzhiyun case IPPROTO_IPV6:
214*4882a593Smuzhiyun X(afinfo, type, ipip6);
215*4882a593Smuzhiyun break;
216*4882a593Smuzhiyun default:
217*4882a593Smuzhiyun WARN_ON(1);
218*4882a593Smuzhiyun err = -EPROTONOSUPPORT;
219*4882a593Smuzhiyun break;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun #undef X
222*4882a593Smuzhiyun rcu_read_unlock();
223*4882a593Smuzhiyun return err;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_register_type);
226*4882a593Smuzhiyun
xfrm_unregister_type(const struct xfrm_type * type,unsigned short family)227*4882a593Smuzhiyun void xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (unlikely(afinfo == NULL))
232*4882a593Smuzhiyun return;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun #define X(afi, T, name) do { \
235*4882a593Smuzhiyun WARN_ON((afi)->type_ ## name != (T)); \
236*4882a593Smuzhiyun (afi)->type_ ## name = NULL; \
237*4882a593Smuzhiyun } while (0)
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun switch (type->proto) {
240*4882a593Smuzhiyun case IPPROTO_COMP:
241*4882a593Smuzhiyun X(afinfo, type, comp);
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun case IPPROTO_AH:
244*4882a593Smuzhiyun X(afinfo, type, ah);
245*4882a593Smuzhiyun break;
246*4882a593Smuzhiyun case IPPROTO_ESP:
247*4882a593Smuzhiyun X(afinfo, type, esp);
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun case IPPROTO_IPIP:
250*4882a593Smuzhiyun X(afinfo, type, ipip);
251*4882a593Smuzhiyun break;
252*4882a593Smuzhiyun case IPPROTO_DSTOPTS:
253*4882a593Smuzhiyun X(afinfo, type, dstopts);
254*4882a593Smuzhiyun break;
255*4882a593Smuzhiyun case IPPROTO_ROUTING:
256*4882a593Smuzhiyun X(afinfo, type, routing);
257*4882a593Smuzhiyun break;
258*4882a593Smuzhiyun case IPPROTO_IPV6:
259*4882a593Smuzhiyun X(afinfo, type, ipip6);
260*4882a593Smuzhiyun break;
261*4882a593Smuzhiyun default:
262*4882a593Smuzhiyun WARN_ON(1);
263*4882a593Smuzhiyun break;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun #undef X
266*4882a593Smuzhiyun rcu_read_unlock();
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_unregister_type);
269*4882a593Smuzhiyun
xfrm_get_type(u8 proto,unsigned short family)270*4882a593Smuzhiyun static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun const struct xfrm_type *type = NULL;
273*4882a593Smuzhiyun struct xfrm_state_afinfo *afinfo;
274*4882a593Smuzhiyun int modload_attempted = 0;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun retry:
277*4882a593Smuzhiyun afinfo = xfrm_state_get_afinfo(family);
278*4882a593Smuzhiyun if (unlikely(afinfo == NULL))
279*4882a593Smuzhiyun return NULL;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun switch (proto) {
282*4882a593Smuzhiyun case IPPROTO_COMP:
283*4882a593Smuzhiyun type = afinfo->type_comp;
284*4882a593Smuzhiyun break;
285*4882a593Smuzhiyun case IPPROTO_AH:
286*4882a593Smuzhiyun type = afinfo->type_ah;
287*4882a593Smuzhiyun break;
288*4882a593Smuzhiyun case IPPROTO_ESP:
289*4882a593Smuzhiyun type = afinfo->type_esp;
290*4882a593Smuzhiyun break;
291*4882a593Smuzhiyun case IPPROTO_IPIP:
292*4882a593Smuzhiyun type = afinfo->type_ipip;
293*4882a593Smuzhiyun break;
294*4882a593Smuzhiyun case IPPROTO_DSTOPTS:
295*4882a593Smuzhiyun type = afinfo->type_dstopts;
296*4882a593Smuzhiyun break;
297*4882a593Smuzhiyun case IPPROTO_ROUTING:
298*4882a593Smuzhiyun type = afinfo->type_routing;
299*4882a593Smuzhiyun break;
300*4882a593Smuzhiyun case IPPROTO_IPV6:
301*4882a593Smuzhiyun type = afinfo->type_ipip6;
302*4882a593Smuzhiyun break;
303*4882a593Smuzhiyun default:
304*4882a593Smuzhiyun break;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (unlikely(type && !try_module_get(type->owner)))
308*4882a593Smuzhiyun type = NULL;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun rcu_read_unlock();
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun if (!type && !modload_attempted) {
313*4882a593Smuzhiyun request_module("xfrm-type-%d-%d", family, proto);
314*4882a593Smuzhiyun modload_attempted = 1;
315*4882a593Smuzhiyun goto retry;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun return type;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
xfrm_put_type(const struct xfrm_type * type)321*4882a593Smuzhiyun static void xfrm_put_type(const struct xfrm_type *type)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun module_put(type->owner);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
xfrm_register_type_offload(const struct xfrm_type_offload * type,unsigned short family)326*4882a593Smuzhiyun int xfrm_register_type_offload(const struct xfrm_type_offload *type,
327*4882a593Smuzhiyun unsigned short family)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
330*4882a593Smuzhiyun int err = 0;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (unlikely(afinfo == NULL))
333*4882a593Smuzhiyun return -EAFNOSUPPORT;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun switch (type->proto) {
336*4882a593Smuzhiyun case IPPROTO_ESP:
337*4882a593Smuzhiyun WARN_ON(afinfo->type_offload_esp);
338*4882a593Smuzhiyun afinfo->type_offload_esp = type;
339*4882a593Smuzhiyun break;
340*4882a593Smuzhiyun default:
341*4882a593Smuzhiyun WARN_ON(1);
342*4882a593Smuzhiyun err = -EPROTONOSUPPORT;
343*4882a593Smuzhiyun break;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun rcu_read_unlock();
347*4882a593Smuzhiyun return err;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_register_type_offload);
350*4882a593Smuzhiyun
xfrm_unregister_type_offload(const struct xfrm_type_offload * type,unsigned short family)351*4882a593Smuzhiyun void xfrm_unregister_type_offload(const struct xfrm_type_offload *type,
352*4882a593Smuzhiyun unsigned short family)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if (unlikely(afinfo == NULL))
357*4882a593Smuzhiyun return;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun switch (type->proto) {
360*4882a593Smuzhiyun case IPPROTO_ESP:
361*4882a593Smuzhiyun WARN_ON(afinfo->type_offload_esp != type);
362*4882a593Smuzhiyun afinfo->type_offload_esp = NULL;
363*4882a593Smuzhiyun break;
364*4882a593Smuzhiyun default:
365*4882a593Smuzhiyun WARN_ON(1);
366*4882a593Smuzhiyun break;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun rcu_read_unlock();
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_unregister_type_offload);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun static const struct xfrm_type_offload *
xfrm_get_type_offload(u8 proto,unsigned short family,bool try_load)373*4882a593Smuzhiyun xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun const struct xfrm_type_offload *type = NULL;
376*4882a593Smuzhiyun struct xfrm_state_afinfo *afinfo;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun retry:
379*4882a593Smuzhiyun afinfo = xfrm_state_get_afinfo(family);
380*4882a593Smuzhiyun if (unlikely(afinfo == NULL))
381*4882a593Smuzhiyun return NULL;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun switch (proto) {
384*4882a593Smuzhiyun case IPPROTO_ESP:
385*4882a593Smuzhiyun type = afinfo->type_offload_esp;
386*4882a593Smuzhiyun break;
387*4882a593Smuzhiyun default:
388*4882a593Smuzhiyun break;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun if ((type && !try_module_get(type->owner)))
392*4882a593Smuzhiyun type = NULL;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun rcu_read_unlock();
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun if (!type && try_load) {
397*4882a593Smuzhiyun request_module("xfrm-offload-%d-%d", family, proto);
398*4882a593Smuzhiyun try_load = false;
399*4882a593Smuzhiyun goto retry;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return type;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
xfrm_put_type_offload(const struct xfrm_type_offload * type)405*4882a593Smuzhiyun static void xfrm_put_type_offload(const struct xfrm_type_offload *type)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun module_put(type->owner);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun static const struct xfrm_mode xfrm4_mode_map[XFRM_MODE_MAX] = {
411*4882a593Smuzhiyun [XFRM_MODE_BEET] = {
412*4882a593Smuzhiyun .encap = XFRM_MODE_BEET,
413*4882a593Smuzhiyun .flags = XFRM_MODE_FLAG_TUNNEL,
414*4882a593Smuzhiyun .family = AF_INET,
415*4882a593Smuzhiyun },
416*4882a593Smuzhiyun [XFRM_MODE_TRANSPORT] = {
417*4882a593Smuzhiyun .encap = XFRM_MODE_TRANSPORT,
418*4882a593Smuzhiyun .family = AF_INET,
419*4882a593Smuzhiyun },
420*4882a593Smuzhiyun [XFRM_MODE_TUNNEL] = {
421*4882a593Smuzhiyun .encap = XFRM_MODE_TUNNEL,
422*4882a593Smuzhiyun .flags = XFRM_MODE_FLAG_TUNNEL,
423*4882a593Smuzhiyun .family = AF_INET,
424*4882a593Smuzhiyun },
425*4882a593Smuzhiyun };
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun static const struct xfrm_mode xfrm6_mode_map[XFRM_MODE_MAX] = {
428*4882a593Smuzhiyun [XFRM_MODE_BEET] = {
429*4882a593Smuzhiyun .encap = XFRM_MODE_BEET,
430*4882a593Smuzhiyun .flags = XFRM_MODE_FLAG_TUNNEL,
431*4882a593Smuzhiyun .family = AF_INET6,
432*4882a593Smuzhiyun },
433*4882a593Smuzhiyun [XFRM_MODE_ROUTEOPTIMIZATION] = {
434*4882a593Smuzhiyun .encap = XFRM_MODE_ROUTEOPTIMIZATION,
435*4882a593Smuzhiyun .family = AF_INET6,
436*4882a593Smuzhiyun },
437*4882a593Smuzhiyun [XFRM_MODE_TRANSPORT] = {
438*4882a593Smuzhiyun .encap = XFRM_MODE_TRANSPORT,
439*4882a593Smuzhiyun .family = AF_INET6,
440*4882a593Smuzhiyun },
441*4882a593Smuzhiyun [XFRM_MODE_TUNNEL] = {
442*4882a593Smuzhiyun .encap = XFRM_MODE_TUNNEL,
443*4882a593Smuzhiyun .flags = XFRM_MODE_FLAG_TUNNEL,
444*4882a593Smuzhiyun .family = AF_INET6,
445*4882a593Smuzhiyun },
446*4882a593Smuzhiyun };
447*4882a593Smuzhiyun
xfrm_get_mode(unsigned int encap,int family)448*4882a593Smuzhiyun static const struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun const struct xfrm_mode *mode;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (unlikely(encap >= XFRM_MODE_MAX))
453*4882a593Smuzhiyun return NULL;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun switch (family) {
456*4882a593Smuzhiyun case AF_INET:
457*4882a593Smuzhiyun mode = &xfrm4_mode_map[encap];
458*4882a593Smuzhiyun if (mode->family == family)
459*4882a593Smuzhiyun return mode;
460*4882a593Smuzhiyun break;
461*4882a593Smuzhiyun case AF_INET6:
462*4882a593Smuzhiyun mode = &xfrm6_mode_map[encap];
463*4882a593Smuzhiyun if (mode->family == family)
464*4882a593Smuzhiyun return mode;
465*4882a593Smuzhiyun break;
466*4882a593Smuzhiyun default:
467*4882a593Smuzhiyun break;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun return NULL;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
xfrm_state_free(struct xfrm_state * x)473*4882a593Smuzhiyun void xfrm_state_free(struct xfrm_state *x)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun kmem_cache_free(xfrm_state_cache, x);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_free);
478*4882a593Smuzhiyun
___xfrm_state_destroy(struct xfrm_state * x)479*4882a593Smuzhiyun static void ___xfrm_state_destroy(struct xfrm_state *x)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun hrtimer_cancel(&x->mtimer);
482*4882a593Smuzhiyun del_timer_sync(&x->rtimer);
483*4882a593Smuzhiyun kfree(x->aead);
484*4882a593Smuzhiyun kfree(x->aalg);
485*4882a593Smuzhiyun kfree(x->ealg);
486*4882a593Smuzhiyun kfree(x->calg);
487*4882a593Smuzhiyun kfree(x->encap);
488*4882a593Smuzhiyun kfree(x->coaddr);
489*4882a593Smuzhiyun kfree(x->replay_esn);
490*4882a593Smuzhiyun kfree(x->preplay_esn);
491*4882a593Smuzhiyun if (x->type_offload)
492*4882a593Smuzhiyun xfrm_put_type_offload(x->type_offload);
493*4882a593Smuzhiyun if (x->type) {
494*4882a593Smuzhiyun x->type->destructor(x);
495*4882a593Smuzhiyun xfrm_put_type(x->type);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun if (x->xfrag.page)
498*4882a593Smuzhiyun put_page(x->xfrag.page);
499*4882a593Smuzhiyun xfrm_dev_state_free(x);
500*4882a593Smuzhiyun security_xfrm_state_free(x);
501*4882a593Smuzhiyun xfrm_state_free(x);
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
xfrm_state_gc_task(struct work_struct * work)504*4882a593Smuzhiyun static void xfrm_state_gc_task(struct work_struct *work)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun struct xfrm_state *x;
507*4882a593Smuzhiyun struct hlist_node *tmp;
508*4882a593Smuzhiyun struct hlist_head gc_list;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun spin_lock_bh(&xfrm_state_gc_lock);
511*4882a593Smuzhiyun hlist_move_list(&xfrm_state_gc_list, &gc_list);
512*4882a593Smuzhiyun spin_unlock_bh(&xfrm_state_gc_lock);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun synchronize_rcu();
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
517*4882a593Smuzhiyun ___xfrm_state_destroy(x);
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
xfrm_timer_handler(struct hrtimer * me)520*4882a593Smuzhiyun static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun struct xfrm_state *x = container_of(me, struct xfrm_state, mtimer);
523*4882a593Smuzhiyun enum hrtimer_restart ret = HRTIMER_NORESTART;
524*4882a593Smuzhiyun time64_t now = ktime_get_real_seconds();
525*4882a593Smuzhiyun time64_t next = TIME64_MAX;
526*4882a593Smuzhiyun int warn = 0;
527*4882a593Smuzhiyun int err = 0;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun spin_lock(&x->lock);
530*4882a593Smuzhiyun if (x->km.state == XFRM_STATE_DEAD)
531*4882a593Smuzhiyun goto out;
532*4882a593Smuzhiyun if (x->km.state == XFRM_STATE_EXPIRED)
533*4882a593Smuzhiyun goto expired;
534*4882a593Smuzhiyun if (x->lft.hard_add_expires_seconds) {
535*4882a593Smuzhiyun long tmo = x->lft.hard_add_expires_seconds +
536*4882a593Smuzhiyun x->curlft.add_time - now;
537*4882a593Smuzhiyun if (tmo <= 0) {
538*4882a593Smuzhiyun if (x->xflags & XFRM_SOFT_EXPIRE) {
539*4882a593Smuzhiyun /* enter hard expire without soft expire first?!
540*4882a593Smuzhiyun * setting a new date could trigger this.
541*4882a593Smuzhiyun * workaround: fix x->curflt.add_time by below:
542*4882a593Smuzhiyun */
543*4882a593Smuzhiyun x->curlft.add_time = now - x->saved_tmo - 1;
544*4882a593Smuzhiyun tmo = x->lft.hard_add_expires_seconds - x->saved_tmo;
545*4882a593Smuzhiyun } else
546*4882a593Smuzhiyun goto expired;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun if (tmo < next)
549*4882a593Smuzhiyun next = tmo;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun if (x->lft.hard_use_expires_seconds) {
552*4882a593Smuzhiyun long tmo = x->lft.hard_use_expires_seconds +
553*4882a593Smuzhiyun (x->curlft.use_time ? : now) - now;
554*4882a593Smuzhiyun if (tmo <= 0)
555*4882a593Smuzhiyun goto expired;
556*4882a593Smuzhiyun if (tmo < next)
557*4882a593Smuzhiyun next = tmo;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun if (x->km.dying)
560*4882a593Smuzhiyun goto resched;
561*4882a593Smuzhiyun if (x->lft.soft_add_expires_seconds) {
562*4882a593Smuzhiyun long tmo = x->lft.soft_add_expires_seconds +
563*4882a593Smuzhiyun x->curlft.add_time - now;
564*4882a593Smuzhiyun if (tmo <= 0) {
565*4882a593Smuzhiyun warn = 1;
566*4882a593Smuzhiyun x->xflags &= ~XFRM_SOFT_EXPIRE;
567*4882a593Smuzhiyun } else if (tmo < next) {
568*4882a593Smuzhiyun next = tmo;
569*4882a593Smuzhiyun x->xflags |= XFRM_SOFT_EXPIRE;
570*4882a593Smuzhiyun x->saved_tmo = tmo;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun if (x->lft.soft_use_expires_seconds) {
574*4882a593Smuzhiyun long tmo = x->lft.soft_use_expires_seconds +
575*4882a593Smuzhiyun (x->curlft.use_time ? : now) - now;
576*4882a593Smuzhiyun if (tmo <= 0)
577*4882a593Smuzhiyun warn = 1;
578*4882a593Smuzhiyun else if (tmo < next)
579*4882a593Smuzhiyun next = tmo;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun x->km.dying = warn;
583*4882a593Smuzhiyun if (warn)
584*4882a593Smuzhiyun km_state_expired(x, 0, 0);
585*4882a593Smuzhiyun resched:
586*4882a593Smuzhiyun if (next != TIME64_MAX) {
587*4882a593Smuzhiyun hrtimer_forward_now(&x->mtimer, ktime_set(next, 0));
588*4882a593Smuzhiyun ret = HRTIMER_RESTART;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun goto out;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun expired:
594*4882a593Smuzhiyun if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0)
595*4882a593Smuzhiyun x->km.state = XFRM_STATE_EXPIRED;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun err = __xfrm_state_delete(x);
598*4882a593Smuzhiyun if (!err)
599*4882a593Smuzhiyun km_state_expired(x, 1, 0);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun xfrm_audit_state_delete(x, err ? 0 : 1, true);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun out:
604*4882a593Smuzhiyun spin_unlock(&x->lock);
605*4882a593Smuzhiyun return ret;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun static void xfrm_replay_timer_handler(struct timer_list *t);
609*4882a593Smuzhiyun
xfrm_state_alloc(struct net * net)610*4882a593Smuzhiyun struct xfrm_state *xfrm_state_alloc(struct net *net)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun struct xfrm_state *x;
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun x = kmem_cache_zalloc(xfrm_state_cache, GFP_ATOMIC);
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun if (x) {
617*4882a593Smuzhiyun write_pnet(&x->xs_net, net);
618*4882a593Smuzhiyun refcount_set(&x->refcnt, 1);
619*4882a593Smuzhiyun atomic_set(&x->tunnel_users, 0);
620*4882a593Smuzhiyun INIT_LIST_HEAD(&x->km.all);
621*4882a593Smuzhiyun INIT_HLIST_NODE(&x->bydst);
622*4882a593Smuzhiyun INIT_HLIST_NODE(&x->bysrc);
623*4882a593Smuzhiyun INIT_HLIST_NODE(&x->byspi);
624*4882a593Smuzhiyun hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
625*4882a593Smuzhiyun x->mtimer.function = xfrm_timer_handler;
626*4882a593Smuzhiyun timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0);
627*4882a593Smuzhiyun x->curlft.add_time = ktime_get_real_seconds();
628*4882a593Smuzhiyun x->lft.soft_byte_limit = XFRM_INF;
629*4882a593Smuzhiyun x->lft.soft_packet_limit = XFRM_INF;
630*4882a593Smuzhiyun x->lft.hard_byte_limit = XFRM_INF;
631*4882a593Smuzhiyun x->lft.hard_packet_limit = XFRM_INF;
632*4882a593Smuzhiyun x->replay_maxage = 0;
633*4882a593Smuzhiyun x->replay_maxdiff = 0;
634*4882a593Smuzhiyun spin_lock_init(&x->lock);
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun return x;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_alloc);
639*4882a593Smuzhiyun
__xfrm_state_destroy(struct xfrm_state * x,bool sync)640*4882a593Smuzhiyun void __xfrm_state_destroy(struct xfrm_state *x, bool sync)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun WARN_ON(x->km.state != XFRM_STATE_DEAD);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun if (sync) {
645*4882a593Smuzhiyun synchronize_rcu();
646*4882a593Smuzhiyun ___xfrm_state_destroy(x);
647*4882a593Smuzhiyun } else {
648*4882a593Smuzhiyun spin_lock_bh(&xfrm_state_gc_lock);
649*4882a593Smuzhiyun hlist_add_head(&x->gclist, &xfrm_state_gc_list);
650*4882a593Smuzhiyun spin_unlock_bh(&xfrm_state_gc_lock);
651*4882a593Smuzhiyun schedule_work(&xfrm_state_gc_work);
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun EXPORT_SYMBOL(__xfrm_state_destroy);
655*4882a593Smuzhiyun
__xfrm_state_delete(struct xfrm_state * x)656*4882a593Smuzhiyun int __xfrm_state_delete(struct xfrm_state *x)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun struct net *net = xs_net(x);
659*4882a593Smuzhiyun int err = -ESRCH;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (x->km.state != XFRM_STATE_DEAD) {
662*4882a593Smuzhiyun x->km.state = XFRM_STATE_DEAD;
663*4882a593Smuzhiyun spin_lock(&net->xfrm.xfrm_state_lock);
664*4882a593Smuzhiyun list_del(&x->km.all);
665*4882a593Smuzhiyun hlist_del_rcu(&x->bydst);
666*4882a593Smuzhiyun hlist_del_rcu(&x->bysrc);
667*4882a593Smuzhiyun if (x->id.spi)
668*4882a593Smuzhiyun hlist_del_rcu(&x->byspi);
669*4882a593Smuzhiyun net->xfrm.state_num--;
670*4882a593Smuzhiyun spin_unlock(&net->xfrm.xfrm_state_lock);
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (x->encap_sk)
673*4882a593Smuzhiyun sock_put(rcu_dereference_raw(x->encap_sk));
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun xfrm_dev_state_delete(x);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /* All xfrm_state objects are created by xfrm_state_alloc.
678*4882a593Smuzhiyun * The xfrm_state_alloc call gives a reference, and that
679*4882a593Smuzhiyun * is what we are dropping here.
680*4882a593Smuzhiyun */
681*4882a593Smuzhiyun xfrm_state_put(x);
682*4882a593Smuzhiyun err = 0;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun return err;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun EXPORT_SYMBOL(__xfrm_state_delete);
688*4882a593Smuzhiyun
xfrm_state_delete(struct xfrm_state * x)689*4882a593Smuzhiyun int xfrm_state_delete(struct xfrm_state *x)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun int err;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun spin_lock_bh(&x->lock);
694*4882a593Smuzhiyun err = __xfrm_state_delete(x);
695*4882a593Smuzhiyun spin_unlock_bh(&x->lock);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun return err;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_delete);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun #ifdef CONFIG_SECURITY_NETWORK_XFRM
702*4882a593Smuzhiyun static inline int
xfrm_state_flush_secctx_check(struct net * net,u8 proto,bool task_valid)703*4882a593Smuzhiyun xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun int i, err = 0;
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun for (i = 0; i <= net->xfrm.state_hmask; i++) {
708*4882a593Smuzhiyun struct xfrm_state *x;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
711*4882a593Smuzhiyun if (xfrm_id_proto_match(x->id.proto, proto) &&
712*4882a593Smuzhiyun (err = security_xfrm_state_delete(x)) != 0) {
713*4882a593Smuzhiyun xfrm_audit_state_delete(x, 0, task_valid);
714*4882a593Smuzhiyun return err;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun return err;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun static inline int
xfrm_dev_state_flush_secctx_check(struct net * net,struct net_device * dev,bool task_valid)723*4882a593Smuzhiyun xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun int i, err = 0;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun for (i = 0; i <= net->xfrm.state_hmask; i++) {
728*4882a593Smuzhiyun struct xfrm_state *x;
729*4882a593Smuzhiyun struct xfrm_state_offload *xso;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
732*4882a593Smuzhiyun xso = &x->xso;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun if (xso->dev == dev &&
735*4882a593Smuzhiyun (err = security_xfrm_state_delete(x)) != 0) {
736*4882a593Smuzhiyun xfrm_audit_state_delete(x, 0, task_valid);
737*4882a593Smuzhiyun return err;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun return err;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun #else
745*4882a593Smuzhiyun static inline int
xfrm_state_flush_secctx_check(struct net * net,u8 proto,bool task_valid)746*4882a593Smuzhiyun xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun return 0;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun static inline int
xfrm_dev_state_flush_secctx_check(struct net * net,struct net_device * dev,bool task_valid)752*4882a593Smuzhiyun xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun return 0;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun #endif
757*4882a593Smuzhiyun
xfrm_state_flush(struct net * net,u8 proto,bool task_valid,bool sync)758*4882a593Smuzhiyun int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun int i, err = 0, cnt = 0;
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
763*4882a593Smuzhiyun err = xfrm_state_flush_secctx_check(net, proto, task_valid);
764*4882a593Smuzhiyun if (err)
765*4882a593Smuzhiyun goto out;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun err = -ESRCH;
768*4882a593Smuzhiyun for (i = 0; i <= net->xfrm.state_hmask; i++) {
769*4882a593Smuzhiyun struct xfrm_state *x;
770*4882a593Smuzhiyun restart:
771*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
772*4882a593Smuzhiyun if (!xfrm_state_kern(x) &&
773*4882a593Smuzhiyun xfrm_id_proto_match(x->id.proto, proto)) {
774*4882a593Smuzhiyun xfrm_state_hold(x);
775*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun err = xfrm_state_delete(x);
778*4882a593Smuzhiyun xfrm_audit_state_delete(x, err ? 0 : 1,
779*4882a593Smuzhiyun task_valid);
780*4882a593Smuzhiyun if (sync)
781*4882a593Smuzhiyun xfrm_state_put_sync(x);
782*4882a593Smuzhiyun else
783*4882a593Smuzhiyun xfrm_state_put(x);
784*4882a593Smuzhiyun if (!err)
785*4882a593Smuzhiyun cnt++;
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
788*4882a593Smuzhiyun goto restart;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun out:
793*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
794*4882a593Smuzhiyun if (cnt)
795*4882a593Smuzhiyun err = 0;
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun return err;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_flush);
800*4882a593Smuzhiyun
xfrm_dev_state_flush(struct net * net,struct net_device * dev,bool task_valid)801*4882a593Smuzhiyun int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun int i, err = 0, cnt = 0;
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
806*4882a593Smuzhiyun err = xfrm_dev_state_flush_secctx_check(net, dev, task_valid);
807*4882a593Smuzhiyun if (err)
808*4882a593Smuzhiyun goto out;
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun err = -ESRCH;
811*4882a593Smuzhiyun for (i = 0; i <= net->xfrm.state_hmask; i++) {
812*4882a593Smuzhiyun struct xfrm_state *x;
813*4882a593Smuzhiyun struct xfrm_state_offload *xso;
814*4882a593Smuzhiyun restart:
815*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
816*4882a593Smuzhiyun xso = &x->xso;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun if (!xfrm_state_kern(x) && xso->dev == dev) {
819*4882a593Smuzhiyun xfrm_state_hold(x);
820*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun err = xfrm_state_delete(x);
823*4882a593Smuzhiyun xfrm_audit_state_delete(x, err ? 0 : 1,
824*4882a593Smuzhiyun task_valid);
825*4882a593Smuzhiyun xfrm_state_put(x);
826*4882a593Smuzhiyun if (!err)
827*4882a593Smuzhiyun cnt++;
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
830*4882a593Smuzhiyun goto restart;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun if (cnt)
835*4882a593Smuzhiyun err = 0;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun out:
838*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
839*4882a593Smuzhiyun return err;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_dev_state_flush);
842*4882a593Smuzhiyun
xfrm_sad_getinfo(struct net * net,struct xfrmk_sadinfo * si)843*4882a593Smuzhiyun void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
846*4882a593Smuzhiyun si->sadcnt = net->xfrm.state_num;
847*4882a593Smuzhiyun si->sadhcnt = net->xfrm.state_hmask + 1;
848*4882a593Smuzhiyun si->sadhmcnt = xfrm_state_hashmax;
849*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_sad_getinfo);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun static void
__xfrm4_init_tempsel(struct xfrm_selector * sel,const struct flowi * fl)854*4882a593Smuzhiyun __xfrm4_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun const struct flowi4 *fl4 = &fl->u.ip4;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun sel->daddr.a4 = fl4->daddr;
859*4882a593Smuzhiyun sel->saddr.a4 = fl4->saddr;
860*4882a593Smuzhiyun sel->dport = xfrm_flowi_dport(fl, &fl4->uli);
861*4882a593Smuzhiyun sel->dport_mask = htons(0xffff);
862*4882a593Smuzhiyun sel->sport = xfrm_flowi_sport(fl, &fl4->uli);
863*4882a593Smuzhiyun sel->sport_mask = htons(0xffff);
864*4882a593Smuzhiyun sel->family = AF_INET;
865*4882a593Smuzhiyun sel->prefixlen_d = 32;
866*4882a593Smuzhiyun sel->prefixlen_s = 32;
867*4882a593Smuzhiyun sel->proto = fl4->flowi4_proto;
868*4882a593Smuzhiyun sel->ifindex = fl4->flowi4_oif;
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun static void
__xfrm6_init_tempsel(struct xfrm_selector * sel,const struct flowi * fl)872*4882a593Smuzhiyun __xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun const struct flowi6 *fl6 = &fl->u.ip6;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun /* Initialize temporary selector matching only to current session. */
877*4882a593Smuzhiyun *(struct in6_addr *)&sel->daddr = fl6->daddr;
878*4882a593Smuzhiyun *(struct in6_addr *)&sel->saddr = fl6->saddr;
879*4882a593Smuzhiyun sel->dport = xfrm_flowi_dport(fl, &fl6->uli);
880*4882a593Smuzhiyun sel->dport_mask = htons(0xffff);
881*4882a593Smuzhiyun sel->sport = xfrm_flowi_sport(fl, &fl6->uli);
882*4882a593Smuzhiyun sel->sport_mask = htons(0xffff);
883*4882a593Smuzhiyun sel->family = AF_INET6;
884*4882a593Smuzhiyun sel->prefixlen_d = 128;
885*4882a593Smuzhiyun sel->prefixlen_s = 128;
886*4882a593Smuzhiyun sel->proto = fl6->flowi6_proto;
887*4882a593Smuzhiyun sel->ifindex = fl6->flowi6_oif;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun static void
xfrm_init_tempstate(struct xfrm_state * x,const struct flowi * fl,const struct xfrm_tmpl * tmpl,const xfrm_address_t * daddr,const xfrm_address_t * saddr,unsigned short family)891*4882a593Smuzhiyun xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl,
892*4882a593Smuzhiyun const struct xfrm_tmpl *tmpl,
893*4882a593Smuzhiyun const xfrm_address_t *daddr, const xfrm_address_t *saddr,
894*4882a593Smuzhiyun unsigned short family)
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun switch (family) {
897*4882a593Smuzhiyun case AF_INET:
898*4882a593Smuzhiyun __xfrm4_init_tempsel(&x->sel, fl);
899*4882a593Smuzhiyun break;
900*4882a593Smuzhiyun case AF_INET6:
901*4882a593Smuzhiyun __xfrm6_init_tempsel(&x->sel, fl);
902*4882a593Smuzhiyun break;
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun x->id = tmpl->id;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun switch (tmpl->encap_family) {
908*4882a593Smuzhiyun case AF_INET:
909*4882a593Smuzhiyun if (x->id.daddr.a4 == 0)
910*4882a593Smuzhiyun x->id.daddr.a4 = daddr->a4;
911*4882a593Smuzhiyun x->props.saddr = tmpl->saddr;
912*4882a593Smuzhiyun if (x->props.saddr.a4 == 0)
913*4882a593Smuzhiyun x->props.saddr.a4 = saddr->a4;
914*4882a593Smuzhiyun break;
915*4882a593Smuzhiyun case AF_INET6:
916*4882a593Smuzhiyun if (ipv6_addr_any((struct in6_addr *)&x->id.daddr))
917*4882a593Smuzhiyun memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
918*4882a593Smuzhiyun memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
919*4882a593Smuzhiyun if (ipv6_addr_any((struct in6_addr *)&x->props.saddr))
920*4882a593Smuzhiyun memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
921*4882a593Smuzhiyun break;
922*4882a593Smuzhiyun }
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun x->props.mode = tmpl->mode;
925*4882a593Smuzhiyun x->props.reqid = tmpl->reqid;
926*4882a593Smuzhiyun x->props.family = tmpl->encap_family;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun
__xfrm_state_lookup(struct net * net,u32 mark,const xfrm_address_t * daddr,__be32 spi,u8 proto,unsigned short family)929*4882a593Smuzhiyun static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
930*4882a593Smuzhiyun const xfrm_address_t *daddr,
931*4882a593Smuzhiyun __be32 spi, u8 proto,
932*4882a593Smuzhiyun unsigned short family)
933*4882a593Smuzhiyun {
934*4882a593Smuzhiyun unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
935*4882a593Smuzhiyun struct xfrm_state *x;
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) {
938*4882a593Smuzhiyun if (x->props.family != family ||
939*4882a593Smuzhiyun x->id.spi != spi ||
940*4882a593Smuzhiyun x->id.proto != proto ||
941*4882a593Smuzhiyun !xfrm_addr_equal(&x->id.daddr, daddr, family))
942*4882a593Smuzhiyun continue;
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun if ((mark & x->mark.m) != x->mark.v)
945*4882a593Smuzhiyun continue;
946*4882a593Smuzhiyun if (!xfrm_state_hold_rcu(x))
947*4882a593Smuzhiyun continue;
948*4882a593Smuzhiyun return x;
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun return NULL;
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
__xfrm_state_lookup_byaddr(struct net * net,u32 mark,const xfrm_address_t * daddr,const xfrm_address_t * saddr,u8 proto,unsigned short family)954*4882a593Smuzhiyun static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark,
955*4882a593Smuzhiyun const xfrm_address_t *daddr,
956*4882a593Smuzhiyun const xfrm_address_t *saddr,
957*4882a593Smuzhiyun u8 proto, unsigned short family)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
960*4882a593Smuzhiyun struct xfrm_state *x;
961*4882a593Smuzhiyun
962*4882a593Smuzhiyun hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) {
963*4882a593Smuzhiyun if (x->props.family != family ||
964*4882a593Smuzhiyun x->id.proto != proto ||
965*4882a593Smuzhiyun !xfrm_addr_equal(&x->id.daddr, daddr, family) ||
966*4882a593Smuzhiyun !xfrm_addr_equal(&x->props.saddr, saddr, family))
967*4882a593Smuzhiyun continue;
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun if ((mark & x->mark.m) != x->mark.v)
970*4882a593Smuzhiyun continue;
971*4882a593Smuzhiyun if (!xfrm_state_hold_rcu(x))
972*4882a593Smuzhiyun continue;
973*4882a593Smuzhiyun return x;
974*4882a593Smuzhiyun }
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun return NULL;
977*4882a593Smuzhiyun }
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun static inline struct xfrm_state *
__xfrm_state_locate(struct xfrm_state * x,int use_spi,int family)980*4882a593Smuzhiyun __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun struct net *net = xs_net(x);
983*4882a593Smuzhiyun u32 mark = x->mark.v & x->mark.m;
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun if (use_spi)
986*4882a593Smuzhiyun return __xfrm_state_lookup(net, mark, &x->id.daddr,
987*4882a593Smuzhiyun x->id.spi, x->id.proto, family);
988*4882a593Smuzhiyun else
989*4882a593Smuzhiyun return __xfrm_state_lookup_byaddr(net, mark,
990*4882a593Smuzhiyun &x->id.daddr,
991*4882a593Smuzhiyun &x->props.saddr,
992*4882a593Smuzhiyun x->id.proto, family);
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun
xfrm_hash_grow_check(struct net * net,int have_hash_collision)995*4882a593Smuzhiyun static void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
996*4882a593Smuzhiyun {
997*4882a593Smuzhiyun if (have_hash_collision &&
998*4882a593Smuzhiyun (net->xfrm.state_hmask + 1) < xfrm_state_hashmax &&
999*4882a593Smuzhiyun net->xfrm.state_num > net->xfrm.state_hmask)
1000*4882a593Smuzhiyun schedule_work(&net->xfrm.state_hash_work);
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun
xfrm_state_look_at(struct xfrm_policy * pol,struct xfrm_state * x,const struct flowi * fl,unsigned short family,struct xfrm_state ** best,int * acq_in_progress,int * error)1003*4882a593Smuzhiyun static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
1004*4882a593Smuzhiyun const struct flowi *fl, unsigned short family,
1005*4882a593Smuzhiyun struct xfrm_state **best, int *acq_in_progress,
1006*4882a593Smuzhiyun int *error)
1007*4882a593Smuzhiyun {
1008*4882a593Smuzhiyun /* Resolution logic:
1009*4882a593Smuzhiyun * 1. There is a valid state with matching selector. Done.
1010*4882a593Smuzhiyun * 2. Valid state with inappropriate selector. Skip.
1011*4882a593Smuzhiyun *
1012*4882a593Smuzhiyun * Entering area of "sysdeps".
1013*4882a593Smuzhiyun *
1014*4882a593Smuzhiyun * 3. If state is not valid, selector is temporary, it selects
1015*4882a593Smuzhiyun * only session which triggered previous resolution. Key
1016*4882a593Smuzhiyun * manager will do something to install a state with proper
1017*4882a593Smuzhiyun * selector.
1018*4882a593Smuzhiyun */
1019*4882a593Smuzhiyun if (x->km.state == XFRM_STATE_VALID) {
1020*4882a593Smuzhiyun if ((x->sel.family &&
1021*4882a593Smuzhiyun (x->sel.family != family ||
1022*4882a593Smuzhiyun !xfrm_selector_match(&x->sel, fl, family))) ||
1023*4882a593Smuzhiyun !security_xfrm_state_pol_flow_match(x, pol,
1024*4882a593Smuzhiyun &fl->u.__fl_common))
1025*4882a593Smuzhiyun return;
1026*4882a593Smuzhiyun
1027*4882a593Smuzhiyun if (!*best ||
1028*4882a593Smuzhiyun (*best)->km.dying > x->km.dying ||
1029*4882a593Smuzhiyun ((*best)->km.dying == x->km.dying &&
1030*4882a593Smuzhiyun (*best)->curlft.add_time < x->curlft.add_time))
1031*4882a593Smuzhiyun *best = x;
1032*4882a593Smuzhiyun } else if (x->km.state == XFRM_STATE_ACQ) {
1033*4882a593Smuzhiyun *acq_in_progress = 1;
1034*4882a593Smuzhiyun } else if (x->km.state == XFRM_STATE_ERROR ||
1035*4882a593Smuzhiyun x->km.state == XFRM_STATE_EXPIRED) {
1036*4882a593Smuzhiyun if ((!x->sel.family ||
1037*4882a593Smuzhiyun (x->sel.family == family &&
1038*4882a593Smuzhiyun xfrm_selector_match(&x->sel, fl, family))) &&
1039*4882a593Smuzhiyun security_xfrm_state_pol_flow_match(x, pol,
1040*4882a593Smuzhiyun &fl->u.__fl_common))
1041*4882a593Smuzhiyun *error = -ESRCH;
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun struct xfrm_state *
xfrm_state_find(const xfrm_address_t * daddr,const xfrm_address_t * saddr,const struct flowi * fl,struct xfrm_tmpl * tmpl,struct xfrm_policy * pol,int * err,unsigned short family,u32 if_id)1046*4882a593Smuzhiyun xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1047*4882a593Smuzhiyun const struct flowi *fl, struct xfrm_tmpl *tmpl,
1048*4882a593Smuzhiyun struct xfrm_policy *pol, int *err,
1049*4882a593Smuzhiyun unsigned short family, u32 if_id)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun static xfrm_address_t saddr_wildcard = { };
1052*4882a593Smuzhiyun struct net *net = xp_net(pol);
1053*4882a593Smuzhiyun unsigned int h, h_wildcard;
1054*4882a593Smuzhiyun struct xfrm_state *x, *x0, *to_put;
1055*4882a593Smuzhiyun int acquire_in_progress = 0;
1056*4882a593Smuzhiyun int error = 0;
1057*4882a593Smuzhiyun struct xfrm_state *best = NULL;
1058*4882a593Smuzhiyun u32 mark = pol->mark.v & pol->mark.m;
1059*4882a593Smuzhiyun unsigned short encap_family = tmpl->encap_family;
1060*4882a593Smuzhiyun unsigned int sequence;
1061*4882a593Smuzhiyun struct km_event c;
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun to_put = NULL;
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun rcu_read_lock();
1068*4882a593Smuzhiyun h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
1069*4882a593Smuzhiyun hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
1070*4882a593Smuzhiyun if (x->props.family == encap_family &&
1071*4882a593Smuzhiyun x->props.reqid == tmpl->reqid &&
1072*4882a593Smuzhiyun (mark & x->mark.m) == x->mark.v &&
1073*4882a593Smuzhiyun x->if_id == if_id &&
1074*4882a593Smuzhiyun !(x->props.flags & XFRM_STATE_WILDRECV) &&
1075*4882a593Smuzhiyun xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
1076*4882a593Smuzhiyun tmpl->mode == x->props.mode &&
1077*4882a593Smuzhiyun tmpl->id.proto == x->id.proto &&
1078*4882a593Smuzhiyun (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
1079*4882a593Smuzhiyun xfrm_state_look_at(pol, x, fl, family,
1080*4882a593Smuzhiyun &best, &acquire_in_progress, &error);
1081*4882a593Smuzhiyun }
1082*4882a593Smuzhiyun if (best || acquire_in_progress)
1083*4882a593Smuzhiyun goto found;
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
1086*4882a593Smuzhiyun hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) {
1087*4882a593Smuzhiyun if (x->props.family == encap_family &&
1088*4882a593Smuzhiyun x->props.reqid == tmpl->reqid &&
1089*4882a593Smuzhiyun (mark & x->mark.m) == x->mark.v &&
1090*4882a593Smuzhiyun x->if_id == if_id &&
1091*4882a593Smuzhiyun !(x->props.flags & XFRM_STATE_WILDRECV) &&
1092*4882a593Smuzhiyun xfrm_addr_equal(&x->id.daddr, daddr, encap_family) &&
1093*4882a593Smuzhiyun tmpl->mode == x->props.mode &&
1094*4882a593Smuzhiyun tmpl->id.proto == x->id.proto &&
1095*4882a593Smuzhiyun (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
1096*4882a593Smuzhiyun xfrm_state_look_at(pol, x, fl, family,
1097*4882a593Smuzhiyun &best, &acquire_in_progress, &error);
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun found:
1101*4882a593Smuzhiyun x = best;
1102*4882a593Smuzhiyun if (!x && !error && !acquire_in_progress) {
1103*4882a593Smuzhiyun if (tmpl->id.spi &&
1104*4882a593Smuzhiyun (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
1105*4882a593Smuzhiyun tmpl->id.proto, encap_family)) != NULL) {
1106*4882a593Smuzhiyun to_put = x0;
1107*4882a593Smuzhiyun error = -EEXIST;
1108*4882a593Smuzhiyun goto out;
1109*4882a593Smuzhiyun }
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun c.net = net;
1112*4882a593Smuzhiyun /* If the KMs have no listeners (yet...), avoid allocating an SA
1113*4882a593Smuzhiyun * for each and every packet - garbage collection might not
1114*4882a593Smuzhiyun * handle the flood.
1115*4882a593Smuzhiyun */
1116*4882a593Smuzhiyun if (!km_is_alive(&c)) {
1117*4882a593Smuzhiyun error = -ESRCH;
1118*4882a593Smuzhiyun goto out;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun x = xfrm_state_alloc(net);
1122*4882a593Smuzhiyun if (x == NULL) {
1123*4882a593Smuzhiyun error = -ENOMEM;
1124*4882a593Smuzhiyun goto out;
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun /* Initialize temporary state matching only
1127*4882a593Smuzhiyun * to current session. */
1128*4882a593Smuzhiyun xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
1129*4882a593Smuzhiyun memcpy(&x->mark, &pol->mark, sizeof(x->mark));
1130*4882a593Smuzhiyun x->if_id = if_id;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid);
1133*4882a593Smuzhiyun if (error) {
1134*4882a593Smuzhiyun x->km.state = XFRM_STATE_DEAD;
1135*4882a593Smuzhiyun to_put = x;
1136*4882a593Smuzhiyun x = NULL;
1137*4882a593Smuzhiyun goto out;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun if (km_query(x, tmpl, pol) == 0) {
1141*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1142*4882a593Smuzhiyun x->km.state = XFRM_STATE_ACQ;
1143*4882a593Smuzhiyun list_add(&x->km.all, &net->xfrm.state_all);
1144*4882a593Smuzhiyun hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
1145*4882a593Smuzhiyun h = xfrm_src_hash(net, daddr, saddr, encap_family);
1146*4882a593Smuzhiyun hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
1147*4882a593Smuzhiyun if (x->id.spi) {
1148*4882a593Smuzhiyun h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
1149*4882a593Smuzhiyun hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
1150*4882a593Smuzhiyun }
1151*4882a593Smuzhiyun x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
1152*4882a593Smuzhiyun hrtimer_start(&x->mtimer,
1153*4882a593Smuzhiyun ktime_set(net->xfrm.sysctl_acq_expires, 0),
1154*4882a593Smuzhiyun HRTIMER_MODE_REL_SOFT);
1155*4882a593Smuzhiyun net->xfrm.state_num++;
1156*4882a593Smuzhiyun xfrm_hash_grow_check(net, x->bydst.next != NULL);
1157*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1158*4882a593Smuzhiyun } else {
1159*4882a593Smuzhiyun x->km.state = XFRM_STATE_DEAD;
1160*4882a593Smuzhiyun to_put = x;
1161*4882a593Smuzhiyun x = NULL;
1162*4882a593Smuzhiyun error = -ESRCH;
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun out:
1166*4882a593Smuzhiyun if (x) {
1167*4882a593Smuzhiyun if (!xfrm_state_hold_rcu(x)) {
1168*4882a593Smuzhiyun *err = -EAGAIN;
1169*4882a593Smuzhiyun x = NULL;
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun } else {
1172*4882a593Smuzhiyun *err = acquire_in_progress ? -EAGAIN : error;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun rcu_read_unlock();
1175*4882a593Smuzhiyun if (to_put)
1176*4882a593Smuzhiyun xfrm_state_put(to_put);
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun if (read_seqcount_retry(&net->xfrm.xfrm_state_hash_generation, sequence)) {
1179*4882a593Smuzhiyun *err = -EAGAIN;
1180*4882a593Smuzhiyun if (x) {
1181*4882a593Smuzhiyun xfrm_state_put(x);
1182*4882a593Smuzhiyun x = NULL;
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun }
1185*4882a593Smuzhiyun
1186*4882a593Smuzhiyun return x;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun struct xfrm_state *
xfrm_stateonly_find(struct net * net,u32 mark,u32 if_id,xfrm_address_t * daddr,xfrm_address_t * saddr,unsigned short family,u8 mode,u8 proto,u32 reqid)1190*4882a593Smuzhiyun xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
1191*4882a593Smuzhiyun xfrm_address_t *daddr, xfrm_address_t *saddr,
1192*4882a593Smuzhiyun unsigned short family, u8 mode, u8 proto, u32 reqid)
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun unsigned int h;
1195*4882a593Smuzhiyun struct xfrm_state *rx = NULL, *x = NULL;
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1198*4882a593Smuzhiyun h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
1199*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1200*4882a593Smuzhiyun if (x->props.family == family &&
1201*4882a593Smuzhiyun x->props.reqid == reqid &&
1202*4882a593Smuzhiyun (mark & x->mark.m) == x->mark.v &&
1203*4882a593Smuzhiyun x->if_id == if_id &&
1204*4882a593Smuzhiyun !(x->props.flags & XFRM_STATE_WILDRECV) &&
1205*4882a593Smuzhiyun xfrm_state_addr_check(x, daddr, saddr, family) &&
1206*4882a593Smuzhiyun mode == x->props.mode &&
1207*4882a593Smuzhiyun proto == x->id.proto &&
1208*4882a593Smuzhiyun x->km.state == XFRM_STATE_VALID) {
1209*4882a593Smuzhiyun rx = x;
1210*4882a593Smuzhiyun break;
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun }
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun if (rx)
1215*4882a593Smuzhiyun xfrm_state_hold(rx);
1216*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun return rx;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_stateonly_find);
1222*4882a593Smuzhiyun
xfrm_state_lookup_byspi(struct net * net,__be32 spi,unsigned short family)1223*4882a593Smuzhiyun struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
1224*4882a593Smuzhiyun unsigned short family)
1225*4882a593Smuzhiyun {
1226*4882a593Smuzhiyun struct xfrm_state *x;
1227*4882a593Smuzhiyun struct xfrm_state_walk *w;
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1230*4882a593Smuzhiyun list_for_each_entry(w, &net->xfrm.state_all, all) {
1231*4882a593Smuzhiyun x = container_of(w, struct xfrm_state, km);
1232*4882a593Smuzhiyun if (x->props.family != family ||
1233*4882a593Smuzhiyun x->id.spi != spi)
1234*4882a593Smuzhiyun continue;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun xfrm_state_hold(x);
1237*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1238*4882a593Smuzhiyun return x;
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1241*4882a593Smuzhiyun return NULL;
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_lookup_byspi);
1244*4882a593Smuzhiyun
__xfrm_state_insert(struct xfrm_state * x)1245*4882a593Smuzhiyun static void __xfrm_state_insert(struct xfrm_state *x)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun struct net *net = xs_net(x);
1248*4882a593Smuzhiyun unsigned int h;
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun list_add(&x->km.all, &net->xfrm.state_all);
1251*4882a593Smuzhiyun
1252*4882a593Smuzhiyun h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
1253*4882a593Smuzhiyun x->props.reqid, x->props.family);
1254*4882a593Smuzhiyun hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
1257*4882a593Smuzhiyun hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun if (x->id.spi) {
1260*4882a593Smuzhiyun h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
1261*4882a593Smuzhiyun x->props.family);
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
1264*4882a593Smuzhiyun }
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
1267*4882a593Smuzhiyun if (x->replay_maxage)
1268*4882a593Smuzhiyun mod_timer(&x->rtimer, jiffies + x->replay_maxage);
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun net->xfrm.state_num++;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun xfrm_hash_grow_check(net, x->bydst.next != NULL);
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun /* net->xfrm.xfrm_state_lock is held */
__xfrm_state_bump_genids(struct xfrm_state * xnew)1276*4882a593Smuzhiyun static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
1277*4882a593Smuzhiyun {
1278*4882a593Smuzhiyun struct net *net = xs_net(xnew);
1279*4882a593Smuzhiyun unsigned short family = xnew->props.family;
1280*4882a593Smuzhiyun u32 reqid = xnew->props.reqid;
1281*4882a593Smuzhiyun struct xfrm_state *x;
1282*4882a593Smuzhiyun unsigned int h;
1283*4882a593Smuzhiyun u32 mark = xnew->mark.v & xnew->mark.m;
1284*4882a593Smuzhiyun u32 if_id = xnew->if_id;
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
1287*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1288*4882a593Smuzhiyun if (x->props.family == family &&
1289*4882a593Smuzhiyun x->props.reqid == reqid &&
1290*4882a593Smuzhiyun x->if_id == if_id &&
1291*4882a593Smuzhiyun (mark & x->mark.m) == x->mark.v &&
1292*4882a593Smuzhiyun xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) &&
1293*4882a593Smuzhiyun xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family))
1294*4882a593Smuzhiyun x->genid++;
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun
xfrm_state_insert(struct xfrm_state * x)1298*4882a593Smuzhiyun void xfrm_state_insert(struct xfrm_state *x)
1299*4882a593Smuzhiyun {
1300*4882a593Smuzhiyun struct net *net = xs_net(x);
1301*4882a593Smuzhiyun
1302*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1303*4882a593Smuzhiyun __xfrm_state_bump_genids(x);
1304*4882a593Smuzhiyun __xfrm_state_insert(x);
1305*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1306*4882a593Smuzhiyun }
1307*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_insert);
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun /* net->xfrm.xfrm_state_lock is held */
__find_acq_core(struct net * net,const struct xfrm_mark * m,unsigned short family,u8 mode,u32 reqid,u32 if_id,u8 proto,const xfrm_address_t * daddr,const xfrm_address_t * saddr,int create)1310*4882a593Smuzhiyun static struct xfrm_state *__find_acq_core(struct net *net,
1311*4882a593Smuzhiyun const struct xfrm_mark *m,
1312*4882a593Smuzhiyun unsigned short family, u8 mode,
1313*4882a593Smuzhiyun u32 reqid, u32 if_id, u8 proto,
1314*4882a593Smuzhiyun const xfrm_address_t *daddr,
1315*4882a593Smuzhiyun const xfrm_address_t *saddr,
1316*4882a593Smuzhiyun int create)
1317*4882a593Smuzhiyun {
1318*4882a593Smuzhiyun unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
1319*4882a593Smuzhiyun struct xfrm_state *x;
1320*4882a593Smuzhiyun u32 mark = m->v & m->m;
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1323*4882a593Smuzhiyun if (x->props.reqid != reqid ||
1324*4882a593Smuzhiyun x->props.mode != mode ||
1325*4882a593Smuzhiyun x->props.family != family ||
1326*4882a593Smuzhiyun x->km.state != XFRM_STATE_ACQ ||
1327*4882a593Smuzhiyun x->id.spi != 0 ||
1328*4882a593Smuzhiyun x->id.proto != proto ||
1329*4882a593Smuzhiyun (mark & x->mark.m) != x->mark.v ||
1330*4882a593Smuzhiyun !xfrm_addr_equal(&x->id.daddr, daddr, family) ||
1331*4882a593Smuzhiyun !xfrm_addr_equal(&x->props.saddr, saddr, family))
1332*4882a593Smuzhiyun continue;
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun xfrm_state_hold(x);
1335*4882a593Smuzhiyun return x;
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun if (!create)
1339*4882a593Smuzhiyun return NULL;
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun x = xfrm_state_alloc(net);
1342*4882a593Smuzhiyun if (likely(x)) {
1343*4882a593Smuzhiyun switch (family) {
1344*4882a593Smuzhiyun case AF_INET:
1345*4882a593Smuzhiyun x->sel.daddr.a4 = daddr->a4;
1346*4882a593Smuzhiyun x->sel.saddr.a4 = saddr->a4;
1347*4882a593Smuzhiyun x->sel.prefixlen_d = 32;
1348*4882a593Smuzhiyun x->sel.prefixlen_s = 32;
1349*4882a593Smuzhiyun x->props.saddr.a4 = saddr->a4;
1350*4882a593Smuzhiyun x->id.daddr.a4 = daddr->a4;
1351*4882a593Smuzhiyun break;
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun case AF_INET6:
1354*4882a593Smuzhiyun x->sel.daddr.in6 = daddr->in6;
1355*4882a593Smuzhiyun x->sel.saddr.in6 = saddr->in6;
1356*4882a593Smuzhiyun x->sel.prefixlen_d = 128;
1357*4882a593Smuzhiyun x->sel.prefixlen_s = 128;
1358*4882a593Smuzhiyun x->props.saddr.in6 = saddr->in6;
1359*4882a593Smuzhiyun x->id.daddr.in6 = daddr->in6;
1360*4882a593Smuzhiyun break;
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyun x->km.state = XFRM_STATE_ACQ;
1364*4882a593Smuzhiyun x->id.proto = proto;
1365*4882a593Smuzhiyun x->props.family = family;
1366*4882a593Smuzhiyun x->props.mode = mode;
1367*4882a593Smuzhiyun x->props.reqid = reqid;
1368*4882a593Smuzhiyun x->if_id = if_id;
1369*4882a593Smuzhiyun x->mark.v = m->v;
1370*4882a593Smuzhiyun x->mark.m = m->m;
1371*4882a593Smuzhiyun x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
1372*4882a593Smuzhiyun xfrm_state_hold(x);
1373*4882a593Smuzhiyun hrtimer_start(&x->mtimer,
1374*4882a593Smuzhiyun ktime_set(net->xfrm.sysctl_acq_expires, 0),
1375*4882a593Smuzhiyun HRTIMER_MODE_REL_SOFT);
1376*4882a593Smuzhiyun list_add(&x->km.all, &net->xfrm.state_all);
1377*4882a593Smuzhiyun hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
1378*4882a593Smuzhiyun h = xfrm_src_hash(net, daddr, saddr, family);
1379*4882a593Smuzhiyun hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
1380*4882a593Smuzhiyun
1381*4882a593Smuzhiyun net->xfrm.state_num++;
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun xfrm_hash_grow_check(net, x->bydst.next != NULL);
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun return x;
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
1390*4882a593Smuzhiyun
xfrm_state_add(struct xfrm_state * x)1391*4882a593Smuzhiyun int xfrm_state_add(struct xfrm_state *x)
1392*4882a593Smuzhiyun {
1393*4882a593Smuzhiyun struct net *net = xs_net(x);
1394*4882a593Smuzhiyun struct xfrm_state *x1, *to_put;
1395*4882a593Smuzhiyun int family;
1396*4882a593Smuzhiyun int err;
1397*4882a593Smuzhiyun u32 mark = x->mark.v & x->mark.m;
1398*4882a593Smuzhiyun int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun family = x->props.family;
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun to_put = NULL;
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun x1 = __xfrm_state_locate(x, use_spi, family);
1407*4882a593Smuzhiyun if (x1) {
1408*4882a593Smuzhiyun to_put = x1;
1409*4882a593Smuzhiyun x1 = NULL;
1410*4882a593Smuzhiyun err = -EEXIST;
1411*4882a593Smuzhiyun goto out;
1412*4882a593Smuzhiyun }
1413*4882a593Smuzhiyun
1414*4882a593Smuzhiyun if (use_spi && x->km.seq) {
1415*4882a593Smuzhiyun x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq);
1416*4882a593Smuzhiyun if (x1 && ((x1->id.proto != x->id.proto) ||
1417*4882a593Smuzhiyun !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) {
1418*4882a593Smuzhiyun to_put = x1;
1419*4882a593Smuzhiyun x1 = NULL;
1420*4882a593Smuzhiyun }
1421*4882a593Smuzhiyun }
1422*4882a593Smuzhiyun
1423*4882a593Smuzhiyun if (use_spi && !x1)
1424*4882a593Smuzhiyun x1 = __find_acq_core(net, &x->mark, family, x->props.mode,
1425*4882a593Smuzhiyun x->props.reqid, x->if_id, x->id.proto,
1426*4882a593Smuzhiyun &x->id.daddr, &x->props.saddr, 0);
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun __xfrm_state_bump_genids(x);
1429*4882a593Smuzhiyun __xfrm_state_insert(x);
1430*4882a593Smuzhiyun err = 0;
1431*4882a593Smuzhiyun
1432*4882a593Smuzhiyun out:
1433*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun if (x1) {
1436*4882a593Smuzhiyun xfrm_state_delete(x1);
1437*4882a593Smuzhiyun xfrm_state_put(x1);
1438*4882a593Smuzhiyun }
1439*4882a593Smuzhiyun
1440*4882a593Smuzhiyun if (to_put)
1441*4882a593Smuzhiyun xfrm_state_put(to_put);
1442*4882a593Smuzhiyun
1443*4882a593Smuzhiyun return err;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_add);
1446*4882a593Smuzhiyun
1447*4882a593Smuzhiyun #ifdef CONFIG_XFRM_MIGRATE
clone_security(struct xfrm_state * x,struct xfrm_sec_ctx * security)1448*4882a593Smuzhiyun static inline int clone_security(struct xfrm_state *x, struct xfrm_sec_ctx *security)
1449*4882a593Smuzhiyun {
1450*4882a593Smuzhiyun struct xfrm_user_sec_ctx *uctx;
1451*4882a593Smuzhiyun int size = sizeof(*uctx) + security->ctx_len;
1452*4882a593Smuzhiyun int err;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun uctx = kmalloc(size, GFP_KERNEL);
1455*4882a593Smuzhiyun if (!uctx)
1456*4882a593Smuzhiyun return -ENOMEM;
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun uctx->exttype = XFRMA_SEC_CTX;
1459*4882a593Smuzhiyun uctx->len = size;
1460*4882a593Smuzhiyun uctx->ctx_doi = security->ctx_doi;
1461*4882a593Smuzhiyun uctx->ctx_alg = security->ctx_alg;
1462*4882a593Smuzhiyun uctx->ctx_len = security->ctx_len;
1463*4882a593Smuzhiyun memcpy(uctx + 1, security->ctx_str, security->ctx_len);
1464*4882a593Smuzhiyun err = security_xfrm_state_alloc(x, uctx);
1465*4882a593Smuzhiyun kfree(uctx);
1466*4882a593Smuzhiyun if (err)
1467*4882a593Smuzhiyun return err;
1468*4882a593Smuzhiyun
1469*4882a593Smuzhiyun return 0;
1470*4882a593Smuzhiyun }
1471*4882a593Smuzhiyun
xfrm_state_clone(struct xfrm_state * orig,struct xfrm_encap_tmpl * encap)1472*4882a593Smuzhiyun static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
1473*4882a593Smuzhiyun struct xfrm_encap_tmpl *encap)
1474*4882a593Smuzhiyun {
1475*4882a593Smuzhiyun struct net *net = xs_net(orig);
1476*4882a593Smuzhiyun struct xfrm_state *x = xfrm_state_alloc(net);
1477*4882a593Smuzhiyun if (!x)
1478*4882a593Smuzhiyun goto out;
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun memcpy(&x->id, &orig->id, sizeof(x->id));
1481*4882a593Smuzhiyun memcpy(&x->sel, &orig->sel, sizeof(x->sel));
1482*4882a593Smuzhiyun memcpy(&x->lft, &orig->lft, sizeof(x->lft));
1483*4882a593Smuzhiyun x->props.mode = orig->props.mode;
1484*4882a593Smuzhiyun x->props.replay_window = orig->props.replay_window;
1485*4882a593Smuzhiyun x->props.reqid = orig->props.reqid;
1486*4882a593Smuzhiyun x->props.family = orig->props.family;
1487*4882a593Smuzhiyun x->props.saddr = orig->props.saddr;
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun if (orig->aalg) {
1490*4882a593Smuzhiyun x->aalg = xfrm_algo_auth_clone(orig->aalg);
1491*4882a593Smuzhiyun if (!x->aalg)
1492*4882a593Smuzhiyun goto error;
1493*4882a593Smuzhiyun }
1494*4882a593Smuzhiyun x->props.aalgo = orig->props.aalgo;
1495*4882a593Smuzhiyun
1496*4882a593Smuzhiyun if (orig->aead) {
1497*4882a593Smuzhiyun x->aead = xfrm_algo_aead_clone(orig->aead);
1498*4882a593Smuzhiyun x->geniv = orig->geniv;
1499*4882a593Smuzhiyun if (!x->aead)
1500*4882a593Smuzhiyun goto error;
1501*4882a593Smuzhiyun }
1502*4882a593Smuzhiyun if (orig->ealg) {
1503*4882a593Smuzhiyun x->ealg = xfrm_algo_clone(orig->ealg);
1504*4882a593Smuzhiyun if (!x->ealg)
1505*4882a593Smuzhiyun goto error;
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun x->props.ealgo = orig->props.ealgo;
1508*4882a593Smuzhiyun
1509*4882a593Smuzhiyun if (orig->calg) {
1510*4882a593Smuzhiyun x->calg = xfrm_algo_clone(orig->calg);
1511*4882a593Smuzhiyun if (!x->calg)
1512*4882a593Smuzhiyun goto error;
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun x->props.calgo = orig->props.calgo;
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun if (encap || orig->encap) {
1517*4882a593Smuzhiyun if (encap)
1518*4882a593Smuzhiyun x->encap = kmemdup(encap, sizeof(*x->encap),
1519*4882a593Smuzhiyun GFP_KERNEL);
1520*4882a593Smuzhiyun else
1521*4882a593Smuzhiyun x->encap = kmemdup(orig->encap, sizeof(*x->encap),
1522*4882a593Smuzhiyun GFP_KERNEL);
1523*4882a593Smuzhiyun
1524*4882a593Smuzhiyun if (!x->encap)
1525*4882a593Smuzhiyun goto error;
1526*4882a593Smuzhiyun }
1527*4882a593Smuzhiyun
1528*4882a593Smuzhiyun if (orig->security)
1529*4882a593Smuzhiyun if (clone_security(x, orig->security))
1530*4882a593Smuzhiyun goto error;
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun if (orig->coaddr) {
1533*4882a593Smuzhiyun x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr),
1534*4882a593Smuzhiyun GFP_KERNEL);
1535*4882a593Smuzhiyun if (!x->coaddr)
1536*4882a593Smuzhiyun goto error;
1537*4882a593Smuzhiyun }
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun if (orig->replay_esn) {
1540*4882a593Smuzhiyun if (xfrm_replay_clone(x, orig))
1541*4882a593Smuzhiyun goto error;
1542*4882a593Smuzhiyun }
1543*4882a593Smuzhiyun
1544*4882a593Smuzhiyun memcpy(&x->mark, &orig->mark, sizeof(x->mark));
1545*4882a593Smuzhiyun memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun x->props.flags = orig->props.flags;
1548*4882a593Smuzhiyun x->props.extra_flags = orig->props.extra_flags;
1549*4882a593Smuzhiyun
1550*4882a593Smuzhiyun x->if_id = orig->if_id;
1551*4882a593Smuzhiyun x->tfcpad = orig->tfcpad;
1552*4882a593Smuzhiyun x->replay_maxdiff = orig->replay_maxdiff;
1553*4882a593Smuzhiyun x->replay_maxage = orig->replay_maxage;
1554*4882a593Smuzhiyun memcpy(&x->curlft, &orig->curlft, sizeof(x->curlft));
1555*4882a593Smuzhiyun x->km.state = orig->km.state;
1556*4882a593Smuzhiyun x->km.seq = orig->km.seq;
1557*4882a593Smuzhiyun x->replay = orig->replay;
1558*4882a593Smuzhiyun x->preplay = orig->preplay;
1559*4882a593Smuzhiyun x->lastused = orig->lastused;
1560*4882a593Smuzhiyun
1561*4882a593Smuzhiyun return x;
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun error:
1564*4882a593Smuzhiyun xfrm_state_put(x);
1565*4882a593Smuzhiyun out:
1566*4882a593Smuzhiyun return NULL;
1567*4882a593Smuzhiyun }
1568*4882a593Smuzhiyun
xfrm_migrate_state_find(struct xfrm_migrate * m,struct net * net,u32 if_id)1569*4882a593Smuzhiyun struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
1570*4882a593Smuzhiyun u32 if_id)
1571*4882a593Smuzhiyun {
1572*4882a593Smuzhiyun unsigned int h;
1573*4882a593Smuzhiyun struct xfrm_state *x = NULL;
1574*4882a593Smuzhiyun
1575*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun if (m->reqid) {
1578*4882a593Smuzhiyun h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
1579*4882a593Smuzhiyun m->reqid, m->old_family);
1580*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1581*4882a593Smuzhiyun if (x->props.mode != m->mode ||
1582*4882a593Smuzhiyun x->id.proto != m->proto)
1583*4882a593Smuzhiyun continue;
1584*4882a593Smuzhiyun if (m->reqid && x->props.reqid != m->reqid)
1585*4882a593Smuzhiyun continue;
1586*4882a593Smuzhiyun if (if_id != 0 && x->if_id != if_id)
1587*4882a593Smuzhiyun continue;
1588*4882a593Smuzhiyun if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
1589*4882a593Smuzhiyun m->old_family) ||
1590*4882a593Smuzhiyun !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
1591*4882a593Smuzhiyun m->old_family))
1592*4882a593Smuzhiyun continue;
1593*4882a593Smuzhiyun xfrm_state_hold(x);
1594*4882a593Smuzhiyun break;
1595*4882a593Smuzhiyun }
1596*4882a593Smuzhiyun } else {
1597*4882a593Smuzhiyun h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
1598*4882a593Smuzhiyun m->old_family);
1599*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) {
1600*4882a593Smuzhiyun if (x->props.mode != m->mode ||
1601*4882a593Smuzhiyun x->id.proto != m->proto)
1602*4882a593Smuzhiyun continue;
1603*4882a593Smuzhiyun if (if_id != 0 && x->if_id != if_id)
1604*4882a593Smuzhiyun continue;
1605*4882a593Smuzhiyun if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
1606*4882a593Smuzhiyun m->old_family) ||
1607*4882a593Smuzhiyun !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
1608*4882a593Smuzhiyun m->old_family))
1609*4882a593Smuzhiyun continue;
1610*4882a593Smuzhiyun xfrm_state_hold(x);
1611*4882a593Smuzhiyun break;
1612*4882a593Smuzhiyun }
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun
1615*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1616*4882a593Smuzhiyun
1617*4882a593Smuzhiyun return x;
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_migrate_state_find);
1620*4882a593Smuzhiyun
xfrm_state_migrate(struct xfrm_state * x,struct xfrm_migrate * m,struct xfrm_encap_tmpl * encap)1621*4882a593Smuzhiyun struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
1622*4882a593Smuzhiyun struct xfrm_migrate *m,
1623*4882a593Smuzhiyun struct xfrm_encap_tmpl *encap)
1624*4882a593Smuzhiyun {
1625*4882a593Smuzhiyun struct xfrm_state *xc;
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun xc = xfrm_state_clone(x, encap);
1628*4882a593Smuzhiyun if (!xc)
1629*4882a593Smuzhiyun return NULL;
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun xc->props.family = m->new_family;
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun if (xfrm_init_state(xc) < 0)
1634*4882a593Smuzhiyun goto error;
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
1637*4882a593Smuzhiyun memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun /* add state */
1640*4882a593Smuzhiyun if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) {
1641*4882a593Smuzhiyun /* a care is needed when the destination address of the
1642*4882a593Smuzhiyun state is to be updated as it is a part of triplet */
1643*4882a593Smuzhiyun xfrm_state_insert(xc);
1644*4882a593Smuzhiyun } else {
1645*4882a593Smuzhiyun if (xfrm_state_add(xc) < 0)
1646*4882a593Smuzhiyun goto error;
1647*4882a593Smuzhiyun }
1648*4882a593Smuzhiyun
1649*4882a593Smuzhiyun return xc;
1650*4882a593Smuzhiyun error:
1651*4882a593Smuzhiyun xfrm_state_put(xc);
1652*4882a593Smuzhiyun return NULL;
1653*4882a593Smuzhiyun }
1654*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_migrate);
1655*4882a593Smuzhiyun #endif
1656*4882a593Smuzhiyun
xfrm_state_update(struct xfrm_state * x)1657*4882a593Smuzhiyun int xfrm_state_update(struct xfrm_state *x)
1658*4882a593Smuzhiyun {
1659*4882a593Smuzhiyun struct xfrm_state *x1, *to_put;
1660*4882a593Smuzhiyun int err;
1661*4882a593Smuzhiyun int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
1662*4882a593Smuzhiyun struct net *net = xs_net(x);
1663*4882a593Smuzhiyun
1664*4882a593Smuzhiyun to_put = NULL;
1665*4882a593Smuzhiyun
1666*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1667*4882a593Smuzhiyun x1 = __xfrm_state_locate(x, use_spi, x->props.family);
1668*4882a593Smuzhiyun
1669*4882a593Smuzhiyun err = -ESRCH;
1670*4882a593Smuzhiyun if (!x1)
1671*4882a593Smuzhiyun goto out;
1672*4882a593Smuzhiyun
1673*4882a593Smuzhiyun if (xfrm_state_kern(x1)) {
1674*4882a593Smuzhiyun to_put = x1;
1675*4882a593Smuzhiyun err = -EEXIST;
1676*4882a593Smuzhiyun goto out;
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun
1679*4882a593Smuzhiyun if (x1->km.state == XFRM_STATE_ACQ) {
1680*4882a593Smuzhiyun __xfrm_state_insert(x);
1681*4882a593Smuzhiyun x = NULL;
1682*4882a593Smuzhiyun }
1683*4882a593Smuzhiyun err = 0;
1684*4882a593Smuzhiyun
1685*4882a593Smuzhiyun out:
1686*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1687*4882a593Smuzhiyun
1688*4882a593Smuzhiyun if (to_put)
1689*4882a593Smuzhiyun xfrm_state_put(to_put);
1690*4882a593Smuzhiyun
1691*4882a593Smuzhiyun if (err)
1692*4882a593Smuzhiyun return err;
1693*4882a593Smuzhiyun
1694*4882a593Smuzhiyun if (!x) {
1695*4882a593Smuzhiyun xfrm_state_delete(x1);
1696*4882a593Smuzhiyun xfrm_state_put(x1);
1697*4882a593Smuzhiyun return 0;
1698*4882a593Smuzhiyun }
1699*4882a593Smuzhiyun
1700*4882a593Smuzhiyun err = -EINVAL;
1701*4882a593Smuzhiyun spin_lock_bh(&x1->lock);
1702*4882a593Smuzhiyun if (likely(x1->km.state == XFRM_STATE_VALID)) {
1703*4882a593Smuzhiyun if (x->encap && x1->encap &&
1704*4882a593Smuzhiyun x->encap->encap_type == x1->encap->encap_type)
1705*4882a593Smuzhiyun memcpy(x1->encap, x->encap, sizeof(*x1->encap));
1706*4882a593Smuzhiyun else if (x->encap || x1->encap)
1707*4882a593Smuzhiyun goto fail;
1708*4882a593Smuzhiyun
1709*4882a593Smuzhiyun if (x->coaddr && x1->coaddr) {
1710*4882a593Smuzhiyun memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
1711*4882a593Smuzhiyun }
1712*4882a593Smuzhiyun if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel)))
1713*4882a593Smuzhiyun memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
1714*4882a593Smuzhiyun memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
1715*4882a593Smuzhiyun x1->km.dying = 0;
1716*4882a593Smuzhiyun
1717*4882a593Smuzhiyun hrtimer_start(&x1->mtimer, ktime_set(1, 0),
1718*4882a593Smuzhiyun HRTIMER_MODE_REL_SOFT);
1719*4882a593Smuzhiyun if (x1->curlft.use_time)
1720*4882a593Smuzhiyun xfrm_state_check_expire(x1);
1721*4882a593Smuzhiyun
1722*4882a593Smuzhiyun if (x->props.smark.m || x->props.smark.v || x->if_id) {
1723*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun if (x->props.smark.m || x->props.smark.v)
1726*4882a593Smuzhiyun x1->props.smark = x->props.smark;
1727*4882a593Smuzhiyun
1728*4882a593Smuzhiyun if (x->if_id)
1729*4882a593Smuzhiyun x1->if_id = x->if_id;
1730*4882a593Smuzhiyun
1731*4882a593Smuzhiyun __xfrm_state_bump_genids(x1);
1732*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1733*4882a593Smuzhiyun }
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun err = 0;
1736*4882a593Smuzhiyun x->km.state = XFRM_STATE_DEAD;
1737*4882a593Smuzhiyun __xfrm_state_put(x);
1738*4882a593Smuzhiyun }
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun fail:
1741*4882a593Smuzhiyun spin_unlock_bh(&x1->lock);
1742*4882a593Smuzhiyun
1743*4882a593Smuzhiyun xfrm_state_put(x1);
1744*4882a593Smuzhiyun
1745*4882a593Smuzhiyun return err;
1746*4882a593Smuzhiyun }
1747*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_update);
1748*4882a593Smuzhiyun
xfrm_state_check_expire(struct xfrm_state * x)1749*4882a593Smuzhiyun int xfrm_state_check_expire(struct xfrm_state *x)
1750*4882a593Smuzhiyun {
1751*4882a593Smuzhiyun if (!x->curlft.use_time)
1752*4882a593Smuzhiyun x->curlft.use_time = ktime_get_real_seconds();
1753*4882a593Smuzhiyun
1754*4882a593Smuzhiyun if (x->curlft.bytes >= x->lft.hard_byte_limit ||
1755*4882a593Smuzhiyun x->curlft.packets >= x->lft.hard_packet_limit) {
1756*4882a593Smuzhiyun x->km.state = XFRM_STATE_EXPIRED;
1757*4882a593Smuzhiyun hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL_SOFT);
1758*4882a593Smuzhiyun return -EINVAL;
1759*4882a593Smuzhiyun }
1760*4882a593Smuzhiyun
1761*4882a593Smuzhiyun if (!x->km.dying &&
1762*4882a593Smuzhiyun (x->curlft.bytes >= x->lft.soft_byte_limit ||
1763*4882a593Smuzhiyun x->curlft.packets >= x->lft.soft_packet_limit)) {
1764*4882a593Smuzhiyun x->km.dying = 1;
1765*4882a593Smuzhiyun km_state_expired(x, 0, 0);
1766*4882a593Smuzhiyun }
1767*4882a593Smuzhiyun return 0;
1768*4882a593Smuzhiyun }
1769*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_check_expire);
1770*4882a593Smuzhiyun
1771*4882a593Smuzhiyun struct xfrm_state *
xfrm_state_lookup(struct net * net,u32 mark,const xfrm_address_t * daddr,__be32 spi,u8 proto,unsigned short family)1772*4882a593Smuzhiyun xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi,
1773*4882a593Smuzhiyun u8 proto, unsigned short family)
1774*4882a593Smuzhiyun {
1775*4882a593Smuzhiyun struct xfrm_state *x;
1776*4882a593Smuzhiyun
1777*4882a593Smuzhiyun rcu_read_lock();
1778*4882a593Smuzhiyun x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family);
1779*4882a593Smuzhiyun rcu_read_unlock();
1780*4882a593Smuzhiyun return x;
1781*4882a593Smuzhiyun }
1782*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_lookup);
1783*4882a593Smuzhiyun
1784*4882a593Smuzhiyun struct xfrm_state *
xfrm_state_lookup_byaddr(struct net * net,u32 mark,const xfrm_address_t * daddr,const xfrm_address_t * saddr,u8 proto,unsigned short family)1785*4882a593Smuzhiyun xfrm_state_lookup_byaddr(struct net *net, u32 mark,
1786*4882a593Smuzhiyun const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1787*4882a593Smuzhiyun u8 proto, unsigned short family)
1788*4882a593Smuzhiyun {
1789*4882a593Smuzhiyun struct xfrm_state *x;
1790*4882a593Smuzhiyun
1791*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1792*4882a593Smuzhiyun x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family);
1793*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1794*4882a593Smuzhiyun return x;
1795*4882a593Smuzhiyun }
1796*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1797*4882a593Smuzhiyun
1798*4882a593Smuzhiyun struct xfrm_state *
xfrm_find_acq(struct net * net,const struct xfrm_mark * mark,u8 mode,u32 reqid,u32 if_id,u8 proto,const xfrm_address_t * daddr,const xfrm_address_t * saddr,int create,unsigned short family)1799*4882a593Smuzhiyun xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
1800*4882a593Smuzhiyun u32 if_id, u8 proto, const xfrm_address_t *daddr,
1801*4882a593Smuzhiyun const xfrm_address_t *saddr, int create, unsigned short family)
1802*4882a593Smuzhiyun {
1803*4882a593Smuzhiyun struct xfrm_state *x;
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1806*4882a593Smuzhiyun x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create);
1807*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1808*4882a593Smuzhiyun
1809*4882a593Smuzhiyun return x;
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_find_acq);
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun #ifdef CONFIG_XFRM_SUB_POLICY
1814*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
1815*4882a593Smuzhiyun /* distribution counting sort function for xfrm_state and xfrm_tmpl */
1816*4882a593Smuzhiyun static void
__xfrm6_sort(void ** dst,void ** src,int n,int (* cmp)(const void * p),int maxclass)1817*4882a593Smuzhiyun __xfrm6_sort(void **dst, void **src, int n,
1818*4882a593Smuzhiyun int (*cmp)(const void *p), int maxclass)
1819*4882a593Smuzhiyun {
1820*4882a593Smuzhiyun int count[XFRM_MAX_DEPTH] = { };
1821*4882a593Smuzhiyun int class[XFRM_MAX_DEPTH];
1822*4882a593Smuzhiyun int i;
1823*4882a593Smuzhiyun
1824*4882a593Smuzhiyun for (i = 0; i < n; i++) {
1825*4882a593Smuzhiyun int c = cmp(src[i]);
1826*4882a593Smuzhiyun
1827*4882a593Smuzhiyun class[i] = c;
1828*4882a593Smuzhiyun count[c]++;
1829*4882a593Smuzhiyun }
1830*4882a593Smuzhiyun
1831*4882a593Smuzhiyun for (i = 2; i < maxclass; i++)
1832*4882a593Smuzhiyun count[i] += count[i - 1];
1833*4882a593Smuzhiyun
1834*4882a593Smuzhiyun for (i = 0; i < n; i++) {
1835*4882a593Smuzhiyun dst[count[class[i] - 1]++] = src[i];
1836*4882a593Smuzhiyun src[i] = NULL;
1837*4882a593Smuzhiyun }
1838*4882a593Smuzhiyun }
1839*4882a593Smuzhiyun
1840*4882a593Smuzhiyun /* Rule for xfrm_state:
1841*4882a593Smuzhiyun *
1842*4882a593Smuzhiyun * rule 1: select IPsec transport except AH
1843*4882a593Smuzhiyun * rule 2: select MIPv6 RO or inbound trigger
1844*4882a593Smuzhiyun * rule 3: select IPsec transport AH
1845*4882a593Smuzhiyun * rule 4: select IPsec tunnel
1846*4882a593Smuzhiyun * rule 5: others
1847*4882a593Smuzhiyun */
__xfrm6_state_sort_cmp(const void * p)1848*4882a593Smuzhiyun static int __xfrm6_state_sort_cmp(const void *p)
1849*4882a593Smuzhiyun {
1850*4882a593Smuzhiyun const struct xfrm_state *v = p;
1851*4882a593Smuzhiyun
1852*4882a593Smuzhiyun switch (v->props.mode) {
1853*4882a593Smuzhiyun case XFRM_MODE_TRANSPORT:
1854*4882a593Smuzhiyun if (v->id.proto != IPPROTO_AH)
1855*4882a593Smuzhiyun return 1;
1856*4882a593Smuzhiyun else
1857*4882a593Smuzhiyun return 3;
1858*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6_MIP6)
1859*4882a593Smuzhiyun case XFRM_MODE_ROUTEOPTIMIZATION:
1860*4882a593Smuzhiyun case XFRM_MODE_IN_TRIGGER:
1861*4882a593Smuzhiyun return 2;
1862*4882a593Smuzhiyun #endif
1863*4882a593Smuzhiyun case XFRM_MODE_TUNNEL:
1864*4882a593Smuzhiyun case XFRM_MODE_BEET:
1865*4882a593Smuzhiyun return 4;
1866*4882a593Smuzhiyun }
1867*4882a593Smuzhiyun return 5;
1868*4882a593Smuzhiyun }
1869*4882a593Smuzhiyun
1870*4882a593Smuzhiyun /* Rule for xfrm_tmpl:
1871*4882a593Smuzhiyun *
1872*4882a593Smuzhiyun * rule 1: select IPsec transport
1873*4882a593Smuzhiyun * rule 2: select MIPv6 RO or inbound trigger
1874*4882a593Smuzhiyun * rule 3: select IPsec tunnel
1875*4882a593Smuzhiyun * rule 4: others
1876*4882a593Smuzhiyun */
__xfrm6_tmpl_sort_cmp(const void * p)1877*4882a593Smuzhiyun static int __xfrm6_tmpl_sort_cmp(const void *p)
1878*4882a593Smuzhiyun {
1879*4882a593Smuzhiyun const struct xfrm_tmpl *v = p;
1880*4882a593Smuzhiyun
1881*4882a593Smuzhiyun switch (v->mode) {
1882*4882a593Smuzhiyun case XFRM_MODE_TRANSPORT:
1883*4882a593Smuzhiyun return 1;
1884*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6_MIP6)
1885*4882a593Smuzhiyun case XFRM_MODE_ROUTEOPTIMIZATION:
1886*4882a593Smuzhiyun case XFRM_MODE_IN_TRIGGER:
1887*4882a593Smuzhiyun return 2;
1888*4882a593Smuzhiyun #endif
1889*4882a593Smuzhiyun case XFRM_MODE_TUNNEL:
1890*4882a593Smuzhiyun case XFRM_MODE_BEET:
1891*4882a593Smuzhiyun return 3;
1892*4882a593Smuzhiyun }
1893*4882a593Smuzhiyun return 4;
1894*4882a593Smuzhiyun }
1895*4882a593Smuzhiyun #else
__xfrm6_state_sort_cmp(const void * p)1896*4882a593Smuzhiyun static inline int __xfrm6_state_sort_cmp(const void *p) { return 5; }
__xfrm6_tmpl_sort_cmp(const void * p)1897*4882a593Smuzhiyun static inline int __xfrm6_tmpl_sort_cmp(const void *p) { return 4; }
1898*4882a593Smuzhiyun
1899*4882a593Smuzhiyun static inline void
__xfrm6_sort(void ** dst,void ** src,int n,int (* cmp)(const void * p),int maxclass)1900*4882a593Smuzhiyun __xfrm6_sort(void **dst, void **src, int n,
1901*4882a593Smuzhiyun int (*cmp)(const void *p), int maxclass)
1902*4882a593Smuzhiyun {
1903*4882a593Smuzhiyun int i;
1904*4882a593Smuzhiyun
1905*4882a593Smuzhiyun for (i = 0; i < n; i++)
1906*4882a593Smuzhiyun dst[i] = src[i];
1907*4882a593Smuzhiyun }
1908*4882a593Smuzhiyun #endif /* CONFIG_IPV6 */
1909*4882a593Smuzhiyun
1910*4882a593Smuzhiyun void
xfrm_tmpl_sort(struct xfrm_tmpl ** dst,struct xfrm_tmpl ** src,int n,unsigned short family)1911*4882a593Smuzhiyun xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
1912*4882a593Smuzhiyun unsigned short family)
1913*4882a593Smuzhiyun {
1914*4882a593Smuzhiyun int i;
1915*4882a593Smuzhiyun
1916*4882a593Smuzhiyun if (family == AF_INET6)
1917*4882a593Smuzhiyun __xfrm6_sort((void **)dst, (void **)src, n,
1918*4882a593Smuzhiyun __xfrm6_tmpl_sort_cmp, 5);
1919*4882a593Smuzhiyun else
1920*4882a593Smuzhiyun for (i = 0; i < n; i++)
1921*4882a593Smuzhiyun dst[i] = src[i];
1922*4882a593Smuzhiyun }
1923*4882a593Smuzhiyun
1924*4882a593Smuzhiyun void
xfrm_state_sort(struct xfrm_state ** dst,struct xfrm_state ** src,int n,unsigned short family)1925*4882a593Smuzhiyun xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
1926*4882a593Smuzhiyun unsigned short family)
1927*4882a593Smuzhiyun {
1928*4882a593Smuzhiyun int i;
1929*4882a593Smuzhiyun
1930*4882a593Smuzhiyun if (family == AF_INET6)
1931*4882a593Smuzhiyun __xfrm6_sort((void **)dst, (void **)src, n,
1932*4882a593Smuzhiyun __xfrm6_state_sort_cmp, 6);
1933*4882a593Smuzhiyun else
1934*4882a593Smuzhiyun for (i = 0; i < n; i++)
1935*4882a593Smuzhiyun dst[i] = src[i];
1936*4882a593Smuzhiyun }
1937*4882a593Smuzhiyun #endif
1938*4882a593Smuzhiyun
1939*4882a593Smuzhiyun /* Silly enough, but I'm lazy to build resolution list */
1940*4882a593Smuzhiyun
__xfrm_find_acq_byseq(struct net * net,u32 mark,u32 seq)1941*4882a593Smuzhiyun static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
1942*4882a593Smuzhiyun {
1943*4882a593Smuzhiyun int i;
1944*4882a593Smuzhiyun
1945*4882a593Smuzhiyun for (i = 0; i <= net->xfrm.state_hmask; i++) {
1946*4882a593Smuzhiyun struct xfrm_state *x;
1947*4882a593Smuzhiyun
1948*4882a593Smuzhiyun hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
1949*4882a593Smuzhiyun if (x->km.seq == seq &&
1950*4882a593Smuzhiyun (mark & x->mark.m) == x->mark.v &&
1951*4882a593Smuzhiyun x->km.state == XFRM_STATE_ACQ) {
1952*4882a593Smuzhiyun xfrm_state_hold(x);
1953*4882a593Smuzhiyun return x;
1954*4882a593Smuzhiyun }
1955*4882a593Smuzhiyun }
1956*4882a593Smuzhiyun }
1957*4882a593Smuzhiyun return NULL;
1958*4882a593Smuzhiyun }
1959*4882a593Smuzhiyun
xfrm_find_acq_byseq(struct net * net,u32 mark,u32 seq)1960*4882a593Smuzhiyun struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq)
1961*4882a593Smuzhiyun {
1962*4882a593Smuzhiyun struct xfrm_state *x;
1963*4882a593Smuzhiyun
1964*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
1965*4882a593Smuzhiyun x = __xfrm_find_acq_byseq(net, mark, seq);
1966*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1967*4882a593Smuzhiyun return x;
1968*4882a593Smuzhiyun }
1969*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_find_acq_byseq);
1970*4882a593Smuzhiyun
xfrm_get_acqseq(void)1971*4882a593Smuzhiyun u32 xfrm_get_acqseq(void)
1972*4882a593Smuzhiyun {
1973*4882a593Smuzhiyun u32 res;
1974*4882a593Smuzhiyun static atomic_t acqseq;
1975*4882a593Smuzhiyun
1976*4882a593Smuzhiyun do {
1977*4882a593Smuzhiyun res = atomic_inc_return(&acqseq);
1978*4882a593Smuzhiyun } while (!res);
1979*4882a593Smuzhiyun
1980*4882a593Smuzhiyun return res;
1981*4882a593Smuzhiyun }
1982*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_get_acqseq);
1983*4882a593Smuzhiyun
verify_spi_info(u8 proto,u32 min,u32 max)1984*4882a593Smuzhiyun int verify_spi_info(u8 proto, u32 min, u32 max)
1985*4882a593Smuzhiyun {
1986*4882a593Smuzhiyun switch (proto) {
1987*4882a593Smuzhiyun case IPPROTO_AH:
1988*4882a593Smuzhiyun case IPPROTO_ESP:
1989*4882a593Smuzhiyun break;
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun case IPPROTO_COMP:
1992*4882a593Smuzhiyun /* IPCOMP spi is 16-bits. */
1993*4882a593Smuzhiyun if (max >= 0x10000)
1994*4882a593Smuzhiyun return -EINVAL;
1995*4882a593Smuzhiyun break;
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun default:
1998*4882a593Smuzhiyun return -EINVAL;
1999*4882a593Smuzhiyun }
2000*4882a593Smuzhiyun
2001*4882a593Smuzhiyun if (min > max)
2002*4882a593Smuzhiyun return -EINVAL;
2003*4882a593Smuzhiyun
2004*4882a593Smuzhiyun return 0;
2005*4882a593Smuzhiyun }
2006*4882a593Smuzhiyun EXPORT_SYMBOL(verify_spi_info);
2007*4882a593Smuzhiyun
xfrm_alloc_spi(struct xfrm_state * x,u32 low,u32 high)2008*4882a593Smuzhiyun int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
2009*4882a593Smuzhiyun {
2010*4882a593Smuzhiyun struct net *net = xs_net(x);
2011*4882a593Smuzhiyun unsigned int h;
2012*4882a593Smuzhiyun struct xfrm_state *x0;
2013*4882a593Smuzhiyun int err = -ENOENT;
2014*4882a593Smuzhiyun __be32 minspi = htonl(low);
2015*4882a593Smuzhiyun __be32 maxspi = htonl(high);
2016*4882a593Smuzhiyun __be32 newspi = 0;
2017*4882a593Smuzhiyun u32 mark = x->mark.v & x->mark.m;
2018*4882a593Smuzhiyun
2019*4882a593Smuzhiyun spin_lock_bh(&x->lock);
2020*4882a593Smuzhiyun if (x->km.state == XFRM_STATE_DEAD)
2021*4882a593Smuzhiyun goto unlock;
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun err = 0;
2024*4882a593Smuzhiyun if (x->id.spi)
2025*4882a593Smuzhiyun goto unlock;
2026*4882a593Smuzhiyun
2027*4882a593Smuzhiyun err = -ENOENT;
2028*4882a593Smuzhiyun
2029*4882a593Smuzhiyun if (minspi == maxspi) {
2030*4882a593Smuzhiyun x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family);
2031*4882a593Smuzhiyun if (x0) {
2032*4882a593Smuzhiyun xfrm_state_put(x0);
2033*4882a593Smuzhiyun goto unlock;
2034*4882a593Smuzhiyun }
2035*4882a593Smuzhiyun newspi = minspi;
2036*4882a593Smuzhiyun } else {
2037*4882a593Smuzhiyun u32 spi = 0;
2038*4882a593Smuzhiyun for (h = 0; h < high-low+1; h++) {
2039*4882a593Smuzhiyun spi = low + prandom_u32()%(high-low+1);
2040*4882a593Smuzhiyun x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
2041*4882a593Smuzhiyun if (x0 == NULL) {
2042*4882a593Smuzhiyun newspi = htonl(spi);
2043*4882a593Smuzhiyun break;
2044*4882a593Smuzhiyun }
2045*4882a593Smuzhiyun xfrm_state_put(x0);
2046*4882a593Smuzhiyun }
2047*4882a593Smuzhiyun }
2048*4882a593Smuzhiyun if (newspi) {
2049*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
2050*4882a593Smuzhiyun x->id.spi = newspi;
2051*4882a593Smuzhiyun h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
2052*4882a593Smuzhiyun hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
2053*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
2054*4882a593Smuzhiyun
2055*4882a593Smuzhiyun err = 0;
2056*4882a593Smuzhiyun }
2057*4882a593Smuzhiyun
2058*4882a593Smuzhiyun unlock:
2059*4882a593Smuzhiyun spin_unlock_bh(&x->lock);
2060*4882a593Smuzhiyun
2061*4882a593Smuzhiyun return err;
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_alloc_spi);
2064*4882a593Smuzhiyun
__xfrm_state_filter_match(struct xfrm_state * x,struct xfrm_address_filter * filter)2065*4882a593Smuzhiyun static bool __xfrm_state_filter_match(struct xfrm_state *x,
2066*4882a593Smuzhiyun struct xfrm_address_filter *filter)
2067*4882a593Smuzhiyun {
2068*4882a593Smuzhiyun if (filter) {
2069*4882a593Smuzhiyun if ((filter->family == AF_INET ||
2070*4882a593Smuzhiyun filter->family == AF_INET6) &&
2071*4882a593Smuzhiyun x->props.family != filter->family)
2072*4882a593Smuzhiyun return false;
2073*4882a593Smuzhiyun
2074*4882a593Smuzhiyun return addr_match(&x->props.saddr, &filter->saddr,
2075*4882a593Smuzhiyun filter->splen) &&
2076*4882a593Smuzhiyun addr_match(&x->id.daddr, &filter->daddr,
2077*4882a593Smuzhiyun filter->dplen);
2078*4882a593Smuzhiyun }
2079*4882a593Smuzhiyun return true;
2080*4882a593Smuzhiyun }
2081*4882a593Smuzhiyun
xfrm_state_walk(struct net * net,struct xfrm_state_walk * walk,int (* func)(struct xfrm_state *,int,void *),void * data)2082*4882a593Smuzhiyun int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
2083*4882a593Smuzhiyun int (*func)(struct xfrm_state *, int, void*),
2084*4882a593Smuzhiyun void *data)
2085*4882a593Smuzhiyun {
2086*4882a593Smuzhiyun struct xfrm_state *state;
2087*4882a593Smuzhiyun struct xfrm_state_walk *x;
2088*4882a593Smuzhiyun int err = 0;
2089*4882a593Smuzhiyun
2090*4882a593Smuzhiyun if (walk->seq != 0 && list_empty(&walk->all))
2091*4882a593Smuzhiyun return 0;
2092*4882a593Smuzhiyun
2093*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
2094*4882a593Smuzhiyun if (list_empty(&walk->all))
2095*4882a593Smuzhiyun x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all);
2096*4882a593Smuzhiyun else
2097*4882a593Smuzhiyun x = list_first_entry(&walk->all, struct xfrm_state_walk, all);
2098*4882a593Smuzhiyun list_for_each_entry_from(x, &net->xfrm.state_all, all) {
2099*4882a593Smuzhiyun if (x->state == XFRM_STATE_DEAD)
2100*4882a593Smuzhiyun continue;
2101*4882a593Smuzhiyun state = container_of(x, struct xfrm_state, km);
2102*4882a593Smuzhiyun if (!xfrm_id_proto_match(state->id.proto, walk->proto))
2103*4882a593Smuzhiyun continue;
2104*4882a593Smuzhiyun if (!__xfrm_state_filter_match(state, walk->filter))
2105*4882a593Smuzhiyun continue;
2106*4882a593Smuzhiyun err = func(state, walk->seq, data);
2107*4882a593Smuzhiyun if (err) {
2108*4882a593Smuzhiyun list_move_tail(&walk->all, &x->all);
2109*4882a593Smuzhiyun goto out;
2110*4882a593Smuzhiyun }
2111*4882a593Smuzhiyun walk->seq++;
2112*4882a593Smuzhiyun }
2113*4882a593Smuzhiyun if (walk->seq == 0) {
2114*4882a593Smuzhiyun err = -ENOENT;
2115*4882a593Smuzhiyun goto out;
2116*4882a593Smuzhiyun }
2117*4882a593Smuzhiyun list_del_init(&walk->all);
2118*4882a593Smuzhiyun out:
2119*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
2120*4882a593Smuzhiyun return err;
2121*4882a593Smuzhiyun }
2122*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_walk);
2123*4882a593Smuzhiyun
xfrm_state_walk_init(struct xfrm_state_walk * walk,u8 proto,struct xfrm_address_filter * filter)2124*4882a593Smuzhiyun void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto,
2125*4882a593Smuzhiyun struct xfrm_address_filter *filter)
2126*4882a593Smuzhiyun {
2127*4882a593Smuzhiyun INIT_LIST_HEAD(&walk->all);
2128*4882a593Smuzhiyun walk->proto = proto;
2129*4882a593Smuzhiyun walk->state = XFRM_STATE_DEAD;
2130*4882a593Smuzhiyun walk->seq = 0;
2131*4882a593Smuzhiyun walk->filter = filter;
2132*4882a593Smuzhiyun }
2133*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_walk_init);
2134*4882a593Smuzhiyun
xfrm_state_walk_done(struct xfrm_state_walk * walk,struct net * net)2135*4882a593Smuzhiyun void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net)
2136*4882a593Smuzhiyun {
2137*4882a593Smuzhiyun kfree(walk->filter);
2138*4882a593Smuzhiyun
2139*4882a593Smuzhiyun if (list_empty(&walk->all))
2140*4882a593Smuzhiyun return;
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun spin_lock_bh(&net->xfrm.xfrm_state_lock);
2143*4882a593Smuzhiyun list_del(&walk->all);
2144*4882a593Smuzhiyun spin_unlock_bh(&net->xfrm.xfrm_state_lock);
2145*4882a593Smuzhiyun }
2146*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_walk_done);
2147*4882a593Smuzhiyun
xfrm_replay_timer_handler(struct timer_list * t)2148*4882a593Smuzhiyun static void xfrm_replay_timer_handler(struct timer_list *t)
2149*4882a593Smuzhiyun {
2150*4882a593Smuzhiyun struct xfrm_state *x = from_timer(x, t, rtimer);
2151*4882a593Smuzhiyun
2152*4882a593Smuzhiyun spin_lock(&x->lock);
2153*4882a593Smuzhiyun
2154*4882a593Smuzhiyun if (x->km.state == XFRM_STATE_VALID) {
2155*4882a593Smuzhiyun if (xfrm_aevent_is_on(xs_net(x)))
2156*4882a593Smuzhiyun x->repl->notify(x, XFRM_REPLAY_TIMEOUT);
2157*4882a593Smuzhiyun else
2158*4882a593Smuzhiyun x->xflags |= XFRM_TIME_DEFER;
2159*4882a593Smuzhiyun }
2160*4882a593Smuzhiyun
2161*4882a593Smuzhiyun spin_unlock(&x->lock);
2162*4882a593Smuzhiyun }
2163*4882a593Smuzhiyun
2164*4882a593Smuzhiyun static LIST_HEAD(xfrm_km_list);
2165*4882a593Smuzhiyun
km_policy_notify(struct xfrm_policy * xp,int dir,const struct km_event * c)2166*4882a593Smuzhiyun void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
2167*4882a593Smuzhiyun {
2168*4882a593Smuzhiyun struct xfrm_mgr *km;
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun rcu_read_lock();
2171*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list)
2172*4882a593Smuzhiyun if (km->notify_policy)
2173*4882a593Smuzhiyun km->notify_policy(xp, dir, c);
2174*4882a593Smuzhiyun rcu_read_unlock();
2175*4882a593Smuzhiyun }
2176*4882a593Smuzhiyun
km_state_notify(struct xfrm_state * x,const struct km_event * c)2177*4882a593Smuzhiyun void km_state_notify(struct xfrm_state *x, const struct km_event *c)
2178*4882a593Smuzhiyun {
2179*4882a593Smuzhiyun struct xfrm_mgr *km;
2180*4882a593Smuzhiyun rcu_read_lock();
2181*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list)
2182*4882a593Smuzhiyun if (km->notify)
2183*4882a593Smuzhiyun km->notify(x, c);
2184*4882a593Smuzhiyun rcu_read_unlock();
2185*4882a593Smuzhiyun }
2186*4882a593Smuzhiyun
2187*4882a593Smuzhiyun EXPORT_SYMBOL(km_policy_notify);
2188*4882a593Smuzhiyun EXPORT_SYMBOL(km_state_notify);
2189*4882a593Smuzhiyun
km_state_expired(struct xfrm_state * x,int hard,u32 portid)2190*4882a593Smuzhiyun void km_state_expired(struct xfrm_state *x, int hard, u32 portid)
2191*4882a593Smuzhiyun {
2192*4882a593Smuzhiyun struct km_event c;
2193*4882a593Smuzhiyun
2194*4882a593Smuzhiyun c.data.hard = hard;
2195*4882a593Smuzhiyun c.portid = portid;
2196*4882a593Smuzhiyun c.event = XFRM_MSG_EXPIRE;
2197*4882a593Smuzhiyun km_state_notify(x, &c);
2198*4882a593Smuzhiyun }
2199*4882a593Smuzhiyun
2200*4882a593Smuzhiyun EXPORT_SYMBOL(km_state_expired);
2201*4882a593Smuzhiyun /*
2202*4882a593Smuzhiyun * We send to all registered managers regardless of failure
2203*4882a593Smuzhiyun * We are happy with one success
2204*4882a593Smuzhiyun */
km_query(struct xfrm_state * x,struct xfrm_tmpl * t,struct xfrm_policy * pol)2205*4882a593Smuzhiyun int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
2206*4882a593Smuzhiyun {
2207*4882a593Smuzhiyun int err = -EINVAL, acqret;
2208*4882a593Smuzhiyun struct xfrm_mgr *km;
2209*4882a593Smuzhiyun
2210*4882a593Smuzhiyun rcu_read_lock();
2211*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list) {
2212*4882a593Smuzhiyun acqret = km->acquire(x, t, pol);
2213*4882a593Smuzhiyun if (!acqret)
2214*4882a593Smuzhiyun err = acqret;
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun rcu_read_unlock();
2217*4882a593Smuzhiyun return err;
2218*4882a593Smuzhiyun }
2219*4882a593Smuzhiyun EXPORT_SYMBOL(km_query);
2220*4882a593Smuzhiyun
km_new_mapping(struct xfrm_state * x,xfrm_address_t * ipaddr,__be16 sport)2221*4882a593Smuzhiyun int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport)
2222*4882a593Smuzhiyun {
2223*4882a593Smuzhiyun int err = -EINVAL;
2224*4882a593Smuzhiyun struct xfrm_mgr *km;
2225*4882a593Smuzhiyun
2226*4882a593Smuzhiyun rcu_read_lock();
2227*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list) {
2228*4882a593Smuzhiyun if (km->new_mapping)
2229*4882a593Smuzhiyun err = km->new_mapping(x, ipaddr, sport);
2230*4882a593Smuzhiyun if (!err)
2231*4882a593Smuzhiyun break;
2232*4882a593Smuzhiyun }
2233*4882a593Smuzhiyun rcu_read_unlock();
2234*4882a593Smuzhiyun return err;
2235*4882a593Smuzhiyun }
2236*4882a593Smuzhiyun EXPORT_SYMBOL(km_new_mapping);
2237*4882a593Smuzhiyun
km_policy_expired(struct xfrm_policy * pol,int dir,int hard,u32 portid)2238*4882a593Smuzhiyun void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid)
2239*4882a593Smuzhiyun {
2240*4882a593Smuzhiyun struct km_event c;
2241*4882a593Smuzhiyun
2242*4882a593Smuzhiyun c.data.hard = hard;
2243*4882a593Smuzhiyun c.portid = portid;
2244*4882a593Smuzhiyun c.event = XFRM_MSG_POLEXPIRE;
2245*4882a593Smuzhiyun km_policy_notify(pol, dir, &c);
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun EXPORT_SYMBOL(km_policy_expired);
2248*4882a593Smuzhiyun
2249*4882a593Smuzhiyun #ifdef CONFIG_XFRM_MIGRATE
km_migrate(const struct xfrm_selector * sel,u8 dir,u8 type,const struct xfrm_migrate * m,int num_migrate,const struct xfrm_kmaddress * k,const struct xfrm_encap_tmpl * encap)2250*4882a593Smuzhiyun int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
2251*4882a593Smuzhiyun const struct xfrm_migrate *m, int num_migrate,
2252*4882a593Smuzhiyun const struct xfrm_kmaddress *k,
2253*4882a593Smuzhiyun const struct xfrm_encap_tmpl *encap)
2254*4882a593Smuzhiyun {
2255*4882a593Smuzhiyun int err = -EINVAL;
2256*4882a593Smuzhiyun int ret;
2257*4882a593Smuzhiyun struct xfrm_mgr *km;
2258*4882a593Smuzhiyun
2259*4882a593Smuzhiyun rcu_read_lock();
2260*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list) {
2261*4882a593Smuzhiyun if (km->migrate) {
2262*4882a593Smuzhiyun ret = km->migrate(sel, dir, type, m, num_migrate, k,
2263*4882a593Smuzhiyun encap);
2264*4882a593Smuzhiyun if (!ret)
2265*4882a593Smuzhiyun err = ret;
2266*4882a593Smuzhiyun }
2267*4882a593Smuzhiyun }
2268*4882a593Smuzhiyun rcu_read_unlock();
2269*4882a593Smuzhiyun return err;
2270*4882a593Smuzhiyun }
2271*4882a593Smuzhiyun EXPORT_SYMBOL(km_migrate);
2272*4882a593Smuzhiyun #endif
2273*4882a593Smuzhiyun
km_report(struct net * net,u8 proto,struct xfrm_selector * sel,xfrm_address_t * addr)2274*4882a593Smuzhiyun int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr)
2275*4882a593Smuzhiyun {
2276*4882a593Smuzhiyun int err = -EINVAL;
2277*4882a593Smuzhiyun int ret;
2278*4882a593Smuzhiyun struct xfrm_mgr *km;
2279*4882a593Smuzhiyun
2280*4882a593Smuzhiyun rcu_read_lock();
2281*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list) {
2282*4882a593Smuzhiyun if (km->report) {
2283*4882a593Smuzhiyun ret = km->report(net, proto, sel, addr);
2284*4882a593Smuzhiyun if (!ret)
2285*4882a593Smuzhiyun err = ret;
2286*4882a593Smuzhiyun }
2287*4882a593Smuzhiyun }
2288*4882a593Smuzhiyun rcu_read_unlock();
2289*4882a593Smuzhiyun return err;
2290*4882a593Smuzhiyun }
2291*4882a593Smuzhiyun EXPORT_SYMBOL(km_report);
2292*4882a593Smuzhiyun
km_is_alive(const struct km_event * c)2293*4882a593Smuzhiyun static bool km_is_alive(const struct km_event *c)
2294*4882a593Smuzhiyun {
2295*4882a593Smuzhiyun struct xfrm_mgr *km;
2296*4882a593Smuzhiyun bool is_alive = false;
2297*4882a593Smuzhiyun
2298*4882a593Smuzhiyun rcu_read_lock();
2299*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list) {
2300*4882a593Smuzhiyun if (km->is_alive && km->is_alive(c)) {
2301*4882a593Smuzhiyun is_alive = true;
2302*4882a593Smuzhiyun break;
2303*4882a593Smuzhiyun }
2304*4882a593Smuzhiyun }
2305*4882a593Smuzhiyun rcu_read_unlock();
2306*4882a593Smuzhiyun
2307*4882a593Smuzhiyun return is_alive;
2308*4882a593Smuzhiyun }
2309*4882a593Smuzhiyun
2310*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_XFRM_USER_COMPAT)
2311*4882a593Smuzhiyun static DEFINE_SPINLOCK(xfrm_translator_lock);
2312*4882a593Smuzhiyun static struct xfrm_translator __rcu *xfrm_translator;
2313*4882a593Smuzhiyun
xfrm_get_translator(void)2314*4882a593Smuzhiyun struct xfrm_translator *xfrm_get_translator(void)
2315*4882a593Smuzhiyun {
2316*4882a593Smuzhiyun struct xfrm_translator *xtr;
2317*4882a593Smuzhiyun
2318*4882a593Smuzhiyun rcu_read_lock();
2319*4882a593Smuzhiyun xtr = rcu_dereference(xfrm_translator);
2320*4882a593Smuzhiyun if (unlikely(!xtr))
2321*4882a593Smuzhiyun goto out;
2322*4882a593Smuzhiyun if (!try_module_get(xtr->owner))
2323*4882a593Smuzhiyun xtr = NULL;
2324*4882a593Smuzhiyun out:
2325*4882a593Smuzhiyun rcu_read_unlock();
2326*4882a593Smuzhiyun return xtr;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_get_translator);
2329*4882a593Smuzhiyun
xfrm_put_translator(struct xfrm_translator * xtr)2330*4882a593Smuzhiyun void xfrm_put_translator(struct xfrm_translator *xtr)
2331*4882a593Smuzhiyun {
2332*4882a593Smuzhiyun module_put(xtr->owner);
2333*4882a593Smuzhiyun }
2334*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_put_translator);
2335*4882a593Smuzhiyun
xfrm_register_translator(struct xfrm_translator * xtr)2336*4882a593Smuzhiyun int xfrm_register_translator(struct xfrm_translator *xtr)
2337*4882a593Smuzhiyun {
2338*4882a593Smuzhiyun int err = 0;
2339*4882a593Smuzhiyun
2340*4882a593Smuzhiyun spin_lock_bh(&xfrm_translator_lock);
2341*4882a593Smuzhiyun if (unlikely(xfrm_translator != NULL))
2342*4882a593Smuzhiyun err = -EEXIST;
2343*4882a593Smuzhiyun else
2344*4882a593Smuzhiyun rcu_assign_pointer(xfrm_translator, xtr);
2345*4882a593Smuzhiyun spin_unlock_bh(&xfrm_translator_lock);
2346*4882a593Smuzhiyun
2347*4882a593Smuzhiyun return err;
2348*4882a593Smuzhiyun }
2349*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_register_translator);
2350*4882a593Smuzhiyun
xfrm_unregister_translator(struct xfrm_translator * xtr)2351*4882a593Smuzhiyun int xfrm_unregister_translator(struct xfrm_translator *xtr)
2352*4882a593Smuzhiyun {
2353*4882a593Smuzhiyun int err = 0;
2354*4882a593Smuzhiyun
2355*4882a593Smuzhiyun spin_lock_bh(&xfrm_translator_lock);
2356*4882a593Smuzhiyun if (likely(xfrm_translator != NULL)) {
2357*4882a593Smuzhiyun if (rcu_access_pointer(xfrm_translator) != xtr)
2358*4882a593Smuzhiyun err = -EINVAL;
2359*4882a593Smuzhiyun else
2360*4882a593Smuzhiyun RCU_INIT_POINTER(xfrm_translator, NULL);
2361*4882a593Smuzhiyun }
2362*4882a593Smuzhiyun spin_unlock_bh(&xfrm_translator_lock);
2363*4882a593Smuzhiyun synchronize_rcu();
2364*4882a593Smuzhiyun
2365*4882a593Smuzhiyun return err;
2366*4882a593Smuzhiyun }
2367*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_unregister_translator);
2368*4882a593Smuzhiyun #endif
2369*4882a593Smuzhiyun
xfrm_user_policy(struct sock * sk,int optname,sockptr_t optval,int optlen)2370*4882a593Smuzhiyun int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
2371*4882a593Smuzhiyun {
2372*4882a593Smuzhiyun int err;
2373*4882a593Smuzhiyun u8 *data;
2374*4882a593Smuzhiyun struct xfrm_mgr *km;
2375*4882a593Smuzhiyun struct xfrm_policy *pol = NULL;
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun if (sockptr_is_null(optval) && !optlen) {
2378*4882a593Smuzhiyun xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
2379*4882a593Smuzhiyun xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
2380*4882a593Smuzhiyun __sk_dst_reset(sk);
2381*4882a593Smuzhiyun return 0;
2382*4882a593Smuzhiyun }
2383*4882a593Smuzhiyun
2384*4882a593Smuzhiyun if (optlen <= 0 || optlen > PAGE_SIZE)
2385*4882a593Smuzhiyun return -EMSGSIZE;
2386*4882a593Smuzhiyun
2387*4882a593Smuzhiyun data = memdup_sockptr(optval, optlen);
2388*4882a593Smuzhiyun if (IS_ERR(data))
2389*4882a593Smuzhiyun return PTR_ERR(data);
2390*4882a593Smuzhiyun
2391*4882a593Smuzhiyun /* Use the 64-bit / untranslated format on Android, even for compat */
2392*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_ANDROID) || IS_ENABLED(CONFIG_XFRM_USER_COMPAT)) {
2393*4882a593Smuzhiyun if (in_compat_syscall()) {
2394*4882a593Smuzhiyun struct xfrm_translator *xtr = xfrm_get_translator();
2395*4882a593Smuzhiyun
2396*4882a593Smuzhiyun if (!xtr) {
2397*4882a593Smuzhiyun kfree(data);
2398*4882a593Smuzhiyun return -EOPNOTSUPP;
2399*4882a593Smuzhiyun }
2400*4882a593Smuzhiyun
2401*4882a593Smuzhiyun err = xtr->xlate_user_policy_sockptr(&data, optlen);
2402*4882a593Smuzhiyun xfrm_put_translator(xtr);
2403*4882a593Smuzhiyun if (err) {
2404*4882a593Smuzhiyun kfree(data);
2405*4882a593Smuzhiyun return err;
2406*4882a593Smuzhiyun }
2407*4882a593Smuzhiyun }
2408*4882a593Smuzhiyun }
2409*4882a593Smuzhiyun
2410*4882a593Smuzhiyun err = -EINVAL;
2411*4882a593Smuzhiyun rcu_read_lock();
2412*4882a593Smuzhiyun list_for_each_entry_rcu(km, &xfrm_km_list, list) {
2413*4882a593Smuzhiyun pol = km->compile_policy(sk, optname, data,
2414*4882a593Smuzhiyun optlen, &err);
2415*4882a593Smuzhiyun if (err >= 0)
2416*4882a593Smuzhiyun break;
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun rcu_read_unlock();
2419*4882a593Smuzhiyun
2420*4882a593Smuzhiyun if (err >= 0) {
2421*4882a593Smuzhiyun xfrm_sk_policy_insert(sk, err, pol);
2422*4882a593Smuzhiyun xfrm_pol_put(pol);
2423*4882a593Smuzhiyun __sk_dst_reset(sk);
2424*4882a593Smuzhiyun err = 0;
2425*4882a593Smuzhiyun }
2426*4882a593Smuzhiyun
2427*4882a593Smuzhiyun kfree(data);
2428*4882a593Smuzhiyun return err;
2429*4882a593Smuzhiyun }
2430*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_user_policy);
2431*4882a593Smuzhiyun
2432*4882a593Smuzhiyun static DEFINE_SPINLOCK(xfrm_km_lock);
2433*4882a593Smuzhiyun
xfrm_register_km(struct xfrm_mgr * km)2434*4882a593Smuzhiyun int xfrm_register_km(struct xfrm_mgr *km)
2435*4882a593Smuzhiyun {
2436*4882a593Smuzhiyun spin_lock_bh(&xfrm_km_lock);
2437*4882a593Smuzhiyun list_add_tail_rcu(&km->list, &xfrm_km_list);
2438*4882a593Smuzhiyun spin_unlock_bh(&xfrm_km_lock);
2439*4882a593Smuzhiyun return 0;
2440*4882a593Smuzhiyun }
2441*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_register_km);
2442*4882a593Smuzhiyun
xfrm_unregister_km(struct xfrm_mgr * km)2443*4882a593Smuzhiyun int xfrm_unregister_km(struct xfrm_mgr *km)
2444*4882a593Smuzhiyun {
2445*4882a593Smuzhiyun spin_lock_bh(&xfrm_km_lock);
2446*4882a593Smuzhiyun list_del_rcu(&km->list);
2447*4882a593Smuzhiyun spin_unlock_bh(&xfrm_km_lock);
2448*4882a593Smuzhiyun synchronize_rcu();
2449*4882a593Smuzhiyun return 0;
2450*4882a593Smuzhiyun }
2451*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_unregister_km);
2452*4882a593Smuzhiyun
xfrm_state_register_afinfo(struct xfrm_state_afinfo * afinfo)2453*4882a593Smuzhiyun int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo)
2454*4882a593Smuzhiyun {
2455*4882a593Smuzhiyun int err = 0;
2456*4882a593Smuzhiyun
2457*4882a593Smuzhiyun if (WARN_ON(afinfo->family >= NPROTO))
2458*4882a593Smuzhiyun return -EAFNOSUPPORT;
2459*4882a593Smuzhiyun
2460*4882a593Smuzhiyun spin_lock_bh(&xfrm_state_afinfo_lock);
2461*4882a593Smuzhiyun if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL))
2462*4882a593Smuzhiyun err = -EEXIST;
2463*4882a593Smuzhiyun else
2464*4882a593Smuzhiyun rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo);
2465*4882a593Smuzhiyun spin_unlock_bh(&xfrm_state_afinfo_lock);
2466*4882a593Smuzhiyun return err;
2467*4882a593Smuzhiyun }
2468*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_register_afinfo);
2469*4882a593Smuzhiyun
xfrm_state_unregister_afinfo(struct xfrm_state_afinfo * afinfo)2470*4882a593Smuzhiyun int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo)
2471*4882a593Smuzhiyun {
2472*4882a593Smuzhiyun int err = 0, family = afinfo->family;
2473*4882a593Smuzhiyun
2474*4882a593Smuzhiyun if (WARN_ON(family >= NPROTO))
2475*4882a593Smuzhiyun return -EAFNOSUPPORT;
2476*4882a593Smuzhiyun
2477*4882a593Smuzhiyun spin_lock_bh(&xfrm_state_afinfo_lock);
2478*4882a593Smuzhiyun if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) {
2479*4882a593Smuzhiyun if (rcu_access_pointer(xfrm_state_afinfo[family]) != afinfo)
2480*4882a593Smuzhiyun err = -EINVAL;
2481*4882a593Smuzhiyun else
2482*4882a593Smuzhiyun RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL);
2483*4882a593Smuzhiyun }
2484*4882a593Smuzhiyun spin_unlock_bh(&xfrm_state_afinfo_lock);
2485*4882a593Smuzhiyun synchronize_rcu();
2486*4882a593Smuzhiyun return err;
2487*4882a593Smuzhiyun }
2488*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
2489*4882a593Smuzhiyun
xfrm_state_afinfo_get_rcu(unsigned int family)2490*4882a593Smuzhiyun struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family)
2491*4882a593Smuzhiyun {
2492*4882a593Smuzhiyun if (unlikely(family >= NPROTO))
2493*4882a593Smuzhiyun return NULL;
2494*4882a593Smuzhiyun
2495*4882a593Smuzhiyun return rcu_dereference(xfrm_state_afinfo[family]);
2496*4882a593Smuzhiyun }
2497*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu);
2498*4882a593Smuzhiyun
xfrm_state_get_afinfo(unsigned int family)2499*4882a593Smuzhiyun struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
2500*4882a593Smuzhiyun {
2501*4882a593Smuzhiyun struct xfrm_state_afinfo *afinfo;
2502*4882a593Smuzhiyun if (unlikely(family >= NPROTO))
2503*4882a593Smuzhiyun return NULL;
2504*4882a593Smuzhiyun rcu_read_lock();
2505*4882a593Smuzhiyun afinfo = rcu_dereference(xfrm_state_afinfo[family]);
2506*4882a593Smuzhiyun if (unlikely(!afinfo))
2507*4882a593Smuzhiyun rcu_read_unlock();
2508*4882a593Smuzhiyun return afinfo;
2509*4882a593Smuzhiyun }
2510*4882a593Smuzhiyun
xfrm_flush_gc(void)2511*4882a593Smuzhiyun void xfrm_flush_gc(void)
2512*4882a593Smuzhiyun {
2513*4882a593Smuzhiyun flush_work(&xfrm_state_gc_work);
2514*4882a593Smuzhiyun }
2515*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_flush_gc);
2516*4882a593Smuzhiyun
2517*4882a593Smuzhiyun /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
xfrm_state_delete_tunnel(struct xfrm_state * x)2518*4882a593Smuzhiyun void xfrm_state_delete_tunnel(struct xfrm_state *x)
2519*4882a593Smuzhiyun {
2520*4882a593Smuzhiyun if (x->tunnel) {
2521*4882a593Smuzhiyun struct xfrm_state *t = x->tunnel;
2522*4882a593Smuzhiyun
2523*4882a593Smuzhiyun if (atomic_read(&t->tunnel_users) == 2)
2524*4882a593Smuzhiyun xfrm_state_delete(t);
2525*4882a593Smuzhiyun atomic_dec(&t->tunnel_users);
2526*4882a593Smuzhiyun xfrm_state_put_sync(t);
2527*4882a593Smuzhiyun x->tunnel = NULL;
2528*4882a593Smuzhiyun }
2529*4882a593Smuzhiyun }
2530*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_state_delete_tunnel);
2531*4882a593Smuzhiyun
xfrm_state_mtu(struct xfrm_state * x,int mtu)2532*4882a593Smuzhiyun u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
2533*4882a593Smuzhiyun {
2534*4882a593Smuzhiyun const struct xfrm_type *type = READ_ONCE(x->type);
2535*4882a593Smuzhiyun struct crypto_aead *aead;
2536*4882a593Smuzhiyun u32 blksize, net_adj = 0;
2537*4882a593Smuzhiyun
2538*4882a593Smuzhiyun if (x->km.state != XFRM_STATE_VALID ||
2539*4882a593Smuzhiyun !type || type->proto != IPPROTO_ESP)
2540*4882a593Smuzhiyun return mtu - x->props.header_len;
2541*4882a593Smuzhiyun
2542*4882a593Smuzhiyun aead = x->data;
2543*4882a593Smuzhiyun blksize = ALIGN(crypto_aead_blocksize(aead), 4);
2544*4882a593Smuzhiyun
2545*4882a593Smuzhiyun switch (x->props.mode) {
2546*4882a593Smuzhiyun case XFRM_MODE_TRANSPORT:
2547*4882a593Smuzhiyun case XFRM_MODE_BEET:
2548*4882a593Smuzhiyun if (x->props.family == AF_INET)
2549*4882a593Smuzhiyun net_adj = sizeof(struct iphdr);
2550*4882a593Smuzhiyun else if (x->props.family == AF_INET6)
2551*4882a593Smuzhiyun net_adj = sizeof(struct ipv6hdr);
2552*4882a593Smuzhiyun break;
2553*4882a593Smuzhiyun case XFRM_MODE_TUNNEL:
2554*4882a593Smuzhiyun break;
2555*4882a593Smuzhiyun default:
2556*4882a593Smuzhiyun WARN_ON_ONCE(1);
2557*4882a593Smuzhiyun break;
2558*4882a593Smuzhiyun }
2559*4882a593Smuzhiyun
2560*4882a593Smuzhiyun return ((mtu - x->props.header_len - crypto_aead_authsize(aead) -
2561*4882a593Smuzhiyun net_adj) & ~(blksize - 1)) + net_adj - 2;
2562*4882a593Smuzhiyun }
2563*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_state_mtu);
2564*4882a593Smuzhiyun
__xfrm_init_state(struct xfrm_state * x,bool init_replay,bool offload)2565*4882a593Smuzhiyun int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
2566*4882a593Smuzhiyun {
2567*4882a593Smuzhiyun const struct xfrm_mode *inner_mode;
2568*4882a593Smuzhiyun const struct xfrm_mode *outer_mode;
2569*4882a593Smuzhiyun int family = x->props.family;
2570*4882a593Smuzhiyun int err;
2571*4882a593Smuzhiyun
2572*4882a593Smuzhiyun if (family == AF_INET &&
2573*4882a593Smuzhiyun READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc))
2574*4882a593Smuzhiyun x->props.flags |= XFRM_STATE_NOPMTUDISC;
2575*4882a593Smuzhiyun
2576*4882a593Smuzhiyun err = -EPROTONOSUPPORT;
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun if (x->sel.family != AF_UNSPEC) {
2579*4882a593Smuzhiyun inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
2580*4882a593Smuzhiyun if (inner_mode == NULL)
2581*4882a593Smuzhiyun goto error;
2582*4882a593Smuzhiyun
2583*4882a593Smuzhiyun if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
2584*4882a593Smuzhiyun family != x->sel.family)
2585*4882a593Smuzhiyun goto error;
2586*4882a593Smuzhiyun
2587*4882a593Smuzhiyun x->inner_mode = *inner_mode;
2588*4882a593Smuzhiyun } else {
2589*4882a593Smuzhiyun const struct xfrm_mode *inner_mode_iaf;
2590*4882a593Smuzhiyun int iafamily = AF_INET;
2591*4882a593Smuzhiyun
2592*4882a593Smuzhiyun inner_mode = xfrm_get_mode(x->props.mode, x->props.family);
2593*4882a593Smuzhiyun if (inner_mode == NULL)
2594*4882a593Smuzhiyun goto error;
2595*4882a593Smuzhiyun
2596*4882a593Smuzhiyun if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL))
2597*4882a593Smuzhiyun goto error;
2598*4882a593Smuzhiyun
2599*4882a593Smuzhiyun x->inner_mode = *inner_mode;
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun if (x->props.family == AF_INET)
2602*4882a593Smuzhiyun iafamily = AF_INET6;
2603*4882a593Smuzhiyun
2604*4882a593Smuzhiyun inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily);
2605*4882a593Smuzhiyun if (inner_mode_iaf) {
2606*4882a593Smuzhiyun if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)
2607*4882a593Smuzhiyun x->inner_mode_iaf = *inner_mode_iaf;
2608*4882a593Smuzhiyun }
2609*4882a593Smuzhiyun }
2610*4882a593Smuzhiyun
2611*4882a593Smuzhiyun x->type = xfrm_get_type(x->id.proto, family);
2612*4882a593Smuzhiyun if (x->type == NULL)
2613*4882a593Smuzhiyun goto error;
2614*4882a593Smuzhiyun
2615*4882a593Smuzhiyun x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload);
2616*4882a593Smuzhiyun
2617*4882a593Smuzhiyun err = x->type->init_state(x);
2618*4882a593Smuzhiyun if (err)
2619*4882a593Smuzhiyun goto error;
2620*4882a593Smuzhiyun
2621*4882a593Smuzhiyun outer_mode = xfrm_get_mode(x->props.mode, family);
2622*4882a593Smuzhiyun if (!outer_mode) {
2623*4882a593Smuzhiyun err = -EPROTONOSUPPORT;
2624*4882a593Smuzhiyun goto error;
2625*4882a593Smuzhiyun }
2626*4882a593Smuzhiyun
2627*4882a593Smuzhiyun x->outer_mode = *outer_mode;
2628*4882a593Smuzhiyun if (init_replay) {
2629*4882a593Smuzhiyun err = xfrm_init_replay(x);
2630*4882a593Smuzhiyun if (err)
2631*4882a593Smuzhiyun goto error;
2632*4882a593Smuzhiyun }
2633*4882a593Smuzhiyun
2634*4882a593Smuzhiyun error:
2635*4882a593Smuzhiyun return err;
2636*4882a593Smuzhiyun }
2637*4882a593Smuzhiyun
2638*4882a593Smuzhiyun EXPORT_SYMBOL(__xfrm_init_state);
2639*4882a593Smuzhiyun
xfrm_init_state(struct xfrm_state * x)2640*4882a593Smuzhiyun int xfrm_init_state(struct xfrm_state *x)
2641*4882a593Smuzhiyun {
2642*4882a593Smuzhiyun int err;
2643*4882a593Smuzhiyun
2644*4882a593Smuzhiyun err = __xfrm_init_state(x, true, false);
2645*4882a593Smuzhiyun if (!err)
2646*4882a593Smuzhiyun x->km.state = XFRM_STATE_VALID;
2647*4882a593Smuzhiyun
2648*4882a593Smuzhiyun return err;
2649*4882a593Smuzhiyun }
2650*4882a593Smuzhiyun
2651*4882a593Smuzhiyun EXPORT_SYMBOL(xfrm_init_state);
2652*4882a593Smuzhiyun
xfrm_state_init(struct net * net)2653*4882a593Smuzhiyun int __net_init xfrm_state_init(struct net *net)
2654*4882a593Smuzhiyun {
2655*4882a593Smuzhiyun unsigned int sz;
2656*4882a593Smuzhiyun
2657*4882a593Smuzhiyun if (net_eq(net, &init_net))
2658*4882a593Smuzhiyun xfrm_state_cache = KMEM_CACHE(xfrm_state,
2659*4882a593Smuzhiyun SLAB_HWCACHE_ALIGN | SLAB_PANIC);
2660*4882a593Smuzhiyun
2661*4882a593Smuzhiyun INIT_LIST_HEAD(&net->xfrm.state_all);
2662*4882a593Smuzhiyun
2663*4882a593Smuzhiyun sz = sizeof(struct hlist_head) * 8;
2664*4882a593Smuzhiyun
2665*4882a593Smuzhiyun net->xfrm.state_bydst = xfrm_hash_alloc(sz);
2666*4882a593Smuzhiyun if (!net->xfrm.state_bydst)
2667*4882a593Smuzhiyun goto out_bydst;
2668*4882a593Smuzhiyun net->xfrm.state_bysrc = xfrm_hash_alloc(sz);
2669*4882a593Smuzhiyun if (!net->xfrm.state_bysrc)
2670*4882a593Smuzhiyun goto out_bysrc;
2671*4882a593Smuzhiyun net->xfrm.state_byspi = xfrm_hash_alloc(sz);
2672*4882a593Smuzhiyun if (!net->xfrm.state_byspi)
2673*4882a593Smuzhiyun goto out_byspi;
2674*4882a593Smuzhiyun net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1);
2675*4882a593Smuzhiyun
2676*4882a593Smuzhiyun net->xfrm.state_num = 0;
2677*4882a593Smuzhiyun INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
2678*4882a593Smuzhiyun spin_lock_init(&net->xfrm.xfrm_state_lock);
2679*4882a593Smuzhiyun seqcount_init(&net->xfrm.xfrm_state_hash_generation);
2680*4882a593Smuzhiyun return 0;
2681*4882a593Smuzhiyun
2682*4882a593Smuzhiyun out_byspi:
2683*4882a593Smuzhiyun xfrm_hash_free(net->xfrm.state_bysrc, sz);
2684*4882a593Smuzhiyun out_bysrc:
2685*4882a593Smuzhiyun xfrm_hash_free(net->xfrm.state_bydst, sz);
2686*4882a593Smuzhiyun out_bydst:
2687*4882a593Smuzhiyun return -ENOMEM;
2688*4882a593Smuzhiyun }
2689*4882a593Smuzhiyun
xfrm_state_fini(struct net * net)2690*4882a593Smuzhiyun void xfrm_state_fini(struct net *net)
2691*4882a593Smuzhiyun {
2692*4882a593Smuzhiyun unsigned int sz;
2693*4882a593Smuzhiyun
2694*4882a593Smuzhiyun flush_work(&net->xfrm.state_hash_work);
2695*4882a593Smuzhiyun flush_work(&xfrm_state_gc_work);
2696*4882a593Smuzhiyun xfrm_state_flush(net, 0, false, true);
2697*4882a593Smuzhiyun
2698*4882a593Smuzhiyun WARN_ON(!list_empty(&net->xfrm.state_all));
2699*4882a593Smuzhiyun
2700*4882a593Smuzhiyun sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head);
2701*4882a593Smuzhiyun WARN_ON(!hlist_empty(net->xfrm.state_byspi));
2702*4882a593Smuzhiyun xfrm_hash_free(net->xfrm.state_byspi, sz);
2703*4882a593Smuzhiyun WARN_ON(!hlist_empty(net->xfrm.state_bysrc));
2704*4882a593Smuzhiyun xfrm_hash_free(net->xfrm.state_bysrc, sz);
2705*4882a593Smuzhiyun WARN_ON(!hlist_empty(net->xfrm.state_bydst));
2706*4882a593Smuzhiyun xfrm_hash_free(net->xfrm.state_bydst, sz);
2707*4882a593Smuzhiyun }
2708*4882a593Smuzhiyun
2709*4882a593Smuzhiyun #ifdef CONFIG_AUDITSYSCALL
xfrm_audit_helper_sainfo(struct xfrm_state * x,struct audit_buffer * audit_buf)2710*4882a593Smuzhiyun static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
2711*4882a593Smuzhiyun struct audit_buffer *audit_buf)
2712*4882a593Smuzhiyun {
2713*4882a593Smuzhiyun struct xfrm_sec_ctx *ctx = x->security;
2714*4882a593Smuzhiyun u32 spi = ntohl(x->id.spi);
2715*4882a593Smuzhiyun
2716*4882a593Smuzhiyun if (ctx)
2717*4882a593Smuzhiyun audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
2718*4882a593Smuzhiyun ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
2719*4882a593Smuzhiyun
2720*4882a593Smuzhiyun switch (x->props.family) {
2721*4882a593Smuzhiyun case AF_INET:
2722*4882a593Smuzhiyun audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2723*4882a593Smuzhiyun &x->props.saddr.a4, &x->id.daddr.a4);
2724*4882a593Smuzhiyun break;
2725*4882a593Smuzhiyun case AF_INET6:
2726*4882a593Smuzhiyun audit_log_format(audit_buf, " src=%pI6 dst=%pI6",
2727*4882a593Smuzhiyun x->props.saddr.a6, x->id.daddr.a6);
2728*4882a593Smuzhiyun break;
2729*4882a593Smuzhiyun }
2730*4882a593Smuzhiyun
2731*4882a593Smuzhiyun audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2732*4882a593Smuzhiyun }
2733*4882a593Smuzhiyun
xfrm_audit_helper_pktinfo(struct sk_buff * skb,u16 family,struct audit_buffer * audit_buf)2734*4882a593Smuzhiyun static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
2735*4882a593Smuzhiyun struct audit_buffer *audit_buf)
2736*4882a593Smuzhiyun {
2737*4882a593Smuzhiyun const struct iphdr *iph4;
2738*4882a593Smuzhiyun const struct ipv6hdr *iph6;
2739*4882a593Smuzhiyun
2740*4882a593Smuzhiyun switch (family) {
2741*4882a593Smuzhiyun case AF_INET:
2742*4882a593Smuzhiyun iph4 = ip_hdr(skb);
2743*4882a593Smuzhiyun audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
2744*4882a593Smuzhiyun &iph4->saddr, &iph4->daddr);
2745*4882a593Smuzhiyun break;
2746*4882a593Smuzhiyun case AF_INET6:
2747*4882a593Smuzhiyun iph6 = ipv6_hdr(skb);
2748*4882a593Smuzhiyun audit_log_format(audit_buf,
2749*4882a593Smuzhiyun " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
2750*4882a593Smuzhiyun &iph6->saddr, &iph6->daddr,
2751*4882a593Smuzhiyun iph6->flow_lbl[0] & 0x0f,
2752*4882a593Smuzhiyun iph6->flow_lbl[1],
2753*4882a593Smuzhiyun iph6->flow_lbl[2]);
2754*4882a593Smuzhiyun break;
2755*4882a593Smuzhiyun }
2756*4882a593Smuzhiyun }
2757*4882a593Smuzhiyun
xfrm_audit_state_add(struct xfrm_state * x,int result,bool task_valid)2758*4882a593Smuzhiyun void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid)
2759*4882a593Smuzhiyun {
2760*4882a593Smuzhiyun struct audit_buffer *audit_buf;
2761*4882a593Smuzhiyun
2762*4882a593Smuzhiyun audit_buf = xfrm_audit_start("SAD-add");
2763*4882a593Smuzhiyun if (audit_buf == NULL)
2764*4882a593Smuzhiyun return;
2765*4882a593Smuzhiyun xfrm_audit_helper_usrinfo(task_valid, audit_buf);
2766*4882a593Smuzhiyun xfrm_audit_helper_sainfo(x, audit_buf);
2767*4882a593Smuzhiyun audit_log_format(audit_buf, " res=%u", result);
2768*4882a593Smuzhiyun audit_log_end(audit_buf);
2769*4882a593Smuzhiyun }
2770*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
2771*4882a593Smuzhiyun
xfrm_audit_state_delete(struct xfrm_state * x,int result,bool task_valid)2772*4882a593Smuzhiyun void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid)
2773*4882a593Smuzhiyun {
2774*4882a593Smuzhiyun struct audit_buffer *audit_buf;
2775*4882a593Smuzhiyun
2776*4882a593Smuzhiyun audit_buf = xfrm_audit_start("SAD-delete");
2777*4882a593Smuzhiyun if (audit_buf == NULL)
2778*4882a593Smuzhiyun return;
2779*4882a593Smuzhiyun xfrm_audit_helper_usrinfo(task_valid, audit_buf);
2780*4882a593Smuzhiyun xfrm_audit_helper_sainfo(x, audit_buf);
2781*4882a593Smuzhiyun audit_log_format(audit_buf, " res=%u", result);
2782*4882a593Smuzhiyun audit_log_end(audit_buf);
2783*4882a593Smuzhiyun }
2784*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
2785*4882a593Smuzhiyun
xfrm_audit_state_replay_overflow(struct xfrm_state * x,struct sk_buff * skb)2786*4882a593Smuzhiyun void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
2787*4882a593Smuzhiyun struct sk_buff *skb)
2788*4882a593Smuzhiyun {
2789*4882a593Smuzhiyun struct audit_buffer *audit_buf;
2790*4882a593Smuzhiyun u32 spi;
2791*4882a593Smuzhiyun
2792*4882a593Smuzhiyun audit_buf = xfrm_audit_start("SA-replay-overflow");
2793*4882a593Smuzhiyun if (audit_buf == NULL)
2794*4882a593Smuzhiyun return;
2795*4882a593Smuzhiyun xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2796*4882a593Smuzhiyun /* don't record the sequence number because it's inherent in this kind
2797*4882a593Smuzhiyun * of audit message */
2798*4882a593Smuzhiyun spi = ntohl(x->id.spi);
2799*4882a593Smuzhiyun audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
2800*4882a593Smuzhiyun audit_log_end(audit_buf);
2801*4882a593Smuzhiyun }
2802*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
2803*4882a593Smuzhiyun
xfrm_audit_state_replay(struct xfrm_state * x,struct sk_buff * skb,__be32 net_seq)2804*4882a593Smuzhiyun void xfrm_audit_state_replay(struct xfrm_state *x,
2805*4882a593Smuzhiyun struct sk_buff *skb, __be32 net_seq)
2806*4882a593Smuzhiyun {
2807*4882a593Smuzhiyun struct audit_buffer *audit_buf;
2808*4882a593Smuzhiyun u32 spi;
2809*4882a593Smuzhiyun
2810*4882a593Smuzhiyun audit_buf = xfrm_audit_start("SA-replayed-pkt");
2811*4882a593Smuzhiyun if (audit_buf == NULL)
2812*4882a593Smuzhiyun return;
2813*4882a593Smuzhiyun xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2814*4882a593Smuzhiyun spi = ntohl(x->id.spi);
2815*4882a593Smuzhiyun audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2816*4882a593Smuzhiyun spi, spi, ntohl(net_seq));
2817*4882a593Smuzhiyun audit_log_end(audit_buf);
2818*4882a593Smuzhiyun }
2819*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_audit_state_replay);
2820*4882a593Smuzhiyun
xfrm_audit_state_notfound_simple(struct sk_buff * skb,u16 family)2821*4882a593Smuzhiyun void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
2822*4882a593Smuzhiyun {
2823*4882a593Smuzhiyun struct audit_buffer *audit_buf;
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun audit_buf = xfrm_audit_start("SA-notfound");
2826*4882a593Smuzhiyun if (audit_buf == NULL)
2827*4882a593Smuzhiyun return;
2828*4882a593Smuzhiyun xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2829*4882a593Smuzhiyun audit_log_end(audit_buf);
2830*4882a593Smuzhiyun }
2831*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
2832*4882a593Smuzhiyun
xfrm_audit_state_notfound(struct sk_buff * skb,u16 family,__be32 net_spi,__be32 net_seq)2833*4882a593Smuzhiyun void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
2834*4882a593Smuzhiyun __be32 net_spi, __be32 net_seq)
2835*4882a593Smuzhiyun {
2836*4882a593Smuzhiyun struct audit_buffer *audit_buf;
2837*4882a593Smuzhiyun u32 spi;
2838*4882a593Smuzhiyun
2839*4882a593Smuzhiyun audit_buf = xfrm_audit_start("SA-notfound");
2840*4882a593Smuzhiyun if (audit_buf == NULL)
2841*4882a593Smuzhiyun return;
2842*4882a593Smuzhiyun xfrm_audit_helper_pktinfo(skb, family, audit_buf);
2843*4882a593Smuzhiyun spi = ntohl(net_spi);
2844*4882a593Smuzhiyun audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2845*4882a593Smuzhiyun spi, spi, ntohl(net_seq));
2846*4882a593Smuzhiyun audit_log_end(audit_buf);
2847*4882a593Smuzhiyun }
2848*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
2849*4882a593Smuzhiyun
xfrm_audit_state_icvfail(struct xfrm_state * x,struct sk_buff * skb,u8 proto)2850*4882a593Smuzhiyun void xfrm_audit_state_icvfail(struct xfrm_state *x,
2851*4882a593Smuzhiyun struct sk_buff *skb, u8 proto)
2852*4882a593Smuzhiyun {
2853*4882a593Smuzhiyun struct audit_buffer *audit_buf;
2854*4882a593Smuzhiyun __be32 net_spi;
2855*4882a593Smuzhiyun __be32 net_seq;
2856*4882a593Smuzhiyun
2857*4882a593Smuzhiyun audit_buf = xfrm_audit_start("SA-icv-failure");
2858*4882a593Smuzhiyun if (audit_buf == NULL)
2859*4882a593Smuzhiyun return;
2860*4882a593Smuzhiyun xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
2861*4882a593Smuzhiyun if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
2862*4882a593Smuzhiyun u32 spi = ntohl(net_spi);
2863*4882a593Smuzhiyun audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
2864*4882a593Smuzhiyun spi, spi, ntohl(net_seq));
2865*4882a593Smuzhiyun }
2866*4882a593Smuzhiyun audit_log_end(audit_buf);
2867*4882a593Smuzhiyun }
2868*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
2869*4882a593Smuzhiyun #endif /* CONFIG_AUDITSYSCALL */
2870