Blame view

net/xfrm/xfrm_policy.c 71.1 KB
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
   * xfrm_policy.c
   *
   * Changes:
   *	Mitsuru KANDA @USAGI
   * 	Kazunori MIYAZAWA @USAGI
   * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
   * 		IPv6 support
   * 	Kazunori MIYAZAWA @USAGI
   * 	YOSHIFUJI Hideaki
   * 		Split up af-specific portion
   *	Derek Atkins <derek@ihtfp.com>		Add the post_input processor
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
13
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
   */
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
15
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
22
  #include <linux/slab.h>
  #include <linux/kmod.h>
  #include <linux/list.h>
  #include <linux/spinlock.h>
  #include <linux/workqueue.h>
  #include <linux/notifier.h>
  #include <linux/netdevice.h>
eb9c7ebe6   Patrick McHardy   [NETFILTER]: Hand...
23
  #include <linux/netfilter.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/module.h>
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
25
  #include <linux/cache.h>
68277accb   Paul Moore   [XFRM]: Assorted ...
26
  #include <linux/audit.h>
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
27
  #include <net/dst.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  #include <net/xfrm.h>
  #include <net/ip.h>
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
30
31
32
  #ifdef CONFIG_XFRM_STATISTICS
  #include <net/snmp.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

44e36b42a   David S. Miller   [XFRM]: Extract c...
34
  #include "xfrm_hash.h"
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
35
36
  DEFINE_MUTEX(xfrm_cfg_mutex);
  EXPORT_SYMBOL(xfrm_cfg_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

80c802f30   Timo Teräs   xfrm: cache bundl...
38
39
  static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
  static struct dst_entry *xfrm_policy_sk_bundles;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  static DEFINE_RWLOCK(xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
  static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
43
  static struct kmem_cache *xfrm_dst_cache __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
  static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
47
  static void xfrm_init_pmtu(struct dst_entry *dst);
80c802f30   Timo Teräs   xfrm: cache bundl...
48
  static int stale_bundle(struct dst_entry *dst);
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
49
  static int xfrm_bundle_ok(struct xfrm_dst *xdst);
1c4c40c42   stephen hemminger   xfrm: make xfrm_b...
50

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

29fa0b301   Wei Yongjun   xfrm: Cleanup for...
52
53
  static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
  						int dir);
776810217   Andrew Morton   [XFRM]: uninline ...
54
  static inline int
200ce96e5   David S. Miller   xfrm: Const'ify s...
55
  __xfrm4_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
776810217   Andrew Morton   [XFRM]: uninline ...
56
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
57
  	const struct flowi4 *fl4 = &fl->u.ip4;
26bff940d   Alexey Dobriyan   xfrm: optimize ip...
58
59
  	return  addr4_match(fl4->daddr, sel->daddr.a4, sel->prefixlen_d) &&
  		addr4_match(fl4->saddr, sel->saddr.a4, sel->prefixlen_s) &&
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
60
61
62
63
  		!((xfrm_flowi_dport(fl, &fl4->uli) ^ sel->dport) & sel->dport_mask) &&
  		!((xfrm_flowi_sport(fl, &fl4->uli) ^ sel->sport) & sel->sport_mask) &&
  		(fl4->flowi4_proto == sel->proto || !sel->proto) &&
  		(fl4->flowi4_oif == sel->ifindex || !sel->ifindex);
776810217   Andrew Morton   [XFRM]: uninline ...
64
65
66
  }
  
  static inline int
200ce96e5   David S. Miller   xfrm: Const'ify s...
67
  __xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
776810217   Andrew Morton   [XFRM]: uninline ...
68
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
69
70
71
72
73
74
75
76
  	const struct flowi6 *fl6 = &fl->u.ip6;
  
  	return  addr_match(&fl6->daddr, &sel->daddr, sel->prefixlen_d) &&
  		addr_match(&fl6->saddr, &sel->saddr, sel->prefixlen_s) &&
  		!((xfrm_flowi_dport(fl, &fl6->uli) ^ sel->dport) & sel->dport_mask) &&
  		!((xfrm_flowi_sport(fl, &fl6->uli) ^ sel->sport) & sel->sport_mask) &&
  		(fl6->flowi6_proto == sel->proto || !sel->proto) &&
  		(fl6->flowi6_oif == sel->ifindex || !sel->ifindex);
776810217   Andrew Morton   [XFRM]: uninline ...
77
  }
200ce96e5   David S. Miller   xfrm: Const'ify s...
78
  int xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl,
e1ad2ab2c   David S. Miller   xfrm: Mark flowi ...
79
  			unsigned short family)
776810217   Andrew Morton   [XFRM]: uninline ...
80
81
82
83
84
85
86
87
88
  {
  	switch (family) {
  	case AF_INET:
  		return __xfrm4_selector_match(sel, fl);
  	case AF_INET6:
  		return __xfrm6_selector_match(sel, fl);
  	}
  	return 0;
  }
c5b3cf46e   Alexey Dobriyan   netns xfrm: ->dst...
89
  static inline struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos,
6418c4e07   David S. Miller   xfrm: Const'ify a...
90
91
  						  const xfrm_address_t *saddr,
  						  const xfrm_address_t *daddr,
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
92
93
94
95
96
97
98
99
  						  int family)
  {
  	struct xfrm_policy_afinfo *afinfo;
  	struct dst_entry *dst;
  
  	afinfo = xfrm_policy_get_afinfo(family);
  	if (unlikely(afinfo == NULL))
  		return ERR_PTR(-EAFNOSUPPORT);
c5b3cf46e   Alexey Dobriyan   netns xfrm: ->dst...
100
  	dst = afinfo->dst_lookup(net, tos, saddr, daddr);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
101
102
103
104
105
  
  	xfrm_policy_put_afinfo(afinfo);
  
  	return dst;
  }
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
106
  static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
107
108
  						xfrm_address_t *prev_saddr,
  						xfrm_address_t *prev_daddr,
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
109
  						int family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  {
c5b3cf46e   Alexey Dobriyan   netns xfrm: ->dst...
111
  	struct net *net = xs_net(x);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
112
113
  	xfrm_address_t *saddr = &x->props.saddr;
  	xfrm_address_t *daddr = &x->id.daddr;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
114
  	struct dst_entry *dst;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
115
  	if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
116
  		saddr = x->coaddr;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
117
118
119
120
  		daddr = prev_daddr;
  	}
  	if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
  		saddr = prev_saddr;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
121
  		daddr = x->coaddr;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
122
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123

c5b3cf46e   Alexey Dobriyan   netns xfrm: ->dst...
124
  	dst = __xfrm_dst_lookup(net, tos, saddr, daddr, family);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
125
126
127
128
129
130
131
  
  	if (!IS_ERR(dst)) {
  		if (prev_saddr != saddr)
  			memcpy(prev_saddr, saddr,  sizeof(*prev_saddr));
  		if (prev_daddr != daddr)
  			memcpy(prev_daddr, daddr,  sizeof(*prev_daddr));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132

66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
133
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
  static inline unsigned long make_jiffies(long secs)
  {
  	if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
  		return MAX_SCHEDULE_TIMEOUT-1;
  	else
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
141
  		return secs*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
  }
  
  static void xfrm_policy_timer(unsigned long data)
  {
  	struct xfrm_policy *xp = (struct xfrm_policy*)data;
9d729f72d   James Morris   [NET]: Convert xt...
147
  	unsigned long now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
152
  	long next = LONG_MAX;
  	int warn = 0;
  	int dir;
  
  	read_lock(&xp->lock);
ea2dea9da   Timo Teräs   xfrm: remove poli...
153
  	if (unlikely(xp->walk.dead))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  		goto out;
77d8d7a68   Herbert Xu   [IPSEC]: Document...
155
  	dir = xfrm_policy_id2dir(xp->index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  
  	if (xp->lft.hard_add_expires_seconds) {
  		long tmo = xp->lft.hard_add_expires_seconds +
  			xp->curlft.add_time - now;
  		if (tmo <= 0)
  			goto expired;
  		if (tmo < next)
  			next = tmo;
  	}
  	if (xp->lft.hard_use_expires_seconds) {
  		long tmo = xp->lft.hard_use_expires_seconds +
  			(xp->curlft.use_time ? : xp->curlft.add_time) - now;
  		if (tmo <= 0)
  			goto expired;
  		if (tmo < next)
  			next = tmo;
  	}
  	if (xp->lft.soft_add_expires_seconds) {
  		long tmo = xp->lft.soft_add_expires_seconds +
  			xp->curlft.add_time - now;
  		if (tmo <= 0) {
  			warn = 1;
  			tmo = XFRM_KM_TIMEOUT;
  		}
  		if (tmo < next)
  			next = tmo;
  	}
  	if (xp->lft.soft_use_expires_seconds) {
  		long tmo = xp->lft.soft_use_expires_seconds +
  			(xp->curlft.use_time ? : xp->curlft.add_time) - now;
  		if (tmo <= 0) {
  			warn = 1;
  			tmo = XFRM_KM_TIMEOUT;
  		}
  		if (tmo < next)
  			next = tmo;
  	}
  
  	if (warn)
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
195
  		km_policy_expired(xp, dir, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
203
204
205
206
  	if (next != LONG_MAX &&
  	    !mod_timer(&xp->timer, jiffies + make_jiffies(next)))
  		xfrm_pol_hold(xp);
  
  out:
  	read_unlock(&xp->lock);
  	xfrm_pol_put(xp);
  	return;
  
  expired:
  	read_unlock(&xp->lock);
4666faab0   Herbert Xu   [IPSEC] Kill spur...
207
  	if (!xfrm_policy_delete(xp, dir))
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
208
  		km_policy_expired(xp, dir, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
  	xfrm_pol_put(xp);
  }
fe1a5f031   Timo Teräs   flow: virtualize ...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  static struct flow_cache_object *xfrm_policy_flo_get(struct flow_cache_object *flo)
  {
  	struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
  
  	if (unlikely(pol->walk.dead))
  		flo = NULL;
  	else
  		xfrm_pol_hold(pol);
  
  	return flo;
  }
  
  static int xfrm_policy_flo_check(struct flow_cache_object *flo)
  {
  	struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
  
  	return !pol->walk.dead;
  }
  
  static void xfrm_policy_flo_delete(struct flow_cache_object *flo)
  {
  	xfrm_pol_put(container_of(flo, struct xfrm_policy, flo));
  }
  
  static const struct flow_cache_ops xfrm_policy_fc_ops = {
  	.get = xfrm_policy_flo_get,
  	.check = xfrm_policy_flo_check,
  	.delete = xfrm_policy_flo_delete,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
  
  /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
   * SPD calls.
   */
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
244
  struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
  {
  	struct xfrm_policy *policy;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
247
  	policy = kzalloc(sizeof(struct xfrm_policy), gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
  
  	if (policy) {
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
250
  		write_pnet(&policy->xp_net, net);
12a169e7d   Herbert Xu   ipsec: Put dumper...
251
  		INIT_LIST_HEAD(&policy->walk.all);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
252
253
  		INIT_HLIST_NODE(&policy->bydst);
  		INIT_HLIST_NODE(&policy->byidx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  		rwlock_init(&policy->lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
255
  		atomic_set(&policy->refcnt, 1);
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
256
257
  		setup_timer(&policy->timer, xfrm_policy_timer,
  				(unsigned long)policy);
fe1a5f031   Timo Teräs   flow: virtualize ...
258
  		policy->flo.ops = &xfrm_policy_fc_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
264
  	}
  	return policy;
  }
  EXPORT_SYMBOL(xfrm_policy_alloc);
  
  /* Destroy xfrm_policy: descendant resources must be released to this moment. */
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
265
  void xfrm_policy_destroy(struct xfrm_policy *policy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
267
  	BUG_ON(!policy->walk.dead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
  	if (del_timer(&policy->timer))
  		BUG();
03e1ad7b5   Paul Moore   LSM: Make the Lab...
271
  	security_xfrm_policy_free(policy->security);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
  	kfree(policy);
  }
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
274
  EXPORT_SYMBOL(xfrm_policy_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
  /* Rule must be locked. Release descentant resources, announce
   * entry dead. The rule must be unlinked from lists to the moment.
   */
  
  static void xfrm_policy_kill(struct xfrm_policy *policy)
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
282
  	policy->walk.dead = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

285ead175   Timo Teräs   xfrm: remove poli...
284
  	atomic_inc(&policy->genid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285

285ead175   Timo Teräs   xfrm: remove poli...
286
287
288
289
  	if (del_timer(&policy->timer))
  		xfrm_pol_put(policy);
  
  	xfrm_pol_put(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  }
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
291
  static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
e92303f87   Alexey Dobriyan   netns xfrm: propa...
292
  static inline unsigned int idx_hash(struct net *net, u32 index)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
293
  {
e92303f87   Alexey Dobriyan   netns xfrm: propa...
294
  	return __idx_hash(index, net->xfrm.policy_idx_hmask);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
295
  }
5f803b58c   David S. Miller   xfrm: Const'ify a...
296
297
298
  static struct hlist_head *policy_hash_bysel(struct net *net,
  					    const struct xfrm_selector *sel,
  					    unsigned short family, int dir)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
299
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
300
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
301
302
303
  	unsigned int hash = __sel_hash(sel, family, hmask);
  
  	return (hash == hmask + 1 ?
1121994c8   Alexey Dobriyan   netns xfrm: polic...
304
305
  		&net->xfrm.policy_inexact[dir] :
  		net->xfrm.policy_bydst[dir].table + hash);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
306
  }
5f803b58c   David S. Miller   xfrm: Const'ify a...
307
308
309
310
  static struct hlist_head *policy_hash_direct(struct net *net,
  					     const xfrm_address_t *daddr,
  					     const xfrm_address_t *saddr,
  					     unsigned short family, int dir)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
311
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
312
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
313
  	unsigned int hash = __addr_hash(daddr, saddr, family, hmask);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
314
  	return net->xfrm.policy_bydst[dir].table + hash;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
315
  }
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
316
317
318
319
  static void xfrm_dst_hash_transfer(struct hlist_head *list,
  				   struct hlist_head *ndsttable,
  				   unsigned int nhashmask)
  {
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
320
  	struct hlist_node *entry, *tmp, *entry0 = NULL;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
321
  	struct xfrm_policy *pol;
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
322
  	unsigned int h0 = 0;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
323

b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
324
  redo:
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
325
326
327
328
329
  	hlist_for_each_entry_safe(pol, entry, tmp, list, bydst) {
  		unsigned int h;
  
  		h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
  				pol->family, nhashmask);
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  		if (!entry0) {
  			hlist_del(entry);
  			hlist_add_head(&pol->bydst, ndsttable+h);
  			h0 = h;
  		} else {
  			if (h != h0)
  				continue;
  			hlist_del(entry);
  			hlist_add_after(entry0, &pol->bydst);
  		}
  		entry0 = entry;
  	}
  	if (!hlist_empty(list)) {
  		entry0 = NULL;
  		goto redo;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  	}
  }
  
  static void xfrm_idx_hash_transfer(struct hlist_head *list,
  				   struct hlist_head *nidxtable,
  				   unsigned int nhashmask)
  {
  	struct hlist_node *entry, *tmp;
  	struct xfrm_policy *pol;
  
  	hlist_for_each_entry_safe(pol, entry, tmp, list, byidx) {
  		unsigned int h;
  
  		h = __idx_hash(pol->index, nhashmask);
  		hlist_add_head(&pol->byidx, nidxtable+h);
  	}
  }
  
  static unsigned long xfrm_new_hash_mask(unsigned int old_hmask)
  {
  	return ((old_hmask + 1) << 1) - 1;
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
367
  static void xfrm_bydst_resize(struct net *net, int dir)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
368
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
369
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
370
371
  	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
  	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
372
  	struct hlist_head *odst = net->xfrm.policy_bydst[dir].table;
44e36b42a   David S. Miller   [XFRM]: Extract c...
373
  	struct hlist_head *ndst = xfrm_hash_alloc(nsize);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
374
375
376
377
378
379
380
381
382
  	int i;
  
  	if (!ndst)
  		return;
  
  	write_lock_bh(&xfrm_policy_lock);
  
  	for (i = hmask; i >= 0; i--)
  		xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
383
384
  	net->xfrm.policy_bydst[dir].table = ndst;
  	net->xfrm.policy_bydst[dir].hmask = nhashmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
385
386
  
  	write_unlock_bh(&xfrm_policy_lock);
44e36b42a   David S. Miller   [XFRM]: Extract c...
387
  	xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
388
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
389
  static void xfrm_byidx_resize(struct net *net, int total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
390
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
391
  	unsigned int hmask = net->xfrm.policy_idx_hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
392
393
  	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
  	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
394
  	struct hlist_head *oidx = net->xfrm.policy_byidx;
44e36b42a   David S. Miller   [XFRM]: Extract c...
395
  	struct hlist_head *nidx = xfrm_hash_alloc(nsize);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
396
397
398
399
400
401
402
403
404
  	int i;
  
  	if (!nidx)
  		return;
  
  	write_lock_bh(&xfrm_policy_lock);
  
  	for (i = hmask; i >= 0; i--)
  		xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
405
406
  	net->xfrm.policy_byidx = nidx;
  	net->xfrm.policy_idx_hmask = nhashmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
407
408
  
  	write_unlock_bh(&xfrm_policy_lock);
44e36b42a   David S. Miller   [XFRM]: Extract c...
409
  	xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
410
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
411
  static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
412
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
413
414
  	unsigned int cnt = net->xfrm.policy_count[dir];
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
415
416
417
418
419
420
421
422
423
424
  
  	if (total)
  		*total += cnt;
  
  	if ((hmask + 1) < xfrm_policy_hashmax &&
  	    cnt > hmask)
  		return 1;
  
  	return 0;
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
425
  static inline int xfrm_byidx_should_resize(struct net *net, int total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
426
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
427
  	unsigned int hmask = net->xfrm.policy_idx_hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
428
429
430
431
432
433
434
  
  	if ((hmask + 1) < xfrm_policy_hashmax &&
  	    total > hmask)
  		return 1;
  
  	return 0;
  }
e071041be   Alexey Dobriyan   netns xfrm: fix "...
435
  void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
436
437
  {
  	read_lock_bh(&xfrm_policy_lock);
e071041be   Alexey Dobriyan   netns xfrm: fix "...
438
439
440
441
442
443
444
  	si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN];
  	si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT];
  	si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD];
  	si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX];
  	si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX];
  	si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
  	si->spdhcnt = net->xfrm.policy_idx_hmask;
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
445
446
447
448
  	si->spdhmcnt = xfrm_policy_hashmax;
  	read_unlock_bh(&xfrm_policy_lock);
  }
  EXPORT_SYMBOL(xfrm_spd_getinfo);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
449

ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
450
  static DEFINE_MUTEX(hash_resize_mutex);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
451
  static void xfrm_hash_resize(struct work_struct *work)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
452
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
453
  	struct net *net = container_of(work, struct net, xfrm.policy_hash_work);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
454
455
456
457
458
459
  	int dir, total;
  
  	mutex_lock(&hash_resize_mutex);
  
  	total = 0;
  	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
460
461
  		if (xfrm_bydst_should_resize(net, dir, &total))
  			xfrm_bydst_resize(net, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
462
  	}
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
463
464
  	if (xfrm_byidx_should_resize(net, total))
  		xfrm_byidx_resize(net, total);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
465
466
467
  
  	mutex_unlock(&hash_resize_mutex);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  /* Generate new index... KAME seems to generate them ordered by cost
   * of an absolute inpredictability of ordering of rules. This will not pass. */
1121994c8   Alexey Dobriyan   netns xfrm: polic...
470
  static u32 xfrm_gen_index(struct net *net, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
  	static u32 idx_generator;
  
  	for (;;) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
475
476
477
478
479
  		struct hlist_node *entry;
  		struct hlist_head *list;
  		struct xfrm_policy *p;
  		u32 idx;
  		int found;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
483
  		idx = (idx_generator | dir);
  		idx_generator += 8;
  		if (idx == 0)
  			idx = 8;
1121994c8   Alexey Dobriyan   netns xfrm: polic...
484
  		list = net->xfrm.policy_byidx + idx_hash(net, idx);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
485
486
487
488
  		found = 0;
  		hlist_for_each_entry(p, entry, list, byidx) {
  			if (p->index == idx) {
  				found = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  				break;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
490
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  		}
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
492
  		if (!found)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
  			return idx;
  	}
  }
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2)
  {
  	u32 *p1 = (u32 *) s1;
  	u32 *p2 = (u32 *) s2;
  	int len = sizeof(struct xfrm_selector) / sizeof(u32);
  	int i;
  
  	for (i = 0; i < len; i++) {
  		if (p1[i] != p2[i])
  			return 1;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
  int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
512
  	struct net *net = xp_net(policy);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
513
514
515
  	struct xfrm_policy *pol;
  	struct xfrm_policy *delpol;
  	struct hlist_head *chain;
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
516
  	struct hlist_node *entry, *newpos;
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
517
  	u32 mark = policy->mark.v & policy->mark.m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
  
  	write_lock_bh(&xfrm_policy_lock);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
520
  	chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
521
522
  	delpol = NULL;
  	newpos = NULL;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
523
  	hlist_for_each_entry(pol, entry, chain, bydst) {
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
524
  		if (pol->type == policy->type &&
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
525
  		    !selector_cmp(&pol->selector, &policy->selector) &&
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
526
  		    (mark & pol->mark.m) == pol->mark.v &&
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
527
528
  		    xfrm_sec_ctx_match(pol->security, policy->security) &&
  		    !WARN_ON(delpol)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
  			if (excl) {
  				write_unlock_bh(&xfrm_policy_lock);
  				return -EEXIST;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
  			delpol = pol;
  			if (policy->priority > pol->priority)
  				continue;
  		} else if (policy->priority >= pol->priority) {
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
537
  			newpos = &pol->bydst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
  		if (delpol)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  	}
  	if (newpos)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
544
545
546
  		hlist_add_after(newpos, &policy->bydst);
  	else
  		hlist_add_head(&policy->bydst, chain);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  	xfrm_pol_hold(policy);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
548
  	net->xfrm.policy_count[dir]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  	atomic_inc(&flow_cache_genid);
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
550
551
  	if (delpol)
  		__xfrm_policy_unlink(delpol, dir);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
552
553
  	policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir);
  	hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
9d729f72d   James Morris   [NET]: Convert xt...
554
  	policy->curlft.add_time = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
  	policy->curlft.use_time = 0;
  	if (!mod_timer(&policy->timer, jiffies + HZ))
  		xfrm_pol_hold(policy);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
558
  	list_add(&policy->walk.all, &net->xfrm.policy_all);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  	write_unlock_bh(&xfrm_policy_lock);
9b78a82c1   David S. Miller   [IPSEC]: Fix poli...
560
  	if (delpol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  		xfrm_policy_kill(delpol);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
562
563
  	else if (xfrm_bydst_should_resize(net, dir, NULL))
  		schedule_work(&net->xfrm.policy_hash_work);
9b78a82c1   David S. Miller   [IPSEC]: Fix poli...
564

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_policy_insert);
8ca2e93b5   Jamal Hadi Salim   xfrm: SP lookups ...
568
569
  struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
  					  int dir, struct xfrm_selector *sel,
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
570
571
  					  struct xfrm_sec_ctx *ctx, int delete,
  					  int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
573
574
575
  	struct xfrm_policy *pol, *ret;
  	struct hlist_head *chain;
  	struct hlist_node *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576

ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
577
  	*err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  	write_lock_bh(&xfrm_policy_lock);
8d1211a6a   Alexey Dobriyan   netns xfrm: findi...
579
  	chain = policy_hash_bysel(net, sel, sel->family, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
580
581
582
  	ret = NULL;
  	hlist_for_each_entry(pol, entry, chain, bydst) {
  		if (pol->type == type &&
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
583
  		    (mark & pol->mark.m) == pol->mark.v &&
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
584
585
  		    !selector_cmp(sel, &pol->selector) &&
  		    xfrm_sec_ctx_match(ctx, pol->security)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  			xfrm_pol_hold(pol);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
587
  			if (delete) {
03e1ad7b5   Paul Moore   LSM: Make the Lab...
588
589
  				*err = security_xfrm_policy_delete(
  								pol->security);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
590
591
592
593
  				if (*err) {
  					write_unlock_bh(&xfrm_policy_lock);
  					return pol;
  				}
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
594
  				__xfrm_policy_unlink(pol, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
595
596
  			}
  			ret = pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
  			break;
  		}
  	}
  	write_unlock_bh(&xfrm_policy_lock);
fe1a5f031   Timo Teräs   flow: virtualize ...
601
  	if (ret && delete)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
602
  		xfrm_policy_kill(ret);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
603
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
605
  EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606

8ca2e93b5   Jamal Hadi Salim   xfrm: SP lookups ...
607
608
  struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
  				     int dir, u32 id, int delete, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
610
611
612
  	struct xfrm_policy *pol, *ret;
  	struct hlist_head *chain;
  	struct hlist_node *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613

b5505c6e1   Herbert Xu   [IPSEC]: Check va...
614
615
616
  	*err = -ENOENT;
  	if (xfrm_policy_id2dir(id) != dir)
  		return NULL;
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
617
  	*err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  	write_lock_bh(&xfrm_policy_lock);
8d1211a6a   Alexey Dobriyan   netns xfrm: findi...
619
  	chain = net->xfrm.policy_byidx + idx_hash(net, id);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
620
621
  	ret = NULL;
  	hlist_for_each_entry(pol, entry, chain, byidx) {
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
622
623
  		if (pol->type == type && pol->index == id &&
  		    (mark & pol->mark.m) == pol->mark.v) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  			xfrm_pol_hold(pol);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
625
  			if (delete) {
03e1ad7b5   Paul Moore   LSM: Make the Lab...
626
627
  				*err = security_xfrm_policy_delete(
  								pol->security);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
628
629
630
631
  				if (*err) {
  					write_unlock_bh(&xfrm_policy_lock);
  					return pol;
  				}
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
632
  				__xfrm_policy_unlink(pol, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
633
634
  			}
  			ret = pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
  			break;
  		}
  	}
  	write_unlock_bh(&xfrm_policy_lock);
fe1a5f031   Timo Teräs   flow: virtualize ...
639
  	if (ret && delete)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
640
  		xfrm_policy_kill(ret);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
641
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
  }
  EXPORT_SYMBOL(xfrm_policy_byid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
644
645
  #ifdef CONFIG_SECURITY_NETWORK_XFRM
  static inline int
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
646
  xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  {
4aa2e62c4   Joy Latten   xfrm: Add securit...
648
649
650
651
652
653
654
655
  	int dir, err = 0;
  
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
  		struct xfrm_policy *pol;
  		struct hlist_node *entry;
  		int i;
  
  		hlist_for_each_entry(pol, entry,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
656
  				     &net->xfrm.policy_inexact[dir], bydst) {
4aa2e62c4   Joy Latten   xfrm: Add securit...
657
658
  			if (pol->type != type)
  				continue;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
659
  			err = security_xfrm_policy_delete(pol->security);
4aa2e62c4   Joy Latten   xfrm: Add securit...
660
  			if (err) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
661
662
  				xfrm_audit_policy_delete(pol, 0,
  							 audit_info->loginuid,
2532386f4   Eric Paris   Audit: collect se...
663
  							 audit_info->sessionid,
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
664
  							 audit_info->secid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
665
666
  				return err;
  			}
7dc12d6dd   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
667
  		}
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
668
  		for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
4aa2e62c4   Joy Latten   xfrm: Add securit...
669
  			hlist_for_each_entry(pol, entry,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
670
  					     net->xfrm.policy_bydst[dir].table + i,
4aa2e62c4   Joy Latten   xfrm: Add securit...
671
672
673
  					     bydst) {
  				if (pol->type != type)
  					continue;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
674
675
  				err = security_xfrm_policy_delete(
  								pol->security);
4aa2e62c4   Joy Latten   xfrm: Add securit...
676
  				if (err) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
677
678
  					xfrm_audit_policy_delete(pol, 0,
  							audit_info->loginuid,
2532386f4   Eric Paris   Audit: collect se...
679
  							audit_info->sessionid,
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
680
  							audit_info->secid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
681
682
683
684
685
686
687
688
689
  					return err;
  				}
  			}
  		}
  	}
  	return err;
  }
  #else
  static inline int
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
690
  xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info)
4aa2e62c4   Joy Latten   xfrm: Add securit...
691
692
693
694
  {
  	return 0;
  }
  #endif
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
695
  int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
4aa2e62c4   Joy Latten   xfrm: Add securit...
696
  {
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
697
  	int dir, err = 0, cnt = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
  
  	write_lock_bh(&xfrm_policy_lock);
4aa2e62c4   Joy Latten   xfrm: Add securit...
700

33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
701
  	err = xfrm_policy_flush_secctx_check(net, type, audit_info);
4aa2e62c4   Joy Latten   xfrm: Add securit...
702
703
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
705
706
  		struct xfrm_policy *pol;
  		struct hlist_node *entry;
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
707
  		int i;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
708
709
710
  
  	again1:
  		hlist_for_each_entry(pol, entry,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
711
  				     &net->xfrm.policy_inexact[dir], bydst) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
712
713
  			if (pol->type != type)
  				continue;
ea2dea9da   Timo Teräs   xfrm: remove poli...
714
  			__xfrm_policy_unlink(pol, dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
  			write_unlock_bh(&xfrm_policy_lock);
ea2dea9da   Timo Teräs   xfrm: remove poli...
716
  			cnt++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717

ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
718
  			xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
2532386f4   Eric Paris   Audit: collect se...
719
  						 audit_info->sessionid,
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
720
  						 audit_info->secid);
161a09e73   Joy Latten   audit: Add auditi...
721

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
722
  			xfrm_policy_kill(pol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
  
  			write_lock_bh(&xfrm_policy_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
725
726
  			goto again1;
  		}
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
727
  		for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
728
729
  	again2:
  			hlist_for_each_entry(pol, entry,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
730
  					     net->xfrm.policy_bydst[dir].table + i,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
731
732
733
  					     bydst) {
  				if (pol->type != type)
  					continue;
ea2dea9da   Timo Teräs   xfrm: remove poli...
734
  				__xfrm_policy_unlink(pol, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
735
  				write_unlock_bh(&xfrm_policy_lock);
ea2dea9da   Timo Teräs   xfrm: remove poli...
736
  				cnt++;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
737

ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
738
739
  				xfrm_audit_policy_delete(pol, 1,
  							 audit_info->loginuid,
2532386f4   Eric Paris   Audit: collect se...
740
  							 audit_info->sessionid,
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
741
  							 audit_info->secid);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
742
743
744
745
746
  				xfrm_policy_kill(pol);
  
  				write_lock_bh(&xfrm_policy_lock);
  				goto again2;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  		}
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
748

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  	}
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
750
751
  	if (!cnt)
  		err = -ESRCH;
4aa2e62c4   Joy Latten   xfrm: Add securit...
752
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  	write_unlock_bh(&xfrm_policy_lock);
4aa2e62c4   Joy Latten   xfrm: Add securit...
754
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
  }
  EXPORT_SYMBOL(xfrm_policy_flush);
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
757
  int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
4c563f766   Timo Teras   [XFRM]: Speed up ...
758
  		     int (*func)(struct xfrm_policy *, int, int, void*),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
  		     void *data)
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
761
762
  	struct xfrm_policy *pol;
  	struct xfrm_policy_walk_entry *x;
4c563f766   Timo Teras   [XFRM]: Speed up ...
763
764
765
766
767
  	int error = 0;
  
  	if (walk->type >= XFRM_POLICY_TYPE_MAX &&
  	    walk->type != XFRM_POLICY_TYPE_ANY)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768

12a169e7d   Herbert Xu   ipsec: Put dumper...
769
  	if (list_empty(&walk->walk.all) && walk->seq != 0)
4c563f766   Timo Teras   [XFRM]: Speed up ...
770
  		return 0;
12a169e7d   Herbert Xu   ipsec: Put dumper...
771
772
  	write_lock_bh(&xfrm_policy_lock);
  	if (list_empty(&walk->walk.all))
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
773
  		x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
12a169e7d   Herbert Xu   ipsec: Put dumper...
774
775
  	else
  		x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all);
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
776
  	list_for_each_entry_from(x, &net->xfrm.policy_all, all) {
12a169e7d   Herbert Xu   ipsec: Put dumper...
777
  		if (x->dead)
4c563f766   Timo Teras   [XFRM]: Speed up ...
778
  			continue;
12a169e7d   Herbert Xu   ipsec: Put dumper...
779
780
781
782
783
784
785
786
787
  		pol = container_of(x, struct xfrm_policy, walk);
  		if (walk->type != XFRM_POLICY_TYPE_ANY &&
  		    walk->type != pol->type)
  			continue;
  		error = func(pol, xfrm_policy_id2dir(pol->index),
  			     walk->seq, data);
  		if (error) {
  			list_move_tail(&walk->walk.all, &x->all);
  			goto out;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
788
  		}
12a169e7d   Herbert Xu   ipsec: Put dumper...
789
  		walk->seq++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
  	}
12a169e7d   Herbert Xu   ipsec: Put dumper...
791
  	if (walk->seq == 0) {
baf5d743d   Jamal Hadi Salim   [XFRM] Optimize p...
792
793
794
  		error = -ENOENT;
  		goto out;
  	}
12a169e7d   Herbert Xu   ipsec: Put dumper...
795
  	list_del_init(&walk->walk.all);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
  out:
12a169e7d   Herbert Xu   ipsec: Put dumper...
797
  	write_unlock_bh(&xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
  	return error;
  }
  EXPORT_SYMBOL(xfrm_policy_walk);
12a169e7d   Herbert Xu   ipsec: Put dumper...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
  {
  	INIT_LIST_HEAD(&walk->walk.all);
  	walk->walk.dead = 1;
  	walk->type = type;
  	walk->seq = 0;
  }
  EXPORT_SYMBOL(xfrm_policy_walk_init);
  
  void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
  {
  	if (list_empty(&walk->walk.all))
  		return;
  
  	write_lock_bh(&xfrm_policy_lock);
  	list_del(&walk->walk.all);
  	write_unlock_bh(&xfrm_policy_lock);
  }
  EXPORT_SYMBOL(xfrm_policy_walk_done);
134b0fc54   James Morris   IPsec: propagate ...
820
821
822
823
824
  /*
   * Find policy to apply to this flow.
   *
   * Returns 0 if policy found, else an -errno.
   */
f299d557c   David S. Miller   xfrm: Const'ify p...
825
826
  static int xfrm_policy_match(const struct xfrm_policy *pol,
  			     const struct flowi *fl,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
827
  			     u8 type, u16 family, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  {
f299d557c   David S. Miller   xfrm: Const'ify p...
829
  	const struct xfrm_selector *sel = &pol->selector;
134b0fc54   James Morris   IPsec: propagate ...
830
  	int match, ret = -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
832
  	if (pol->family != family ||
1d28f42c1   David S. Miller   net: Put flowi_* ...
833
  	    (fl->flowi_mark & pol->mark.m) != pol->mark.v ||
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
834
  	    pol->type != type)
134b0fc54   James Morris   IPsec: propagate ...
835
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
837
  	match = xfrm_selector_match(sel, fl, family);
134b0fc54   James Morris   IPsec: propagate ...
838
  	if (match)
1d28f42c1   David S. Miller   net: Put flowi_* ...
839
  		ret = security_xfrm_policy_lookup(pol->security, fl->flowi_secid,
03e1ad7b5   Paul Moore   LSM: Make the Lab...
840
  						  dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
841

134b0fc54   James Morris   IPsec: propagate ...
842
  	return ret;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
843
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844

52479b623   Alexey Dobriyan   netns xfrm: looku...
845
  static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
062cdb43b   David S. Miller   xfrm: Mark flowi ...
846
  						     const struct flowi *fl,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
847
848
  						     u16 family, u8 dir)
  {
134b0fc54   James Morris   IPsec: propagate ...
849
  	int err;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
850
  	struct xfrm_policy *pol, *ret;
0b597e7ed   David S. Miller   xfrm: Const'ify l...
851
  	const xfrm_address_t *daddr, *saddr;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
852
853
  	struct hlist_node *entry;
  	struct hlist_head *chain;
acba48e1a   David S. Miller   [XFRM]: Respect p...
854
  	u32 priority = ~0U;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
855

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
856
857
858
859
860
861
  	daddr = xfrm_flowi_daddr(fl, family);
  	saddr = xfrm_flowi_saddr(fl, family);
  	if (unlikely(!daddr || !saddr))
  		return NULL;
  
  	read_lock_bh(&xfrm_policy_lock);
52479b623   Alexey Dobriyan   netns xfrm: looku...
862
  	chain = policy_hash_direct(net, daddr, saddr, family, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
863
864
  	ret = NULL;
  	hlist_for_each_entry(pol, entry, chain, bydst) {
134b0fc54   James Morris   IPsec: propagate ...
865
866
867
868
869
870
871
872
873
  		err = xfrm_policy_match(pol, fl, type, family, dir);
  		if (err) {
  			if (err == -ESRCH)
  				continue;
  			else {
  				ret = ERR_PTR(err);
  				goto fail;
  			}
  		} else {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
874
  			ret = pol;
acba48e1a   David S. Miller   [XFRM]: Respect p...
875
  			priority = ret->priority;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
876
877
878
  			break;
  		}
  	}
52479b623   Alexey Dobriyan   netns xfrm: looku...
879
  	chain = &net->xfrm.policy_inexact[dir];
acba48e1a   David S. Miller   [XFRM]: Respect p...
880
  	hlist_for_each_entry(pol, entry, chain, bydst) {
134b0fc54   James Morris   IPsec: propagate ...
881
882
883
884
885
886
887
888
889
  		err = xfrm_policy_match(pol, fl, type, family, dir);
  		if (err) {
  			if (err == -ESRCH)
  				continue;
  			else {
  				ret = ERR_PTR(err);
  				goto fail;
  			}
  		} else if (pol->priority < priority) {
acba48e1a   David S. Miller   [XFRM]: Respect p...
890
891
  			ret = pol;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
  		}
  	}
acba48e1a   David S. Miller   [XFRM]: Respect p...
894
895
  	if (ret)
  		xfrm_pol_hold(ret);
134b0fc54   James Morris   IPsec: propagate ...
896
  fail:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  	read_unlock_bh(&xfrm_policy_lock);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
898

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
899
  	return ret;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
900
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
901
  static struct xfrm_policy *
73ff93cd0   David S. Miller   xfrm: Mark flowi ...
902
  __xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir)
80c802f30   Timo Teräs   xfrm: cache bundl...
903
904
905
906
907
908
909
910
911
912
  {
  #ifdef CONFIG_XFRM_SUB_POLICY
  	struct xfrm_policy *pol;
  
  	pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
  	if (pol != NULL)
  		return pol;
  #endif
  	return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
  }
fe1a5f031   Timo Teräs   flow: virtualize ...
913
  static struct flow_cache_object *
dee9f4bce   David S. Miller   net: Make flow ca...
914
  xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family,
fe1a5f031   Timo Teräs   flow: virtualize ...
915
  		   u8 dir, struct flow_cache_object *old_obj, void *ctx)
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
916
917
  {
  	struct xfrm_policy *pol;
fe1a5f031   Timo Teräs   flow: virtualize ...
918
919
920
  
  	if (old_obj)
  		xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo));
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
921

80c802f30   Timo Teräs   xfrm: cache bundl...
922
923
  	pol = __xfrm_policy_lookup(net, fl, family, dir);
  	if (IS_ERR_OR_NULL(pol))
fe1a5f031   Timo Teräs   flow: virtualize ...
924
  		return ERR_CAST(pol);
fe1a5f031   Timo Teräs   flow: virtualize ...
925

fe1a5f031   Timo Teräs   flow: virtualize ...
926
927
928
929
930
  	/* Resolver returns two references:
  	 * one for cache and one for caller of flow_cache_lookup() */
  	xfrm_pol_hold(pol);
  
  	return &pol->flo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
932
933
934
  static inline int policy_to_flow_dir(int dir)
  {
  	if (XFRM_POLICY_IN == FLOW_DIR_IN &&
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
935
936
937
938
939
940
941
942
943
944
945
  	    XFRM_POLICY_OUT == FLOW_DIR_OUT &&
  	    XFRM_POLICY_FWD == FLOW_DIR_FWD)
  		return dir;
  	switch (dir) {
  	default:
  	case XFRM_POLICY_IN:
  		return FLOW_DIR_IN;
  	case XFRM_POLICY_OUT:
  		return FLOW_DIR_OUT;
  	case XFRM_POLICY_FWD:
  		return FLOW_DIR_FWD;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
946
  	}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
947
  }
dee9f4bce   David S. Miller   net: Make flow ca...
948
949
  static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir,
  						 const struct flowi *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
954
  {
  	struct xfrm_policy *pol;
  
  	read_lock_bh(&xfrm_policy_lock);
  	if ((pol = sk->sk_policy[dir]) != NULL) {
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
955
  		int match = xfrm_selector_match(&pol->selector, fl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
  						sk->sk_family);
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
957
  		int err = 0;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
958

3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
959
  		if (match) {
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
960
961
962
963
  			if ((sk->sk_mark & pol->mark.m) != pol->mark.v) {
  				pol = NULL;
  				goto out;
  			}
03e1ad7b5   Paul Moore   LSM: Make the Lab...
964
  			err = security_xfrm_policy_lookup(pol->security,
1d28f42c1   David S. Miller   net: Put flowi_* ...
965
  						      fl->flowi_secid,
03e1ad7b5   Paul Moore   LSM: Make the Lab...
966
  						      policy_to_flow_dir(dir));
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
967
968
969
970
971
972
973
  			if (!err)
  				xfrm_pol_hold(pol);
  			else if (err == -ESRCH)
  				pol = NULL;
  			else
  				pol = ERR_PTR(err);
  		} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
  			pol = NULL;
  	}
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
976
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
980
981
982
  	read_unlock_bh(&xfrm_policy_lock);
  	return pol;
  }
  
  static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
  {
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
983
  	struct net *net = xp_net(pol);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
984
  	struct hlist_head *chain = policy_hash_bysel(net, &pol->selector,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
985
  						     pol->family, dir);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
986

98806f75b   Alexey Dobriyan   netns xfrm: trivi...
987
  	list_add(&pol->walk.all, &net->xfrm.policy_all);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
988
  	hlist_add_head(&pol->bydst, chain);
e92303f87   Alexey Dobriyan   netns xfrm: propa...
989
  	hlist_add_head(&pol->byidx, net->xfrm.policy_byidx+idx_hash(net, pol->index));
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
990
  	net->xfrm.policy_count[dir]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
  	xfrm_pol_hold(pol);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
992

98806f75b   Alexey Dobriyan   netns xfrm: trivi...
993
994
  	if (xfrm_bydst_should_resize(net, dir, NULL))
  		schedule_work(&net->xfrm.policy_hash_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
998
999
  }
  
  static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
  						int dir)
  {
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
1000
  	struct net *net = xp_net(pol);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1001
1002
  	if (hlist_unhashed(&pol->bydst))
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1004
1005
  	hlist_del(&pol->bydst);
  	hlist_del(&pol->byidx);
12a169e7d   Herbert Xu   ipsec: Put dumper...
1006
  	list_del(&pol->walk.all);
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
1007
  	net->xfrm.policy_count[dir]--;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1008
1009
  
  	return pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  }
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1011
  int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
1014
1015
1016
  {
  	write_lock_bh(&xfrm_policy_lock);
  	pol = __xfrm_policy_unlink(pol, dir);
  	write_unlock_bh(&xfrm_policy_lock);
  	if (pol) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
  		xfrm_policy_kill(pol);
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1018
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
  	}
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1020
  	return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
  }
a70fcb0ba   David S. Miller   [XFRM]: Add some ...
1022
  EXPORT_SYMBOL(xfrm_policy_delete);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
  
  int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
1026
  	struct net *net = xp_net(pol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
  	struct xfrm_policy *old_pol;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1028
1029
1030
1031
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pol && pol->type != XFRM_POLICY_TYPE_MAIN)
  		return -EINVAL;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
1034
1035
  	write_lock_bh(&xfrm_policy_lock);
  	old_pol = sk->sk_policy[dir];
  	sk->sk_policy[dir] = pol;
  	if (pol) {
9d729f72d   James Morris   [NET]: Convert xt...
1036
  		pol->curlft.add_time = get_seconds();
1121994c8   Alexey Dobriyan   netns xfrm: polic...
1037
  		pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
  		__xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
  	}
  	if (old_pol)
ea2dea9da   Timo Teräs   xfrm: remove poli...
1041
1042
1043
  		/* Unlinking succeeds always. This is the only function
  		 * allowed to delete or replace socket policy.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
1047
1048
1049
1050
1051
  		__xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir);
  	write_unlock_bh(&xfrm_policy_lock);
  
  	if (old_pol) {
  		xfrm_policy_kill(old_pol);
  	}
  	return 0;
  }
d3e40a9f5   David S. Miller   xfrm: Const'ify p...
1052
  static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
  {
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
1054
  	struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
1057
  
  	if (newp) {
  		newp->selector = old->selector;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1058
1059
  		if (security_xfrm_policy_clone(old->security,
  					       &newp->security)) {
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1060
1061
1062
  			kfree(newp);
  			return NULL;  /* ENOMEM */
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
  		newp->lft = old->lft;
  		newp->curlft = old->curlft;
fb977e2ca   Jamal Hadi Salim   xfrm: clone mark ...
1065
  		newp->mark = old->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
1067
1068
1069
  		newp->action = old->action;
  		newp->flags = old->flags;
  		newp->xfrm_nr = old->xfrm_nr;
  		newp->index = old->index;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1070
  		newp->type = old->type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  		memcpy(newp->xfrm_vec, old->xfrm_vec,
  		       newp->xfrm_nr*sizeof(struct xfrm_tmpl));
  		write_lock_bh(&xfrm_policy_lock);
  		__xfrm_policy_link(newp, XFRM_POLICY_MAX+dir);
  		write_unlock_bh(&xfrm_policy_lock);
  		xfrm_pol_put(newp);
  	}
  	return newp;
  }
  
  int __xfrm_sk_clone_policy(struct sock *sk)
  {
  	struct xfrm_policy *p0 = sk->sk_policy[0],
  			   *p1 = sk->sk_policy[1];
  
  	sk->sk_policy[0] = sk->sk_policy[1] = NULL;
  	if (p0 && (sk->sk_policy[0] = clone_policy(p0, 0)) == NULL)
  		return -ENOMEM;
  	if (p1 && (sk->sk_policy[1] = clone_policy(p1, 1)) == NULL)
  		return -ENOMEM;
  	return 0;
  }
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1093
  static int
fbda33b2b   Alexey Dobriyan   netns xfrm: ->get...
1094
  xfrm_get_saddr(struct net *net, xfrm_address_t *local, xfrm_address_t *remote,
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1095
1096
1097
1098
1099
1100
1101
  	       unsigned short family)
  {
  	int err;
  	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
  
  	if (unlikely(afinfo == NULL))
  		return -EINVAL;
fbda33b2b   Alexey Dobriyan   netns xfrm: ->get...
1102
  	err = afinfo->get_saddr(net, local, remote);
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1103
1104
1105
  	xfrm_policy_put_afinfo(afinfo);
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
1107
1108
  /* Resolve list of templates for the flow, given policy. */
  
  static int
a6c2e6111   David S. Miller   xfrm: Mark flowi ...
1109
1110
  xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
  		      struct xfrm_state **xfrm, unsigned short family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
  {
fbda33b2b   Alexey Dobriyan   netns xfrm: ->get...
1112
  	struct net *net = xp_net(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
1115
1116
  	int nx;
  	int i, error;
  	xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
  	xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1117
  	xfrm_address_t tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
  
  	for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
  		struct xfrm_state *x;
  		xfrm_address_t *remote = daddr;
  		xfrm_address_t *local  = saddr;
  		struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
48b8d7831   Joakim Koskela   [XFRM]: State sel...
1124
1125
  		if (tmpl->mode == XFRM_MODE_TUNNEL ||
  		    tmpl->mode == XFRM_MODE_BEET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
  			remote = &tmpl->id.daddr;
  			local = &tmpl->saddr;
8444cf712   Thomas Egerer   xfrm: Allow diffe...
1128
1129
  			if (xfrm_addr_any(local, tmpl->encap_family)) {
  				error = xfrm_get_saddr(net, &tmp, remote, tmpl->encap_family);
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1130
1131
1132
1133
  				if (error)
  					goto fail;
  				local = &tmp;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
  		}
  
  		x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
  
  		if (x && x->km.state == XFRM_STATE_VALID) {
  			xfrm[nx++] = x;
  			daddr = remote;
  			saddr = local;
  			continue;
  		}
  		if (x) {
  			error = (x->km.state == XFRM_STATE_ERROR ?
  				 -EINVAL : -EAGAIN);
  			xfrm_state_put(x);
  		}
a43222661   fernando@oss.ntt.co   xfrm: do not leak...
1149
1150
  		else if (error == -ESRCH)
  			error = -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
  
  		if (!tmpl->optional)
  			goto fail;
  	}
  	return nx;
  
  fail:
  	for (nx--; nx>=0; nx--)
  		xfrm_state_put(xfrm[nx]);
  	return error;
  }
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1162
  static int
a6c2e6111   David S. Miller   xfrm: Mark flowi ...
1163
1164
  xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl,
  		  struct xfrm_state **xfrm, unsigned short family)
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1165
  {
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1166
1167
  	struct xfrm_state *tp[XFRM_MAX_DEPTH];
  	struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
  	int cnx = 0;
  	int error;
  	int ret;
  	int i;
  
  	for (i = 0; i < npols; i++) {
  		if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) {
  			error = -ENOBUFS;
  			goto fail;
  		}
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1178
1179
  
  		ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1180
1181
1182
1183
1184
1185
  		if (ret < 0) {
  			error = ret;
  			goto fail;
  		} else
  			cnx += ret;
  	}
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1186
1187
1188
  	/* found states are sorted for outbound processing */
  	if (npols > 1)
  		xfrm_state_sort(xfrm, tpp, cnx, family);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1189
1190
1191
1192
  	return cnx;
  
   fail:
  	for (cnx--; cnx>=0; cnx--)
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1193
  		xfrm_state_put(tpp[cnx]);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1194
1195
1196
  	return error;
  
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
1198
1199
  /* Check that the bundle accepts the flow and its components are
   * still valid.
   */
05d840257   David S. Miller   xfrm: Mark flowi ...
1200
  static inline int xfrm_get_tos(const struct flowi *fl, int family)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1201
1202
1203
  {
  	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
  	int tos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1205
1206
1207
1208
1209
1210
1211
1212
1213
  	if (!afinfo)
  		return -EINVAL;
  
  	tos = afinfo->get_tos(fl);
  
  	xfrm_policy_put_afinfo(afinfo);
  
  	return tos;
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  static struct flow_cache_object *xfrm_bundle_flo_get(struct flow_cache_object *flo)
  {
  	struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
  	struct dst_entry *dst = &xdst->u.dst;
  
  	if (xdst->route == NULL) {
  		/* Dummy bundle - if it has xfrms we were not
  		 * able to build bundle as template resolution failed.
  		 * It means we need to try again resolving. */
  		if (xdst->num_xfrms > 0)
  			return NULL;
  	} else {
  		/* Real bundle */
  		if (stale_bundle(dst))
  			return NULL;
  	}
  
  	dst_hold(dst);
  	return flo;
  }
  
  static int xfrm_bundle_flo_check(struct flow_cache_object *flo)
  {
  	struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
  	struct dst_entry *dst = &xdst->u.dst;
  
  	if (!xdst->route)
  		return 0;
  	if (stale_bundle(dst))
  		return 0;
  
  	return 1;
  }
  
  static void xfrm_bundle_flo_delete(struct flow_cache_object *flo)
  {
  	struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
  	struct dst_entry *dst = &xdst->u.dst;
  
  	dst_free(dst);
  }
  
  static const struct flow_cache_ops xfrm_bundle_fc_ops = {
  	.get = xfrm_bundle_flo_get,
  	.check = xfrm_bundle_flo_check,
  	.delete = xfrm_bundle_flo_delete,
  };
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1261
  static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1263
  	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1264
  	struct dst_ops *dst_ops;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1265
1266
1267
1268
  	struct xfrm_dst *xdst;
  
  	if (!afinfo)
  		return ERR_PTR(-EINVAL);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1269
1270
1271
1272
  	switch (family) {
  	case AF_INET:
  		dst_ops = &net->xfrm.xfrm4_dst_ops;
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1273
  #if IS_ENABLED(CONFIG_IPV6)
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1274
1275
1276
1277
1278
1279
1280
  	case AF_INET6:
  		dst_ops = &net->xfrm.xfrm6_dst_ops;
  		break;
  #endif
  	default:
  		BUG();
  	}
5c1e6aa30   David S. Miller   net: Make dst_all...
1281
  	xdst = dst_alloc(dst_ops, NULL, 0, 0, 0);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1282

d4cae5621   Madalin Bucur   net: check return...
1283
1284
1285
  	if (likely(xdst)) {
  		memset(&xdst->u.rt6.rt6i_table, 0,
  			sizeof(*xdst) - sizeof(struct dst_entry));
0b1509321   Hiroaki SHIMODA   xfrm: avoid possi...
1286
  		xdst->flo.ops = &xfrm_bundle_fc_ops;
d4cae5621   Madalin Bucur   net: check return...
1287
  	} else
0b1509321   Hiroaki SHIMODA   xfrm: avoid possi...
1288
  		xdst = ERR_PTR(-ENOBUFS);
80c802f30   Timo Teräs   xfrm: cache bundl...
1289

d4cae5621   Madalin Bucur   net: check return...
1290
  	xfrm_policy_put_afinfo(afinfo);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1291
1292
  	return xdst;
  }
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
  static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst,
  				 int nfheader_len)
  {
  	struct xfrm_policy_afinfo *afinfo =
  		xfrm_policy_get_afinfo(dst->ops->family);
  	int err;
  
  	if (!afinfo)
  		return -EINVAL;
  
  	err = afinfo->init_path(path, dst, nfheader_len);
  
  	xfrm_policy_put_afinfo(afinfo);
  
  	return err;
  }
87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
1309
  static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
0c7b3eefb   David S. Miller   xfrm: Mark flowi ...
1310
  				const struct flowi *fl)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1311
1312
1313
1314
1315
1316
  {
  	struct xfrm_policy_afinfo *afinfo =
  		xfrm_policy_get_afinfo(xdst->u.dst.ops->family);
  	int err;
  
  	if (!afinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
  		return -EINVAL;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1318

87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
1319
  	err = afinfo->fill_dst(xdst, dev, fl);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1320

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
  	xfrm_policy_put_afinfo(afinfo);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1322

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
  	return err;
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
1325

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1326
1327
1328
1329
1330
1331
  /* Allocate chain of dst_entry's, attach known xfrm's, calculate
   * all the metrics... Shortly, bundle a bundle.
   */
  
  static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
  					    struct xfrm_state **xfrm, int nx,
98313adaa   David S. Miller   xfrm: Mark flowi ...
1332
  					    const struct flowi *fl,
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1333
1334
  					    struct dst_entry *dst)
  {
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1335
  	struct net *net = xp_net(policy);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1336
1337
  	unsigned long now = jiffies;
  	struct net_device *dev;
43a4dea4c   Steffen Klassert   xfrm: Assign the ...
1338
  	struct xfrm_mode *inner_mode;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1339
1340
1341
1342
1343
  	struct dst_entry *dst_prev = NULL;
  	struct dst_entry *dst0 = NULL;
  	int i = 0;
  	int err;
  	int header_len = 0;
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1344
  	int nfheader_len = 0;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1345
1346
1347
  	int trailer_len = 0;
  	int tos;
  	int family = policy->selector.family;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
1348
1349
1350
  	xfrm_address_t saddr, daddr;
  
  	xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1351
1352
1353
1354
1355
1356
1357
1358
1359
  
  	tos = xfrm_get_tos(fl, family);
  	err = tos;
  	if (tos < 0)
  		goto put_states;
  
  	dst_hold(dst);
  
  	for (; i < nx; i++) {
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1360
  		struct xfrm_dst *xdst = xfrm_alloc_dst(net, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1361
1362
1363
1364
1365
1366
1367
  		struct dst_entry *dst1 = &xdst->u.dst;
  
  		err = PTR_ERR(xdst);
  		if (IS_ERR(xdst)) {
  			dst_release(dst);
  			goto put_states;
  		}
43a4dea4c   Steffen Klassert   xfrm: Assign the ...
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
  		if (xfrm[i]->sel.family == AF_UNSPEC) {
  			inner_mode = xfrm_ip2inner_mode(xfrm[i],
  							xfrm_af2proto(family));
  			if (!inner_mode) {
  				err = -EAFNOSUPPORT;
  				dst_release(dst);
  				goto put_states;
  			}
  		} else
  			inner_mode = xfrm[i]->inner_mode;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1378
1379
1380
1381
1382
1383
1384
1385
  		if (!dst_prev)
  			dst0 = dst1;
  		else {
  			dst_prev->child = dst_clone(dst1);
  			dst1->flags |= DST_NOHASH;
  		}
  
  		xdst->route = dst;
defb3519a   David S. Miller   net: Abstract awa...
1386
  		dst_copy_metrics(dst1, dst);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1387
1388
1389
  
  		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
  			family = xfrm[i]->props.family;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
1390
1391
  			dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr,
  					      family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1392
1393
1394
1395
1396
1397
1398
  			err = PTR_ERR(dst);
  			if (IS_ERR(dst))
  				goto put_states;
  		} else
  			dst_hold(dst);
  
  		dst1->xfrm = xfrm[i];
80c802f30   Timo Teräs   xfrm: cache bundl...
1399
  		xdst->xfrm_genid = xfrm[i]->genid;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1400
1401
1402
1403
1404
1405
  
  		dst1->obsolete = -1;
  		dst1->flags |= DST_HOST;
  		dst1->lastuse = now;
  
  		dst1->input = dst_discard;
43a4dea4c   Steffen Klassert   xfrm: Assign the ...
1406
  		dst1->output = inner_mode->afinfo->output;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1407
1408
1409
1410
1411
  
  		dst1->next = dst_prev;
  		dst_prev = dst1;
  
  		header_len += xfrm[i]->props.header_len;
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1412
1413
  		if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
  			nfheader_len += xfrm[i]->props.header_len;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
  		trailer_len += xfrm[i]->props.trailer_len;
  	}
  
  	dst_prev->child = dst;
  	dst0->path = dst;
  
  	err = -ENODEV;
  	dev = dst->dev;
  	if (!dev)
  		goto free_dst;
96c534014   Ralf Baechle   NET: XFRM: Fix sp...
1424
  	/* Copy neighbour for reachability confirmation */
272174550   David Miller   net: Rename dst_g...
1425
  	dst_set_neighbour(dst0, neigh_clone(dst_get_neighbour_noref(dst)));
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1426

a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1427
  	xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1428
1429
1430
1431
  	xfrm_init_pmtu(dst_prev);
  
  	for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) {
  		struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev;
87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
1432
  		err = xfrm_fill_dst(xdst, dev, fl);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
  		if (err)
  			goto free_dst;
  
  		dst_prev->header_len = header_len;
  		dst_prev->trailer_len = trailer_len;
  		header_len -= xdst->u.dst.xfrm->props.header_len;
  		trailer_len -= xdst->u.dst.xfrm->props.trailer_len;
  	}
  
  out:
  	return dst0;
  
  put_states:
  	for (; i < nx; i++)
  		xfrm_state_put(xfrm[i]);
  free_dst:
  	if (dst0)
  		dst_free(dst0);
  	dst0 = ERR_PTR(err);
  	goto out;
  }
157bfc250   Masahide NAKAMURA   [XFRM]: Restrict ...
1454
  static int inline
3f0e18fb0   David S. Miller   xfrm: Mark flowi ...
1455
  xfrm_dst_alloc_copy(void **target, const void *src, int size)
157bfc250   Masahide NAKAMURA   [XFRM]: Restrict ...
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
  {
  	if (!*target) {
  		*target = kmalloc(size, GFP_ATOMIC);
  		if (!*target)
  			return -ENOMEM;
  	}
  	memcpy(*target, src, size);
  	return 0;
  }
  
  static int inline
1786b3891   David S. Miller   xfrm: Const'ify s...
1467
  xfrm_dst_update_parent(struct dst_entry *dst, const struct xfrm_selector *sel)
157bfc250   Masahide NAKAMURA   [XFRM]: Restrict ...
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
  {
  #ifdef CONFIG_XFRM_SUB_POLICY
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  	return xfrm_dst_alloc_copy((void **)&(xdst->partner),
  				   sel, sizeof(*sel));
  #else
  	return 0;
  #endif
  }
  
  static int inline
3f0e18fb0   David S. Miller   xfrm: Mark flowi ...
1479
  xfrm_dst_update_origin(struct dst_entry *dst, const struct flowi *fl)
157bfc250   Masahide NAKAMURA   [XFRM]: Restrict ...
1480
1481
1482
1483
1484
1485
1486
1487
  {
  #ifdef CONFIG_XFRM_SUB_POLICY
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  	return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl));
  #else
  	return 0;
  #endif
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1488

73ff93cd0   David S. Miller   xfrm: Mark flowi ...
1489
  static int xfrm_expand_policies(const struct flowi *fl, u16 family,
80c802f30   Timo Teräs   xfrm: cache bundl...
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
  				struct xfrm_policy **pols,
  				int *num_pols, int *num_xfrms)
  {
  	int i;
  
  	if (*num_pols == 0 || !pols[0]) {
  		*num_pols = 0;
  		*num_xfrms = 0;
  		return 0;
  	}
  	if (IS_ERR(pols[0]))
  		return PTR_ERR(pols[0]);
  
  	*num_xfrms = pols[0]->xfrm_nr;
  
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pols[0] && pols[0]->action == XFRM_POLICY_ALLOW &&
  	    pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
  		pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]),
  						    XFRM_POLICY_TYPE_MAIN,
  						    fl, family,
  						    XFRM_POLICY_OUT);
  		if (pols[1]) {
  			if (IS_ERR(pols[1])) {
  				xfrm_pols_put(pols, *num_pols);
  				return PTR_ERR(pols[1]);
  			}
  			(*num_pols) ++;
  			(*num_xfrms) += pols[1]->xfrm_nr;
  		}
  	}
  #endif
  	for (i = 0; i < *num_pols; i++) {
  		if (pols[i]->action != XFRM_POLICY_ALLOW) {
  			*num_xfrms = -1;
  			break;
  		}
  	}
  
  	return 0;
  
  }
  
  static struct xfrm_dst *
  xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
4ca2e6851   David S. Miller   xfrm: Mark flowi ...
1535
  			       const struct flowi *fl, u16 family,
80c802f30   Timo Teräs   xfrm: cache bundl...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
  			       struct dst_entry *dst_orig)
  {
  	struct net *net = xp_net(pols[0]);
  	struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
  	struct dst_entry *dst;
  	struct xfrm_dst *xdst;
  	int err;
  
  	/* Try to instantiate a bundle */
  	err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
d809ec895   Timo Teräs   xfrm: do not assu...
1546
1547
  	if (err <= 0) {
  		if (err != 0 && err != -EAGAIN)
80c802f30   Timo Teräs   xfrm: cache bundl...
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
  		return ERR_PTR(err);
  	}
  
  	dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
  	if (IS_ERR(dst)) {
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
  		return ERR_CAST(dst);
  	}
  
  	xdst = (struct xfrm_dst *)dst;
  	xdst->num_xfrms = err;
  	if (num_pols > 1)
  		err = xfrm_dst_update_parent(dst, &pols[1]->selector);
  	else
  		err = xfrm_dst_update_origin(dst, fl);
  	if (unlikely(err)) {
  		dst_free(dst);
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
  		return ERR_PTR(err);
  	}
  
  	xdst->num_pols = num_pols;
  	memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
  	xdst->policy_genid = atomic_read(&pols[0]->genid);
  
  	return xdst;
  }
  
  static struct flow_cache_object *
dee9f4bce   David S. Miller   net: Make flow ca...
1578
  xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
80c802f30   Timo Teräs   xfrm: cache bundl...
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
  		   struct flow_cache_object *oldflo, void *ctx)
  {
  	struct dst_entry *dst_orig = (struct dst_entry *)ctx;
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
  	struct xfrm_dst *xdst, *new_xdst;
  	int num_pols = 0, num_xfrms = 0, i, err, pol_dead;
  
  	/* Check if the policies from old bundle are usable */
  	xdst = NULL;
  	if (oldflo) {
  		xdst = container_of(oldflo, struct xfrm_dst, flo);
  		num_pols = xdst->num_pols;
  		num_xfrms = xdst->num_xfrms;
  		pol_dead = 0;
  		for (i = 0; i < num_pols; i++) {
  			pols[i] = xdst->pols[i];
  			pol_dead |= pols[i]->walk.dead;
  		}
  		if (pol_dead) {
  			dst_free(&xdst->u.dst);
  			xdst = NULL;
  			num_pols = 0;
  			num_xfrms = 0;
  			oldflo = NULL;
  		}
  	}
  
  	/* Resolve policies to use if we couldn't get them from
  	 * previous cache entry */
  	if (xdst == NULL) {
  		num_pols = 1;
  		pols[0] = __xfrm_policy_lookup(net, fl, family, dir);
  		err = xfrm_expand_policies(fl, family, pols,
  					   &num_pols, &num_xfrms);
  		if (err < 0)
  			goto inc_error;
  		if (num_pols == 0)
  			return NULL;
  		if (num_xfrms <= 0)
  			goto make_dummy_bundle;
  	}
  
  	new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, dst_orig);
  	if (IS_ERR(new_xdst)) {
  		err = PTR_ERR(new_xdst);
  		if (err != -EAGAIN)
  			goto error;
  		if (oldflo == NULL)
  			goto make_dummy_bundle;
  		dst_hold(&xdst->u.dst);
  		return oldflo;
d809ec895   Timo Teräs   xfrm: do not assu...
1630
1631
1632
1633
1634
1635
1636
  	} else if (new_xdst == NULL) {
  		num_xfrms = 0;
  		if (oldflo == NULL)
  			goto make_dummy_bundle;
  		xdst->num_xfrms = 0;
  		dst_hold(&xdst->u.dst);
  		return oldflo;
80c802f30   Timo Teräs   xfrm: cache bundl...
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
  	}
  
  	/* Kill the previous bundle */
  	if (xdst) {
  		/* The policies were stolen for newly generated bundle */
  		xdst->num_pols = 0;
  		dst_free(&xdst->u.dst);
  	}
  
  	/* Flow cache does not have reference, it dst_free()'s,
  	 * but we do need to return one reference for original caller */
  	dst_hold(&new_xdst->u.dst);
  	return &new_xdst->flo;
  
  make_dummy_bundle:
  	/* We found policies, but there's no bundles to instantiate:
  	 * either because the policy blocks, has no transformations or
  	 * we could not build template (no xfrm_states).*/
  	xdst = xfrm_alloc_dst(net, family);
  	if (IS_ERR(xdst)) {
  		xfrm_pols_put(pols, num_pols);
  		return ERR_CAST(xdst);
  	}
  	xdst->num_pols = num_pols;
  	xdst->num_xfrms = num_xfrms;
  	memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
  
  	dst_hold(&xdst->u.dst);
  	return &xdst->flo;
  
  inc_error:
  	XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
  error:
  	if (xdst != NULL)
  		dst_free(&xdst->u.dst);
  	else
  		xfrm_pols_put(pols, num_pols);
  	return ERR_PTR(err);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1676

2774c131b   David S. Miller   xfrm: Handle blac...
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
  static struct dst_entry *make_blackhole(struct net *net, u16 family,
  					struct dst_entry *dst_orig)
  {
  	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
  	struct dst_entry *ret;
  
  	if (!afinfo) {
  		dst_release(dst_orig);
  		ret = ERR_PTR(-EINVAL);
  	} else {
  		ret = afinfo->blackhole_route(net, dst_orig);
  	}
  	xfrm_policy_put_afinfo(afinfo);
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693
1694
1695
1696
1697
  /* Main function: finds/creates a bundle for given flow.
   *
   * At the moment we eat a raw IP route. Mostly to speed up lookups
   * on interfaces with disabled IPsec.
   */
452edd598   David S. Miller   xfrm: Return dst ...
1698
1699
1700
  struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
  			      const struct flowi *fl,
  			      struct sock *sk, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701
  {
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1702
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
80c802f30   Timo Teräs   xfrm: cache bundl...
1703
1704
  	struct flow_cache_object *flo;
  	struct xfrm_dst *xdst;
452edd598   David S. Miller   xfrm: Return dst ...
1705
  	struct dst_entry *dst, *route;
80c802f30   Timo Teräs   xfrm: cache bundl...
1706
  	u16 family = dst_orig->ops->family;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1707
  	u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
4b021628b   Changli Gao   xfrm: potential u...
1708
  	int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
1709

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1710
  restart:
80c802f30   Timo Teräs   xfrm: cache bundl...
1711
1712
1713
  	dst = NULL;
  	xdst = NULL;
  	route = NULL;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1714

f7944fb19   Thomas Graf   [XFRM] policy: Re...
1715
  	if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
80c802f30   Timo Teräs   xfrm: cache bundl...
1716
1717
1718
1719
1720
  		num_pols = 1;
  		pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
  		err = xfrm_expand_policies(fl, family, pols,
  					   &num_pols, &num_xfrms);
  		if (err < 0)
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
1721
  			goto dropdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
  
  		if (num_pols) {
  			if (num_xfrms <= 0) {
  				drop_pols = num_pols;
  				goto no_transform;
  			}
  
  			xdst = xfrm_resolve_and_create_bundle(
  					pols, num_pols, fl,
  					family, dst_orig);
  			if (IS_ERR(xdst)) {
  				xfrm_pols_put(pols, num_pols);
  				err = PTR_ERR(xdst);
  				goto dropdst;
d809ec895   Timo Teräs   xfrm: do not assu...
1736
1737
1738
1739
  			} else if (xdst == NULL) {
  				num_xfrms = 0;
  				drop_pols = num_pols;
  				goto no_transform;
80c802f30   Timo Teräs   xfrm: cache bundl...
1740
  			}
fbd506087   Steffen Klassert   xfrm: Refcount de...
1741
  			dst_hold(&xdst->u.dst);
80c802f30   Timo Teräs   xfrm: cache bundl...
1742
1743
1744
1745
1746
1747
  			spin_lock_bh(&xfrm_policy_sk_bundle_lock);
  			xdst->u.dst.next = xfrm_policy_sk_bundles;
  			xfrm_policy_sk_bundles = &xdst->u.dst;
  			spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
  
  			route = xdst->route;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1748
  		}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1749
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750

80c802f30   Timo Teräs   xfrm: cache bundl...
1751
  	if (xdst == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1752
  		/* To accelerate a bit...  */
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1753
  		if ((dst_orig->flags & DST_NOXFRM) ||
52479b623   Alexey Dobriyan   netns xfrm: looku...
1754
  		    !net->xfrm.policy_count[XFRM_POLICY_OUT])
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
1755
  			goto nopol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1756

80c802f30   Timo Teräs   xfrm: cache bundl...
1757
1758
1759
1760
  		flo = flow_cache_lookup(net, fl, family, dir,
  					xfrm_bundle_lookup, dst_orig);
  		if (flo == NULL)
  			goto nopol;
fe1a5f031   Timo Teräs   flow: virtualize ...
1761
  		if (IS_ERR(flo)) {
80c802f30   Timo Teräs   xfrm: cache bundl...
1762
  			err = PTR_ERR(flo);
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
1763
  			goto dropdst;
d66e37a99   Masahide NAKAMURA   [XFRM] Statistics...
1764
  		}
80c802f30   Timo Teräs   xfrm: cache bundl...
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
  		xdst = container_of(flo, struct xfrm_dst, flo);
  
  		num_pols = xdst->num_pols;
  		num_xfrms = xdst->num_xfrms;
  		memcpy(pols, xdst->pols, sizeof(struct xfrm_policy*) * num_pols);
  		route = xdst->route;
  	}
  
  	dst = &xdst->u.dst;
  	if (route == NULL && num_xfrms > 0) {
  		/* The only case when xfrm_bundle_lookup() returns a
  		 * bundle with null route, is when the template could
  		 * not be resolved. It means policies are there, but
  		 * bundle could not be created, since we don't yet
  		 * have the xfrm_state's. We need to wait for KM to
  		 * negotiate new SA's or bail out with error.*/
  		if (net->xfrm.sysctl_larval_drop) {
  			/* EREMOTE tells the caller to generate
  			 * a one-shot blackhole route. */
  			dst_release(dst);
a1aa34830   Timo Teras   xfrm: fix policy ...
1785
  			xfrm_pols_put(pols, drop_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
1786
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
2774c131b   David S. Miller   xfrm: Handle blac...
1787

452edd598   David S. Miller   xfrm: Return dst ...
1788
  			return make_blackhole(net, family, dst_orig);
80c802f30   Timo Teräs   xfrm: cache bundl...
1789
  		}
1d28f42c1   David S. Miller   net: Put flowi_* ...
1790
  		if (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP) {
80c802f30   Timo Teräs   xfrm: cache bundl...
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
  			DECLARE_WAITQUEUE(wait, current);
  
  			add_wait_queue(&net->xfrm.km_waitq, &wait);
  			set_current_state(TASK_INTERRUPTIBLE);
  			schedule();
  			set_current_state(TASK_RUNNING);
  			remove_wait_queue(&net->xfrm.km_waitq, &wait);
  
  			if (!signal_pending(current)) {
  				dst_release(dst);
  				goto restart;
  			}
  
  			err = -ERESTART;
  		} else
  			err = -EAGAIN;
  
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
1811
1812
  no_transform:
  	if (num_pols == 0)
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
1813
  		goto nopol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814

80c802f30   Timo Teräs   xfrm: cache bundl...
1815
1816
1817
  	if ((flags & XFRM_LOOKUP_ICMP) &&
  	    !(pols[0]->flags & XFRM_POLICY_ICMP)) {
  		err = -ENOENT;
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
1818
  		goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
1819
  	}
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
1820

80c802f30   Timo Teräs   xfrm: cache bundl...
1821
1822
  	for (i = 0; i < num_pols; i++)
  		pols[i]->curlft.use_time = get_seconds();
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
1823

80c802f30   Timo Teräs   xfrm: cache bundl...
1824
  	if (num_xfrms < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1825
  		/* Prohibit the flow */
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
1826
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
e104411b8   Patrick McHardy   [XFRM]: Always re...
1827
1828
  		err = -EPERM;
  		goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
1829
1830
  	} else if (num_xfrms > 0) {
  		/* Flow transformed */
80c802f30   Timo Teräs   xfrm: cache bundl...
1831
1832
1833
1834
  		dst_release(dst_orig);
  	} else {
  		/* Flow passes untransformed */
  		dst_release(dst);
452edd598   David S. Miller   xfrm: Return dst ...
1835
  		dst = dst_orig;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1836
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
1837
1838
  ok:
  	xfrm_pols_put(pols, drop_pols);
452edd598   David S. Miller   xfrm: Return dst ...
1839
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840

80c802f30   Timo Teräs   xfrm: cache bundl...
1841
  nopol:
452edd598   David S. Miller   xfrm: Return dst ...
1842
1843
  	if (!(flags & XFRM_LOOKUP_ICMP)) {
  		dst = dst_orig;
80c802f30   Timo Teräs   xfrm: cache bundl...
1844
  		goto ok;
452edd598   David S. Miller   xfrm: Return dst ...
1845
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
1846
  	err = -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1847
  error:
80c802f30   Timo Teräs   xfrm: cache bundl...
1848
  	dst_release(dst);
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
1849
1850
  dropdst:
  	dst_release(dst_orig);
80c802f30   Timo Teräs   xfrm: cache bundl...
1851
  	xfrm_pols_put(pols, drop_pols);
452edd598   David S. Miller   xfrm: Return dst ...
1852
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1853
1854
  }
  EXPORT_SYMBOL(xfrm_lookup);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1855
  static inline int
8f029de28   David S. Miller   xfrm: Mark flowi ...
1856
  xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl)
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1857
1858
  {
  	struct xfrm_state *x;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1859
1860
1861
1862
1863
1864
  
  	if (!skb->sp || idx < 0 || idx >= skb->sp->len)
  		return 0;
  	x = skb->sp->xvec[idx];
  	if (!x->type->reject)
  		return 0;
1ecafede8   Herbert Xu   [IPSEC]: Remove b...
1865
  	return x->type->reject(x, skb, fl);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1866
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1867
1868
1869
1870
1871
1872
1873
  /* When skb is transformed back to its "native" form, we have to
   * check policy restrictions. At the moment we make this in maximally
   * stupid way. Shame on me. :-) Of course, connected sockets must
   * have policy cached at them.
   */
  
  static inline int
7db454b91   David S. Miller   xfrm: Const'ify p...
1874
  xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1875
1876
1877
  	      unsigned short family)
  {
  	if (xfrm_state_kern(x))
928ba4169   Kazunori MIYAZAWA   [IPSEC]: Fix the ...
1878
  		return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1879
1880
1881
1882
  	return	x->id.proto == tmpl->id.proto &&
  		(x->id.spi == tmpl->id.spi || !tmpl->id.spi) &&
  		(x->props.reqid == tmpl->reqid || !tmpl->reqid) &&
  		x->props.mode == tmpl->mode &&
c5d18e984   Herbert Xu   [IPSEC]: Fix catc...
1883
  		(tmpl->allalgs || (tmpl->aalgos & (1<<x->props.aalgo)) ||
f3bd48402   Masahide NAKAMURA   [XFRM]: Restrict ...
1884
  		 !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) &&
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
1885
1886
  		!(x->props.mode != XFRM_MODE_TRANSPORT &&
  		  xfrm_state_addr_cmp(tmpl, x, family));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1887
  }
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1888
1889
1890
1891
1892
1893
1894
  /*
   * 0 or more than 0 is returned when validation is succeeded (either bypass
   * because of optional transport mode, or next index of the mathced secpath
   * state with the template.
   * -1 is returned when no matching template is found.
   * Otherwise "-2 - errored_index" is returned.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1895
  static inline int
22cccb7e0   David S. Miller   xfrm: Const'ify p...
1896
  xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1897
1898
1899
1900
1901
  	       unsigned short family)
  {
  	int idx = start;
  
  	if (tmpl->optional) {
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
1902
  		if (tmpl->mode == XFRM_MODE_TRANSPORT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1903
1904
1905
1906
  			return start;
  	} else
  		start = -1;
  	for (; idx < sp->len; idx++) {
dbe5b4aaa   Herbert Xu   [IPSEC]: Kill unu...
1907
  		if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1908
  			return ++idx;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1909
1910
1911
  		if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
  			if (start == -1)
  				start = -2-idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1912
  			break;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1913
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
1915
1916
  	}
  	return start;
  }
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
1917
1918
  int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
  			  unsigned int family, int reverse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1919
1920
  {
  	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
1921
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1922
1923
1924
  
  	if (unlikely(afinfo == NULL))
  		return -EAFNOSUPPORT;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
1925
  	afinfo->decode_session(skb, fl, reverse);
1d28f42c1   David S. Miller   net: Put flowi_* ...
1926
  	err = security_xfrm_decode_session(skb, &fl->flowi_secid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1927
  	xfrm_policy_put_afinfo(afinfo);
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
1928
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
  }
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
1930
  EXPORT_SYMBOL(__xfrm_decode_session);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1931

9a7386ec9   David S. Miller   xfrm: Const'ify s...
1932
  static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int *idxp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1933
1934
  {
  	for (; k < sp->len; k++) {
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1935
  		if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) {
d1d9facfd   James Morris   [XFRM]: remove xe...
1936
  			*idxp = k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
  			return 1;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1938
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
1940
1941
1942
  	}
  
  	return 0;
  }
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
1943
  int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1944
1945
  			unsigned short family)
  {
f6e1e25d7   Alexey Dobriyan   netns xfrm: xfrm_...
1946
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947
  	struct xfrm_policy *pol;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1948
1949
1950
1951
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
  	int npols = 0;
  	int xfrm_nr;
  	int pi;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
1952
  	int reverse;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1953
  	struct flowi fl;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
1954
  	u8 fl_dir;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
1955
  	int xerr_idx = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956

d5422efe6   Herbert Xu   [IPSEC]: Added xf...
1957
1958
1959
  	reverse = dir & ~XFRM_POLICY_MASK;
  	dir &= XFRM_POLICY_MASK;
  	fl_dir = policy_to_flow_dir(dir);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1960
  	if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
1961
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
  		return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1963
  	}
eb9c7ebe6   Patrick McHardy   [NETFILTER]: Hand...
1964
  	nf_nat_decode_session(skb, &fl, family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1965
1966
1967
1968
1969
1970
  
  	/* First, check used SA against their selectors. */
  	if (skb->sp) {
  		int i;
  
  		for (i=skb->sp->len-1; i>=0; i--) {
dbe5b4aaa   Herbert Xu   [IPSEC]: Kill unu...
1971
  			struct xfrm_state *x = skb->sp->xvec[i];
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1972
  			if (!xfrm_selector_match(&x->sel, &fl, family)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
1973
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1974
  				return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1975
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1976
1977
1978
1979
  		}
  	}
  
  	pol = NULL;
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1980
  	if (sk && sk->sk_policy[dir]) {
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
1981
  		pol = xfrm_sk_policy_lookup(sk, dir, &fl);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1982
  		if (IS_ERR(pol)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
1983
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1984
  			return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1985
  		}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1986
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987

fe1a5f031   Timo Teräs   flow: virtualize ...
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
  	if (!pol) {
  		struct flow_cache_object *flo;
  
  		flo = flow_cache_lookup(net, &fl, family, fl_dir,
  					xfrm_policy_lookup, NULL);
  		if (IS_ERR_OR_NULL(flo))
  			pol = ERR_CAST(flo);
  		else
  			pol = container_of(flo, struct xfrm_policy, flo);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
1999
  	if (IS_ERR(pol)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2000
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
134b0fc54   James Morris   IPsec: propagate ...
2001
  		return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2002
  	}
134b0fc54   James Morris   IPsec: propagate ...
2003

df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2004
  	if (!pol) {
d1d9facfd   James Morris   [XFRM]: remove xe...
2005
  		if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2006
  			xfrm_secpath_reject(xerr_idx, skb, &fl);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2007
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2008
2009
2010
2011
  			return 0;
  		}
  		return 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2012

9d729f72d   James Morris   [NET]: Convert xt...
2013
  	pol->curlft.use_time = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2014

4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2015
2016
2017
2018
  	pols[0] = pol;
  	npols ++;
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
f6e1e25d7   Alexey Dobriyan   netns xfrm: xfrm_...
2019
  		pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2020
2021
2022
  						    &fl, family,
  						    XFRM_POLICY_IN);
  		if (pols[1]) {
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2023
  			if (IS_ERR(pols[1])) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2024
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
134b0fc54   James Morris   IPsec: propagate ...
2025
  				return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2026
  			}
9d729f72d   James Morris   [NET]: Convert xt...
2027
  			pols[1]->curlft.use_time = get_seconds();
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2028
2029
2030
2031
  			npols ++;
  		}
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2032
2033
2034
  	if (pol->action == XFRM_POLICY_ALLOW) {
  		struct sec_path *sp;
  		static struct sec_path dummy;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2035
  		struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
2036
  		struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2037
2038
  		struct xfrm_tmpl **tpp = tp;
  		int ti = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
2040
2041
2042
  		int i, k;
  
  		if ((sp = skb->sp) == NULL)
  			sp = &dummy;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2043
2044
  		for (pi = 0; pi < npols; pi++) {
  			if (pols[pi] != pol &&
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2045
  			    pols[pi]->action != XFRM_POLICY_ALLOW) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2046
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2047
  				goto reject;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2048
2049
  			}
  			if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2050
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2051
  				goto reject_error;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2052
  			}
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2053
2054
2055
2056
  			for (i = 0; i < pols[pi]->xfrm_nr; i++)
  				tpp[ti++] = &pols[pi]->xfrm_vec[i];
  		}
  		xfrm_nr = ti;
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
2057
2058
2059
2060
  		if (npols > 1) {
  			xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
  			tpp = stp;
  		}
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2061

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2062
2063
2064
2065
2066
2067
  		/* For each tunnel xfrm, find the first matching tmpl.
  		 * For each tmpl before that, find corresponding xfrm.
  		 * Order is _important_. Later we will implement
  		 * some barriers, but at the moment barriers
  		 * are implied between each two transformations.
  		 */
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2068
2069
  		for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
  			k = xfrm_policy_ok(tpp[i], sp, k, family);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2070
  			if (k < 0) {
d1d9facfd   James Morris   [XFRM]: remove xe...
2071
2072
2073
  				if (k < -1)
  					/* "-2 - errored_index" returned */
  					xerr_idx = -(2+k);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2074
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075
  				goto reject;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2076
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
  		}
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2078
  		if (secpath_has_nontransport(sp, k, &xerr_idx)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2079
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2080
  			goto reject;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2081
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082

4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2083
  		xfrm_pols_put(pols, npols);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2084
2085
  		return 1;
  	}
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2086
  	XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2087
2088
  
  reject:
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2089
  	xfrm_secpath_reject(xerr_idx, skb, &fl);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2090
2091
  reject_error:
  	xfrm_pols_put(pols, npols);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092
2093
2094
2095
2096
2097
  	return 0;
  }
  EXPORT_SYMBOL(__xfrm_policy_check);
  
  int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
  {
99a66657b   Alexey Dobriyan   netns xfrm: xfrm_...
2098
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
  	struct flowi fl;
adf30907d   Eric Dumazet   net: skb->dst acc...
2100
  	struct dst_entry *dst;
731371477   Eric Dumazet   xfrm: fix __xfrm_...
2101
  	int res = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2103
  	if (xfrm_decode_session(skb, &fl, family) < 0) {
72032fdbc   jamal   xfrm: Introduce L...
2104
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
  		return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2106
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2107

fafeeb6c8   Eric Dumazet   xfrm: force a dst...
2108
  	skb_dst_force(skb);
adf30907d   Eric Dumazet   net: skb->dst acc...
2109

452edd598   David S. Miller   xfrm: Return dst ...
2110
2111
  	dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, 0);
  	if (IS_ERR(dst)) {
731371477   Eric Dumazet   xfrm: fix __xfrm_...
2112
  		res = 0;
452edd598   David S. Miller   xfrm: Return dst ...
2113
2114
  		dst = NULL;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
2115
2116
  	skb_dst_set(skb, dst);
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117
2118
  }
  EXPORT_SYMBOL(__xfrm_route_forward);
d49c73c72   David S. Miller   [IPSEC]: Validate...
2119
  /* Optimize later using cookies and generation ids. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2120
2121
  static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
  {
d49c73c72   David S. Miller   [IPSEC]: Validate...
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
  	/* Code (such as __xfrm4_bundle_create()) sets dst->obsolete
  	 * to "-1" to force all XFRM destinations to get validated by
  	 * dst_ops->check on every use.  We do this because when a
  	 * normal route referenced by an XFRM dst is obsoleted we do
  	 * not go looking around for all parent referencing XFRM dsts
  	 * so that we can invalidate them.  It is just too much work.
  	 * Instead we make the checks here on every use.  For example:
  	 *
  	 *	XFRM dst A --> IPv4 dst X
  	 *
  	 * X is the "xdst->route" of A (X is also the "dst->path" of A
  	 * in this example).  If X is marked obsolete, "A" will not
  	 * notice.  That's what we are validating here via the
  	 * stale_bundle() check.
  	 *
  	 * When a policy's bundle is pruned, we dst_free() the XFRM
  	 * dst which causes it's ->obsolete field to be set to a
  	 * positive non-zero integer.  If an XFRM dst has been pruned
  	 * like this, we want to force a new route lookup.
399c180ac   David S. Miller   [IPSEC]: Perform ...
2141
  	 */
d49c73c72   David S. Miller   [IPSEC]: Validate...
2142
2143
  	if (dst->obsolete < 0 && !stale_bundle(dst))
  		return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2144
2145
2146
2147
2148
  	return NULL;
  }
  
  static int stale_bundle(struct dst_entry *dst)
  {
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
2149
  	return !xfrm_bundle_ok((struct xfrm_dst *)dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2150
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
2151
  void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153
  	while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2154
  		dst->dev = dev_net(dev)->loopback_dev;
de3cb747f   Daniel Lezcano   [NET]: Dynamicall...
2155
  		dev_hold(dst->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156
2157
2158
  		dev_put(dev);
  	}
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
2159
  EXPORT_SYMBOL(xfrm_dst_ifdown);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
2161
2162
2163
  
  static void xfrm_link_failure(struct sk_buff *skb)
  {
  	/* Impossible. Such dst must be popped before reaches point of failure. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
  }
  
  static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
  {
  	if (dst) {
  		if (dst->obsolete) {
  			dst_release(dst);
  			dst = NULL;
  		}
  	}
  	return dst;
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
2176
  static void __xfrm_garbage_collect(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2177
  {
80c802f30   Timo Teräs   xfrm: cache bundl...
2178
  	struct dst_entry *head, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2179

80c802f30   Timo Teräs   xfrm: cache bundl...
2180
2181
2182
2183
  	spin_lock_bh(&xfrm_policy_sk_bundle_lock);
  	head = xfrm_policy_sk_bundles;
  	xfrm_policy_sk_bundles = NULL;
  	spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2184

80c802f30   Timo Teräs   xfrm: cache bundl...
2185
2186
2187
2188
  	while (head) {
  		next = head->next;
  		dst_free(head);
  		head = next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
2190
  	}
  }
c0ed1c14a   Steffen Klassert   net: Add a flow_c...
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
  static void xfrm_garbage_collect(struct net *net)
  {
  	flow_cache_flush();
  	__xfrm_garbage_collect(net);
  }
  
  static void xfrm_garbage_collect_deferred(struct net *net)
  {
  	flow_cache_flush_deferred();
  	__xfrm_garbage_collect(net);
  }
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2202
  static void xfrm_init_pmtu(struct dst_entry *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
  {
  	do {
  		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  		u32 pmtu, route_mtu_cached;
  
  		pmtu = dst_mtu(dst->child);
  		xdst->child_mtu_cached = pmtu;
  
  		pmtu = xfrm_state_mtu(dst->xfrm, pmtu);
  
  		route_mtu_cached = dst_mtu(xdst->route);
  		xdst->route_mtu_cached = route_mtu_cached;
  
  		if (pmtu > route_mtu_cached)
  			pmtu = route_mtu_cached;
defb3519a   David S. Miller   net: Abstract awa...
2218
  		dst_metric_set(dst, RTAX_MTU, pmtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2219
2220
  	} while ((dst = dst->next));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221
2222
2223
  /* Check that the bundle accepts the flow and its components are
   * still valid.
   */
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
2224
  static int xfrm_bundle_ok(struct xfrm_dst *first)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
2226
2227
2228
  {
  	struct dst_entry *dst = &first->u.dst;
  	struct xfrm_dst *last;
  	u32 mtu;
92d63decc   Hideaki YOSHIFUJI   From: Kazunori Mi...
2229
  	if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230
2231
2232
2233
2234
2235
2236
  	    (dst->dev && !netif_running(dst->dev)))
  		return 0;
  
  	last = NULL;
  
  	do {
  		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2237
2238
  		if (dst->xfrm->km.state != XFRM_STATE_VALID)
  			return 0;
80c802f30   Timo Teräs   xfrm: cache bundl...
2239
2240
  		if (xdst->xfrm_genid != dst->xfrm->genid)
  			return 0;
b1312c89f   Timo Teräs   xfrm: check bundl...
2241
2242
  		if (xdst->num_pols > 0 &&
  		    xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))
9d4a706d8   David S. Miller   [XFRM]: Add gener...
2243
  			return 0;
e53820de0   Masahide NAKAMURA   [XFRM] IPV6: Rest...
2244

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2245
2246
2247
2248
2249
  		mtu = dst_mtu(dst->child);
  		if (xdst->child_mtu_cached != mtu) {
  			last = xdst;
  			xdst->child_mtu_cached = mtu;
  		}
92d63decc   Hideaki YOSHIFUJI   From: Kazunori Mi...
2250
  		if (!dst_check(xdst->route, xdst->route_cookie))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
  			return 0;
  		mtu = dst_mtu(xdst->route);
  		if (xdst->route_mtu_cached != mtu) {
  			last = xdst;
  			xdst->route_mtu_cached = mtu;
  		}
  
  		dst = dst->child;
  	} while (dst->xfrm);
  
  	if (likely(!last))
  		return 1;
  
  	mtu = last->child_mtu_cached;
  	for (;;) {
  		dst = &last->u.dst;
  
  		mtu = xfrm_state_mtu(dst->xfrm, mtu);
  		if (mtu > last->route_mtu_cached)
  			mtu = last->route_mtu_cached;
defb3519a   David S. Miller   net: Abstract awa...
2271
  		dst_metric_set(dst, RTAX_MTU, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
2273
2274
  
  		if (last == first)
  			break;
bd0bf0765   Patrick McHardy   [XFRM]: Fix crash...
2275
  		last = (struct xfrm_dst *)last->u.dst.next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2276
2277
2278
2279
2280
  		last->child_mtu_cached = mtu;
  	}
  
  	return 1;
  }
0dbaee3b3   David S. Miller   net: Abstract def...
2281
2282
2283
2284
  static unsigned int xfrm_default_advmss(const struct dst_entry *dst)
  {
  	return dst_metric_advmss(dst->path);
  }
ebb762f27   Steffen Klassert   net: Rename the d...
2285
  static unsigned int xfrm_mtu(const struct dst_entry *dst)
d33e45533   David S. Miller   net: Abstract def...
2286
  {
618f9bc74   Steffen Klassert   net: Move mtu han...
2287
2288
2289
  	unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
  
  	return mtu ? : dst_mtu(dst->path);
d33e45533   David S. Miller   net: Abstract def...
2290
  }
d3aaeb38c   David S. Miller   net: Add ->neigh_...
2291
2292
2293
2294
  static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst, const void *daddr)
  {
  	return dst_neigh_lookup(dst->path, daddr);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2295
2296
  int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
  {
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2297
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
2299
2300
2301
2302
  	int err = 0;
  	if (unlikely(afinfo == NULL))
  		return -EINVAL;
  	if (unlikely(afinfo->family >= NPROTO))
  		return -EAFNOSUPPORT;
e959d8121   Ingo Molnar   [XFRM]: fix incor...
2303
  	write_lock_bh(&xfrm_policy_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
2305
2306
2307
2308
2309
2310
2311
  	if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL))
  		err = -ENOBUFS;
  	else {
  		struct dst_ops *dst_ops = afinfo->dst_ops;
  		if (likely(dst_ops->kmem_cachep == NULL))
  			dst_ops->kmem_cachep = xfrm_dst_cache;
  		if (likely(dst_ops->check == NULL))
  			dst_ops->check = xfrm_dst_check;
0dbaee3b3   David S. Miller   net: Abstract def...
2312
2313
  		if (likely(dst_ops->default_advmss == NULL))
  			dst_ops->default_advmss = xfrm_default_advmss;
ebb762f27   Steffen Klassert   net: Rename the d...
2314
2315
  		if (likely(dst_ops->mtu == NULL))
  			dst_ops->mtu = xfrm_mtu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2316
2317
2318
2319
  		if (likely(dst_ops->negative_advice == NULL))
  			dst_ops->negative_advice = xfrm_negative_advice;
  		if (likely(dst_ops->link_failure == NULL))
  			dst_ops->link_failure = xfrm_link_failure;
d3aaeb38c   David S. Miller   net: Add ->neigh_...
2320
2321
  		if (likely(dst_ops->neigh_lookup == NULL))
  			dst_ops->neigh_lookup = xfrm_neigh_lookup;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2322
  		if (likely(afinfo->garbage_collect == NULL))
c0ed1c14a   Steffen Klassert   net: Add a flow_c...
2323
  			afinfo->garbage_collect = xfrm_garbage_collect_deferred;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2324
2325
  		xfrm_policy_afinfo[afinfo->family] = afinfo;
  	}
e959d8121   Ingo Molnar   [XFRM]: fix incor...
2326
  	write_unlock_bh(&xfrm_policy_afinfo_lock);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2327
2328
2329
2330
2331
2332
2333
2334
2335
  
  	rtnl_lock();
  	for_each_net(net) {
  		struct dst_ops *xfrm_dst_ops;
  
  		switch (afinfo->family) {
  		case AF_INET:
  			xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops;
  			break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
2336
  #if IS_ENABLED(CONFIG_IPV6)
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
  		case AF_INET6:
  			xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops;
  			break;
  #endif
  		default:
  			BUG();
  		}
  		*xfrm_dst_ops = *afinfo->dst_ops;
  	}
  	rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
  	return err;
  }
  EXPORT_SYMBOL(xfrm_policy_register_afinfo);
  
  int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
  {
  	int err = 0;
  	if (unlikely(afinfo == NULL))
  		return -EINVAL;
  	if (unlikely(afinfo->family >= NPROTO))
  		return -EAFNOSUPPORT;
e959d8121   Ingo Molnar   [XFRM]: fix incor...
2358
  	write_lock_bh(&xfrm_policy_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2359
2360
2361
2362
2363
2364
2365
2366
  	if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) {
  		if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo))
  			err = -EINVAL;
  		else {
  			struct dst_ops *dst_ops = afinfo->dst_ops;
  			xfrm_policy_afinfo[afinfo->family] = NULL;
  			dst_ops->kmem_cachep = NULL;
  			dst_ops->check = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2367
2368
  			dst_ops->negative_advice = NULL;
  			dst_ops->link_failure = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2369
2370
2371
  			afinfo->garbage_collect = NULL;
  		}
  	}
e959d8121   Ingo Molnar   [XFRM]: fix incor...
2372
  	write_unlock_bh(&xfrm_policy_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
2374
2375
  	return err;
  }
  EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2376
2377
2378
2379
2380
2381
2382
2383
  static void __net_init xfrm_dst_ops_init(struct net *net)
  {
  	struct xfrm_policy_afinfo *afinfo;
  
  	read_lock_bh(&xfrm_policy_afinfo_lock);
  	afinfo = xfrm_policy_afinfo[AF_INET];
  	if (afinfo)
  		net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
2384
  #if IS_ENABLED(CONFIG_IPV6)
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2385
2386
2387
2388
2389
2390
  	afinfo = xfrm_policy_afinfo[AF_INET6];
  	if (afinfo)
  		net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
  #endif
  	read_unlock_bh(&xfrm_policy_afinfo_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2391
2392
2393
2394
2395
2396
2397
  static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
  {
  	struct xfrm_policy_afinfo *afinfo;
  	if (unlikely(family >= NPROTO))
  		return NULL;
  	read_lock(&xfrm_policy_afinfo_lock);
  	afinfo = xfrm_policy_afinfo[family];
546be2405   Herbert Xu   [IPSEC] xfrm: Und...
2398
2399
  	if (unlikely(!afinfo))
  		read_unlock(&xfrm_policy_afinfo_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2400
2401
2402
2403
2404
  	return afinfo;
  }
  
  static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
  {
546be2405   Herbert Xu   [IPSEC] xfrm: Und...
2405
2406
  	read_unlock(&xfrm_policy_afinfo_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2407
2408
  static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
  {
e9dc86534   Eric W. Biederman   [NET]: Make devic...
2409
  	struct net_device *dev = ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
2411
  	switch (event) {
  	case NETDEV_DOWN:
c0ed1c14a   Steffen Klassert   net: Add a flow_c...
2412
  		xfrm_garbage_collect(dev_net(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
2414
2415
2416
2417
  	}
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block xfrm_dev_notifier = {
d5917a35a   Alexey Dobriyan   xfrm: C99 for xfr...
2418
  	.notifier_call	= xfrm_dev_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
  };
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2420
  #ifdef CONFIG_XFRM_STATISTICS
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2421
  static int __net_init xfrm_statistics_init(struct net *net)
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2422
  {
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2423
  	int rv;
7d720c3e4   Tejun Heo   percpu: add __per...
2424
  	if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics,
1823e4c80   Eric Dumazet   snmp: add align p...
2425
2426
  			  sizeof(struct linux_xfrm_mib),
  			  __alignof__(struct linux_xfrm_mib)) < 0)
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2427
  		return -ENOMEM;
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2428
2429
  	rv = xfrm_proc_init(net);
  	if (rv < 0)
7d720c3e4   Tejun Heo   percpu: add __per...
2430
  		snmp_mib_free((void __percpu **)net->mib.xfrm_statistics);
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2431
  	return rv;
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2432
  }
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2433
2434
2435
  
  static void xfrm_statistics_fini(struct net *net)
  {
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2436
  	xfrm_proc_fini(net);
7d720c3e4   Tejun Heo   percpu: add __per...
2437
  	snmp_mib_free((void __percpu **)net->mib.xfrm_statistics);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
  }
  #else
  static int __net_init xfrm_statistics_init(struct net *net)
  {
  	return 0;
  }
  
  static void xfrm_statistics_fini(struct net *net)
  {
  }
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2448
  #endif
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2449
  static int __net_init xfrm_policy_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2451
2452
  	unsigned int hmask, sz;
  	int dir;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2453
2454
  	if (net_eq(net, &init_net))
  		xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2455
  					   sizeof(struct xfrm_dst),
e5d679f33   Alexey Dobriyan   [NET]: Use SLAB_P...
2456
  					   0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
20c2df83d   Paul Mundt   mm: Remove slab d...
2457
  					   NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2458

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2459
2460
  	hmask = 8 - 1;
  	sz = (hmask+1) * sizeof(struct hlist_head);
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2461
2462
2463
  	net->xfrm.policy_byidx = xfrm_hash_alloc(sz);
  	if (!net->xfrm.policy_byidx)
  		goto out_byidx;
8100bea7d   Alexey Dobriyan   netns xfrm: per-n...
2464
  	net->xfrm.policy_idx_hmask = hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2465
2466
2467
  
  	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
  		struct xfrm_policy_hash *htab;
dc2caba7b   Alexey Dobriyan   netns xfrm: per-n...
2468
  		net->xfrm.policy_count[dir] = 0;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2469
  		INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2470

a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2471
  		htab = &net->xfrm.policy_bydst[dir];
44e36b42a   David S. Miller   [XFRM]: Extract c...
2472
  		htab->table = xfrm_hash_alloc(sz);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2473
  		if (!htab->table)
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2474
2475
  			goto out_bydst;
  		htab->hmask = hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2476
  	}
adfcf0b27   Alexey Dobriyan   netns xfrm: per-n...
2477
  	INIT_LIST_HEAD(&net->xfrm.policy_all);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
2478
  	INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2479
2480
2481
  	if (net_eq(net, &init_net))
  		register_netdevice_notifier(&xfrm_dev_notifier);
  	return 0;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2482

a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2483
2484
2485
2486
2487
2488
2489
2490
  out_bydst:
  	for (dir--; dir >= 0; dir--) {
  		struct xfrm_policy_hash *htab;
  
  		htab = &net->xfrm.policy_bydst[dir];
  		xfrm_hash_free(htab->table, sz);
  	}
  	xfrm_hash_free(net->xfrm.policy_byidx, sz);
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2491
2492
  out_byidx:
  	return -ENOMEM;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2493
2494
2495
2496
  }
  
  static void xfrm_policy_fini(struct net *net)
  {
7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
2497
  	struct xfrm_audit audit_info;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2498
  	unsigned int sz;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2499
  	int dir;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2500

7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
  	flush_work(&net->xfrm.policy_hash_work);
  #ifdef CONFIG_XFRM_SUB_POLICY
  	audit_info.loginuid = -1;
  	audit_info.sessionid = -1;
  	audit_info.secid = 0;
  	xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info);
  #endif
  	audit_info.loginuid = -1;
  	audit_info.sessionid = -1;
  	audit_info.secid = 0;
  	xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
2512

adfcf0b27   Alexey Dobriyan   netns xfrm: per-n...
2513
  	WARN_ON(!list_empty(&net->xfrm.policy_all));
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2514

8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2515
  	for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2516
  		struct xfrm_policy_hash *htab;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2517
  		WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2518
2519
2520
2521
2522
  
  		htab = &net->xfrm.policy_bydst[dir];
  		sz = (htab->hmask + 1);
  		WARN_ON(!hlist_empty(htab->table));
  		xfrm_hash_free(htab->table, sz);
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2523
  	}
8100bea7d   Alexey Dobriyan   netns xfrm: per-n...
2524
  	sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head);
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2525
2526
  	WARN_ON(!hlist_empty(net->xfrm.policy_byidx));
  	xfrm_hash_free(net->xfrm.policy_byidx, sz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2527
  }
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2528
2529
2530
  static int __net_init xfrm_net_init(struct net *net)
  {
  	int rv;
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2531
2532
2533
  	rv = xfrm_statistics_init(net);
  	if (rv < 0)
  		goto out_statistics;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2534
2535
2536
2537
2538
2539
  	rv = xfrm_state_init(net);
  	if (rv < 0)
  		goto out_state;
  	rv = xfrm_policy_init(net);
  	if (rv < 0)
  		goto out_policy;
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2540
  	xfrm_dst_ops_init(net);
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
2541
2542
2543
  	rv = xfrm_sysctl_init(net);
  	if (rv < 0)
  		goto out_sysctl;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2544
  	return 0;
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
2545
2546
  out_sysctl:
  	xfrm_policy_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2547
2548
2549
  out_policy:
  	xfrm_state_fini(net);
  out_state:
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2550
2551
  	xfrm_statistics_fini(net);
  out_statistics:
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2552
2553
2554
2555
2556
  	return rv;
  }
  
  static void __net_exit xfrm_net_exit(struct net *net)
  {
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
2557
  	xfrm_sysctl_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2558
2559
  	xfrm_policy_fini(net);
  	xfrm_state_fini(net);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2560
  	xfrm_statistics_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2561
2562
2563
2564
2565
2566
  }
  
  static struct pernet_operations __net_initdata xfrm_net_ops = {
  	.init = xfrm_net_init,
  	.exit = xfrm_net_exit,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2567
2568
  void __init xfrm_init(void)
  {
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2569
  	register_pernet_subsys(&xfrm_net_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2570
2571
  	xfrm_input_init();
  }
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2572
  #ifdef CONFIG_AUDITSYSCALL
1486cbd77   Ilpo Järvinen   [XFRM] xfrm_polic...
2573
2574
  static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
  					 struct audit_buffer *audit_buf)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2575
  {
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2576
2577
2578
2579
  	struct xfrm_sec_ctx *ctx = xp->security;
  	struct xfrm_selector *sel = &xp->selector;
  
  	if (ctx)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2580
  		audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2581
  				 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2582

875179fa6   Paul Moore   [IPSEC]: SPD audi...
2583
  	switch(sel->family) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2584
  	case AF_INET:
21454aaad   Harvey Harrison   net: replace NIPQ...
2585
  		audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2586
2587
2588
  		if (sel->prefixlen_s != 32)
  			audit_log_format(audit_buf, " src_prefixlen=%d",
  					 sel->prefixlen_s);
21454aaad   Harvey Harrison   net: replace NIPQ...
2589
  		audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2590
2591
2592
  		if (sel->prefixlen_d != 32)
  			audit_log_format(audit_buf, " dst_prefixlen=%d",
  					 sel->prefixlen_d);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2593
2594
  		break;
  	case AF_INET6:
5b095d989   Harvey Harrison   net: replace %p6 ...
2595
  		audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2596
2597
2598
  		if (sel->prefixlen_s != 128)
  			audit_log_format(audit_buf, " src_prefixlen=%d",
  					 sel->prefixlen_s);
5b095d989   Harvey Harrison   net: replace %p6 ...
2599
  		audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2600
2601
2602
  		if (sel->prefixlen_d != 128)
  			audit_log_format(audit_buf, " dst_prefixlen=%d",
  					 sel->prefixlen_d);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2603
2604
2605
  		break;
  	}
  }
68277accb   Paul Moore   [XFRM]: Assorted ...
2606
  void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
2532386f4   Eric Paris   Audit: collect se...
2607
  			   uid_t auid, u32 sessionid, u32 secid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2608
2609
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2610

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2611
  	audit_buf = xfrm_audit_start("SPD-add");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2612
2613
  	if (audit_buf == NULL)
  		return;
2532386f4   Eric Paris   Audit: collect se...
2614
  	xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2615
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2616
2617
2618
2619
  	xfrm_audit_common_policyinfo(xp, audit_buf);
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
68277accb   Paul Moore   [XFRM]: Assorted ...
2620
  void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
2532386f4   Eric Paris   Audit: collect se...
2621
  			      uid_t auid, u32 sessionid, u32 secid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2622
2623
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2624

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2625
  	audit_buf = xfrm_audit_start("SPD-delete");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2626
2627
  	if (audit_buf == NULL)
  		return;
2532386f4   Eric Paris   Audit: collect se...
2628
  	xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2629
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2630
2631
2632
2633
2634
  	xfrm_audit_common_policyinfo(xp, audit_buf);
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete);
  #endif
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2635
  #ifdef CONFIG_XFRM_MIGRATE
b4b7c0b38   David S. Miller   xfrm: Const'ify s...
2636
2637
  static int xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
  				       const struct xfrm_selector *sel_tgt)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2638
2639
2640
2641
  {
  	if (sel_cmp->proto == IPSEC_ULPROTO_ANY) {
  		if (sel_tgt->family == sel_cmp->family &&
  		    xfrm_addr_cmp(&sel_tgt->daddr, &sel_cmp->daddr,
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
2642
  				  sel_cmp->family) == 0 &&
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
  		    xfrm_addr_cmp(&sel_tgt->saddr, &sel_cmp->saddr,
  				  sel_cmp->family) == 0 &&
  		    sel_tgt->prefixlen_d == sel_cmp->prefixlen_d &&
  		    sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) {
  			return 1;
  		}
  	} else {
  		if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) {
  			return 1;
  		}
  	}
  	return 0;
  }
b4b7c0b38   David S. Miller   xfrm: Const'ify s...
2656
  static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector *sel,
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2657
2658
2659
2660
2661
2662
2663
2664
  						     u8 dir, u8 type)
  {
  	struct xfrm_policy *pol, *ret = NULL;
  	struct hlist_node *entry;
  	struct hlist_head *chain;
  	u32 priority = ~0U;
  
  	read_lock_bh(&xfrm_policy_lock);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
2665
  	chain = policy_hash_direct(&init_net, &sel->daddr, &sel->saddr, sel->family, dir);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2666
2667
2668
2669
2670
2671
2672
2673
  	hlist_for_each_entry(pol, entry, chain, bydst) {
  		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
  		    pol->type == type) {
  			ret = pol;
  			priority = ret->priority;
  			break;
  		}
  	}
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2674
  	chain = &init_net.xfrm.policy_inexact[dir];
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
  	hlist_for_each_entry(pol, entry, chain, bydst) {
  		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
  		    pol->type == type &&
  		    pol->priority < priority) {
  			ret = pol;
  			break;
  		}
  	}
  
  	if (ret)
  		xfrm_pol_hold(ret);
  
  	read_unlock_bh(&xfrm_policy_lock);
  
  	return ret;
  }
dd701754e   David S. Miller   xfrm: Const'ify p...
2691
  static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tmpl *t)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
  {
  	int match = 0;
  
  	if (t->mode == m->mode && t->id.proto == m->proto &&
  	    (m->reqid == 0 || t->reqid == m->reqid)) {
  		switch (t->mode) {
  		case XFRM_MODE_TUNNEL:
  		case XFRM_MODE_BEET:
  			if (xfrm_addr_cmp(&t->id.daddr, &m->old_daddr,
  					  m->old_family) == 0 &&
  			    xfrm_addr_cmp(&t->saddr, &m->old_saddr,
  					  m->old_family) == 0) {
  				match = 1;
  			}
  			break;
  		case XFRM_MODE_TRANSPORT:
  			/* in case of transport mode, template does not store
  			   any IP addresses, hence we just compare mode and
  			   protocol */
  			match = 1;
  			break;
  		default:
  			break;
  		}
  	}
  	return match;
  }
  
  /* update endpoint address(es) of template(s) */
  static int xfrm_policy_migrate(struct xfrm_policy *pol,
  			       struct xfrm_migrate *m, int num_migrate)
  {
  	struct xfrm_migrate *mp;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2725
2726
2727
  	int i, j, n = 0;
  
  	write_lock_bh(&pol->lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
2728
  	if (unlikely(pol->walk.dead)) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
  		/* target policy has been deleted */
  		write_unlock_bh(&pol->lock);
  		return -ENOENT;
  	}
  
  	for (i = 0; i < pol->xfrm_nr; i++) {
  		for (j = 0, mp = m; j < num_migrate; j++, mp++) {
  			if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i]))
  				continue;
  			n++;
1bfcb10f6   Herbert Xu   [IPSEC]: Add miss...
2739
2740
  			if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL &&
  			    pol->xfrm_vec[i].mode != XFRM_MODE_BEET)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2741
2742
2743
2744
2745
2746
2747
2748
  				continue;
  			/* update endpoints */
  			memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr,
  			       sizeof(pol->xfrm_vec[i].id.daddr));
  			memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr,
  			       sizeof(pol->xfrm_vec[i].saddr));
  			pol->xfrm_vec[i].encap_family = mp->new_family;
  			/* flush bundles */
80c802f30   Timo Teräs   xfrm: cache bundl...
2749
  			atomic_inc(&pol->genid);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
  		}
  	}
  
  	write_unlock_bh(&pol->lock);
  
  	if (!n)
  		return -ENODATA;
  
  	return 0;
  }
dd701754e   David S. Miller   xfrm: Const'ify p...
2760
  static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
  {
  	int i, j;
  
  	if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH)
  		return -EINVAL;
  
  	for (i = 0; i < num_migrate; i++) {
  		if ((xfrm_addr_cmp(&m[i].old_daddr, &m[i].new_daddr,
  				   m[i].old_family) == 0) &&
  		    (xfrm_addr_cmp(&m[i].old_saddr, &m[i].new_saddr,
  				   m[i].old_family) == 0))
  			return -EINVAL;
  		if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||
  		    xfrm_addr_any(&m[i].new_saddr, m[i].new_family))
  			return -EINVAL;
  
  		/* check if there is any duplicated entry */
  		for (j = i + 1; j < num_migrate; j++) {
  			if (!memcmp(&m[i].old_daddr, &m[j].old_daddr,
  				    sizeof(m[i].old_daddr)) &&
  			    !memcmp(&m[i].old_saddr, &m[j].old_saddr,
  				    sizeof(m[i].old_saddr)) &&
  			    m[i].proto == m[j].proto &&
  			    m[i].mode == m[j].mode &&
  			    m[i].reqid == m[j].reqid &&
  			    m[i].old_family == m[j].old_family)
  				return -EINVAL;
  		}
  	}
  
  	return 0;
  }
b4b7c0b38   David S. Miller   xfrm: Const'ify s...
2793
  int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2794
2795
  		 struct xfrm_migrate *m, int num_migrate,
  		 struct xfrm_kmaddress *k)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
  {
  	int i, err, nx_cur = 0, nx_new = 0;
  	struct xfrm_policy *pol = NULL;
  	struct xfrm_state *x, *xc;
  	struct xfrm_state *x_cur[XFRM_MAX_DEPTH];
  	struct xfrm_state *x_new[XFRM_MAX_DEPTH];
  	struct xfrm_migrate *mp;
  
  	if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
  		goto out;
  
  	/* Stage 1 - find policy */
  	if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) {
  		err = -ENOENT;
  		goto out;
  	}
  
  	/* Stage 2 - find and update state(s) */
  	for (i = 0, mp = m; i < num_migrate; i++, mp++) {
  		if ((x = xfrm_migrate_state_find(mp))) {
  			x_cur[nx_cur] = x;
  			nx_cur++;
  			if ((xc = xfrm_state_migrate(x, mp))) {
  				x_new[nx_new] = xc;
  				nx_new++;
  			} else {
  				err = -ENODATA;
  				goto restore_state;
  			}
  		}
  	}
  
  	/* Stage 3 - update policy */
  	if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0)
  		goto restore_state;
  
  	/* Stage 4 - delete old state(s) */
  	if (nx_cur) {
  		xfrm_states_put(x_cur, nx_cur);
  		xfrm_states_delete(x_cur, nx_cur);
  	}
  
  	/* Stage 5 - announce */
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2839
  	km_migrate(sel, dir, type, m, num_migrate, k);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
  
  	xfrm_pol_put(pol);
  
  	return 0;
  out:
  	return err;
  
  restore_state:
  	if (pol)
  		xfrm_pol_put(pol);
  	if (nx_cur)
  		xfrm_states_put(x_cur, nx_cur);
  	if (nx_new)
  		xfrm_states_delete(x_new, nx_new);
  
  	return err;
  }
e610e679d   David S. Miller   [XFRM]: xfrm_migr...
2857
  EXPORT_SYMBOL(xfrm_migrate);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2858
  #endif