Blame view

net/xfrm/xfrm_policy.c 106 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
2
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
   * 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...
14
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
   */
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
16
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
  #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...
24
  #include <linux/netfilter.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/module.h>
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
26
  #include <linux/cache.h>
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
27
  #include <linux/cpu.h>
68277accb   Paul Moore   [XFRM]: Assorted ...
28
  #include <linux/audit.h>
24969facd   Florian Westphal   xfrm: policy: sto...
29
  #include <linux/rhashtable.h>
c53ac41e3   Florian Westphal   xfrm: remove deco...
30
  #include <linux/if_tunnel.h>
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
31
  #include <net/dst.h>
6ce74ec75   Eric Paris   SELinux: include ...
32
  #include <net/flow.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  #include <net/xfrm.h>
  #include <net/ip.h>
c53ac41e3   Florian Westphal   xfrm: remove deco...
35
36
37
  #if IS_ENABLED(CONFIG_IPV6_MIP6)
  #include <net/mip6.h>
  #endif
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
38
39
40
  #ifdef CONFIG_XFRM_STATISTICS
  #include <net/snmp.h>
  #endif
95a35b42b   Sabrina Dubroca   xfrm: policy: fix...
41
  #ifdef CONFIG_XFRM_ESPINTCP
e27cca96c   Sabrina Dubroca   xfrm: add espintc...
42
43
  #include <net/espintcp.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

44e36b42a   David S. Miller   [XFRM]: Extract c...
45
  #include "xfrm_hash.h"
a0073fe18   Steffen Klassert   xfrm: Add a state...
46
47
48
  #define XFRM_QUEUE_TMO_MIN ((unsigned)(HZ/10))
  #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
  #define XFRM_MAX_QUEUE_LEN	100
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
49
50
51
52
  struct xfrm_flo {
  	struct dst_entry *dst_orig;
  	u8 flags;
  };
6be3b0db6   Florian Westphal   xfrm: policy: add...
53
54
55
  /* prefixes smaller than this are stored in lists, not trees. */
  #define INEXACT_PREFIXLEN_IPV4	16
  #define INEXACT_PREFIXLEN_IPV6	48
9cf545ebd   Florian Westphal   xfrm: policy: sto...
56
57
58
59
60
61
62
63
  
  struct xfrm_pol_inexact_node {
  	struct rb_node node;
  	union {
  		xfrm_address_t addr;
  		struct rcu_head rcu;
  	};
  	u8 prefixlen;
6ac098b2a   Florian Westphal   xfrm: policy: add...
64
  	struct rb_root root;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
65
66
67
68
69
70
71
72
73
74
75
  	/* the policies matching this node, can be empty list */
  	struct hlist_head hhead;
  };
  
  /* xfrm inexact policy search tree:
   * xfrm_pol_inexact_bin = hash(dir,type,family,if_id);
   *  |
   * +---- root_d: sorted by daddr:prefix
   * |                 |
   * |        xfrm_pol_inexact_node
   * |                 |
6ac098b2a   Florian Westphal   xfrm: policy: add...
76
77
78
79
80
81
82
83
   * |                 +- root: sorted by saddr/prefix
   * |                 |              |
   * |                 |         xfrm_pol_inexact_node
   * |                 |              |
   * |                 |              + root: unused
   * |                 |              |
   * |                 |              + hhead: saddr:daddr policies
   * |                 |
9cf545ebd   Florian Westphal   xfrm: policy: sto...
84
85
   * |                 +- coarse policies and all any:daddr policies
   * |
64a09a7bf   Florian Westphal   xfrm: policy: sto...
86
87
88
89
90
91
92
93
   * +---- root_s: sorted by saddr:prefix
   * |                 |
   * |        xfrm_pol_inexact_node
   * |                 |
   * |                 + root: unused
   * |                 |
   * |                 + hhead: saddr:any policies
   * |
9cf545ebd   Florian Westphal   xfrm: policy: sto...
94
95
   * +---- coarse policies and all any:any policies
   *
6ac098b2a   Florian Westphal   xfrm: policy: add...
96
   * Lookups return four candidate lists:
9cf545ebd   Florian Westphal   xfrm: policy: sto...
97
98
   * 1. any:any list from top-level xfrm_pol_inexact_bin
   * 2. any:daddr list from daddr tree
6ac098b2a   Florian Westphal   xfrm: policy: add...
99
100
   * 3. saddr:daddr list from 2nd level daddr tree
   * 4. saddr:any list from saddr tree
9cf545ebd   Florian Westphal   xfrm: policy: sto...
101
102
103
104
   *
   * This result set then needs to be searched for the policy with
   * the lowest priority.  If two results have same prio, youngest one wins.
   */
24969facd   Florian Westphal   xfrm: policy: sto...
105
106
  struct xfrm_pol_inexact_key {
  	possible_net_t net;
b5fe22e23   Florian Westphal   xfrm: policy: con...
107
  	u32 if_id;
24969facd   Florian Westphal   xfrm: policy: sto...
108
109
110
111
112
113
114
  	u16 family;
  	u8 dir, type;
  };
  
  struct xfrm_pol_inexact_bin {
  	struct xfrm_pol_inexact_key k;
  	struct rhash_head head;
6be3b0db6   Florian Westphal   xfrm: policy: add...
115
  	/* list containing '*:*' policies */
24969facd   Florian Westphal   xfrm: policy: sto...
116
  	struct hlist_head hhead;
77cc278f7   Ahmed S. Darwish   xfrm: policy: Use...
117
  	seqcount_spinlock_t count;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
118
119
  	/* tree sorted by daddr/prefix */
  	struct rb_root root_d;
64a09a7bf   Florian Westphal   xfrm: policy: sto...
120
121
  	/* tree sorted by saddr/prefix */
  	struct rb_root root_s;
24969facd   Florian Westphal   xfrm: policy: sto...
122
123
124
125
  	/* slow path below */
  	struct list_head inexact_bins;
  	struct rcu_head rcu;
  };
6be3b0db6   Florian Westphal   xfrm: policy: add...
126
  enum xfrm_pol_inexact_candidate_type {
6ac098b2a   Florian Westphal   xfrm: policy: add...
127
  	XFRM_POL_CAND_BOTH,
64a09a7bf   Florian Westphal   xfrm: policy: sto...
128
  	XFRM_POL_CAND_SADDR,
9cf545ebd   Florian Westphal   xfrm: policy: sto...
129
  	XFRM_POL_CAND_DADDR,
6be3b0db6   Florian Westphal   xfrm: policy: add...
130
131
132
133
134
135
136
137
  	XFRM_POL_CAND_ANY,
  
  	XFRM_POL_CAND_MAX,
  };
  
  struct xfrm_pol_inexact_candidates {
  	struct hlist_head *res[XFRM_POL_CAND_MAX];
  };
f203b76d7   Steffen Klassert   xfrm: Add virtual...
138
139
  static DEFINE_SPINLOCK(xfrm_if_cb_lock);
  static struct xfrm_if_cb const __rcu *xfrm_if_cb __read_mostly;
418a99ac6   Priyanka Jain   Replace rwlock on...
140
  static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
37b103830   Florian Westphal   xfrm: policy: mak...
141
  static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1]
418a99ac6   Priyanka Jain   Replace rwlock on...
142
  						__read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

f8c3d0dda   Alexey Dobriyan   xfrm: mark kmem_c...
144
  static struct kmem_cache *xfrm_dst_cache __ro_after_init;
77cc278f7   Ahmed S. Darwish   xfrm: policy: Use...
145
  static __read_mostly seqcount_mutex_t xfrm_policy_hash_generation;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

24969facd   Florian Westphal   xfrm: policy: sto...
147
148
  static struct rhashtable xfrm_policy_inexact_table;
  static const struct rhashtable_params xfrm_pol_inexact_params;
5492093dc   David Miller   xfrm: Stop using ...
149
  static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr);
80c802f30   Timo Teräs   xfrm: cache bundl...
150
  static int stale_bundle(struct dst_entry *dst);
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
151
  static int xfrm_bundle_ok(struct xfrm_dst *xdst);
c3aed7095   Kees Cook   xfrm: Convert tim...
152
  static void xfrm_policy_queue_process(struct timer_list *t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153

12bfa8bdb   Herbert Xu   xfrm: Use __xfrm_...
154
  static void __xfrm_policy_link(struct xfrm_policy *pol, int dir);
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
155
156
  static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
  						int dir);
24969facd   Florian Westphal   xfrm: policy: sto...
157
  static struct xfrm_pol_inexact_bin *
b5fe22e23   Florian Westphal   xfrm: policy: con...
158
159
  xfrm_policy_inexact_lookup(struct net *net, u8 type, u16 family, u8 dir,
  			   u32 if_id);
24969facd   Florian Westphal   xfrm: policy: sto...
160
161
162
  
  static struct xfrm_pol_inexact_bin *
  xfrm_policy_inexact_lookup_rcu(struct net *net,
b5fe22e23   Florian Westphal   xfrm: policy: con...
163
  			       u8 type, u16 family, u8 dir, u32 if_id);
24969facd   Florian Westphal   xfrm: policy: sto...
164
165
166
167
168
  static struct xfrm_policy *
  xfrm_policy_insert_list(struct hlist_head *chain, struct xfrm_policy *policy,
  			bool excl);
  static void xfrm_policy_insert_inexact_list(struct hlist_head *chain,
  					    struct xfrm_policy *policy);
6be3b0db6   Florian Westphal   xfrm: policy: add...
169
170
171
172
173
  static bool
  xfrm_policy_find_inexact_candidates(struct xfrm_pol_inexact_candidates *cand,
  				    struct xfrm_pol_inexact_bin *b,
  				    const xfrm_address_t *saddr,
  				    const xfrm_address_t *daddr);
e37cc8ade   Florian Westphal   xfrm: policy: use...
174
175
  static inline bool xfrm_pol_hold_rcu(struct xfrm_policy *policy)
  {
850a6212c   Reshetova, Elena   net, xfrm: conver...
176
  	return refcount_inc_not_zero(&policy->refcnt);
e37cc8ade   Florian Westphal   xfrm: policy: use...
177
  }
bc9b35ad4   David S. Miller   xfrm: Convert sev...
178
  static inline bool
200ce96e5   David S. Miller   xfrm: Const'ify s...
179
  __xfrm4_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
776810217   Andrew Morton   [XFRM]: uninline ...
180
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
181
  	const struct flowi4 *fl4 = &fl->u.ip4;
26bff940d   Alexey Dobriyan   xfrm: optimize ip...
182
183
  	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...
184
185
186
187
  		!((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 ...
188
  }
bc9b35ad4   David S. Miller   xfrm: Convert sev...
189
  static inline bool
200ce96e5   David S. Miller   xfrm: Const'ify s...
190
  __xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
776810217   Andrew Morton   [XFRM]: uninline ...
191
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
192
193
194
195
196
197
198
199
  	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 ...
200
  }
bc9b35ad4   David S. Miller   xfrm: Convert sev...
201
202
  bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl,
  			 unsigned short family)
776810217   Andrew Morton   [XFRM]: uninline ...
203
204
205
206
207
208
209
  {
  	switch (family) {
  	case AF_INET:
  		return __xfrm4_selector_match(sel, fl);
  	case AF_INET6:
  		return __xfrm6_selector_match(sel, fl);
  	}
bc9b35ad4   David S. Miller   xfrm: Convert sev...
210
  	return false;
776810217   Andrew Morton   [XFRM]: uninline ...
211
  }
a2817d8b2   Florian Westphal   xfrm: policy: rem...
212
  static const struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
213
  {
a2817d8b2   Florian Westphal   xfrm: policy: rem...
214
  	const struct xfrm_policy_afinfo *afinfo;
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
215

a2817d8b2   Florian Westphal   xfrm: policy: rem...
216
  	if (unlikely(family >= ARRAY_SIZE(xfrm_policy_afinfo)))
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
217
218
219
220
221
222
223
  		return NULL;
  	rcu_read_lock();
  	afinfo = rcu_dereference(xfrm_policy_afinfo[family]);
  	if (unlikely(!afinfo))
  		rcu_read_unlock();
  	return afinfo;
  }
f203b76d7   Steffen Klassert   xfrm: Add virtual...
224
225
226
227
228
  /* Called with rcu_read_lock(). */
  static const struct xfrm_if_cb *xfrm_if_get_cb(void)
  {
  	return rcu_dereference(xfrm_if_cb);
  }
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
229
230
231
  struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
  				    const xfrm_address_t *saddr,
  				    const xfrm_address_t *daddr,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
232
  				    int family, u32 mark)
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
233
  {
37b103830   Florian Westphal   xfrm: policy: mak...
234
  	const struct xfrm_policy_afinfo *afinfo;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
235
236
237
238
239
  	struct dst_entry *dst;
  
  	afinfo = xfrm_policy_get_afinfo(family);
  	if (unlikely(afinfo == NULL))
  		return ERR_PTR(-EAFNOSUPPORT);
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
240
  	dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
241

bdba9fe01   Florian Westphal   xfrm: policy: rem...
242
  	rcu_read_unlock();
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
243
244
245
  
  	return dst;
  }
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
246
  EXPORT_SYMBOL(__xfrm_dst_lookup);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
247

42a7b32b7   David Ahern   xfrm: Add oif to ...
248
249
  static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
  						int tos, int oif,
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
250
251
  						xfrm_address_t *prev_saddr,
  						xfrm_address_t *prev_daddr,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
252
  						int family, u32 mark)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  {
c5b3cf46e   Alexey Dobriyan   netns xfrm: ->dst...
254
  	struct net *net = xs_net(x);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
255
256
  	xfrm_address_t *saddr = &x->props.saddr;
  	xfrm_address_t *daddr = &x->id.daddr;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
257
  	struct dst_entry *dst;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
258
  	if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
259
  		saddr = x->coaddr;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
260
261
262
263
  		daddr = prev_daddr;
  	}
  	if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
  		saddr = prev_saddr;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
264
  		daddr = x->coaddr;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
265
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

077fbac40   Lorenzo Colitti   net: xfrm: suppor...
267
  	dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family, mark);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
268
269
270
271
272
273
274
  
  	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
275

66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
276
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
  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...
284
  		return secs*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  }
c3aed7095   Kees Cook   xfrm: Convert tim...
286
  static void xfrm_policy_timer(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  {
c3aed7095   Kees Cook   xfrm: Convert tim...
288
  	struct xfrm_policy *xp = from_timer(xp, t, timer);
386c5680e   Arnd Bergmann   xfrm: use time64_...
289
290
  	time64_t now = ktime_get_real_seconds();
  	time64_t next = TIME64_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
  	int warn = 0;
  	int dir;
  
  	read_lock(&xp->lock);
ea2dea9da   Timo Teräs   xfrm: remove poli...
295
  	if (unlikely(xp->walk.dead))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  		goto out;
77d8d7a68   Herbert Xu   [IPSEC]: Document...
297
  	dir = xfrm_policy_id2dir(xp->index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  
  	if (xp->lft.hard_add_expires_seconds) {
386c5680e   Arnd Bergmann   xfrm: use time64_...
300
  		time64_t tmo = xp->lft.hard_add_expires_seconds +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
306
307
  			xp->curlft.add_time - now;
  		if (tmo <= 0)
  			goto expired;
  		if (tmo < next)
  			next = tmo;
  	}
  	if (xp->lft.hard_use_expires_seconds) {
386c5680e   Arnd Bergmann   xfrm: use time64_...
308
  		time64_t tmo = xp->lft.hard_use_expires_seconds +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
312
313
314
315
  			(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) {
386c5680e   Arnd Bergmann   xfrm: use time64_...
316
  		time64_t tmo = xp->lft.soft_add_expires_seconds +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
320
321
322
323
324
325
  			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) {
386c5680e   Arnd Bergmann   xfrm: use time64_...
326
  		time64_t tmo = xp->lft.soft_use_expires_seconds +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
332
333
334
335
336
  			(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...
337
  		km_policy_expired(xp, dir, 0, 0);
386c5680e   Arnd Bergmann   xfrm: use time64_...
338
  	if (next != TIME64_MAX &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
344
345
346
347
348
  	    !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...
349
  	if (!xfrm_policy_delete(xp, dir))
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
350
  		km_policy_expired(xp, dir, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  	xfrm_pol_put(xp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
  /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
   * SPD calls.
   */
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
356
  struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  {
  	struct xfrm_policy *policy;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
359
  	policy = kzalloc(sizeof(struct xfrm_policy), gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  
  	if (policy) {
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
362
  		write_pnet(&policy->xp_net, net);
12a169e7d   Herbert Xu   ipsec: Put dumper...
363
  		INIT_LIST_HEAD(&policy->walk.all);
24969facd   Florian Westphal   xfrm: policy: sto...
364
  		INIT_HLIST_NODE(&policy->bydst_inexact_list);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
365
366
  		INIT_HLIST_NODE(&policy->bydst);
  		INIT_HLIST_NODE(&policy->byidx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  		rwlock_init(&policy->lock);
850a6212c   Reshetova, Elena   net, xfrm: conver...
368
  		refcount_set(&policy->refcnt, 1);
a0073fe18   Steffen Klassert   xfrm: Add a state...
369
  		skb_queue_head_init(&policy->polq.hold_queue);
c3aed7095   Kees Cook   xfrm: Convert tim...
370
371
372
  		timer_setup(&policy->timer, xfrm_policy_timer, 0);
  		timer_setup(&policy->polq.hold_timer,
  			    xfrm_policy_queue_process, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
  	}
  	return policy;
  }
  EXPORT_SYMBOL(xfrm_policy_alloc);
56f047305   Eric Dumazet   xfrm: add rcu gra...
377
378
379
380
381
382
383
  static void xfrm_policy_destroy_rcu(struct rcu_head *head)
  {
  	struct xfrm_policy *policy = container_of(head, struct xfrm_policy, rcu);
  
  	security_xfrm_policy_free(policy->security);
  	kfree(policy);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
  /* Destroy xfrm_policy: descendant resources must be released to this moment. */
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
385
  void xfrm_policy_destroy(struct xfrm_policy *policy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
387
  	BUG_ON(!policy->walk.dead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388

0659eea91   Fan Du   xfrm: Delete hold...
389
  	if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  		BUG();
56f047305   Eric Dumazet   xfrm: add rcu gra...
391
  	call_rcu(&policy->rcu, xfrm_policy_destroy_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  }
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
393
  EXPORT_SYMBOL(xfrm_policy_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394

1365e547c   Alexander Alemayhu   xfrm: trivial typos
395
  /* Rule must be locked. Release descendant resources, announce
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
400
   * entry dead. The rule must be unlinked from lists to the moment.
   */
  
  static void xfrm_policy_kill(struct xfrm_policy *policy)
  {
4c59406ed   YueHaibing   xfrm: policy: Fix...
401
  	write_lock_bh(&policy->lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
402
  	policy->walk.dead = 1;
4c59406ed   YueHaibing   xfrm: policy: Fix...
403
  	write_unlock_bh(&policy->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404

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

e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
407
408
  	if (del_timer(&policy->polq.hold_timer))
  		xfrm_pol_put(policy);
1ee5e6676   Li RongQing   xfrm: remove the ...
409
  	skb_queue_purge(&policy->polq.hold_queue);
a0073fe18   Steffen Klassert   xfrm: Add a state...
410

285ead175   Timo Teräs   xfrm: remove poli...
411
412
413
414
  	if (del_timer(&policy->timer))
  		xfrm_pol_put(policy);
  
  	xfrm_pol_put(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  }
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
416
  static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
e92303f87   Alexey Dobriyan   netns xfrm: propa...
417
  static inline unsigned int idx_hash(struct net *net, u32 index)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
418
  {
e92303f87   Alexey Dobriyan   netns xfrm: propa...
419
  	return __idx_hash(index, net->xfrm.policy_idx_hmask);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
420
  }
b58555f17   Christophe Gouault   xfrm: hash prefix...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  /* calculate policy hash thresholds */
  static void __get_hash_thresh(struct net *net,
  			      unsigned short family, int dir,
  			      u8 *dbits, u8 *sbits)
  {
  	switch (family) {
  	case AF_INET:
  		*dbits = net->xfrm.policy_bydst[dir].dbits4;
  		*sbits = net->xfrm.policy_bydst[dir].sbits4;
  		break;
  
  	case AF_INET6:
  		*dbits = net->xfrm.policy_bydst[dir].dbits6;
  		*sbits = net->xfrm.policy_bydst[dir].sbits6;
  		break;
  
  	default:
  		*dbits = 0;
  		*sbits = 0;
  	}
  }
5f803b58c   David S. Miller   xfrm: Const'ify a...
442
443
444
  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...
445
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
446
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
b58555f17   Christophe Gouault   xfrm: hash prefix...
447
448
449
450
451
452
  	unsigned int hash;
  	u8 dbits;
  	u8 sbits;
  
  	__get_hash_thresh(net, family, dir, &dbits, &sbits);
  	hash = __sel_hash(sel, family, hmask, dbits, sbits);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
453

e1e551bc5   Florian Westphal   xfrm: policy: pre...
454
  	if (hash == hmask + 1)
cc1bb845a   Florian Westphal   xfrm: policy: ret...
455
  		return NULL;
e1e551bc5   Florian Westphal   xfrm: policy: pre...
456
457
458
  
  	return rcu_dereference_check(net->xfrm.policy_bydst[dir].table,
  		     lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
459
  }
5f803b58c   David S. Miller   xfrm: Const'ify a...
460
461
462
463
  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...
464
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
465
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
b58555f17   Christophe Gouault   xfrm: hash prefix...
466
467
468
469
470
471
  	unsigned int hash;
  	u8 dbits;
  	u8 sbits;
  
  	__get_hash_thresh(net, family, dir, &dbits, &sbits);
  	hash = __addr_hash(daddr, saddr, family, hmask, dbits, sbits);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
472

e1e551bc5   Florian Westphal   xfrm: policy: pre...
473
474
  	return rcu_dereference_check(net->xfrm.policy_bydst[dir].table,
  		     lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
475
  }
b58555f17   Christophe Gouault   xfrm: hash prefix...
476
477
  static void xfrm_dst_hash_transfer(struct net *net,
  				   struct hlist_head *list,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
478
  				   struct hlist_head *ndsttable,
b58555f17   Christophe Gouault   xfrm: hash prefix...
479
480
  				   unsigned int nhashmask,
  				   int dir)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
481
  {
b67bfe0d4   Sasha Levin   hlist: drop the n...
482
  	struct hlist_node *tmp, *entry0 = NULL;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
483
  	struct xfrm_policy *pol;
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
484
  	unsigned int h0 = 0;
b58555f17   Christophe Gouault   xfrm: hash prefix...
485
486
  	u8 dbits;
  	u8 sbits;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
487

b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
488
  redo:
b67bfe0d4   Sasha Levin   hlist: drop the n...
489
  	hlist_for_each_entry_safe(pol, tmp, list, bydst) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
490
  		unsigned int h;
b58555f17   Christophe Gouault   xfrm: hash prefix...
491
  		__get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
492
  		h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
b58555f17   Christophe Gouault   xfrm: hash prefix...
493
  				pol->family, nhashmask, dbits, sbits);
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
494
  		if (!entry0) {
a5eefc1df   Florian Westphal   xfrm: policy: use...
495
496
  			hlist_del_rcu(&pol->bydst);
  			hlist_add_head_rcu(&pol->bydst, ndsttable + h);
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
497
498
499
500
  			h0 = h;
  		} else {
  			if (h != h0)
  				continue;
a5eefc1df   Florian Westphal   xfrm: policy: use...
501
502
  			hlist_del_rcu(&pol->bydst);
  			hlist_add_behind_rcu(&pol->bydst, entry0);
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
503
  		}
b67bfe0d4   Sasha Levin   hlist: drop the n...
504
  		entry0 = &pol->bydst;
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
505
506
507
508
  	}
  	if (!hlist_empty(list)) {
  		entry0 = NULL;
  		goto redo;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
509
510
511
512
513
514
515
  	}
  }
  
  static void xfrm_idx_hash_transfer(struct hlist_head *list,
  				   struct hlist_head *nidxtable,
  				   unsigned int nhashmask)
  {
b67bfe0d4   Sasha Levin   hlist: drop the n...
516
  	struct hlist_node *tmp;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
517
  	struct xfrm_policy *pol;
b67bfe0d4   Sasha Levin   hlist: drop the n...
518
  	hlist_for_each_entry_safe(pol, tmp, list, byidx) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
519
520
521
522
523
524
525
526
527
528
529
  		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...
530
  static void xfrm_bydst_resize(struct net *net, int dir)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
531
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
532
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
533
534
  	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
  	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
44e36b42a   David S. Miller   [XFRM]: Extract c...
535
  	struct hlist_head *ndst = xfrm_hash_alloc(nsize);
e1e551bc5   Florian Westphal   xfrm: policy: pre...
536
  	struct hlist_head *odst;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
537
538
539
540
  	int i;
  
  	if (!ndst)
  		return;
9d0380df6   Florian Westphal   xfrm: policy: con...
541
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
30846090a   Florian Westphal   xfrm: policy: add...
542
543
544
545
  	write_seqcount_begin(&xfrm_policy_hash_generation);
  
  	odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table,
  				lockdep_is_held(&net->xfrm.xfrm_policy_lock));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
546
547
  
  	for (i = hmask; i >= 0; i--)
b58555f17   Christophe Gouault   xfrm: hash prefix...
548
  		xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
549

e1e551bc5   Florian Westphal   xfrm: policy: pre...
550
  	rcu_assign_pointer(net->xfrm.policy_bydst[dir].table, ndst);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
551
  	net->xfrm.policy_bydst[dir].hmask = nhashmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
552

30846090a   Florian Westphal   xfrm: policy: add...
553
  	write_seqcount_end(&xfrm_policy_hash_generation);
9d0380df6   Florian Westphal   xfrm: policy: con...
554
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
555

e1e551bc5   Florian Westphal   xfrm: policy: pre...
556
  	synchronize_rcu();
44e36b42a   David S. Miller   [XFRM]: Extract c...
557
  	xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
558
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
559
  static void xfrm_byidx_resize(struct net *net, int total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
560
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
561
  	unsigned int hmask = net->xfrm.policy_idx_hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
562
563
  	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
  	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
564
  	struct hlist_head *oidx = net->xfrm.policy_byidx;
44e36b42a   David S. Miller   [XFRM]: Extract c...
565
  	struct hlist_head *nidx = xfrm_hash_alloc(nsize);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
566
567
568
569
  	int i;
  
  	if (!nidx)
  		return;
9d0380df6   Florian Westphal   xfrm: policy: con...
570
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
571
572
573
  
  	for (i = hmask; i >= 0; i--)
  		xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
574
575
  	net->xfrm.policy_byidx = nidx;
  	net->xfrm.policy_idx_hmask = nhashmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
576

9d0380df6   Florian Westphal   xfrm: policy: con...
577
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
578

44e36b42a   David S. Miller   [XFRM]: Extract c...
579
  	xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
580
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
581
  static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
582
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
583
584
  	unsigned int cnt = net->xfrm.policy_count[dir];
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
585
586
587
588
589
590
591
592
593
594
  
  	if (total)
  		*total += cnt;
  
  	if ((hmask + 1) < xfrm_policy_hashmax &&
  	    cnt > hmask)
  		return 1;
  
  	return 0;
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
595
  static inline int xfrm_byidx_should_resize(struct net *net, int total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
596
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
597
  	unsigned int hmask = net->xfrm.policy_idx_hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
598
599
600
601
602
603
604
  
  	if ((hmask + 1) < xfrm_policy_hashmax &&
  	    total > hmask)
  		return 1;
  
  	return 0;
  }
e071041be   Alexey Dobriyan   netns xfrm: fix "...
605
  void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
606
  {
e071041be   Alexey Dobriyan   netns xfrm: fix "...
607
608
609
610
611
612
613
  	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...
614
  	si->spdhmcnt = xfrm_policy_hashmax;
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
615
616
  }
  EXPORT_SYMBOL(xfrm_spd_getinfo);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
617

ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
618
  static DEFINE_MUTEX(hash_resize_mutex);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
619
  static void xfrm_hash_resize(struct work_struct *work)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
620
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
621
  	struct net *net = container_of(work, struct net, xfrm.policy_hash_work);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
622
623
624
625
626
  	int dir, total;
  
  	mutex_lock(&hash_resize_mutex);
  
  	total = 0;
53c2e285f   Herbert Xu   xfrm: Do not hash...
627
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
628
629
  		if (xfrm_bydst_should_resize(net, dir, &total))
  			xfrm_bydst_resize(net, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
630
  	}
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
631
632
  	if (xfrm_byidx_should_resize(net, total))
  		xfrm_byidx_resize(net, total);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
633
634
635
  
  	mutex_unlock(&hash_resize_mutex);
  }
24969facd   Florian Westphal   xfrm: policy: sto...
636
637
638
639
640
641
642
643
644
645
646
647
  /* Make sure *pol can be inserted into fastbin.
   * Useful to check that later insert requests will be sucessful
   * (provided xfrm_policy_lock is held throughout).
   */
  static struct xfrm_pol_inexact_bin *
  xfrm_policy_inexact_alloc_bin(const struct xfrm_policy *pol, u8 dir)
  {
  	struct xfrm_pol_inexact_bin *bin, *prev;
  	struct xfrm_pol_inexact_key k = {
  		.family = pol->family,
  		.type = pol->type,
  		.dir = dir,
b5fe22e23   Florian Westphal   xfrm: policy: con...
648
  		.if_id = pol->if_id,
24969facd   Florian Westphal   xfrm: policy: sto...
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  	};
  	struct net *net = xp_net(pol);
  
  	lockdep_assert_held(&net->xfrm.xfrm_policy_lock);
  
  	write_pnet(&k.net, net);
  	bin = rhashtable_lookup_fast(&xfrm_policy_inexact_table, &k,
  				     xfrm_pol_inexact_params);
  	if (bin)
  		return bin;
  
  	bin = kzalloc(sizeof(*bin), GFP_ATOMIC);
  	if (!bin)
  		return NULL;
  
  	bin->k = k;
  	INIT_HLIST_HEAD(&bin->hhead);
9cf545ebd   Florian Westphal   xfrm: policy: sto...
666
  	bin->root_d = RB_ROOT;
64a09a7bf   Florian Westphal   xfrm: policy: sto...
667
  	bin->root_s = RB_ROOT;
77cc278f7   Ahmed S. Darwish   xfrm: policy: Use...
668
  	seqcount_spinlock_init(&bin->count, &net->xfrm.xfrm_policy_lock);
24969facd   Florian Westphal   xfrm: policy: sto...
669
670
671
672
673
674
675
676
677
678
679
680
681
  
  	prev = rhashtable_lookup_get_insert_key(&xfrm_policy_inexact_table,
  						&bin->k, &bin->head,
  						xfrm_pol_inexact_params);
  	if (!prev) {
  		list_add(&bin->inexact_bins, &net->xfrm.inexact_bins);
  		return bin;
  	}
  
  	kfree(bin);
  
  	return IS_ERR(prev) ? NULL : prev;
  }
6be3b0db6   Florian Westphal   xfrm: policy: add...
682
683
  static bool xfrm_pol_inexact_addr_use_any_list(const xfrm_address_t *addr,
  					       int family, u8 prefixlen)
24969facd   Florian Westphal   xfrm: policy: sto...
684
  {
6be3b0db6   Florian Westphal   xfrm: policy: add...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  	if (xfrm_addr_any(addr, family))
  		return true;
  
  	if (family == AF_INET6 && prefixlen < INEXACT_PREFIXLEN_IPV6)
  		return true;
  
  	if (family == AF_INET && prefixlen < INEXACT_PREFIXLEN_IPV4)
  		return true;
  
  	return false;
  }
  
  static bool
  xfrm_policy_inexact_insert_use_any_list(const struct xfrm_policy *policy)
  {
  	const xfrm_address_t *addr;
  	bool saddr_any, daddr_any;
  	u8 prefixlen;
  
  	addr = &policy->selector.saddr;
  	prefixlen = policy->selector.prefixlen_s;
24969facd   Florian Westphal   xfrm: policy: sto...
706

6be3b0db6   Florian Westphal   xfrm: policy: add...
707
708
709
710
711
712
713
714
715
716
  	saddr_any = xfrm_pol_inexact_addr_use_any_list(addr,
  						       policy->family,
  						       prefixlen);
  	addr = &policy->selector.daddr;
  	prefixlen = policy->selector.prefixlen_d;
  	daddr_any = xfrm_pol_inexact_addr_use_any_list(addr,
  						       policy->family,
  						       prefixlen);
  	return saddr_any && daddr_any;
  }
9cf545ebd   Florian Westphal   xfrm: policy: sto...
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
  static void xfrm_pol_inexact_node_init(struct xfrm_pol_inexact_node *node,
  				       const xfrm_address_t *addr, u8 prefixlen)
  {
  	node->addr = *addr;
  	node->prefixlen = prefixlen;
  }
  
  static struct xfrm_pol_inexact_node *
  xfrm_pol_inexact_node_alloc(const xfrm_address_t *addr, u8 prefixlen)
  {
  	struct xfrm_pol_inexact_node *node;
  
  	node = kzalloc(sizeof(*node), GFP_ATOMIC);
  	if (node)
  		xfrm_pol_inexact_node_init(node, addr, prefixlen);
  
  	return node;
  }
  
  static int xfrm_policy_addr_delta(const xfrm_address_t *a,
  				  const xfrm_address_t *b,
  				  u8 prefixlen, u16 family)
  {
  	unsigned int pdw, pbi;
  	int delta = 0;
  
  	switch (family) {
  	case AF_INET:
  		if (sizeof(long) == 4 && prefixlen == 0)
  			return ntohl(a->a4) - ntohl(b->a4);
  		return (ntohl(a->a4) & ((~0UL << (32 - prefixlen)))) -
  		       (ntohl(b->a4) & ((~0UL << (32 - prefixlen))));
  	case AF_INET6:
  		pdw = prefixlen >> 5;
  		pbi = prefixlen & 0x1f;
  
  		if (pdw) {
  			delta = memcmp(a->a6, b->a6, pdw << 2);
  			if (delta)
  				return delta;
  		}
  		if (pbi) {
  			u32 mask = ~0u << (32 - pbi);
  
  			delta = (ntohl(a->a6[pdw]) & mask) -
  				(ntohl(b->a6[pdw]) & mask);
  		}
  		break;
  	default:
  		break;
  	}
  
  	return delta;
  }
  
  static void xfrm_policy_inexact_list_reinsert(struct net *net,
  					      struct xfrm_pol_inexact_node *n,
  					      u16 family)
  {
e901cbc29   Florian Westphal   xfrm: policy: che...
776
  	unsigned int matched_s, matched_d;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
777
  	struct xfrm_policy *policy, *p;
e901cbc29   Florian Westphal   xfrm: policy: che...
778
779
  	matched_s = 0;
  	matched_d = 0;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
780
  	list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
1d38900cb   Florian Westphal   xfrm: policy: fix...
781
  		struct hlist_node *newpos = NULL;
e901cbc29   Florian Westphal   xfrm: policy: che...
782
  		bool matches_s, matches_d;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
783
784
785
786
787
788
789
  		if (!policy->bydst_reinsert)
  			continue;
  
  		WARN_ON_ONCE(policy->family != family);
  
  		policy->bydst_reinsert = false;
  		hlist_for_each_entry(p, &n->hhead, bydst) {
1d38900cb   Florian Westphal   xfrm: policy: fix...
790
791
792
793
  			if (policy->priority > p->priority)
  				newpos = &p->bydst;
  			else if (policy->priority == p->priority &&
  				 policy->pos > p->pos)
9cf545ebd   Florian Westphal   xfrm: policy: sto...
794
795
796
797
798
799
  				newpos = &p->bydst;
  			else
  				break;
  		}
  
  		if (newpos)
355b00d1e   Florian Westphal   xfrm: policy: use...
800
  			hlist_add_behind_rcu(&policy->bydst, newpos);
9cf545ebd   Florian Westphal   xfrm: policy: sto...
801
  		else
355b00d1e   Florian Westphal   xfrm: policy: use...
802
  			hlist_add_head_rcu(&policy->bydst, &n->hhead);
e901cbc29   Florian Westphal   xfrm: policy: che...
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
  
  		/* paranoia checks follow.
  		 * Check that the reinserted policy matches at least
  		 * saddr or daddr for current node prefix.
  		 *
  		 * Matching both is fine, matching saddr in one policy
  		 * (but not daddr) and then matching only daddr in another
  		 * is a bug.
  		 */
  		matches_s = xfrm_policy_addr_delta(&policy->selector.saddr,
  						   &n->addr,
  						   n->prefixlen,
  						   family) == 0;
  		matches_d = xfrm_policy_addr_delta(&policy->selector.daddr,
  						   &n->addr,
  						   n->prefixlen,
  						   family) == 0;
  		if (matches_s && matches_d)
  			continue;
  
  		WARN_ON_ONCE(!matches_s && !matches_d);
  		if (matches_s)
  			matched_s++;
  		if (matches_d)
  			matched_d++;
  		WARN_ON_ONCE(matched_s && matched_d);
9cf545ebd   Florian Westphal   xfrm: policy: sto...
829
830
  	}
  }
6ac098b2a   Florian Westphal   xfrm: policy: add...
831
832
833
834
835
  static void xfrm_policy_inexact_node_reinsert(struct net *net,
  					      struct xfrm_pol_inexact_node *n,
  					      struct rb_root *new,
  					      u16 family)
  {
6ac098b2a   Florian Westphal   xfrm: policy: add...
836
  	struct xfrm_pol_inexact_node *node;
12750abad   Florian Westphal   xfrm: policy: fix...
837
  	struct rb_node **p, *parent;
6ac098b2a   Florian Westphal   xfrm: policy: add...
838
839
840
  
  	/* we should not have another subtree here */
  	WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root));
12750abad   Florian Westphal   xfrm: policy: fix...
841
842
  restart:
  	parent = NULL;
6ac098b2a   Florian Westphal   xfrm: policy: add...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
  	p = &new->rb_node;
  	while (*p) {
  		u8 prefixlen;
  		int delta;
  
  		parent = *p;
  		node = rb_entry(*p, struct xfrm_pol_inexact_node, node);
  
  		prefixlen = min(node->prefixlen, n->prefixlen);
  
  		delta = xfrm_policy_addr_delta(&n->addr, &node->addr,
  					       prefixlen, family);
  		if (delta < 0) {
  			p = &parent->rb_left;
  		} else if (delta > 0) {
  			p = &parent->rb_right;
  		} else {
769a807d0   Florian Westphal   xfrm: policy: avo...
860
  			bool same_prefixlen = node->prefixlen == n->prefixlen;
6ac098b2a   Florian Westphal   xfrm: policy: add...
861
  			struct xfrm_policy *tmp;
12750abad   Florian Westphal   xfrm: policy: fix...
862
  			hlist_for_each_entry(tmp, &n->hhead, bydst) {
6ac098b2a   Florian Westphal   xfrm: policy: add...
863
  				tmp->bydst_reinsert = true;
12750abad   Florian Westphal   xfrm: policy: fix...
864
865
  				hlist_del_rcu(&tmp->bydst);
  			}
6ac098b2a   Florian Westphal   xfrm: policy: add...
866

769a807d0   Florian Westphal   xfrm: policy: avo...
867
  			node->prefixlen = prefixlen;
6ac098b2a   Florian Westphal   xfrm: policy: add...
868
  			xfrm_policy_inexact_list_reinsert(net, node, family);
769a807d0   Florian Westphal   xfrm: policy: avo...
869
  			if (same_prefixlen) {
6ac098b2a   Florian Westphal   xfrm: policy: add...
870
871
872
873
874
875
876
  				kfree_rcu(n, rcu);
  				return;
  			}
  
  			rb_erase(*p, new);
  			kfree_rcu(n, rcu);
  			n = node;
12750abad   Florian Westphal   xfrm: policy: fix...
877
  			goto restart;
6ac098b2a   Florian Westphal   xfrm: policy: add...
878
879
880
881
882
883
  		}
  	}
  
  	rb_link_node_rcu(&n->node, parent, p);
  	rb_insert_color(&n->node, new);
  }
9cf545ebd   Florian Westphal   xfrm: policy: sto...
884
885
886
887
888
889
  /* merge nodes v and n */
  static void xfrm_policy_inexact_node_merge(struct net *net,
  					   struct xfrm_pol_inexact_node *v,
  					   struct xfrm_pol_inexact_node *n,
  					   u16 family)
  {
6ac098b2a   Florian Westphal   xfrm: policy: add...
890
  	struct xfrm_pol_inexact_node *node;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
891
  	struct xfrm_policy *tmp;
6ac098b2a   Florian Westphal   xfrm: policy: add...
892
893
894
895
896
897
898
899
900
901
902
903
  	struct rb_node *rnode;
  
  	/* To-be-merged node v has a subtree.
  	 *
  	 * Dismantle it and insert its nodes to n->root.
  	 */
  	while ((rnode = rb_first(&v->root)) != NULL) {
  		node = rb_entry(rnode, struct xfrm_pol_inexact_node, node);
  		rb_erase(&node->node, &v->root);
  		xfrm_policy_inexact_node_reinsert(net, node, &n->root,
  						  family);
  	}
9cf545ebd   Florian Westphal   xfrm: policy: sto...
904

1d38900cb   Florian Westphal   xfrm: policy: fix...
905
  	hlist_for_each_entry(tmp, &v->hhead, bydst) {
9cf545ebd   Florian Westphal   xfrm: policy: sto...
906
  		tmp->bydst_reinsert = true;
1d38900cb   Florian Westphal   xfrm: policy: fix...
907
908
  		hlist_del_rcu(&tmp->bydst);
  	}
9cf545ebd   Florian Westphal   xfrm: policy: sto...
909

9cf545ebd   Florian Westphal   xfrm: policy: sto...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
  	xfrm_policy_inexact_list_reinsert(net, n, family);
  }
  
  static struct xfrm_pol_inexact_node *
  xfrm_policy_inexact_insert_node(struct net *net,
  				struct rb_root *root,
  				xfrm_address_t *addr,
  				u16 family, u8 prefixlen, u8 dir)
  {
  	struct xfrm_pol_inexact_node *cached = NULL;
  	struct rb_node **p, *parent = NULL;
  	struct xfrm_pol_inexact_node *node;
  
  	p = &root->rb_node;
  	while (*p) {
  		int delta;
  
  		parent = *p;
  		node = rb_entry(*p, struct xfrm_pol_inexact_node, node);
  
  		delta = xfrm_policy_addr_delta(addr, &node->addr,
  					       node->prefixlen,
  					       family);
  		if (delta == 0 && prefixlen >= node->prefixlen) {
  			WARN_ON_ONCE(cached); /* ipsec policies got lost */
  			return node;
  		}
  
  		if (delta < 0)
  			p = &parent->rb_left;
  		else
  			p = &parent->rb_right;
  
  		if (prefixlen < node->prefixlen) {
  			delta = xfrm_policy_addr_delta(addr, &node->addr,
  						       prefixlen,
  						       family);
  			if (delta)
  				continue;
  
  			/* This node is a subnet of the new prefix. It needs
  			 * to be removed and re-inserted with the smaller
  			 * prefix and all nodes that are now also covered
  			 * by the reduced prefixlen.
  			 */
  			rb_erase(&node->node, root);
  
  			if (!cached) {
  				xfrm_pol_inexact_node_init(node, addr,
  							   prefixlen);
  				cached = node;
  			} else {
  				/* This node also falls within the new
  				 * prefixlen. Merge the to-be-reinserted
  				 * node and this one.
  				 */
  				xfrm_policy_inexact_node_merge(net, node,
  							       cached, family);
  				kfree_rcu(node, rcu);
  			}
  
  			/* restart */
  			p = &root->rb_node;
  			parent = NULL;
  		}
  	}
  
  	node = cached;
  	if (!node) {
  		node = xfrm_pol_inexact_node_alloc(addr, prefixlen);
  		if (!node)
  			return NULL;
  	}
  
  	rb_link_node_rcu(&node->node, parent, p);
  	rb_insert_color(&node->node, root);
  
  	return node;
  }
  
  static void xfrm_policy_inexact_gc_tree(struct rb_root *r, bool rm)
  {
  	struct xfrm_pol_inexact_node *node;
  	struct rb_node *rn = rb_first(r);
  
  	while (rn) {
  		node = rb_entry(rn, struct xfrm_pol_inexact_node, node);
6ac098b2a   Florian Westphal   xfrm: policy: add...
997
  		xfrm_policy_inexact_gc_tree(&node->root, rm);
9cf545ebd   Florian Westphal   xfrm: policy: sto...
998
  		rn = rb_next(rn);
6ac098b2a   Florian Westphal   xfrm: policy: add...
999
  		if (!hlist_empty(&node->hhead) || !RB_EMPTY_ROOT(&node->root)) {
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1000
1001
1002
1003
1004
1005
1006
1007
  			WARN_ON_ONCE(rm);
  			continue;
  		}
  
  		rb_erase(&node->node, r);
  		kfree_rcu(node, rcu);
  	}
  }
6be3b0db6   Florian Westphal   xfrm: policy: add...
1008
1009
  static void __xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b, bool net_exit)
  {
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1010
1011
  	write_seqcount_begin(&b->count);
  	xfrm_policy_inexact_gc_tree(&b->root_d, net_exit);
64a09a7bf   Florian Westphal   xfrm: policy: sto...
1012
  	xfrm_policy_inexact_gc_tree(&b->root_s, net_exit);
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1013
  	write_seqcount_end(&b->count);
64a09a7bf   Florian Westphal   xfrm: policy: sto...
1014
  	if (!RB_EMPTY_ROOT(&b->root_d) || !RB_EMPTY_ROOT(&b->root_s) ||
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1015
  	    !hlist_empty(&b->hhead)) {
6be3b0db6   Florian Westphal   xfrm: policy: add...
1016
  		WARN_ON_ONCE(net_exit);
24969facd   Florian Westphal   xfrm: policy: sto...
1017
  		return;
6be3b0db6   Florian Westphal   xfrm: policy: add...
1018
  	}
24969facd   Florian Westphal   xfrm: policy: sto...
1019
1020
1021
1022
1023
1024
1025
  
  	if (rhashtable_remove_fast(&xfrm_policy_inexact_table, &b->head,
  				   xfrm_pol_inexact_params) == 0) {
  		list_del(&b->inexact_bins);
  		kfree_rcu(b, rcu);
  	}
  }
6be3b0db6   Florian Westphal   xfrm: policy: add...
1026
1027
1028
1029
1030
1031
1032
1033
  static void xfrm_policy_inexact_prune_bin(struct xfrm_pol_inexact_bin *b)
  {
  	struct net *net = read_pnet(&b->k.net);
  
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
  	__xfrm_policy_inexact_prune_bin(b, false);
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
  }
24969facd   Florian Westphal   xfrm: policy: sto...
1034
1035
  static void __xfrm_policy_inexact_flush(struct net *net)
  {
6be3b0db6   Florian Westphal   xfrm: policy: add...
1036
  	struct xfrm_pol_inexact_bin *bin, *t;
24969facd   Florian Westphal   xfrm: policy: sto...
1037
1038
  
  	lockdep_assert_held(&net->xfrm.xfrm_policy_lock);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1039
1040
  	list_for_each_entry_safe(bin, t, &net->xfrm.inexact_bins, inexact_bins)
  		__xfrm_policy_inexact_prune_bin(bin, false);
24969facd   Florian Westphal   xfrm: policy: sto...
1041
  }
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
  static struct hlist_head *
  xfrm_policy_inexact_alloc_chain(struct xfrm_pol_inexact_bin *bin,
  				struct xfrm_policy *policy, u8 dir)
  {
  	struct xfrm_pol_inexact_node *n;
  	struct net *net;
  
  	net = xp_net(policy);
  	lockdep_assert_held(&net->xfrm.xfrm_policy_lock);
  
  	if (xfrm_policy_inexact_insert_use_any_list(policy))
  		return &bin->hhead;
64a09a7bf   Florian Westphal   xfrm: policy: sto...
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
  	if (xfrm_pol_inexact_addr_use_any_list(&policy->selector.daddr,
  					       policy->family,
  					       policy->selector.prefixlen_d)) {
  		write_seqcount_begin(&bin->count);
  		n = xfrm_policy_inexact_insert_node(net,
  						    &bin->root_s,
  						    &policy->selector.saddr,
  						    policy->family,
  						    policy->selector.prefixlen_s,
  						    dir);
  		write_seqcount_end(&bin->count);
  		if (!n)
  			return NULL;
  
  		return &n->hhead;
  	}
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  	/* daddr is fixed */
  	write_seqcount_begin(&bin->count);
  	n = xfrm_policy_inexact_insert_node(net,
  					    &bin->root_d,
  					    &policy->selector.daddr,
  					    policy->family,
  					    policy->selector.prefixlen_d, dir);
  	write_seqcount_end(&bin->count);
  	if (!n)
  		return NULL;
6ac098b2a   Florian Westphal   xfrm: policy: add...
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  
  	/* saddr is wildcard */
  	if (xfrm_pol_inexact_addr_use_any_list(&policy->selector.saddr,
  					       policy->family,
  					       policy->selector.prefixlen_s))
  		return &n->hhead;
  
  	write_seqcount_begin(&bin->count);
  	n = xfrm_policy_inexact_insert_node(net,
  					    &n->root,
  					    &policy->selector.saddr,
  					    policy->family,
  					    policy->selector.prefixlen_s, dir);
  	write_seqcount_end(&bin->count);
  	if (!n)
  		return NULL;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1096
1097
  	return &n->hhead;
  }
24969facd   Florian Westphal   xfrm: policy: sto...
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  static struct xfrm_policy *
  xfrm_policy_inexact_insert(struct xfrm_policy *policy, u8 dir, int excl)
  {
  	struct xfrm_pol_inexact_bin *bin;
  	struct xfrm_policy *delpol;
  	struct hlist_head *chain;
  	struct net *net;
  
  	bin = xfrm_policy_inexact_alloc_bin(policy, dir);
  	if (!bin)
  		return ERR_PTR(-ENOMEM);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1109
1110
  	net = xp_net(policy);
  	lockdep_assert_held(&net->xfrm.xfrm_policy_lock);
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1111
1112
1113
1114
  	chain = xfrm_policy_inexact_alloc_chain(bin, policy, dir);
  	if (!chain) {
  		__xfrm_policy_inexact_prune_bin(bin, false);
  		return ERR_PTR(-ENOMEM);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1115
  	}
6be3b0db6   Florian Westphal   xfrm: policy: add...
1116
1117
1118
  	delpol = xfrm_policy_insert_list(chain, policy, excl);
  	if (delpol && excl) {
  		__xfrm_policy_inexact_prune_bin(bin, false);
24969facd   Florian Westphal   xfrm: policy: sto...
1119
  		return ERR_PTR(-EEXIST);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1120
  	}
24969facd   Florian Westphal   xfrm: policy: sto...
1121

24969facd   Florian Westphal   xfrm: policy: sto...
1122
1123
  	chain = &net->xfrm.policy_inexact[dir];
  	xfrm_policy_insert_inexact_list(chain, policy);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1124
1125
  	if (delpol)
  		__xfrm_policy_inexact_prune_bin(bin, false);
24969facd   Florian Westphal   xfrm: policy: sto...
1126
1127
  	return delpol;
  }
880a6fab8   Christophe Gouault   xfrm: configure p...
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
  static void xfrm_hash_rebuild(struct work_struct *work)
  {
  	struct net *net = container_of(work, struct net,
  				       xfrm.policy_hthresh.work);
  	unsigned int hmask;
  	struct xfrm_policy *pol;
  	struct xfrm_policy *policy;
  	struct hlist_head *chain;
  	struct hlist_head *odst;
  	struct hlist_node *newpos;
  	int i;
  	int dir;
  	unsigned seq;
  	u8 lbits4, rbits4, lbits6, rbits6;
  
  	mutex_lock(&hash_resize_mutex);
  
  	/* read selector prefixlen thresholds */
  	do {
  		seq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
  
  		lbits4 = net->xfrm.policy_hthresh.lbits4;
  		rbits4 = net->xfrm.policy_hthresh.rbits4;
  		lbits6 = net->xfrm.policy_hthresh.lbits6;
  		rbits6 = net->xfrm.policy_hthresh.rbits6;
  	} while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq));
9d0380df6   Florian Westphal   xfrm: policy: con...
1154
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
7a474c365   Florian Westphal   xfrm: policy: inc...
1155
  	write_seqcount_begin(&xfrm_policy_hash_generation);
880a6fab8   Christophe Gouault   xfrm: configure p...
1156

24969facd   Florian Westphal   xfrm: policy: sto...
1157
1158
1159
1160
  	/* make sure that we can insert the indirect policies again before
  	 * we start with destructive action.
  	 */
  	list_for_each_entry(policy, &net->xfrm.policy_all, walk.all) {
6be3b0db6   Florian Westphal   xfrm: policy: add...
1161
  		struct xfrm_pol_inexact_bin *bin;
24969facd   Florian Westphal   xfrm: policy: sto...
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
  		u8 dbits, sbits;
  
  		dir = xfrm_policy_id2dir(policy->index);
  		if (policy->walk.dead || dir >= XFRM_POLICY_MAX)
  			continue;
  
  		if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
  			if (policy->family == AF_INET) {
  				dbits = rbits4;
  				sbits = lbits4;
  			} else {
  				dbits = rbits6;
  				sbits = lbits6;
  			}
  		} else {
  			if (policy->family == AF_INET) {
  				dbits = lbits4;
  				sbits = rbits4;
  			} else {
  				dbits = lbits6;
  				sbits = rbits6;
  			}
  		}
  
  		if (policy->selector.prefixlen_d < dbits ||
  		    policy->selector.prefixlen_s < sbits)
  			continue;
6be3b0db6   Florian Westphal   xfrm: policy: add...
1189
1190
  		bin = xfrm_policy_inexact_alloc_bin(policy, dir);
  		if (!bin)
24969facd   Florian Westphal   xfrm: policy: sto...
1191
  			goto out_unlock;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1192
1193
1194
  
  		if (!xfrm_policy_inexact_alloc_chain(bin, policy, dir))
  			goto out_unlock;
24969facd   Florian Westphal   xfrm: policy: sto...
1195
  	}
880a6fab8   Christophe Gouault   xfrm: configure p...
1196
  	/* reset the bydst and inexact table in all directions */
53c2e285f   Herbert Xu   xfrm: Do not hash...
1197
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
1548bc4e0   Florian Westphal   xfrm: policy: del...
1198
1199
1200
1201
  		struct hlist_node *n;
  
  		hlist_for_each_entry_safe(policy, n,
  					  &net->xfrm.policy_inexact[dir],
fd7097213   Florian Westphal   xfrm: policy: fix...
1202
1203
  					  bydst_inexact_list) {
  			hlist_del_rcu(&policy->bydst);
1548bc4e0   Florian Westphal   xfrm: policy: del...
1204
  			hlist_del_init(&policy->bydst_inexact_list);
fd7097213   Florian Westphal   xfrm: policy: fix...
1205
  		}
1548bc4e0   Florian Westphal   xfrm: policy: del...
1206

880a6fab8   Christophe Gouault   xfrm: configure p...
1207
1208
  		hmask = net->xfrm.policy_bydst[dir].hmask;
  		odst = net->xfrm.policy_bydst[dir].table;
fd7097213   Florian Westphal   xfrm: policy: fix...
1209
1210
1211
1212
  		for (i = hmask; i >= 0; i--) {
  			hlist_for_each_entry_safe(policy, n, odst + i, bydst)
  				hlist_del_rcu(&policy->bydst);
  		}
880a6fab8   Christophe Gouault   xfrm: configure p...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
  		if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
  			/* dir out => dst = remote, src = local */
  			net->xfrm.policy_bydst[dir].dbits4 = rbits4;
  			net->xfrm.policy_bydst[dir].sbits4 = lbits4;
  			net->xfrm.policy_bydst[dir].dbits6 = rbits6;
  			net->xfrm.policy_bydst[dir].sbits6 = lbits6;
  		} else {
  			/* dir in/fwd => dst = local, src = remote */
  			net->xfrm.policy_bydst[dir].dbits4 = lbits4;
  			net->xfrm.policy_bydst[dir].sbits4 = rbits4;
  			net->xfrm.policy_bydst[dir].dbits6 = lbits6;
  			net->xfrm.policy_bydst[dir].sbits6 = rbits6;
  		}
  	}
  
  	/* re-insert all policies by order of creation */
  	list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
88584c30e   Florian Westphal   xfrm: policy: fix...
1230
1231
1232
1233
  		if (policy->walk.dead)
  			continue;
  		dir = xfrm_policy_id2dir(policy->index);
  		if (dir >= XFRM_POLICY_MAX) {
6916fb3b1   Tobias Brunner   xfrm: Ignore sock...
1234
1235
1236
  			/* skip socket policies */
  			continue;
  		}
880a6fab8   Christophe Gouault   xfrm: configure p...
1237
1238
  		newpos = NULL;
  		chain = policy_hash_bysel(net, &policy->selector,
88584c30e   Florian Westphal   xfrm: policy: fix...
1239
  					  policy->family, dir);
1548bc4e0   Florian Westphal   xfrm: policy: del...
1240

24969facd   Florian Westphal   xfrm: policy: sto...
1241
1242
1243
1244
1245
1246
1247
  		if (!chain) {
  			void *p = xfrm_policy_inexact_insert(policy, dir, 0);
  
  			WARN_ONCE(IS_ERR(p), "reinsert: %ld
  ", PTR_ERR(p));
  			continue;
  		}
880a6fab8   Christophe Gouault   xfrm: configure p...
1248
1249
1250
1251
1252
1253
1254
  		hlist_for_each_entry(pol, chain, bydst) {
  			if (policy->priority >= pol->priority)
  				newpos = &pol->bydst;
  			else
  				break;
  		}
  		if (newpos)
9dffff200   Florian Westphal   xfrm: policy: use...
1255
  			hlist_add_behind_rcu(&policy->bydst, newpos);
880a6fab8   Christophe Gouault   xfrm: configure p...
1256
  		else
9dffff200   Florian Westphal   xfrm: policy: use...
1257
  			hlist_add_head_rcu(&policy->bydst, chain);
880a6fab8   Christophe Gouault   xfrm: configure p...
1258
  	}
24969facd   Florian Westphal   xfrm: policy: sto...
1259
  out_unlock:
6be3b0db6   Florian Westphal   xfrm: policy: add...
1260
  	__xfrm_policy_inexact_flush(net);
7a474c365   Florian Westphal   xfrm: policy: inc...
1261
  	write_seqcount_end(&xfrm_policy_hash_generation);
9d0380df6   Florian Westphal   xfrm: policy: con...
1262
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
880a6fab8   Christophe Gouault   xfrm: configure p...
1263
1264
1265
1266
1267
1268
1269
1270
1271
  
  	mutex_unlock(&hash_resize_mutex);
  }
  
  void xfrm_policy_hash_rebuild(struct net *net)
  {
  	schedule_work(&net->xfrm.policy_hthresh.work);
  }
  EXPORT_SYMBOL(xfrm_policy_hash_rebuild);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
  /* Generate new index... KAME seems to generate them ordered by cost
   * of an absolute inpredictability of ordering of rules. This will not pass. */
e682adf02   Fan Du   xfrm: Try to hono...
1274
  static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
  	static u32 idx_generator;
  
  	for (;;) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1279
1280
1281
1282
  		struct hlist_head *list;
  		struct xfrm_policy *p;
  		u32 idx;
  		int found;
e682adf02   Fan Du   xfrm: Try to hono...
1283
1284
1285
1286
1287
1288
1289
  		if (!index) {
  			idx = (idx_generator | dir);
  			idx_generator += 8;
  		} else {
  			idx = index;
  			index = 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290
1291
  		if (idx == 0)
  			idx = 8;
1121994c8   Alexey Dobriyan   netns xfrm: polic...
1292
  		list = net->xfrm.policy_byidx + idx_hash(net, idx);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1293
  		found = 0;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1294
  		hlist_for_each_entry(p, list, byidx) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1295
1296
  			if (p->index == idx) {
  				found = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
  				break;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1298
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
  		}
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1300
  		if (!found)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
1302
1303
  			return idx;
  	}
  }
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
  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;
  }
a0073fe18   Steffen Klassert   xfrm: Add a state...
1318
1319
1320
1321
1322
  static void xfrm_policy_requeue(struct xfrm_policy *old,
  				struct xfrm_policy *new)
  {
  	struct xfrm_policy_queue *pq = &old->polq;
  	struct sk_buff_head list;
de2ad486c   Li RongQing   xfrm: move the ch...
1323
1324
  	if (skb_queue_empty(&pq->hold_queue))
  		return;
a0073fe18   Steffen Klassert   xfrm: Add a state...
1325
1326
1327
1328
  	__skb_queue_head_init(&list);
  
  	spin_lock_bh(&pq->hold_queue.lock);
  	skb_queue_splice_init(&pq->hold_queue, &list);
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
1329
1330
  	if (del_timer(&pq->hold_timer))
  		xfrm_pol_put(old);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1331
  	spin_unlock_bh(&pq->hold_queue.lock);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1332
1333
1334
1335
1336
  	pq = &new->polq;
  
  	spin_lock_bh(&pq->hold_queue.lock);
  	skb_queue_splice(&list, &pq->hold_queue);
  	pq->timeout = XFRM_QUEUE_TMO_MIN;
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
1337
1338
  	if (!mod_timer(&pq->hold_timer, jiffies))
  		xfrm_pol_hold(new);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1339
1340
  	spin_unlock_bh(&pq->hold_queue.lock);
  }
4f47e8ab6   Xin Long   xfrm: policy: mat...
1341
1342
  static inline bool xfrm_policy_mark_match(const struct xfrm_mark *mark,
  					  struct xfrm_policy *pol)
7cb8a9396   Steffen Klassert   xfrm: Allow inser...
1343
  {
4f47e8ab6   Xin Long   xfrm: policy: mat...
1344
  	return mark->v == pol->mark.v && mark->m == pol->mark.m;
7cb8a9396   Steffen Klassert   xfrm: Allow inser...
1345
  }
24969facd   Florian Westphal   xfrm: policy: sto...
1346
1347
1348
1349
  static u32 xfrm_pol_bin_key(const void *data, u32 len, u32 seed)
  {
  	const struct xfrm_pol_inexact_key *k = data;
  	u32 a = k->type << 24 | k->dir << 16 | k->family;
b5fe22e23   Florian Westphal   xfrm: policy: con...
1350
1351
  	return jhash_3words(a, k->if_id, net_hash_mix(read_pnet(&k->net)),
  			    seed);
24969facd   Florian Westphal   xfrm: policy: sto...
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
  }
  
  static u32 xfrm_pol_bin_obj(const void *data, u32 len, u32 seed)
  {
  	const struct xfrm_pol_inexact_bin *b = data;
  
  	return xfrm_pol_bin_key(&b->k, 0, seed);
  }
  
  static int xfrm_pol_bin_cmp(struct rhashtable_compare_arg *arg,
  			    const void *ptr)
  {
  	const struct xfrm_pol_inexact_key *key = arg->key;
  	const struct xfrm_pol_inexact_bin *b = ptr;
  	int ret;
  
  	if (!net_eq(read_pnet(&b->k.net), read_pnet(&key->net)))
  		return -1;
  
  	ret = b->k.dir ^ key->dir;
  	if (ret)
  		return ret;
  
  	ret = b->k.type ^ key->type;
  	if (ret)
  		return ret;
  
  	ret = b->k.family ^ key->family;
  	if (ret)
  		return ret;
b5fe22e23   Florian Westphal   xfrm: policy: con...
1382
  	return b->k.if_id ^ key->if_id;
24969facd   Florian Westphal   xfrm: policy: sto...
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
  }
  
  static const struct rhashtable_params xfrm_pol_inexact_params = {
  	.head_offset		= offsetof(struct xfrm_pol_inexact_bin, head),
  	.hashfn			= xfrm_pol_bin_key,
  	.obj_hashfn		= xfrm_pol_bin_obj,
  	.obj_cmpfn		= xfrm_pol_bin_cmp,
  	.automatic_shrinking	= true,
  };
  
  static void xfrm_policy_insert_inexact_list(struct hlist_head *chain,
  					    struct xfrm_policy *policy)
  {
  	struct xfrm_policy *pol, *delpol = NULL;
  	struct hlist_node *newpos = NULL;
6be3b0db6   Florian Westphal   xfrm: policy: add...
1398
  	int i = 0;
24969facd   Florian Westphal   xfrm: policy: sto...
1399
1400
1401
1402
1403
  
  	hlist_for_each_entry(pol, chain, bydst_inexact_list) {
  		if (pol->type == policy->type &&
  		    pol->if_id == policy->if_id &&
  		    !selector_cmp(&pol->selector, &policy->selector) &&
4f47e8ab6   Xin Long   xfrm: policy: mat...
1404
  		    xfrm_policy_mark_match(&policy->mark, pol) &&
24969facd   Florian Westphal   xfrm: policy: sto...
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
  		    xfrm_sec_ctx_match(pol->security, policy->security) &&
  		    !WARN_ON(delpol)) {
  			delpol = pol;
  			if (policy->priority > pol->priority)
  				continue;
  		} else if (policy->priority >= pol->priority) {
  			newpos = &pol->bydst_inexact_list;
  			continue;
  		}
  		if (delpol)
  			break;
  	}
  
  	if (newpos)
  		hlist_add_behind_rcu(&policy->bydst_inexact_list, newpos);
  	else
  		hlist_add_head_rcu(&policy->bydst_inexact_list, chain);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1422
1423
1424
1425
1426
  
  	hlist_for_each_entry(pol, chain, bydst_inexact_list) {
  		pol->pos = i;
  		i++;
  	}
24969facd   Florian Westphal   xfrm: policy: sto...
1427
  }
a927d6af5   Florian Westphal   xfrm: policy: spl...
1428
1429
1430
  static struct xfrm_policy *xfrm_policy_insert_list(struct hlist_head *chain,
  						   struct xfrm_policy *policy,
  						   bool excl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
  {
a927d6af5   Florian Westphal   xfrm: policy: spl...
1432
  	struct xfrm_policy *pol, *newpos = NULL, *delpol = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433

b67bfe0d4   Sasha Levin   hlist: drop the n...
1434
  	hlist_for_each_entry(pol, chain, bydst) {
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
1435
  		if (pol->type == policy->type &&
7e6526404   Steffen Klassert   xfrm: Add a new l...
1436
  		    pol->if_id == policy->if_id &&
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1437
  		    !selector_cmp(&pol->selector, &policy->selector) &&
4f47e8ab6   Xin Long   xfrm: policy: mat...
1438
  		    xfrm_policy_mark_match(&policy->mark, pol) &&
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
1439
1440
  		    xfrm_sec_ctx_match(pol->security, policy->security) &&
  		    !WARN_ON(delpol)) {
a927d6af5   Florian Westphal   xfrm: policy: spl...
1441
1442
  			if (excl)
  				return ERR_PTR(-EEXIST);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443
1444
1445
1446
  			delpol = pol;
  			if (policy->priority > pol->priority)
  				continue;
  		} else if (policy->priority >= pol->priority) {
a927d6af5   Florian Westphal   xfrm: policy: spl...
1447
  			newpos = pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
1449
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
1451
  		if (delpol)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452
  	}
24969facd   Florian Westphal   xfrm: policy: sto...
1453

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454
  	if (newpos)
a927d6af5   Florian Westphal   xfrm: policy: spl...
1455
  		hlist_add_behind_rcu(&policy->bydst, &newpos->bydst);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1456
  	else
9dffff200   Florian Westphal   xfrm: policy: use...
1457
  		hlist_add_head_rcu(&policy->bydst, chain);
a927d6af5   Florian Westphal   xfrm: policy: spl...
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
  
  	return delpol;
  }
  
  int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
  {
  	struct net *net = xp_net(policy);
  	struct xfrm_policy *delpol;
  	struct hlist_head *chain;
  
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
  	chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
24969facd   Florian Westphal   xfrm: policy: sto...
1470
  	if (chain)
cc1bb845a   Florian Westphal   xfrm: policy: ret...
1471
  		delpol = xfrm_policy_insert_list(chain, policy, excl);
24969facd   Florian Westphal   xfrm: policy: sto...
1472
1473
  	else
  		delpol = xfrm_policy_inexact_insert(policy, dir, excl);
a927d6af5   Florian Westphal   xfrm: policy: spl...
1474
1475
1476
1477
1478
  
  	if (IS_ERR(delpol)) {
  		spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
  		return PTR_ERR(delpol);
  	}
12bfa8bdb   Herbert Xu   xfrm: Use __xfrm_...
1479
  	__xfrm_policy_link(policy, dir);
ca4c3fc24   fan.du   net: split rt_gen...
1480
1481
1482
1483
1484
1485
  
  	/* After previous checking, family can either be AF_INET or AF_INET6 */
  	if (policy->family == AF_INET)
  		rt_genid_bump_ipv4(net);
  	else
  		rt_genid_bump_ipv6(net);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1486
1487
  	if (delpol) {
  		xfrm_policy_requeue(delpol, policy);
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
1488
  		__xfrm_policy_unlink(delpol, dir);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1489
  	}
e682adf02   Fan Du   xfrm: Try to hono...
1490
  	policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
1491
  	hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
386c5680e   Arnd Bergmann   xfrm: use time64_...
1492
  	policy->curlft.add_time = ktime_get_real_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
1495
  	policy->curlft.use_time = 0;
  	if (!mod_timer(&policy->timer, jiffies + HZ))
  		xfrm_pol_hold(policy);
9d0380df6   Florian Westphal   xfrm: policy: con...
1496
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497

9b78a82c1   David S. Miller   [IPSEC]: Fix poli...
1498
  	if (delpol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499
  		xfrm_policy_kill(delpol);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
1500
1501
  	else if (xfrm_bydst_should_resize(net, dir, NULL))
  		schedule_work(&net->xfrm.policy_hash_work);
9b78a82c1   David S. Miller   [IPSEC]: Fix poli...
1502

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
1505
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_policy_insert);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1506
  static struct xfrm_policy *
4f47e8ab6   Xin Long   xfrm: policy: mat...
1507
1508
  __xfrm_policy_bysel_ctx(struct hlist_head *chain, const struct xfrm_mark *mark,
  			u32 if_id, u8 type, int dir, struct xfrm_selector *sel,
6be3b0db6   Florian Westphal   xfrm: policy: add...
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
  			struct xfrm_sec_ctx *ctx)
  {
  	struct xfrm_policy *pol;
  
  	if (!chain)
  		return NULL;
  
  	hlist_for_each_entry(pol, chain, bydst) {
  		if (pol->type == type &&
  		    pol->if_id == if_id &&
4f47e8ab6   Xin Long   xfrm: policy: mat...
1519
  		    xfrm_policy_mark_match(mark, pol) &&
6be3b0db6   Florian Westphal   xfrm: policy: add...
1520
1521
1522
1523
1524
1525
1526
  		    !selector_cmp(sel, &pol->selector) &&
  		    xfrm_sec_ctx_match(ctx, pol->security))
  			return pol;
  	}
  
  	return NULL;
  }
4f47e8ab6   Xin Long   xfrm: policy: mat...
1527
1528
1529
1530
  struct xfrm_policy *
  xfrm_policy_bysel_ctx(struct net *net, const struct xfrm_mark *mark, u32 if_id,
  		      u8 type, int dir, struct xfrm_selector *sel,
  		      struct xfrm_sec_ctx *ctx, int delete, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531
  {
24969facd   Florian Westphal   xfrm: policy: sto...
1532
1533
  	struct xfrm_pol_inexact_bin *bin = NULL;
  	struct xfrm_policy *pol, *ret = NULL;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1534
  	struct hlist_head *chain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535

ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
1536
  	*err = 0;
9d0380df6   Florian Westphal   xfrm: policy: con...
1537
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
8d1211a6a   Alexey Dobriyan   netns xfrm: findi...
1538
  	chain = policy_hash_bysel(net, sel, sel->family, dir);
24969facd   Florian Westphal   xfrm: policy: sto...
1539
  	if (!chain) {
6be3b0db6   Florian Westphal   xfrm: policy: add...
1540
1541
  		struct xfrm_pol_inexact_candidates cand;
  		int i;
24969facd   Florian Westphal   xfrm: policy: sto...
1542
  		bin = xfrm_policy_inexact_lookup(net, type,
b5fe22e23   Florian Westphal   xfrm: policy: con...
1543
  						 sel->family, dir, if_id);
24969facd   Florian Westphal   xfrm: policy: sto...
1544
1545
1546
1547
  		if (!bin) {
  			spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
  			return NULL;
  		}
6be3b0db6   Florian Westphal   xfrm: policy: add...
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
  		if (!xfrm_policy_find_inexact_candidates(&cand, bin,
  							 &sel->saddr,
  							 &sel->daddr)) {
  			spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
  			return NULL;
  		}
  
  		pol = NULL;
  		for (i = 0; i < ARRAY_SIZE(cand.res); i++) {
  			struct xfrm_policy *tmp;
  
  			tmp = __xfrm_policy_bysel_ctx(cand.res[i], mark,
  						      if_id, type, dir,
  						      sel, ctx);
39aa6928d   Florian Westphal   xfrm: policy: fix...
1562
1563
1564
1565
  			if (!tmp)
  				continue;
  
  			if (!pol || tmp->pos < pol->pos)
6be3b0db6   Florian Westphal   xfrm: policy: add...
1566
1567
1568
1569
1570
  				pol = tmp;
  		}
  	} else {
  		pol = __xfrm_policy_bysel_ctx(chain, mark, if_id, type, dir,
  					      sel, ctx);
24969facd   Florian Westphal   xfrm: policy: sto...
1571
  	}
6be3b0db6   Florian Westphal   xfrm: policy: add...
1572
1573
1574
1575
1576
1577
1578
  	if (pol) {
  		xfrm_pol_hold(pol);
  		if (delete) {
  			*err = security_xfrm_policy_delete(pol->security);
  			if (*err) {
  				spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
  				return pol;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1579
  			}
6be3b0db6   Florian Westphal   xfrm: policy: add...
1580
  			__xfrm_policy_unlink(pol, dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581
  		}
6be3b0db6   Florian Westphal   xfrm: policy: add...
1582
  		ret = pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
  	}
9d0380df6   Florian Westphal   xfrm: policy: con...
1584
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1585

fe1a5f031   Timo Teräs   flow: virtualize ...
1586
  	if (ret && delete)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1587
  		xfrm_policy_kill(ret);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1588
1589
  	if (bin && delete)
  		xfrm_policy_inexact_prune_bin(bin);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1590
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1592
  EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593

4f47e8ab6   Xin Long   xfrm: policy: mat...
1594
1595
1596
  struct xfrm_policy *
  xfrm_policy_byid(struct net *net, const struct xfrm_mark *mark, u32 if_id,
  		 u8 type, int dir, u32 id, int delete, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1598
1599
  	struct xfrm_policy *pol, *ret;
  	struct hlist_head *chain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600

b5505c6e1   Herbert Xu   [IPSEC]: Check va...
1601
1602
1603
  	*err = -ENOENT;
  	if (xfrm_policy_id2dir(id) != dir)
  		return NULL;
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
1604
  	*err = 0;
9d0380df6   Florian Westphal   xfrm: policy: con...
1605
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
8d1211a6a   Alexey Dobriyan   netns xfrm: findi...
1606
  	chain = net->xfrm.policy_byidx + idx_hash(net, id);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1607
  	ret = NULL;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1608
  	hlist_for_each_entry(pol, chain, byidx) {
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
1609
  		if (pol->type == type && pol->index == id &&
4f47e8ab6   Xin Long   xfrm: policy: mat...
1610
  		    pol->if_id == if_id && xfrm_policy_mark_match(mark, pol)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
  			xfrm_pol_hold(pol);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1612
  			if (delete) {
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1613
1614
  				*err = security_xfrm_policy_delete(
  								pol->security);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
1615
  				if (*err) {
9d0380df6   Florian Westphal   xfrm: policy: con...
1616
  					spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
1617
1618
  					return pol;
  				}
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
1619
  				__xfrm_policy_unlink(pol, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1620
1621
  			}
  			ret = pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1622
1623
1624
  			break;
  		}
  	}
9d0380df6   Florian Westphal   xfrm: policy: con...
1625
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626

fe1a5f031   Timo Teräs   flow: virtualize ...
1627
  	if (ret && delete)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1628
  		xfrm_policy_kill(ret);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1629
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1630
1631
  }
  EXPORT_SYMBOL(xfrm_policy_byid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
1632
1633
  #ifdef CONFIG_SECURITY_NETWORK_XFRM
  static inline int
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
1634
  xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
  {
ceb159e30   Florian Westphal   xfrm: security: i...
1636
1637
  	struct xfrm_policy *pol;
  	int err = 0;
4aa2e62c4   Joy Latten   xfrm: Add securit...
1638

ceb159e30   Florian Westphal   xfrm: security: i...
1639
1640
1641
1642
1643
  	list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
  		if (pol->walk.dead ||
  		    xfrm_policy_id2dir(pol->index) >= XFRM_POLICY_MAX ||
  		    pol->type != type)
  			continue;
4aa2e62c4   Joy Latten   xfrm: Add securit...
1644

ceb159e30   Florian Westphal   xfrm: security: i...
1645
1646
1647
1648
  		err = security_xfrm_policy_delete(pol->security);
  		if (err) {
  			xfrm_audit_policy_delete(pol, 0, task_valid);
  			return err;
4aa2e62c4   Joy Latten   xfrm: Add securit...
1649
1650
1651
1652
1653
1654
  		}
  	}
  	return err;
  }
  #else
  static inline int
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
1655
  xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
4aa2e62c4   Joy Latten   xfrm: Add securit...
1656
1657
1658
1659
  {
  	return 0;
  }
  #endif
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
1660
  int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
4aa2e62c4   Joy Latten   xfrm: Add securit...
1661
  {
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
1662
  	int dir, err = 0, cnt = 0;
ceb159e30   Florian Westphal   xfrm: security: i...
1663
  	struct xfrm_policy *pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664

9d0380df6   Florian Westphal   xfrm: policy: con...
1665
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
4aa2e62c4   Joy Latten   xfrm: Add securit...
1666

2e71029e2   Tetsuo Handa   xfrm: Remove usel...
1667
  	err = xfrm_policy_flush_secctx_check(net, type, task_valid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
1668
1669
  	if (err)
  		goto out;
ceb159e30   Florian Westphal   xfrm: security: i...
1670
1671
1672
1673
1674
1675
1676
  again:
  	list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
  		dir = xfrm_policy_id2dir(pol->index);
  		if (pol->walk.dead ||
  		    dir >= XFRM_POLICY_MAX ||
  		    pol->type != type)
  			continue;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1677

ceb159e30   Florian Westphal   xfrm: security: i...
1678
1679
1680
1681
1682
1683
1684
  		__xfrm_policy_unlink(pol, dir);
  		spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
  		cnt++;
  		xfrm_audit_policy_delete(pol, 1, task_valid);
  		xfrm_policy_kill(pol);
  		spin_lock_bh(&net->xfrm.xfrm_policy_lock);
  		goto again;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1685
  	}
24969facd   Florian Westphal   xfrm: policy: sto...
1686
1687
1688
  	if (cnt)
  		__xfrm_policy_inexact_flush(net);
  	else
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
1689
  		err = -ESRCH;
4aa2e62c4   Joy Latten   xfrm: Add securit...
1690
  out:
9d0380df6   Florian Westphal   xfrm: policy: con...
1691
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
4aa2e62c4   Joy Latten   xfrm: Add securit...
1692
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693
1694
  }
  EXPORT_SYMBOL(xfrm_policy_flush);
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
1695
  int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
4c563f766   Timo Teras   [XFRM]: Speed up ...
1696
  		     int (*func)(struct xfrm_policy *, int, int, void*),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
1698
  		     void *data)
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
1699
1700
  	struct xfrm_policy *pol;
  	struct xfrm_policy_walk_entry *x;
4c563f766   Timo Teras   [XFRM]: Speed up ...
1701
1702
1703
1704
1705
  	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
1706

12a169e7d   Herbert Xu   ipsec: Put dumper...
1707
  	if (list_empty(&walk->walk.all) && walk->seq != 0)
4c563f766   Timo Teras   [XFRM]: Speed up ...
1708
  		return 0;
9d0380df6   Florian Westphal   xfrm: policy: con...
1709
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
1710
  	if (list_empty(&walk->walk.all))
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
1711
  		x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
12a169e7d   Herbert Xu   ipsec: Put dumper...
1712
  	else
800777026   Li RongQing   xfrm: optimise th...
1713
1714
  		x = list_first_entry(&walk->walk.all,
  				     struct xfrm_policy_walk_entry, all);
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
1715
  	list_for_each_entry_from(x, &net->xfrm.policy_all, all) {
12a169e7d   Herbert Xu   ipsec: Put dumper...
1716
  		if (x->dead)
4c563f766   Timo Teras   [XFRM]: Speed up ...
1717
  			continue;
12a169e7d   Herbert Xu   ipsec: Put dumper...
1718
1719
1720
1721
1722
1723
1724
1725
1726
  		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...
1727
  		}
12a169e7d   Herbert Xu   ipsec: Put dumper...
1728
  		walk->seq++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
  	}
12a169e7d   Herbert Xu   ipsec: Put dumper...
1730
  	if (walk->seq == 0) {
baf5d743d   Jamal Hadi Salim   [XFRM] Optimize p...
1731
1732
1733
  		error = -ENOENT;
  		goto out;
  	}
12a169e7d   Herbert Xu   ipsec: Put dumper...
1734
  	list_del_init(&walk->walk.all);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1735
  out:
9d0380df6   Florian Westphal   xfrm: policy: con...
1736
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1737
1738
1739
  	return error;
  }
  EXPORT_SYMBOL(xfrm_policy_walk);
12a169e7d   Herbert Xu   ipsec: Put dumper...
1740
1741
1742
1743
1744
1745
1746
1747
  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);
283bc9f35   Fan Du   xfrm: Namespacify...
1748
  void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net)
12a169e7d   Herbert Xu   ipsec: Put dumper...
1749
1750
1751
  {
  	if (list_empty(&walk->walk.all))
  		return;
9d0380df6   Florian Westphal   xfrm: policy: con...
1752
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */
12a169e7d   Herbert Xu   ipsec: Put dumper...
1753
  	list_del(&walk->walk.all);
9d0380df6   Florian Westphal   xfrm: policy: con...
1754
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
1755
1756
  }
  EXPORT_SYMBOL(xfrm_policy_walk_done);
134b0fc54   James Morris   IPsec: propagate ...
1757
1758
1759
1760
1761
  /*
   * Find policy to apply to this flow.
   *
   * Returns 0 if policy found, else an -errno.
   */
f299d557c   David S. Miller   xfrm: Const'ify p...
1762
1763
  static int xfrm_policy_match(const struct xfrm_policy *pol,
  			     const struct flowi *fl,
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
1764
  			     u8 type, u16 family, int dir, u32 if_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765
  {
f299d557c   David S. Miller   xfrm: Const'ify p...
1766
  	const struct xfrm_selector *sel = &pol->selector;
bc9b35ad4   David S. Miller   xfrm: Convert sev...
1767
1768
  	int ret = -ESRCH;
  	bool match;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1769

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1770
  	if (pol->family != family ||
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
1771
  	    pol->if_id != if_id ||
1d28f42c1   David S. Miller   net: Put flowi_* ...
1772
  	    (fl->flowi_mark & pol->mark.m) != pol->mark.v ||
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1773
  	    pol->type != type)
134b0fc54   James Morris   IPsec: propagate ...
1774
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1776
  	match = xfrm_selector_match(sel, fl, family);
134b0fc54   James Morris   IPsec: propagate ...
1777
  	if (match)
1d28f42c1   David S. Miller   net: Put flowi_* ...
1778
  		ret = security_xfrm_policy_lookup(pol->security, fl->flowi_secid,
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1779
  						  dir);
134b0fc54   James Morris   IPsec: propagate ...
1780
  	return ret;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1781
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782

9cf545ebd   Florian Westphal   xfrm: policy: sto...
1783
1784
  static struct xfrm_pol_inexact_node *
  xfrm_policy_lookup_inexact_addr(const struct rb_root *r,
77cc278f7   Ahmed S. Darwish   xfrm: policy: Use...
1785
  				seqcount_spinlock_t *count,
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
  				const xfrm_address_t *addr, u16 family)
  {
  	const struct rb_node *parent;
  	int seq;
  
  again:
  	seq = read_seqcount_begin(count);
  
  	parent = rcu_dereference_raw(r->rb_node);
  	while (parent) {
  		struct xfrm_pol_inexact_node *node;
  		int delta;
  
  		node = rb_entry(parent, struct xfrm_pol_inexact_node, node);
  
  		delta = xfrm_policy_addr_delta(addr, &node->addr,
  					       node->prefixlen, family);
  		if (delta < 0) {
  			parent = rcu_dereference_raw(parent->rb_left);
  			continue;
  		} else if (delta > 0) {
  			parent = rcu_dereference_raw(parent->rb_right);
  			continue;
  		}
  
  		return node;
  	}
  
  	if (read_seqcount_retry(count, seq))
  		goto again;
  
  	return NULL;
  }
6be3b0db6   Florian Westphal   xfrm: policy: add...
1819
1820
1821
1822
1823
1824
  static bool
  xfrm_policy_find_inexact_candidates(struct xfrm_pol_inexact_candidates *cand,
  				    struct xfrm_pol_inexact_bin *b,
  				    const xfrm_address_t *saddr,
  				    const xfrm_address_t *daddr)
  {
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1825
1826
  	struct xfrm_pol_inexact_node *n;
  	u16 family;
6be3b0db6   Florian Westphal   xfrm: policy: add...
1827
1828
  	if (!b)
  		return false;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1829
  	family = b->k.family;
6be3b0db6   Florian Westphal   xfrm: policy: add...
1830
1831
  	memset(cand, 0, sizeof(*cand));
  	cand->res[XFRM_POL_CAND_ANY] = &b->hhead;
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1832
1833
1834
  
  	n = xfrm_policy_lookup_inexact_addr(&b->root_d, &b->count, daddr,
  					    family);
6ac098b2a   Florian Westphal   xfrm: policy: add...
1835
  	if (n) {
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1836
  		cand->res[XFRM_POL_CAND_DADDR] = &n->hhead;
6ac098b2a   Florian Westphal   xfrm: policy: add...
1837
1838
1839
1840
1841
  		n = xfrm_policy_lookup_inexact_addr(&n->root, &b->count, saddr,
  						    family);
  		if (n)
  			cand->res[XFRM_POL_CAND_BOTH] = &n->hhead;
  	}
9cf545ebd   Florian Westphal   xfrm: policy: sto...
1842

64a09a7bf   Florian Westphal   xfrm: policy: sto...
1843
1844
1845
1846
  	n = xfrm_policy_lookup_inexact_addr(&b->root_s, &b->count, saddr,
  					    family);
  	if (n)
  		cand->res[XFRM_POL_CAND_SADDR] = &n->hhead;
6be3b0db6   Florian Westphal   xfrm: policy: add...
1847
1848
  	return true;
  }
24969facd   Florian Westphal   xfrm: policy: sto...
1849
  static struct xfrm_pol_inexact_bin *
b5fe22e23   Florian Westphal   xfrm: policy: con...
1850
1851
  xfrm_policy_inexact_lookup_rcu(struct net *net, u8 type, u16 family,
  			       u8 dir, u32 if_id)
24969facd   Florian Westphal   xfrm: policy: sto...
1852
1853
1854
1855
1856
  {
  	struct xfrm_pol_inexact_key k = {
  		.family = family,
  		.type = type,
  		.dir = dir,
b5fe22e23   Florian Westphal   xfrm: policy: con...
1857
  		.if_id = if_id,
24969facd   Florian Westphal   xfrm: policy: sto...
1858
1859
1860
1861
1862
1863
1864
1865
1866
  	};
  
  	write_pnet(&k.net, net);
  
  	return rhashtable_lookup(&xfrm_policy_inexact_table, &k,
  				 xfrm_pol_inexact_params);
  }
  
  static struct xfrm_pol_inexact_bin *
b5fe22e23   Florian Westphal   xfrm: policy: con...
1867
1868
  xfrm_policy_inexact_lookup(struct net *net, u8 type, u16 family,
  			   u8 dir, u32 if_id)
24969facd   Florian Westphal   xfrm: policy: sto...
1869
1870
1871
1872
1873
1874
  {
  	struct xfrm_pol_inexact_bin *bin;
  
  	lockdep_assert_held(&net->xfrm.xfrm_policy_lock);
  
  	rcu_read_lock();
b5fe22e23   Florian Westphal   xfrm: policy: con...
1875
  	bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id);
24969facd   Florian Westphal   xfrm: policy: sto...
1876
1877
1878
1879
  	rcu_read_unlock();
  
  	return bin;
  }
6be3b0db6   Florian Westphal   xfrm: policy: add...
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
  static struct xfrm_policy *
  __xfrm_policy_eval_candidates(struct hlist_head *chain,
  			      struct xfrm_policy *prefer,
  			      const struct flowi *fl,
  			      u8 type, u16 family, int dir, u32 if_id)
  {
  	u32 priority = prefer ? prefer->priority : ~0u;
  	struct xfrm_policy *pol;
  
  	if (!chain)
  		return NULL;
  
  	hlist_for_each_entry_rcu(pol, chain, bydst) {
  		int err;
  
  		if (pol->priority > priority)
  			break;
  
  		err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
  		if (err) {
  			if (err != -ESRCH)
  				return ERR_PTR(err);
  
  			continue;
  		}
  
  		if (prefer) {
  			/* matches.  Is it older than *prefer? */
  			if (pol->priority == priority &&
  			    prefer->pos < pol->pos)
  				return prefer;
  		}
  
  		return pol;
  	}
  
  	return NULL;
  }
  
  static struct xfrm_policy *
  xfrm_policy_eval_candidates(struct xfrm_pol_inexact_candidates *cand,
  			    struct xfrm_policy *prefer,
  			    const struct flowi *fl,
  			    u8 type, u16 family, int dir, u32 if_id)
  {
  	struct xfrm_policy *tmp;
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(cand->res); i++) {
  		tmp = __xfrm_policy_eval_candidates(cand->res[i],
  						    prefer,
  						    fl, type, family, dir,
  						    if_id);
  		if (!tmp)
  			continue;
  
  		if (IS_ERR(tmp))
  			return tmp;
  		prefer = tmp;
  	}
  
  	return prefer;
  }
52479b623   Alexey Dobriyan   netns xfrm: looku...
1943
  static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
062cdb43b   David S. Miller   xfrm: Mark flowi ...
1944
  						     const struct flowi *fl,
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
1945
1946
  						     u16 family, u8 dir,
  						     u32 if_id)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1947
  {
6be3b0db6   Florian Westphal   xfrm: policy: add...
1948
  	struct xfrm_pol_inexact_candidates cand;
0b597e7ed   David S. Miller   xfrm: Const'ify l...
1949
  	const xfrm_address_t *daddr, *saddr;
24969facd   Florian Westphal   xfrm: policy: sto...
1950
1951
  	struct xfrm_pol_inexact_bin *bin;
  	struct xfrm_policy *pol, *ret;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1952
  	struct hlist_head *chain;
30846090a   Florian Westphal   xfrm: policy: add...
1953
  	unsigned int sequence;
24969facd   Florian Westphal   xfrm: policy: sto...
1954
  	int err;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1955

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1956
1957
1958
1959
  	daddr = xfrm_flowi_daddr(fl, family);
  	saddr = xfrm_flowi_saddr(fl, family);
  	if (unlikely(!daddr || !saddr))
  		return NULL;
a7c44247f   Florian Westphal   xfrm: policy: mak...
1960
  	rcu_read_lock();
30846090a   Florian Westphal   xfrm: policy: add...
1961
1962
1963
1964
1965
   retry:
  	do {
  		sequence = read_seqcount_begin(&xfrm_policy_hash_generation);
  		chain = policy_hash_direct(net, daddr, saddr, family, dir);
  	} while (read_seqcount_retry(&xfrm_policy_hash_generation, sequence));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1966
  	ret = NULL;
a5eefc1df   Florian Westphal   xfrm: policy: use...
1967
  	hlist_for_each_entry_rcu(pol, chain, bydst) {
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
1968
  		err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
134b0fc54   James Morris   IPsec: propagate ...
1969
1970
1971
1972
1973
1974
1975
1976
  		if (err) {
  			if (err == -ESRCH)
  				continue;
  			else {
  				ret = ERR_PTR(err);
  				goto fail;
  			}
  		} else {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1977
1978
1979
1980
  			ret = pol;
  			break;
  		}
  	}
b5fe22e23   Florian Westphal   xfrm: policy: con...
1981
  	bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id);
6be3b0db6   Florian Westphal   xfrm: policy: add...
1982
1983
  	if (!bin || !xfrm_policy_find_inexact_candidates(&cand, bin, saddr,
  							 daddr))
24969facd   Florian Westphal   xfrm: policy: sto...
1984
  		goto skip_inexact;
8faf491e6   Li RongQing   xfrm: optimise to...
1985

6be3b0db6   Florian Westphal   xfrm: policy: add...
1986
1987
1988
1989
1990
1991
  	pol = xfrm_policy_eval_candidates(&cand, ret, fl, type,
  					  family, dir, if_id);
  	if (pol) {
  		ret = pol;
  		if (IS_ERR(pol))
  			goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
  	}
586f2eb41   Li RongQing   xfrm: remove the ...
1993

24969facd   Florian Westphal   xfrm: policy: sto...
1994
  skip_inexact:
30846090a   Florian Westphal   xfrm: policy: add...
1995
1996
  	if (read_seqcount_retry(&xfrm_policy_hash_generation, sequence))
  		goto retry;
e37cc8ade   Florian Westphal   xfrm: policy: use...
1997
1998
  	if (ret && !xfrm_pol_hold_rcu(ret))
  		goto retry;
134b0fc54   James Morris   IPsec: propagate ...
1999
  fail:
a7c44247f   Florian Westphal   xfrm: policy: mak...
2000
  	rcu_read_unlock();
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2001

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2002
  	return ret;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2003
  }
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2004
2005
2006
  static struct xfrm_policy *xfrm_policy_lookup(struct net *net,
  					      const struct flowi *fl,
  					      u16 family, u8 dir, u32 if_id)
80c802f30   Timo Teräs   xfrm: cache bundl...
2007
2008
2009
  {
  #ifdef CONFIG_XFRM_SUB_POLICY
  	struct xfrm_policy *pol;
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2010
2011
  	pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family,
  					dir, if_id);
80c802f30   Timo Teräs   xfrm: cache bundl...
2012
2013
2014
  	if (pol != NULL)
  		return pol;
  #endif
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2015
2016
  	return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family,
  					 dir, if_id);
80c802f30   Timo Teräs   xfrm: cache bundl...
2017
  }
6f9c96154   Eric Dumazet   inet: constify ip...
2018
  static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2019
2020
  						 const struct flowi *fl,
  						 u16 family, u32 if_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2021
2022
  {
  	struct xfrm_policy *pol;
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
2023
  	rcu_read_lock();
ae33786f7   Florian Westphal   xfrm: policy: onl...
2024
   again:
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
2025
2026
  	pol = rcu_dereference(sk->sk_policy[dir]);
  	if (pol != NULL) {
ddc47e440   Steffen Klassert   xfrm: Fix stack-o...
2027
  		bool match;
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
2028
  		int err = 0;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2029

ddc47e440   Steffen Klassert   xfrm: Fix stack-o...
2030
2031
2032
2033
2034
2035
  		if (pol->family != family) {
  			pol = NULL;
  			goto out;
  		}
  
  		match = xfrm_selector_match(&pol->selector, fl, family);
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2036
  		if (match) {
7e6526404   Steffen Klassert   xfrm: Add a new l...
2037
  			if ((sk->sk_mark & pol->mark.m) != pol->mark.v ||
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2038
  			    pol->if_id != if_id) {
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
2039
2040
2041
  				pol = NULL;
  				goto out;
  			}
03e1ad7b5   Paul Moore   LSM: Make the Lab...
2042
  			err = security_xfrm_policy_lookup(pol->security,
1d28f42c1   David S. Miller   net: Put flowi_* ...
2043
  						      fl->flowi_secid,
aff669bc2   Florian Westphal   xfrm_policy: kill...
2044
  						      dir);
330e832ab   Florian Westphal   xfrm: unbreak xfr...
2045
2046
2047
2048
  			if (!err) {
  				if (!xfrm_pol_hold_rcu(pol))
  					goto again;
  			} else if (err == -ESRCH) {
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2049
  				pol = NULL;
330e832ab   Florian Westphal   xfrm: unbreak xfr...
2050
  			} else {
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2051
  				pol = ERR_PTR(err);
330e832ab   Florian Westphal   xfrm: unbreak xfr...
2052
  			}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2053
  		} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
2055
  			pol = NULL;
  	}
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
2056
  out:
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
2057
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058
2059
2060
2061
2062
  	return pol;
  }
  
  static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
  {
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
2063
  	struct net *net = xp_net(pol);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2064

98806f75b   Alexey Dobriyan   netns xfrm: trivi...
2065
  	list_add(&pol->walk.all, &net->xfrm.policy_all);
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
2066
  	net->xfrm.policy_count[dir]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2067
2068
2069
2070
2071
2072
  	xfrm_pol_hold(pol);
  }
  
  static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
  						int dir)
  {
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
2073
  	struct net *net = xp_net(pol);
53c2e285f   Herbert Xu   xfrm: Do not hash...
2074
  	if (list_empty(&pol->walk.all))
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2075
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2076

53c2e285f   Herbert Xu   xfrm: Do not hash...
2077
2078
  	/* Socket policies are not hashed. */
  	if (!hlist_unhashed(&pol->bydst)) {
a5eefc1df   Florian Westphal   xfrm: policy: use...
2079
  		hlist_del_rcu(&pol->bydst);
24969facd   Florian Westphal   xfrm: policy: sto...
2080
  		hlist_del_init(&pol->bydst_inexact_list);
53c2e285f   Herbert Xu   xfrm: Do not hash...
2081
2082
2083
2084
  		hlist_del(&pol->byidx);
  	}
  
  	list_del_init(&pol->walk.all);
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
2085
  	net->xfrm.policy_count[dir]--;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2086
2087
  
  	return pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2088
  }
53c2e285f   Herbert Xu   xfrm: Do not hash...
2089
2090
2091
2092
2093
2094
2095
2096
2097
  static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir)
  {
  	__xfrm_policy_link(pol, XFRM_POLICY_MAX + dir);
  }
  
  static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir)
  {
  	__xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir);
  }
4666faab0   Herbert Xu   [IPSEC] Kill spur...
2098
  int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
  {
283bc9f35   Fan Du   xfrm: Namespacify...
2100
  	struct net *net = xp_net(pol);
9d0380df6   Florian Westphal   xfrm: policy: con...
2101
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
  	pol = __xfrm_policy_unlink(pol, dir);
9d0380df6   Florian Westphal   xfrm: policy: con...
2103
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2104
  	if (pol) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
  		xfrm_policy_kill(pol);
4666faab0   Herbert Xu   [IPSEC] Kill spur...
2106
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2107
  	}
4666faab0   Herbert Xu   [IPSEC] Kill spur...
2108
  	return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109
  }
a70fcb0ba   David S. Miller   [XFRM]: Add some ...
2110
  EXPORT_SYMBOL(xfrm_policy_delete);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
2112
2113
  
  int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
  {
be8f8284c   Lorenzo Colitti   net: xfrm: allow ...
2114
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2115
  	struct xfrm_policy *old_pol;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2116
2117
2118
2119
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pol && pol->type != XFRM_POLICY_TYPE_MAIN)
  		return -EINVAL;
  #endif
9d0380df6   Florian Westphal   xfrm: policy: con...
2120
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
2121
2122
  	old_pol = rcu_dereference_protected(sk->sk_policy[dir],
  				lockdep_is_held(&net->xfrm.xfrm_policy_lock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123
  	if (pol) {
386c5680e   Arnd Bergmann   xfrm: use time64_...
2124
  		pol->curlft.add_time = ktime_get_real_seconds();
e682adf02   Fan Du   xfrm: Try to hono...
2125
  		pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
53c2e285f   Herbert Xu   xfrm: Do not hash...
2126
  		xfrm_sk_policy_link(pol, dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
  	}
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
2128
  	rcu_assign_pointer(sk->sk_policy[dir], pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2129
2130
2131
  	if (old_pol) {
  		if (pol)
  			xfrm_policy_requeue(old_pol, pol);
ea2dea9da   Timo Teräs   xfrm: remove poli...
2132
2133
2134
  		/* Unlinking succeeds always. This is the only function
  		 * allowed to delete or replace socket policy.
  		 */
53c2e285f   Herbert Xu   xfrm: Do not hash...
2135
  		xfrm_sk_policy_unlink(old_pol, dir);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2136
  	}
9d0380df6   Florian Westphal   xfrm: policy: con...
2137
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2138
2139
2140
2141
2142
2143
  
  	if (old_pol) {
  		xfrm_policy_kill(old_pol);
  	}
  	return 0;
  }
d3e40a9f5   David S. Miller   xfrm: Const'ify p...
2144
  static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2145
  {
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
2146
  	struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
283bc9f35   Fan Du   xfrm: Namespacify...
2147
  	struct net *net = xp_net(old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2148
2149
2150
  
  	if (newp) {
  		newp->selector = old->selector;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
2151
2152
  		if (security_xfrm_policy_clone(old->security,
  					       &newp->security)) {
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2153
2154
2155
  			kfree(newp);
  			return NULL;  /* ENOMEM */
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156
2157
  		newp->lft = old->lft;
  		newp->curlft = old->curlft;
fb977e2ca   Jamal Hadi Salim   xfrm: clone mark ...
2158
  		newp->mark = old->mark;
7e6526404   Steffen Klassert   xfrm: Add a new l...
2159
  		newp->if_id = old->if_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
2161
2162
2163
  		newp->action = old->action;
  		newp->flags = old->flags;
  		newp->xfrm_nr = old->xfrm_nr;
  		newp->index = old->index;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2164
  		newp->type = old->type;
0e74aa1d7   Herbert Xu   xfrm: Copy policy...
2165
  		newp->family = old->family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
2167
  		memcpy(newp->xfrm_vec, old->xfrm_vec,
  		       newp->xfrm_nr*sizeof(struct xfrm_tmpl));
9d0380df6   Florian Westphal   xfrm: policy: con...
2168
  		spin_lock_bh(&net->xfrm.xfrm_policy_lock);
53c2e285f   Herbert Xu   xfrm: Do not hash...
2169
  		xfrm_sk_policy_link(newp, dir);
9d0380df6   Florian Westphal   xfrm: policy: con...
2170
  		spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171
2172
2173
2174
  		xfrm_pol_put(newp);
  	}
  	return newp;
  }
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
2175
  int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
  {
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
  	const struct xfrm_policy *p;
  	struct xfrm_policy *np;
  	int i, ret = 0;
  
  	rcu_read_lock();
  	for (i = 0; i < 2; i++) {
  		p = rcu_dereference(osk->sk_policy[i]);
  		if (p) {
  			np = clone_policy(p, i);
  			if (unlikely(!np)) {
  				ret = -ENOMEM;
  				break;
  			}
  			rcu_assign_pointer(sk->sk_policy[i], np);
  		}
  	}
  	rcu_read_unlock();
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195
  }
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
2196
  static int
42a7b32b7   David Ahern   xfrm: Add oif to ...
2197
  xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
2198
  	       xfrm_address_t *remote, unsigned short family, u32 mark)
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
2199
2200
  {
  	int err;
37b103830   Florian Westphal   xfrm: policy: mak...
2201
  	const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
2202
2203
2204
  
  	if (unlikely(afinfo == NULL))
  		return -EINVAL;
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
2205
  	err = afinfo->get_saddr(net, oif, local, remote, mark);
bdba9fe01   Florian Westphal   xfrm: policy: rem...
2206
  	rcu_read_unlock();
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
2207
2208
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2209
2210
2211
  /* Resolve list of templates for the flow, given policy. */
  
  static int
a6c2e6111   David S. Miller   xfrm: Mark flowi ...
2212
2213
  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
2214
  {
fbda33b2b   Alexey Dobriyan   netns xfrm: ->get...
2215
  	struct net *net = xp_net(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2216
2217
  	int nx;
  	int i, error;
948021518   Steffen Klassert   Revert "xfrm: Fix...
2218
2219
  	xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
  	xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
2220
  	xfrm_address_t tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221

9b7a787d0   Weilong Chen   xfrm: checkpatch ...
2222
  	for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2223
  		struct xfrm_state *x;
948021518   Steffen Klassert   Revert "xfrm: Fix...
2224
2225
  		xfrm_address_t *remote = daddr;
  		xfrm_address_t *local  = saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2226
  		struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
948021518   Steffen Klassert   Revert "xfrm: Fix...
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
  		if (tmpl->mode == XFRM_MODE_TUNNEL ||
  		    tmpl->mode == XFRM_MODE_BEET) {
  			remote = &tmpl->id.daddr;
  			local = &tmpl->saddr;
  			if (xfrm_addr_any(local, tmpl->encap_family)) {
  				error = xfrm_get_saddr(net, fl->flowi_oif,
  						       &tmp, remote,
  						       tmpl->encap_family, 0);
  				if (error)
  					goto fail;
  				local = &tmp;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2239
  		}
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2240
2241
  		x = xfrm_state_find(remote, local, fl, tmpl, policy, &error,
  				    family, policy->if_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2242
2243
2244
  
  		if (x && x->km.state == XFRM_STATE_VALID) {
  			xfrm[nx++] = x;
948021518   Steffen Klassert   Revert "xfrm: Fix...
2245
2246
  			daddr = remote;
  			saddr = local;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2247
2248
2249
2250
2251
2252
  			continue;
  		}
  		if (x) {
  			error = (x->km.state == XFRM_STATE_ERROR ?
  				 -EINVAL : -EAGAIN);
  			xfrm_state_put(x);
42054569f   Weilong Chen   xfrm: fix checkpa...
2253
  		} else if (error == -ESRCH) {
a43222661   fernando@oss.ntt.co   xfrm: do not leak...
2254
  			error = -EAGAIN;
42054569f   Weilong Chen   xfrm: fix checkpa...
2255
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2256
2257
2258
2259
2260
2261
2262
  
  		if (!tmpl->optional)
  			goto fail;
  	}
  	return nx;
  
  fail:
9b7a787d0   Weilong Chen   xfrm: checkpatch ...
2263
  	for (nx--; nx >= 0; nx--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2264
2265
2266
  		xfrm_state_put(xfrm[nx]);
  	return error;
  }
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2267
  static int
a6c2e6111   David S. Miller   xfrm: Mark flowi ...
2268
2269
  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...
2270
  {
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
2271
2272
  	struct xfrm_state *tp[XFRM_MAX_DEPTH];
  	struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
  	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...
2283
2284
  
  		ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2285
2286
2287
2288
2289
2290
  		if (ret < 0) {
  			error = ret;
  			goto fail;
  		} else
  			cnx += ret;
  	}
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
2291
2292
2293
  	/* found states are sorted for outbound processing */
  	if (npols > 1)
  		xfrm_state_sort(xfrm, tpp, cnx, family);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2294
2295
2296
  	return cnx;
  
   fail:
9b7a787d0   Weilong Chen   xfrm: checkpatch ...
2297
  	for (cnx--; cnx >= 0; cnx--)
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
2298
  		xfrm_state_put(tpp[cnx]);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2299
2300
2301
  	return error;
  
  }
f5e2bb4f5   Florian Westphal   xfrm: policy: xfr...
2302
  static int xfrm_get_tos(const struct flowi *fl, int family)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2303
  {
f24ea5287   Florian Westphal   xfrm: remove tos ...
2304
2305
  	if (family == AF_INET)
  		return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos;
143a4454d   Xin Long   xfrm: do not call...
2306

f24ea5287   Florian Westphal   xfrm: remove tos ...
2307
  	return 0;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2308
  }
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2309
  static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2310
  {
37b103830   Florian Westphal   xfrm: policy: mak...
2311
  	const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2312
  	struct dst_ops *dst_ops;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2313
2314
2315
2316
  	struct xfrm_dst *xdst;
  
  	if (!afinfo)
  		return ERR_PTR(-EINVAL);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2317
2318
2319
2320
  	switch (family) {
  	case AF_INET:
  		dst_ops = &net->xfrm.xfrm4_dst_ops;
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
2321
  #if IS_ENABLED(CONFIG_IPV6)
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2322
2323
2324
2325
2326
2327
2328
  	case AF_INET6:
  		dst_ops = &net->xfrm.xfrm6_dst_ops;
  		break;
  #endif
  	default:
  		BUG();
  	}
b2a9c0ed7   Wei Wang   net: remove DST_N...
2329
  	xdst = dst_alloc(dst_ops, NULL, 1, DST_OBSOLETE_NONE, 0);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2330

d4cae5621   Madalin Bucur   net: check return...
2331
  	if (likely(xdst)) {
141e369de   Steffen Klassert   xfrm: Initialize ...
2332
2333
2334
  		struct dst_entry *dst = &xdst->u.dst;
  
  		memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst));
d4cae5621   Madalin Bucur   net: check return...
2335
  	} else
0b1509321   Hiroaki SHIMODA   xfrm: avoid possi...
2336
  		xdst = ERR_PTR(-ENOBUFS);
80c802f30   Timo Teräs   xfrm: cache bundl...
2337

bdba9fe01   Florian Westphal   xfrm: policy: rem...
2338
  	rcu_read_unlock();
d4cae5621   Madalin Bucur   net: check return...
2339

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2340
2341
  	return xdst;
  }
2e8b4aa81   Florian Westphal   xfrm: remove init...
2342
2343
  static void xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst,
  			   int nfheader_len)
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
2344
  {
2e8b4aa81   Florian Westphal   xfrm: remove init...
2345
2346
2347
2348
2349
  	if (dst->ops->family == AF_INET6) {
  		struct rt6_info *rt = (struct rt6_info *)dst;
  		path->path_cookie = rt6_get_cookie(rt);
  		path->u.rt6.rt6i_nfheader_len = nfheader_len;
  	}
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
2350
  }
87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
2351
  static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
0c7b3eefb   David S. Miller   xfrm: Mark flowi ...
2352
  				const struct flowi *fl)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2353
  {
37b103830   Florian Westphal   xfrm: policy: mak...
2354
  	const struct xfrm_policy_afinfo *afinfo =
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2355
2356
2357
2358
  		xfrm_policy_get_afinfo(xdst->u.dst.ops->family);
  	int err;
  
  	if (!afinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2359
  		return -EINVAL;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2360

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

bdba9fe01   Florian Westphal   xfrm: policy: rem...
2363
  	rcu_read_unlock();
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2364

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2365
2366
  	return err;
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
2367

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2368
2369
2370
2371
2372
  /* 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,
5492093dc   David Miller   xfrm: Stop using ...
2373
2374
2375
  					    struct xfrm_state **xfrm,
  					    struct xfrm_dst **bundle,
  					    int nx,
98313adaa   David S. Miller   xfrm: Mark flowi ...
2376
  					    const struct flowi *fl,
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2377
2378
  					    struct dst_entry *dst)
  {
733a5fac2   Florian Westphal   xfrm: remove afin...
2379
  	const struct xfrm_state_afinfo *afinfo;
4c145dce2   Florian Westphal   xfrm: make xfrm m...
2380
  	const struct xfrm_mode *inner_mode;
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2381
  	struct net *net = xp_net(policy);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2382
2383
  	unsigned long now = jiffies;
  	struct net_device *dev;
45b018bed   David Miller   ipsec: Create and...
2384
2385
  	struct xfrm_dst *xdst_prev = NULL;
  	struct xfrm_dst *xdst0 = NULL;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2386
2387
2388
  	int i = 0;
  	int err;
  	int header_len = 0;
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
2389
  	int nfheader_len = 0;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2390
2391
2392
  	int trailer_len = 0;
  	int tos;
  	int family = policy->selector.family;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
2393
2394
2395
  	xfrm_address_t saddr, daddr;
  
  	xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2396
2397
  
  	tos = xfrm_get_tos(fl, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2398
2399
2400
2401
  
  	dst_hold(dst);
  
  	for (; i < nx; i++) {
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2402
  		struct xfrm_dst *xdst = xfrm_alloc_dst(net, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2403
2404
2405
2406
2407
2408
2409
  		struct dst_entry *dst1 = &xdst->u.dst;
  
  		err = PTR_ERR(xdst);
  		if (IS_ERR(xdst)) {
  			dst_release(dst);
  			goto put_states;
  		}
5492093dc   David Miller   xfrm: Stop using ...
2410
  		bundle[i] = xdst;
45b018bed   David Miller   ipsec: Create and...
2411
2412
  		if (!xdst_prev)
  			xdst0 = xdst;
10a7ef336   David Miller   ipsec: Fix dst le...
2413
2414
2415
2416
  		else
  			/* Ref count is taken during xfrm_alloc_dst()
  			 * No need to do dst_clone() on dst1
  			 */
45b018bed   David Miller   ipsec: Create and...
2417
  			xfrm_dst_set_child(xdst_prev, &xdst->u.dst);
10a7ef336   David Miller   ipsec: Fix dst le...
2418

43a4dea4c   Steffen Klassert   xfrm: Assign the ...
2419
2420
2421
2422
2423
2424
2425
2426
2427
  		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
c9500d7b7   Florian Westphal   xfrm: store xfrm_...
2428
  			inner_mode = &xfrm[i]->inner_mode;
43a4dea4c   Steffen Klassert   xfrm: Assign the ...
2429

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2430
  		xdst->route = dst;
defb3519a   David S. Miller   net: Abstract awa...
2431
  		dst_copy_metrics(dst1, dst);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2432
2433
  
  		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
e2612cd49   Benedict Wong   xfrm: Make set-ma...
2434
2435
2436
2437
  			__u32 mark = 0;
  
  			if (xfrm[i]->props.smark.v || xfrm[i]->props.smark.m)
  				mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]);
9b42c1f17   Steffen Klassert   xfrm: Extend the ...
2438

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2439
  			family = xfrm[i]->props.family;
42a7b32b7   David Ahern   xfrm: Add oif to ...
2440
  			dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif,
9b42c1f17   Steffen Klassert   xfrm: Extend the ...
2441
  					      &saddr, &daddr, family, mark);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2442
2443
2444
2445
2446
2447
2448
  			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...
2449
  		xdst->xfrm_genid = xfrm[i]->genid;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2450

f5b0a8743   David S. Miller   net: Document dst...
2451
  		dst1->obsolete = DST_OBSOLETE_FORCE_CHK;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2452
2453
2454
  		dst1->lastuse = now;
  
  		dst1->input = dst_discard;
733a5fac2   Florian Westphal   xfrm: remove afin...
2455
2456
2457
2458
2459
2460
2461
2462
  
  		rcu_read_lock();
  		afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
  		if (likely(afinfo))
  			dst1->output = afinfo->output;
  		else
  			dst1->output = dst_discard_out;
  		rcu_read_unlock();
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2463

45b018bed   David Miller   ipsec: Create and...
2464
  		xdst_prev = xdst;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2465
2466
  
  		header_len += xfrm[i]->props.header_len;
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
2467
2468
  		if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
  			nfheader_len += xfrm[i]->props.header_len;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2469
2470
  		trailer_len += xfrm[i]->props.trailer_len;
  	}
45b018bed   David Miller   ipsec: Create and...
2471
  	xfrm_dst_set_child(xdst_prev, dst);
0f6c480f2   David Miller   xfrm: Move dst->p...
2472
  	xdst0->path = dst;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2473
2474
2475
2476
2477
  
  	err = -ENODEV;
  	dev = dst->dev;
  	if (!dev)
  		goto free_dst;
45b018bed   David Miller   ipsec: Create and...
2478
  	xfrm_init_path(xdst0, dst, nfheader_len);
5492093dc   David Miller   xfrm: Stop using ...
2479
  	xfrm_init_pmtu(bundle, nx);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2480

45b018bed   David Miller   ipsec: Create and...
2481
2482
2483
  	for (xdst_prev = xdst0; xdst_prev != (struct xfrm_dst *)dst;
  	     xdst_prev = (struct xfrm_dst *) xfrm_dst_child(&xdst_prev->u.dst)) {
  		err = xfrm_fill_dst(xdst_prev, dev, fl);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2484
2485
  		if (err)
  			goto free_dst;
45b018bed   David Miller   ipsec: Create and...
2486
2487
2488
2489
  		xdst_prev->u.dst.header_len = header_len;
  		xdst_prev->u.dst.trailer_len = trailer_len;
  		header_len -= xdst_prev->u.dst.xfrm->props.header_len;
  		trailer_len -= xdst_prev->u.dst.xfrm->props.trailer_len;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2490
  	}
45b018bed   David Miller   ipsec: Create and...
2491
  	return &xdst0->u.dst;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2492
2493
2494
2495
2496
  
  put_states:
  	for (; i < nx; i++)
  		xfrm_state_put(xfrm[i]);
  free_dst:
45b018bed   David Miller   ipsec: Create and...
2497
2498
  	if (xdst0)
  		dst_release_immediate(&xdst0->u.dst);
38369f54d   Steffen Klassert   xfrm Fix potentia...
2499
2500
  
  	return ERR_PTR(err);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2501
  }
73ff93cd0   David S. Miller   xfrm: Mark flowi ...
2502
  static int xfrm_expand_policies(const struct flowi *fl, u16 family,
80c802f30   Timo Teräs   xfrm: cache bundl...
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
  				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,
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2524
2525
  						    XFRM_POLICY_OUT,
  						    pols[0]->if_id);
80c802f30   Timo Teräs   xfrm: cache bundl...
2526
2527
2528
2529
2530
  		if (pols[1]) {
  			if (IS_ERR(pols[1])) {
  				xfrm_pols_put(pols, *num_pols);
  				return PTR_ERR(pols[1]);
  			}
02d0892f9   Weilong Chen   xfrm: checkpatch ...
2531
  			(*num_pols)++;
80c802f30   Timo Teräs   xfrm: cache bundl...
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
  			(*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 ...
2549
  			       const struct flowi *fl, u16 family,
80c802f30   Timo Teräs   xfrm: cache bundl...
2550
2551
2552
2553
  			       struct dst_entry *dst_orig)
  {
  	struct net *net = xp_net(pols[0]);
  	struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
5492093dc   David Miller   xfrm: Stop using ...
2554
  	struct xfrm_dst *bundle[XFRM_MAX_DEPTH];
e4db5b61c   Florian Westphal   xfrm: policy: rem...
2555
  	struct xfrm_dst *xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
2556
  	struct dst_entry *dst;
80c802f30   Timo Teräs   xfrm: cache bundl...
2557
  	int err;
cf3796675   Florian Westphal   xfrm: do uncondit...
2558
2559
2560
  	/* Try to instantiate a bundle */
  	err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
  	if (err <= 0) {
934ffce13   YueHaibing   xfrm: fix 'passin...
2561
2562
2563
2564
  		if (err == 0)
  			return NULL;
  
  		if (err != -EAGAIN)
cf3796675   Florian Westphal   xfrm: do uncondit...
2565
2566
2567
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
  		return ERR_PTR(err);
  	}
5492093dc   David Miller   xfrm: Stop using ...
2568
  	dst = xfrm_bundle_create(pols[0], xfrm, bundle, err, fl, dst_orig);
80c802f30   Timo Teräs   xfrm: cache bundl...
2569
2570
2571
2572
2573
2574
2575
  	if (IS_ERR(dst)) {
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
  		return ERR_CAST(dst);
  	}
  
  	xdst = (struct xfrm_dst *)dst;
  	xdst->num_xfrms = err;
80c802f30   Timo Teräs   xfrm: cache bundl...
2576
  	xdst->num_pols = num_pols;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
2577
  	memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
2578
2579
2580
2581
  	xdst->policy_genid = atomic_read(&pols[0]->genid);
  
  	return xdst;
  }
c3aed7095   Kees Cook   xfrm: Convert tim...
2582
  static void xfrm_policy_queue_process(struct timer_list *t)
a0073fe18   Steffen Klassert   xfrm: Add a state...
2583
  {
a0073fe18   Steffen Klassert   xfrm: Add a state...
2584
2585
2586
  	struct sk_buff *skb;
  	struct sock *sk;
  	struct dst_entry *dst;
c3aed7095   Kees Cook   xfrm: Convert tim...
2587
  	struct xfrm_policy *pol = from_timer(pol, t, polq.hold_timer);
3f5312ae6   Eric W. Biederman   xfrm: Only comput...
2588
  	struct net *net = xp_net(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2589
2590
2591
  	struct xfrm_policy_queue *pq = &pol->polq;
  	struct flowi fl;
  	struct sk_buff_head list;
b328ecc46   Steffen Klassert   xfrm: Make the po...
2592
  	__u32 skb_mark;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2593
2594
2595
  
  	spin_lock(&pq->hold_queue.lock);
  	skb = skb_peek(&pq->hold_queue);
2bb53e255   Steffen Klassert   xfrm: check for a...
2596
2597
2598
2599
  	if (!skb) {
  		spin_unlock(&pq->hold_queue.lock);
  		goto out;
  	}
a0073fe18   Steffen Klassert   xfrm: Add a state...
2600
2601
  	dst = skb_dst(skb);
  	sk = skb->sk;
b328ecc46   Steffen Klassert   xfrm: Make the po...
2602
2603
2604
2605
  
  	/* Fixup the mark to support VTI. */
  	skb_mark = skb->mark;
  	skb->mark = pol->mark.v;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2606
  	xfrm_decode_session(skb, &fl, dst->ops->family);
b328ecc46   Steffen Klassert   xfrm: Make the po...
2607
  	skb->mark = skb_mark;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2608
  	spin_unlock(&pq->hold_queue.lock);
0f6c480f2   David Miller   xfrm: Move dst->p...
2609
  	dst_hold(xfrm_dst_path(dst));
2471c9816   Steffen Klassert   xfrm: Fix policy ...
2610
  	dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, XFRM_LOOKUP_QUEUE);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
  	if (IS_ERR(dst))
  		goto purge_queue;
  
  	if (dst->flags & DST_XFRM_QUEUE) {
  		dst_release(dst);
  
  		if (pq->timeout >= XFRM_QUEUE_TMO_MAX)
  			goto purge_queue;
  
  		pq->timeout = pq->timeout << 1;
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
2621
2622
  		if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout))
  			xfrm_pol_hold(pol);
7759d6a83   Colin Ian King   xfrm: policy: add...
2623
  		goto out;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
  	}
  
  	dst_release(dst);
  
  	__skb_queue_head_init(&list);
  
  	spin_lock(&pq->hold_queue.lock);
  	pq->timeout = 0;
  	skb_queue_splice_init(&pq->hold_queue, &list);
  	spin_unlock(&pq->hold_queue.lock);
  
  	while (!skb_queue_empty(&list)) {
  		skb = __skb_dequeue(&list);
b328ecc46   Steffen Klassert   xfrm: Make the po...
2637
2638
2639
  		/* Fixup the mark to support VTI. */
  		skb_mark = skb->mark;
  		skb->mark = pol->mark.v;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2640
  		xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family);
b328ecc46   Steffen Klassert   xfrm: Make the po...
2641
  		skb->mark = skb_mark;
0f6c480f2   David Miller   xfrm: Move dst->p...
2642
2643
  		dst_hold(xfrm_dst_path(skb_dst(skb)));
  		dst = xfrm_lookup(net, xfrm_dst_path(skb_dst(skb)), &fl, skb->sk, 0);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2644
  		if (IS_ERR(dst)) {
a0073fe18   Steffen Klassert   xfrm: Add a state...
2645
2646
2647
  			kfree_skb(skb);
  			continue;
  		}
895b5c9f2   Florian Westphal   netfilter: drop b...
2648
  		nf_reset_ct(skb);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2649
2650
  		skb_dst_drop(skb);
  		skb_dst_set(skb, dst);
13206b6bf   Eric W. Biederman   net: Pass net int...
2651
  		dst_output(net, skb->sk, skb);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2652
  	}
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
2653
2654
  out:
  	xfrm_pol_put(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2655
2656
2657
2658
  	return;
  
  purge_queue:
  	pq->timeout = 0;
1ee5e6676   Li RongQing   xfrm: remove the ...
2659
  	skb_queue_purge(&pq->hold_queue);
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
2660
  	xfrm_pol_put(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2661
  }
ede2059db   Eric W. Biederman   dst: Pass net int...
2662
  static int xdst_queue_output(struct net *net, struct sock *sk, struct sk_buff *skb)
a0073fe18   Steffen Klassert   xfrm: Add a state...
2663
2664
2665
2666
  {
  	unsigned long sched_next;
  	struct dst_entry *dst = skb_dst(skb);
  	struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
2667
2668
  	struct xfrm_policy *pol = xdst->pols[0];
  	struct xfrm_policy_queue *pq = &pol->polq;
4d53eff48   Steffen Klassert   xfrm: Don't queue...
2669

39bb5e628   Eric Dumazet   net: skb_fclone_b...
2670
  	if (unlikely(skb_fclone_busy(sk, skb))) {
4d53eff48   Steffen Klassert   xfrm: Don't queue...
2671
2672
2673
  		kfree_skb(skb);
  		return 0;
  	}
a0073fe18   Steffen Klassert   xfrm: Add a state...
2674
2675
2676
2677
2678
2679
2680
  
  	if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) {
  		kfree_skb(skb);
  		return -EAGAIN;
  	}
  
  	skb_dst_force(skb);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
  
  	spin_lock_bh(&pq->hold_queue.lock);
  
  	if (!pq->timeout)
  		pq->timeout = XFRM_QUEUE_TMO_MIN;
  
  	sched_next = jiffies + pq->timeout;
  
  	if (del_timer(&pq->hold_timer)) {
  		if (time_before(pq->hold_timer.expires, sched_next))
  			sched_next = pq->hold_timer.expires;
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
2692
  		xfrm_pol_put(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2693
2694
2695
  	}
  
  	__skb_queue_tail(&pq->hold_queue, skb);
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
2696
2697
  	if (!mod_timer(&pq->hold_timer, sched_next))
  		xfrm_pol_hold(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
2698
2699
2700
2701
2702
2703
2704
  
  	spin_unlock_bh(&pq->hold_queue.lock);
  
  	return 0;
  }
  
  static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2705
  						 struct xfrm_flo *xflo,
a0073fe18   Steffen Klassert   xfrm: Add a state...
2706
2707
2708
2709
2710
2711
  						 const struct flowi *fl,
  						 int num_xfrms,
  						 u16 family)
  {
  	int err;
  	struct net_device *dev;
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2712
  	struct dst_entry *dst;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2713
2714
2715
2716
2717
2718
  	struct dst_entry *dst1;
  	struct xfrm_dst *xdst;
  
  	xdst = xfrm_alloc_dst(net, family);
  	if (IS_ERR(xdst))
  		return xdst;
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2719
2720
2721
  	if (!(xflo->flags & XFRM_LOOKUP_QUEUE) ||
  	    net->xfrm.sysctl_larval_drop ||
  	    num_xfrms <= 0)
a0073fe18   Steffen Klassert   xfrm: Add a state...
2722
  		return xdst;
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2723
  	dst = xflo->dst_orig;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2724
2725
2726
2727
2728
2729
2730
  	dst1 = &xdst->u.dst;
  	dst_hold(dst);
  	xdst->route = dst;
  
  	dst_copy_metrics(dst1, dst);
  
  	dst1->obsolete = DST_OBSOLETE_FORCE_CHK;
af13b3c33   David Laight   Remove DST_HOST
2731
  	dst1->flags |= DST_XFRM_QUEUE;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2732
2733
2734
2735
2736
2737
  	dst1->lastuse = jiffies;
  
  	dst1->input = dst_discard;
  	dst1->output = xdst_queue_output;
  
  	dst_hold(dst);
45b018bed   David Miller   ipsec: Create and...
2738
  	xfrm_dst_set_child(xdst, dst);
0f6c480f2   David Miller   xfrm: Move dst->p...
2739
  	xdst->path = dst;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
  
  	xfrm_init_path((struct xfrm_dst *)dst1, dst, 0);
  
  	err = -ENODEV;
  	dev = dst->dev;
  	if (!dev)
  		goto free_dst;
  
  	err = xfrm_fill_dst(xdst, dev, fl);
  	if (err)
  		goto free_dst;
  
  out:
  	return xdst;
  
  free_dst:
  	dst_release(dst1);
  	xdst = ERR_PTR(err);
  	goto out;
  }
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2760
2761
2762
2763
  static struct xfrm_dst *xfrm_bundle_lookup(struct net *net,
  					   const struct flowi *fl,
  					   u16 family, u8 dir,
  					   struct xfrm_flo *xflo, u32 if_id)
80c802f30   Timo Teräs   xfrm: cache bundl...
2764
  {
80c802f30   Timo Teräs   xfrm: cache bundl...
2765
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
855dad99c   Florian Westphal   xfrm_policy: remo...
2766
  	int num_pols = 0, num_xfrms = 0, err;
bd45c539b   Florian Westphal   xfrm_policy: make...
2767
  	struct xfrm_dst *xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
2768

80c802f30   Timo Teräs   xfrm: cache bundl...
2769
2770
  	/* Resolve policies to use if we couldn't get them from
  	 * previous cache entry */
855dad99c   Florian Westphal   xfrm_policy: remo...
2771
  	num_pols = 1;
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2772
  	pols[0] = xfrm_policy_lookup(net, fl, family, dir, if_id);
855dad99c   Florian Westphal   xfrm_policy: remo...
2773
  	err = xfrm_expand_policies(fl, family, pols,
80c802f30   Timo Teräs   xfrm: cache bundl...
2774
  					   &num_pols, &num_xfrms);
855dad99c   Florian Westphal   xfrm_policy: remo...
2775
2776
2777
2778
2779
2780
  	if (err < 0)
  		goto inc_error;
  	if (num_pols == 0)
  		return NULL;
  	if (num_xfrms <= 0)
  		goto make_dummy_bundle;
80c802f30   Timo Teräs   xfrm: cache bundl...
2781

bd45c539b   Florian Westphal   xfrm_policy: make...
2782
  	xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family,
76a420119   Steffen Klassert   xfrm: Fix a race ...
2783
  					      xflo->dst_orig);
bd45c539b   Florian Westphal   xfrm_policy: make...
2784
2785
  	if (IS_ERR(xdst)) {
  		err = PTR_ERR(xdst);
f203b76d7   Steffen Klassert   xfrm: Add virtual...
2786
2787
2788
2789
  		if (err == -EREMOTE) {
  			xfrm_pols_put(pols, num_pols);
  			return NULL;
  		}
80c802f30   Timo Teräs   xfrm: cache bundl...
2790
2791
  		if (err != -EAGAIN)
  			goto error;
855dad99c   Florian Westphal   xfrm_policy: remo...
2792
  		goto make_dummy_bundle;
bd45c539b   Florian Westphal   xfrm_policy: make...
2793
  	} else if (xdst == NULL) {
d809ec895   Timo Teräs   xfrm: do not assu...
2794
  		num_xfrms = 0;
855dad99c   Florian Westphal   xfrm_policy: remo...
2795
  		goto make_dummy_bundle;
80c802f30   Timo Teräs   xfrm: cache bundl...
2796
  	}
bd45c539b   Florian Westphal   xfrm_policy: make...
2797
  	return xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
2798
2799
2800
2801
2802
  
  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).*/
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2803
  	xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family);
80c802f30   Timo Teräs   xfrm: cache bundl...
2804
2805
2806
2807
2808
2809
  	if (IS_ERR(xdst)) {
  		xfrm_pols_put(pols, num_pols);
  		return ERR_CAST(xdst);
  	}
  	xdst->num_pols = num_pols;
  	xdst->num_xfrms = num_xfrms;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
2810
  	memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
2811

bd45c539b   Florian Westphal   xfrm_policy: make...
2812
  	return xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
2813
2814
2815
2816
  
  inc_error:
  	XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
  error:
855dad99c   Florian Westphal   xfrm_policy: remo...
2817
  	xfrm_pols_put(pols, num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
2818
2819
  	return ERR_PTR(err);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2820

2774c131b   David S. Miller   xfrm: Handle blac...
2821
2822
2823
  static struct dst_entry *make_blackhole(struct net *net, u16 family,
  					struct dst_entry *dst_orig)
  {
37b103830   Florian Westphal   xfrm: policy: mak...
2824
  	const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
2774c131b   David S. Miller   xfrm: Handle blac...
2825
2826
2827
2828
  	struct dst_entry *ret;
  
  	if (!afinfo) {
  		dst_release(dst_orig);
433a19548   Li RongQing   xfrm: fix a read ...
2829
  		return ERR_PTR(-EINVAL);
2774c131b   David S. Miller   xfrm: Handle blac...
2830
2831
2832
  	} else {
  		ret = afinfo->blackhole_route(net, dst_orig);
  	}
bdba9fe01   Florian Westphal   xfrm: policy: rem...
2833
  	rcu_read_unlock();
2774c131b   David S. Miller   xfrm: Handle blac...
2834
2835
2836
  
  	return ret;
  }
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2837
  /* Finds/creates a bundle for given flow and if_id
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2838
2839
2840
   *
   * At the moment we eat a raw IP route. Mostly to speed up lookups
   * on interfaces with disabled IPsec.
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2841
2842
2843
   *
   * xfrm_lookup uses an if_id of 0 by default, and is provided for
   * compatibility
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2844
   */
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2845
2846
2847
2848
2849
  struct dst_entry *xfrm_lookup_with_ifid(struct net *net,
  					struct dst_entry *dst_orig,
  					const struct flowi *fl,
  					const struct sock *sk,
  					int flags, u32 if_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2850
  {
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2851
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
80c802f30   Timo Teräs   xfrm: cache bundl...
2852
  	struct xfrm_dst *xdst;
452edd598   David S. Miller   xfrm: Return dst ...
2853
  	struct dst_entry *dst, *route;
80c802f30   Timo Teräs   xfrm: cache bundl...
2854
  	u16 family = dst_orig->ops->family;
aff669bc2   Florian Westphal   xfrm_policy: kill...
2855
  	u8 dir = XFRM_POLICY_OUT;
4b021628b   Changli Gao   xfrm: potential u...
2856
  	int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
2857

80c802f30   Timo Teräs   xfrm: cache bundl...
2858
2859
2860
  	dst = NULL;
  	xdst = NULL;
  	route = NULL;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2861

bd5eb35f1   Eric Dumazet   xfrm: take care o...
2862
  	sk = sk_const_to_full_sk(sk);
f7944fb19   Thomas Graf   [XFRM] policy: Re...
2863
  	if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
80c802f30   Timo Teräs   xfrm: cache bundl...
2864
  		num_pols = 1;
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2865
2866
  		pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family,
  						if_id);
80c802f30   Timo Teräs   xfrm: cache bundl...
2867
2868
2869
  		err = xfrm_expand_policies(fl, family, pols,
  					   &num_pols, &num_xfrms);
  		if (err < 0)
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
2870
  			goto dropdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
  
  		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);
76a420119   Steffen Klassert   xfrm: Fix a race ...
2881

80c802f30   Timo Teräs   xfrm: cache bundl...
2882
2883
2884
  			if (IS_ERR(xdst)) {
  				xfrm_pols_put(pols, num_pols);
  				err = PTR_ERR(xdst);
f203b76d7   Steffen Klassert   xfrm: Add virtual...
2885
2886
  				if (err == -EREMOTE)
  					goto nopol;
80c802f30   Timo Teräs   xfrm: cache bundl...
2887
  				goto dropdst;
d809ec895   Timo Teräs   xfrm: do not assu...
2888
2889
2890
2891
  			} else if (xdst == NULL) {
  				num_xfrms = 0;
  				drop_pols = num_pols;
  				goto no_transform;
80c802f30   Timo Teräs   xfrm: cache bundl...
2892
  			}
80c802f30   Timo Teräs   xfrm: cache bundl...
2893
  			route = xdst->route;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2894
  		}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2895
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2896

80c802f30   Timo Teräs   xfrm: cache bundl...
2897
  	if (xdst == NULL) {
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2898
2899
2900
2901
  		struct xfrm_flo xflo;
  
  		xflo.dst_orig = dst_orig;
  		xflo.flags = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2902
  		/* To accelerate a bit...  */
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2903
  		if ((dst_orig->flags & DST_NOXFRM) ||
52479b623   Alexey Dobriyan   netns xfrm: looku...
2904
  		    !net->xfrm.policy_count[XFRM_POLICY_OUT])
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2905
  			goto nopol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2906

bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2907
  		xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo, if_id);
bd45c539b   Florian Westphal   xfrm_policy: make...
2908
  		if (xdst == NULL)
80c802f30   Timo Teräs   xfrm: cache bundl...
2909
  			goto nopol;
bd45c539b   Florian Westphal   xfrm_policy: make...
2910
2911
  		if (IS_ERR(xdst)) {
  			err = PTR_ERR(xdst);
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
2912
  			goto dropdst;
d66e37a99   Masahide NAKAMURA   [XFRM] Statistics...
2913
  		}
80c802f30   Timo Teräs   xfrm: cache bundl...
2914
2915
2916
  
  		num_pols = xdst->num_pols;
  		num_xfrms = xdst->num_xfrms;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
2917
  		memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
  		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) {
80c802f30   Timo Teräs   xfrm: cache bundl...
2930
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
ac37e2515   huaibin Wang   xfrm: release dst...
2931
2932
  			err = -EREMOTE;
  			goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
2933
  		}
80c802f30   Timo Teräs   xfrm: cache bundl...
2934

5b8ef3415   Steffen Klassert   xfrm: Remove anci...
2935
  		err = -EAGAIN;
80c802f30   Timo Teräs   xfrm: cache bundl...
2936
2937
2938
  
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2939
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
2940
2941
  no_transform:
  	if (num_pols == 0)
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2942
  		goto nopol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2943

80c802f30   Timo Teräs   xfrm: cache bundl...
2944
2945
2946
  	if ((flags & XFRM_LOOKUP_ICMP) &&
  	    !(pols[0]->flags & XFRM_POLICY_ICMP)) {
  		err = -ENOENT;
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2947
  		goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
2948
  	}
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2949

80c802f30   Timo Teräs   xfrm: cache bundl...
2950
  	for (i = 0; i < num_pols; i++)
386c5680e   Arnd Bergmann   xfrm: use time64_...
2951
  		pols[i]->curlft.use_time = ktime_get_real_seconds();
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2952

80c802f30   Timo Teräs   xfrm: cache bundl...
2953
  	if (num_xfrms < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2954
  		/* Prohibit the flow */
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2955
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
e104411b8   Patrick McHardy   [XFRM]: Always re...
2956
2957
  		err = -EPERM;
  		goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
2958
2959
  	} else if (num_xfrms > 0) {
  		/* Flow transformed */
80c802f30   Timo Teräs   xfrm: cache bundl...
2960
2961
2962
2963
  		dst_release(dst_orig);
  	} else {
  		/* Flow passes untransformed */
  		dst_release(dst);
452edd598   David S. Miller   xfrm: Return dst ...
2964
  		dst = dst_orig;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2965
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
2966
2967
  ok:
  	xfrm_pols_put(pols, drop_pols);
0c1833797   Gao feng   ipv6: fix incorre...
2968
2969
2970
  	if (dst && dst->xfrm &&
  	    dst->xfrm->props.mode == XFRM_MODE_TUNNEL)
  		dst->flags |= DST_XFRM_TUNNEL;
452edd598   David S. Miller   xfrm: Return dst ...
2971
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2972

80c802f30   Timo Teräs   xfrm: cache bundl...
2973
  nopol:
452edd598   David S. Miller   xfrm: Return dst ...
2974
2975
  	if (!(flags & XFRM_LOOKUP_ICMP)) {
  		dst = dst_orig;
80c802f30   Timo Teräs   xfrm: cache bundl...
2976
  		goto ok;
452edd598   David S. Miller   xfrm: Return dst ...
2977
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
2978
  	err = -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2979
  error:
80c802f30   Timo Teräs   xfrm: cache bundl...
2980
  	dst_release(dst);
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
2981
  dropdst:
ac37e2515   huaibin Wang   xfrm: release dst...
2982
2983
  	if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
  		dst_release(dst_orig);
80c802f30   Timo Teräs   xfrm: cache bundl...
2984
  	xfrm_pols_put(pols, drop_pols);
452edd598   David S. Miller   xfrm: Return dst ...
2985
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2986
  }
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
  EXPORT_SYMBOL(xfrm_lookup_with_ifid);
  
  /* 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.
   */
  struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
  			      const struct flowi *fl, const struct sock *sk,
  			      int flags)
  {
  	return xfrm_lookup_with_ifid(net, dst_orig, fl, sk, flags, 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3000
  EXPORT_SYMBOL(xfrm_lookup);
f92ee6198   Steffen Klassert   xfrm: Generate bl...
3001
3002
3003
3004
3005
  /* Callers of xfrm_lookup_route() must ensure a call to dst_output().
   * Otherwise we may send out blackholed packets.
   */
  struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
  				    const struct flowi *fl,
6f9c96154   Eric Dumazet   inet: constify ip...
3006
  				    const struct sock *sk, int flags)
f92ee6198   Steffen Klassert   xfrm: Generate bl...
3007
  {
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
3008
  	struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
ac37e2515   huaibin Wang   xfrm: release dst...
3009
3010
  					    flags | XFRM_LOOKUP_QUEUE |
  					    XFRM_LOOKUP_KEEP_DST_REF);
f92ee6198   Steffen Klassert   xfrm: Generate bl...
3011

45586c707   Masahiro Yamada   treewide: remove ...
3012
  	if (PTR_ERR(dst) == -EREMOTE)
f92ee6198   Steffen Klassert   xfrm: Generate bl...
3013
  		return make_blackhole(net, dst_orig->ops->family, dst_orig);
8cc887738   Tommi Rantala   xfrm: fix missing...
3014
3015
  	if (IS_ERR(dst))
  		dst_release(dst_orig);
f92ee6198   Steffen Klassert   xfrm: Generate bl...
3016
3017
3018
  	return dst;
  }
  EXPORT_SYMBOL(xfrm_lookup_route);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3019
  static inline int
8f029de28   David S. Miller   xfrm: Mark flowi ...
3020
  xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl)
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3021
  {
2294be0f1   Florian Westphal   net: use skb_sec_...
3022
  	struct sec_path *sp = skb_sec_path(skb);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3023
  	struct xfrm_state *x;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3024

2294be0f1   Florian Westphal   net: use skb_sec_...
3025
  	if (!sp || idx < 0 || idx >= sp->len)
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3026
  		return 0;
2294be0f1   Florian Westphal   net: use skb_sec_...
3027
  	x = sp->xvec[idx];
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3028
3029
  	if (!x->type->reject)
  		return 0;
1ecafede8   Herbert Xu   [IPSEC]: Remove b...
3030
  	return x->type->reject(x, skb, fl);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3031
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3032
3033
3034
3035
3036
3037
3038
  /* 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...
3039
  xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3040
3041
3042
  	      unsigned short family)
  {
  	if (xfrm_state_kern(x))
928ba4169   Kazunori MIYAZAWA   [IPSEC]: Fix the ...
3043
  		return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3044
3045
3046
3047
  	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...
3048
  		(tmpl->allalgs || (tmpl->aalgos & (1<<x->props.aalgo)) ||
f3bd48402   Masahide NAKAMURA   [XFRM]: Restrict ...
3049
  		 !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) &&
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
3050
3051
  		!(x->props.mode != XFRM_MODE_TRANSPORT &&
  		  xfrm_state_addr_cmp(tmpl, x, family));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3052
  }
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3053
3054
3055
3056
3057
3058
3059
  /*
   * 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
3060
  static inline int
22cccb7e0   David S. Miller   xfrm: Const'ify p...
3061
  xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3062
3063
3064
3065
3066
  	       unsigned short family)
  {
  	int idx = start;
  
  	if (tmpl->optional) {
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
3067
  		if (tmpl->mode == XFRM_MODE_TRANSPORT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3068
3069
3070
3071
  			return start;
  	} else
  		start = -1;
  	for (; idx < sp->len; idx++) {
dbe5b4aaa   Herbert Xu   [IPSEC]: Kill unu...
3072
  		if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3073
  			return ++idx;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3074
3075
3076
  		if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
  			if (start == -1)
  				start = -2-idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3077
  			break;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3078
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3079
3080
3081
  	}
  	return start;
  }
c53ac41e3   Florian Westphal   xfrm: remove deco...
3082
3083
3084
3085
  static void
  decode_session4(struct sk_buff *skb, struct flowi *fl, bool reverse)
  {
  	const struct iphdr *iph = ip_hdr(skb);
858e5400e   Florian Westphal   xfrm: ressurrect ...
3086
3087
  	int ihl = iph->ihl;
  	u8 *xprth = skb_network_header(skb) + ihl * 4;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3088
3089
  	struct flowi4 *fl4 = &fl->u.ip4;
  	int oif = 0;
c3b4c3a47   Hangbin Liu   xfrm/xfrm_policy:...
3090
  	if (skb_dst(skb) && skb_dst(skb)->dev)
c53ac41e3   Florian Westphal   xfrm: remove deco...
3091
3092
3093
3094
3095
  		oif = skb_dst(skb)->dev->ifindex;
  
  	memset(fl4, 0, sizeof(struct flowi4));
  	fl4->flowi4_mark = skb->mark;
  	fl4->flowi4_oif = reverse ? skb->skb_iif : oif;
858e5400e   Florian Westphal   xfrm: ressurrect ...
3096
3097
3098
3099
  	fl4->flowi4_proto = iph->protocol;
  	fl4->daddr = reverse ? iph->saddr : iph->daddr;
  	fl4->saddr = reverse ? iph->daddr : iph->saddr;
  	fl4->flowi4_tos = iph->tos;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
  	if (!ip_is_fragment(iph)) {
  		switch (iph->protocol) {
  		case IPPROTO_UDP:
  		case IPPROTO_UDPLITE:
  		case IPPROTO_TCP:
  		case IPPROTO_SCTP:
  		case IPPROTO_DCCP:
  			if (xprth + 4 < skb->data ||
  			    pskb_may_pull(skb, xprth + 4 - skb->data)) {
  				__be16 *ports;
858e5400e   Florian Westphal   xfrm: ressurrect ...
3110
  				xprth = skb_network_header(skb) + ihl * 4;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
  				ports = (__be16 *)xprth;
  
  				fl4->fl4_sport = ports[!!reverse];
  				fl4->fl4_dport = ports[!reverse];
  			}
  			break;
  		case IPPROTO_ICMP:
  			if (xprth + 2 < skb->data ||
  			    pskb_may_pull(skb, xprth + 2 - skb->data)) {
  				u8 *icmp;
858e5400e   Florian Westphal   xfrm: ressurrect ...
3121
  				xprth = skb_network_header(skb) + ihl * 4;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
  				icmp = xprth;
  
  				fl4->fl4_icmp_type = icmp[0];
  				fl4->fl4_icmp_code = icmp[1];
  			}
  			break;
  		case IPPROTO_ESP:
  			if (xprth + 4 < skb->data ||
  			    pskb_may_pull(skb, xprth + 4 - skb->data)) {
  				__be32 *ehdr;
858e5400e   Florian Westphal   xfrm: ressurrect ...
3132
  				xprth = skb_network_header(skb) + ihl * 4;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3133
3134
3135
3136
3137
3138
3139
3140
3141
  				ehdr = (__be32 *)xprth;
  
  				fl4->fl4_ipsec_spi = ehdr[0];
  			}
  			break;
  		case IPPROTO_AH:
  			if (xprth + 8 < skb->data ||
  			    pskb_may_pull(skb, xprth + 8 - skb->data)) {
  				__be32 *ah_hdr;
858e5400e   Florian Westphal   xfrm: ressurrect ...
3142
  				xprth = skb_network_header(skb) + ihl * 4;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3143
3144
3145
3146
3147
3148
3149
3150
3151
  				ah_hdr = (__be32 *)xprth;
  
  				fl4->fl4_ipsec_spi = ah_hdr[1];
  			}
  			break;
  		case IPPROTO_COMP:
  			if (xprth + 4 < skb->data ||
  			    pskb_may_pull(skb, xprth + 4 - skb->data)) {
  				__be16 *ipcomp_hdr;
858e5400e   Florian Westphal   xfrm: ressurrect ...
3152
  				xprth = skb_network_header(skb) + ihl * 4;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
  				ipcomp_hdr = (__be16 *)xprth;
  
  				fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
  			}
  			break;
  		case IPPROTO_GRE:
  			if (xprth + 12 < skb->data ||
  			    pskb_may_pull(skb, xprth + 12 - skb->data)) {
  				__be16 *greflags;
  				__be32 *gre_hdr;
858e5400e   Florian Westphal   xfrm: ressurrect ...
3163
  				xprth = skb_network_header(skb) + ihl * 4;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
  				greflags = (__be16 *)xprth;
  				gre_hdr = (__be32 *)xprth;
  
  				if (greflags[0] & GRE_KEY) {
  					if (greflags[0] & GRE_CSUM)
  						gre_hdr++;
  					fl4->fl4_gre_key = gre_hdr[1];
  				}
  			}
  			break;
  		default:
  			fl4->fl4_ipsec_spi = 0;
  			break;
  		}
  	}
c53ac41e3   Florian Westphal   xfrm: remove deco...
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
  static void
  decode_session6(struct sk_buff *skb, struct flowi *fl, bool reverse)
  {
  	struct flowi6 *fl6 = &fl->u.ip6;
  	int onlyproto = 0;
  	const struct ipv6hdr *hdr = ipv6_hdr(skb);
  	u32 offset = sizeof(*hdr);
  	struct ipv6_opt_hdr *exthdr;
  	const unsigned char *nh = skb_network_header(skb);
  	u16 nhoff = IP6CB(skb)->nhoff;
  	int oif = 0;
  	u8 nexthdr;
  
  	if (!nhoff)
  		nhoff = offsetof(struct ipv6hdr, nexthdr);
  
  	nexthdr = nh[nhoff];
c3b4c3a47   Hangbin Liu   xfrm/xfrm_policy:...
3199
  	if (skb_dst(skb) && skb_dst(skb)->dev)
c53ac41e3   Florian Westphal   xfrm: remove deco...
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
  		oif = skb_dst(skb)->dev->ifindex;
  
  	memset(fl6, 0, sizeof(struct flowi6));
  	fl6->flowi6_mark = skb->mark;
  	fl6->flowi6_oif = reverse ? skb->skb_iif : oif;
  
  	fl6->daddr = reverse ? hdr->saddr : hdr->daddr;
  	fl6->saddr = reverse ? hdr->daddr : hdr->saddr;
  
  	while (nh + offset + sizeof(*exthdr) < skb->data ||
  	       pskb_may_pull(skb, nh + offset + sizeof(*exthdr) - skb->data)) {
  		nh = skb_network_header(skb);
  		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
  
  		switch (nexthdr) {
  		case NEXTHDR_FRAGMENT:
  			onlyproto = 1;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
3217
  			fallthrough;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
  		case NEXTHDR_ROUTING:
  		case NEXTHDR_HOP:
  		case NEXTHDR_DEST:
  			offset += ipv6_optlen(exthdr);
  			nexthdr = exthdr->nexthdr;
  			exthdr = (struct ipv6_opt_hdr *)(nh + offset);
  			break;
  		case IPPROTO_UDP:
  		case IPPROTO_UDPLITE:
  		case IPPROTO_TCP:
  		case IPPROTO_SCTP:
  		case IPPROTO_DCCP:
  			if (!onlyproto && (nh + offset + 4 < skb->data ||
  			     pskb_may_pull(skb, nh + offset + 4 - skb->data))) {
  				__be16 *ports;
  
  				nh = skb_network_header(skb);
  				ports = (__be16 *)(nh + offset);
  				fl6->fl6_sport = ports[!!reverse];
  				fl6->fl6_dport = ports[!reverse];
  			}
  			fl6->flowi6_proto = nexthdr;
  			return;
  		case IPPROTO_ICMPV6:
  			if (!onlyproto && (nh + offset + 2 < skb->data ||
  			    pskb_may_pull(skb, nh + offset + 2 - skb->data))) {
  				u8 *icmp;
  
  				nh = skb_network_header(skb);
  				icmp = (u8 *)(nh + offset);
  				fl6->fl6_icmp_type = icmp[0];
  				fl6->fl6_icmp_code = icmp[1];
  			}
  			fl6->flowi6_proto = nexthdr;
  			return;
  #if IS_ENABLED(CONFIG_IPV6_MIP6)
  		case IPPROTO_MH:
  			offset += ipv6_optlen(exthdr);
  			if (!onlyproto && (nh + offset + 3 < skb->data ||
  			    pskb_may_pull(skb, nh + offset + 3 - skb->data))) {
  				struct ip6_mh *mh;
  
  				nh = skb_network_header(skb);
  				mh = (struct ip6_mh *)(nh + offset);
  				fl6->fl6_mh_type = mh->ip6mh_type;
  			}
  			fl6->flowi6_proto = nexthdr;
  			return;
  #endif
  		/* XXX Why are there these headers? */
  		case IPPROTO_AH:
  		case IPPROTO_ESP:
  		case IPPROTO_COMP:
  		default:
  			fl6->fl6_ipsec_spi = 0;
  			fl6->flowi6_proto = nexthdr;
  			return;
  		}
  	}
  }
  #endif
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
3279
3280
  int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
  			  unsigned int family, int reverse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3281
  {
c53ac41e3   Florian Westphal   xfrm: remove deco...
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
  	switch (family) {
  	case AF_INET:
  		decode_session4(skb, fl, reverse);
  		break;
  #if IS_ENABLED(CONFIG_IPV6)
  	case AF_INET6:
  		decode_session6(skb, fl, reverse);
  		break;
  #endif
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3292
  		return -EAFNOSUPPORT;
c53ac41e3   Florian Westphal   xfrm: remove deco...
3293
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3294

c53ac41e3   Florian Westphal   xfrm: remove deco...
3295
  	return security_xfrm_decode_session(skb, &fl->flowi_secid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3296
  }
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
3297
  EXPORT_SYMBOL(__xfrm_decode_session);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3298

9a7386ec9   David S. Miller   xfrm: Const'ify s...
3299
  static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int *idxp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3300
3301
  {
  	for (; k < sp->len; k++) {
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3302
  		if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) {
d1d9facfd   James Morris   [XFRM]: remove xe...
3303
  			*idxp = k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3304
  			return 1;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3305
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3306
3307
3308
3309
  	}
  
  	return 0;
  }
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
3310
  int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3311
3312
  			unsigned short family)
  {
f6e1e25d7   Alexey Dobriyan   netns xfrm: xfrm_...
3313
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3314
  	struct xfrm_policy *pol;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3315
3316
3317
3318
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
  	int npols = 0;
  	int xfrm_nr;
  	int pi;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
3319
  	int reverse;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3320
  	struct flowi fl;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3321
  	int xerr_idx = -1;
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
3322
  	const struct xfrm_if_cb *ifcb;
2294be0f1   Florian Westphal   net: use skb_sec_...
3323
  	struct sec_path *sp;
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
3324
3325
3326
3327
3328
3329
3330
  	struct xfrm_if *xi;
  	u32 if_id = 0;
  
  	rcu_read_lock();
  	ifcb = xfrm_if_get_cb();
  
  	if (ifcb) {
025c65e11   Martin Willi   xfrm: Honor origi...
3331
  		xi = ifcb->decode_session(skb, family);
660899ddf   Tobias Brunner   xfrm: Fix inbound...
3332
  		if (xi) {
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
3333
  			if_id = xi->p.if_id;
660899ddf   Tobias Brunner   xfrm: Fix inbound...
3334
3335
  			net = xi->net;
  		}
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
3336
3337
  	}
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3338

d5422efe6   Herbert Xu   [IPSEC]: Added xf...
3339
3340
  	reverse = dir & ~XFRM_POLICY_MASK;
  	dir &= XFRM_POLICY_MASK;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
3341

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3342
  	if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3343
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3344
  		return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3345
  	}
eb9c7ebe6   Patrick McHardy   [NETFILTER]: Hand...
3346
  	nf_nat_decode_session(skb, &fl, family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3347
3348
  
  	/* First, check used SA against their selectors. */
2294be0f1   Florian Westphal   net: use skb_sec_...
3349
3350
  	sp = skb_sec_path(skb);
  	if (sp) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3351
  		int i;
2294be0f1   Florian Westphal   net: use skb_sec_...
3352
3353
  		for (i = sp->len - 1; i >= 0; i--) {
  			struct xfrm_state *x = sp->xvec[i];
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3354
  			if (!xfrm_selector_match(&x->sel, &fl, family)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3355
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3356
  				return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3357
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3358
3359
3360
3361
  		}
  	}
  
  	pol = NULL;
bd5eb35f1   Eric Dumazet   xfrm: take care o...
3362
  	sk = sk_to_full_sk(sk);
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
3363
  	if (sk && sk->sk_policy[dir]) {
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
3364
  		pol = xfrm_sk_policy_lookup(sk, dir, &fl, family, if_id);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3365
  		if (IS_ERR(pol)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3366
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
3367
  			return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3368
  		}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
3369
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3370

86dc8ee0b   Florian Westphal   xfrm_policy: remo...
3371
  	if (!pol)
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
3372
  		pol = xfrm_policy_lookup(net, &fl, family, dir, if_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3373

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3374
  	if (IS_ERR(pol)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3375
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
134b0fc54   James Morris   IPsec: propagate ...
3376
  		return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3377
  	}
134b0fc54   James Morris   IPsec: propagate ...
3378

df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3379
  	if (!pol) {
2294be0f1   Florian Westphal   net: use skb_sec_...
3380
  		if (sp && secpath_has_nontransport(sp, 0, &xerr_idx)) {
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3381
  			xfrm_secpath_reject(xerr_idx, skb, &fl);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3382
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3383
3384
3385
3386
  			return 0;
  		}
  		return 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3387

386c5680e   Arnd Bergmann   xfrm: use time64_...
3388
  	pol->curlft.use_time = ktime_get_real_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3389

4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3390
  	pols[0] = pol;
02d0892f9   Weilong Chen   xfrm: checkpatch ...
3391
  	npols++;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3392
3393
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
f6e1e25d7   Alexey Dobriyan   netns xfrm: xfrm_...
3394
  		pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3395
  						    &fl, family,
bc56b3340   Benedict Wong   xfrm: Remove xfrm...
3396
  						    XFRM_POLICY_IN, if_id);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3397
  		if (pols[1]) {
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3398
  			if (IS_ERR(pols[1])) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3399
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
134b0fc54   James Morris   IPsec: propagate ...
3400
  				return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3401
  			}
386c5680e   Arnd Bergmann   xfrm: use time64_...
3402
  			pols[1]->curlft.use_time = ktime_get_real_seconds();
02d0892f9   Weilong Chen   xfrm: checkpatch ...
3403
  			npols++;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3404
3405
3406
  		}
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3407
  	if (pol->action == XFRM_POLICY_ALLOW) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3408
  		static struct sec_path dummy;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3409
  		struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
3410
  		struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3411
3412
  		struct xfrm_tmpl **tpp = tp;
  		int ti = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3413
  		int i, k;
2294be0f1   Florian Westphal   net: use skb_sec_...
3414
3415
  		sp = skb_sec_path(skb);
  		if (!sp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3416
  			sp = &dummy;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3417
3418
  		for (pi = 0; pi < npols; pi++) {
  			if (pols[pi] != pol &&
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3419
  			    pols[pi]->action != XFRM_POLICY_ALLOW) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3420
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3421
  				goto reject;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3422
3423
  			}
  			if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3424
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3425
  				goto reject_error;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3426
  			}
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3427
3428
3429
3430
  			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...
3431
  		if (npols > 1) {
3aaf3915a   Florian Westphal   xfrm: remove stat...
3432
  			xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
3433
3434
  			tpp = stp;
  		}
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3435

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3436
3437
3438
3439
3440
3441
  		/* 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...
3442
3443
  		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...
3444
  			if (k < 0) {
d1d9facfd   James Morris   [XFRM]: remove xe...
3445
3446
3447
  				if (k < -1)
  					/* "-2 - errored_index" returned */
  					xerr_idx = -(2+k);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3448
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3449
  				goto reject;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3450
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3451
  		}
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3452
  		if (secpath_has_nontransport(sp, k, &xerr_idx)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3453
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3454
  			goto reject;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
3455
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3456

4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3457
  		xfrm_pols_put(pols, npols);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3458
3459
  		return 1;
  	}
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3460
  	XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3461
3462
  
  reject:
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
3463
  	xfrm_secpath_reject(xerr_idx, skb, &fl);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
3464
3465
  reject_error:
  	xfrm_pols_put(pols, npols);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3466
3467
3468
3469
3470
3471
  	return 0;
  }
  EXPORT_SYMBOL(__xfrm_policy_check);
  
  int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
  {
99a66657b   Alexey Dobriyan   netns xfrm: xfrm_...
3472
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3473
  	struct flowi fl;
adf30907d   Eric Dumazet   net: skb->dst acc...
3474
  	struct dst_entry *dst;
731371477   Eric Dumazet   xfrm: fix __xfrm_...
3475
  	int res = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3476

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

fafeeb6c8   Eric Dumazet   xfrm: force a dst...
3482
  	skb_dst_force(skb);
9e1437937   Steffen Klassert   xfrm: Fix NULL po...
3483
3484
3485
3486
  	if (!skb_dst(skb)) {
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR);
  		return 0;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
3487

b8c203b2d   Steffen Klassert   xfrm: Generate qu...
3488
  	dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE);
452edd598   David S. Miller   xfrm: Return dst ...
3489
  	if (IS_ERR(dst)) {
731371477   Eric Dumazet   xfrm: fix __xfrm_...
3490
  		res = 0;
452edd598   David S. Miller   xfrm: Return dst ...
3491
3492
  		dst = NULL;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
3493
3494
  	skb_dst_set(skb, dst);
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3495
3496
  }
  EXPORT_SYMBOL(__xfrm_route_forward);
d49c73c72   David S. Miller   [IPSEC]: Validate...
3497
  /* Optimize later using cookies and generation ids. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3498
3499
  static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
  {
d49c73c72   David S. Miller   [IPSEC]: Validate...
3500
  	/* Code (such as __xfrm4_bundle_create()) sets dst->obsolete
f5b0a8743   David S. Miller   net: Document dst...
3501
3502
3503
3504
3505
3506
3507
  	 * to DST_OBSOLETE_FORCE_CHK 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:
d49c73c72   David S. Miller   [IPSEC]: Validate...
3508
3509
3510
3511
3512
3513
3514
3515
  	 *
  	 *	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.
  	 *
52df157f1   Wei Wang   xfrm: take refcnt...
3516
3517
  	 * When a dst is removed from the fib tree, DST_OBSOLETE_DEAD will
  	 * be marked on it.
09c757048   Florian Westphal   xfrm: remove flow...
3518
  	 * This will force stale_bundle() to fail on any xdst bundle with
52df157f1   Wei Wang   xfrm: take refcnt...
3519
  	 * this dst linked in it.
399c180ac   David S. Miller   [IPSEC]: Perform ...
3520
  	 */
d49c73c72   David S. Miller   [IPSEC]: Validate...
3521
3522
  	if (dst->obsolete < 0 && !stale_bundle(dst))
  		return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3523
3524
3525
3526
3527
  	return NULL;
  }
  
  static int stale_bundle(struct dst_entry *dst)
  {
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
3528
  	return !xfrm_bundle_ok((struct xfrm_dst *)dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3529
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
3530
  void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3531
  {
b92cf4aab   David Miller   net: Create and u...
3532
  	while ((dst = xfrm_dst_child(dst)) && dst->xfrm && dst->dev == dev) {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
3533
  		dst->dev = dev_net(dev)->loopback_dev;
de3cb747f   Daniel Lezcano   [NET]: Dynamicall...
3534
  		dev_hold(dst->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3535
3536
3537
  		dev_put(dev);
  	}
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
3538
  EXPORT_SYMBOL(xfrm_dst_ifdown);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3539
3540
3541
3542
  
  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
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
  }
  
  static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
  {
  	if (dst) {
  		if (dst->obsolete) {
  			dst_release(dst);
  			dst = NULL;
  		}
  	}
  	return dst;
  }
5492093dc   David Miller   xfrm: Stop using ...
3555
  static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3556
  {
5492093dc   David Miller   xfrm: Stop using ...
3557
3558
  	while (nr--) {
  		struct xfrm_dst *xdst = bundle[nr];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3559
  		u32 pmtu, route_mtu_cached;
5492093dc   David Miller   xfrm: Stop using ...
3560
  		struct dst_entry *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3561

5492093dc   David Miller   xfrm: Stop using ...
3562
  		dst = &xdst->u.dst;
b92cf4aab   David Miller   net: Create and u...
3563
  		pmtu = dst_mtu(xfrm_dst_child(dst));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3564
3565
3566
3567
3568
3569
3570
3571
3572
  		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...
3573
  		dst_metric_set(dst, RTAX_MTU, pmtu);
5492093dc   David Miller   xfrm: Stop using ...
3574
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3575
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3576
3577
3578
  /* Check that the bundle accepts the flow and its components are
   * still valid.
   */
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
3579
  static int xfrm_bundle_ok(struct xfrm_dst *first)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3580
  {
5492093dc   David Miller   xfrm: Stop using ...
3581
  	struct xfrm_dst *bundle[XFRM_MAX_DEPTH];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3582
  	struct dst_entry *dst = &first->u.dst;
5492093dc   David Miller   xfrm: Stop using ...
3583
3584
  	struct xfrm_dst *xdst;
  	int start_from, nr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3585
  	u32 mtu;
0f6c480f2   David Miller   xfrm: Move dst->p...
3586
  	if (!dst_check(xfrm_dst_path(dst), ((struct xfrm_dst *)dst)->path_cookie) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3587
3588
  	    (dst->dev && !netif_running(dst->dev)))
  		return 0;
a0073fe18   Steffen Klassert   xfrm: Add a state...
3589
3590
  	if (dst->flags & DST_XFRM_QUEUE)
  		return 1;
5492093dc   David Miller   xfrm: Stop using ...
3591
  	start_from = nr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3592
3593
  	do {
  		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3594
3595
  		if (dst->xfrm->km.state != XFRM_STATE_VALID)
  			return 0;
80c802f30   Timo Teräs   xfrm: cache bundl...
3596
3597
  		if (xdst->xfrm_genid != dst->xfrm->genid)
  			return 0;
b1312c89f   Timo Teräs   xfrm: check bundl...
3598
3599
  		if (xdst->num_pols > 0 &&
  		    xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))
9d4a706d8   David S. Miller   [XFRM]: Add gener...
3600
  			return 0;
e53820de0   Masahide NAKAMURA   [XFRM] IPV6: Rest...
3601

5492093dc   David Miller   xfrm: Stop using ...
3602
  		bundle[nr++] = xdst;
b92cf4aab   David Miller   net: Create and u...
3603
  		mtu = dst_mtu(xfrm_dst_child(dst));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3604
  		if (xdst->child_mtu_cached != mtu) {
5492093dc   David Miller   xfrm: Stop using ...
3605
  			start_from = nr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3606
3607
  			xdst->child_mtu_cached = mtu;
  		}
92d63decc   Hideaki YOSHIFUJI   From: Kazunori Mi...
3608
  		if (!dst_check(xdst->route, xdst->route_cookie))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3609
3610
3611
  			return 0;
  		mtu = dst_mtu(xdst->route);
  		if (xdst->route_mtu_cached != mtu) {
5492093dc   David Miller   xfrm: Stop using ...
3612
  			start_from = nr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3613
3614
  			xdst->route_mtu_cached = mtu;
  		}
b92cf4aab   David Miller   net: Create and u...
3615
  		dst = xfrm_dst_child(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3616
  	} while (dst->xfrm);
5492093dc   David Miller   xfrm: Stop using ...
3617
  	if (likely(!start_from))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3618
  		return 1;
5492093dc   David Miller   xfrm: Stop using ...
3619
3620
3621
3622
  	xdst = bundle[start_from - 1];
  	mtu = xdst->child_mtu_cached;
  	while (start_from--) {
  		dst = &xdst->u.dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3623
3624
  
  		mtu = xfrm_state_mtu(dst->xfrm, mtu);
5492093dc   David Miller   xfrm: Stop using ...
3625
3626
  		if (mtu > xdst->route_mtu_cached)
  			mtu = xdst->route_mtu_cached;
defb3519a   David S. Miller   net: Abstract awa...
3627
  		dst_metric_set(dst, RTAX_MTU, mtu);
5492093dc   David Miller   xfrm: Stop using ...
3628
  		if (!start_from)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3629
  			break;
5492093dc   David Miller   xfrm: Stop using ...
3630
3631
  		xdst = bundle[start_from - 1];
  		xdst->child_mtu_cached = mtu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3632
3633
3634
3635
  	}
  
  	return 1;
  }
0dbaee3b3   David S. Miller   net: Abstract def...
3636
3637
  static unsigned int xfrm_default_advmss(const struct dst_entry *dst)
  {
0f6c480f2   David Miller   xfrm: Move dst->p...
3638
  	return dst_metric_advmss(xfrm_dst_path(dst));
0dbaee3b3   David S. Miller   net: Abstract def...
3639
  }
ebb762f27   Steffen Klassert   net: Rename the d...
3640
  static unsigned int xfrm_mtu(const struct dst_entry *dst)
d33e45533   David S. Miller   net: Abstract def...
3641
  {
618f9bc74   Steffen Klassert   net: Move mtu han...
3642
  	unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
0f6c480f2   David Miller   xfrm: Move dst->p...
3643
  	return mtu ? : dst_mtu(xfrm_dst_path(dst));
d33e45533   David S. Miller   net: Abstract def...
3644
  }
1ecc9ad02   Julian Anastasov   xfrm: provide cor...
3645
3646
  static const void *xfrm_get_dst_nexthop(const struct dst_entry *dst,
  					const void *daddr)
63fca65d0   Julian Anastasov   net: add confirm_...
3647
  {
0f6c480f2   David Miller   xfrm: Move dst->p...
3648
  	while (dst->xfrm) {
63fca65d0   Julian Anastasov   net: add confirm_...
3649
  		const struct xfrm_state *xfrm = dst->xfrm;
013cb81e8   Steffen Klassert   xfrm: Fix infinit...
3650
  		dst = xfrm_dst_child(dst);
63fca65d0   Julian Anastasov   net: add confirm_...
3651
3652
3653
3654
3655
3656
3657
  		if (xfrm->props.mode == XFRM_MODE_TRANSPORT)
  			continue;
  		if (xfrm->type->flags & XFRM_TYPE_REMOTE_COADDR)
  			daddr = xfrm->coaddr;
  		else if (!(xfrm->type->flags & XFRM_TYPE_LOCAL_COADDR))
  			daddr = &xfrm->id.daddr;
  	}
1ecc9ad02   Julian Anastasov   xfrm: provide cor...
3658
3659
3660
3661
3662
3663
3664
  	return daddr;
  }
  
  static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
  					   struct sk_buff *skb,
  					   const void *daddr)
  {
0f6c480f2   David Miller   xfrm: Move dst->p...
3665
  	const struct dst_entry *path = xfrm_dst_path(dst);
1ecc9ad02   Julian Anastasov   xfrm: provide cor...
3666
3667
3668
3669
3670
3671
3672
3673
  
  	if (!skb)
  		daddr = xfrm_get_dst_nexthop(dst, daddr);
  	return path->ops->neigh_lookup(path, skb, daddr);
  }
  
  static void xfrm_confirm_neigh(const struct dst_entry *dst, const void *daddr)
  {
0f6c480f2   David Miller   xfrm: Move dst->p...
3674
  	const struct dst_entry *path = xfrm_dst_path(dst);
1ecc9ad02   Julian Anastasov   xfrm: provide cor...
3675
3676
  
  	daddr = xfrm_get_dst_nexthop(dst, daddr);
63fca65d0   Julian Anastasov   net: add confirm_...
3677
3678
  	path->ops->confirm_neigh(path, daddr);
  }
a2817d8b2   Florian Westphal   xfrm: policy: rem...
3679
  int xfrm_policy_register_afinfo(const struct xfrm_policy_afinfo *afinfo, int family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3680
3681
  {
  	int err = 0;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
3682
3683
  
  	if (WARN_ON(family >= ARRAY_SIZE(xfrm_policy_afinfo)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3684
  		return -EAFNOSUPPORT;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
3685

ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
3686
  	spin_lock(&xfrm_policy_afinfo_lock);
a2817d8b2   Florian Westphal   xfrm: policy: rem...
3687
  	if (unlikely(xfrm_policy_afinfo[family] != NULL))
f31e8d4f7   Li RongQing   xfrm: fix the ret...
3688
  		err = -EEXIST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3689
3690
3691
3692
3693
3694
  	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...
3695
3696
  		if (likely(dst_ops->default_advmss == NULL))
  			dst_ops->default_advmss = xfrm_default_advmss;
ebb762f27   Steffen Klassert   net: Rename the d...
3697
3698
  		if (likely(dst_ops->mtu == NULL))
  			dst_ops->mtu = xfrm_mtu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3699
3700
3701
3702
  		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_...
3703
3704
  		if (likely(dst_ops->neigh_lookup == NULL))
  			dst_ops->neigh_lookup = xfrm_neigh_lookup;
63fca65d0   Julian Anastasov   net: add confirm_...
3705
3706
  		if (likely(!dst_ops->confirm_neigh))
  			dst_ops->confirm_neigh = xfrm_confirm_neigh;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
3707
  		rcu_assign_pointer(xfrm_policy_afinfo[family], afinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3708
  	}
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
3709
  	spin_unlock(&xfrm_policy_afinfo_lock);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
3710

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3711
3712
3713
  	return err;
  }
  EXPORT_SYMBOL(xfrm_policy_register_afinfo);
a2817d8b2   Florian Westphal   xfrm: policy: rem...
3714
  void xfrm_policy_unregister_afinfo(const struct xfrm_policy_afinfo *afinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3715
  {
2b61997aa   Florian Westphal   xfrm: policy: xfr...
3716
  	struct dst_ops *dst_ops = afinfo->dst_ops;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
3717
  	int i;
2b61997aa   Florian Westphal   xfrm: policy: xfr...
3718

a2817d8b2   Florian Westphal   xfrm: policy: rem...
3719
3720
3721
3722
3723
  	for (i = 0; i < ARRAY_SIZE(xfrm_policy_afinfo); i++) {
  		if (xfrm_policy_afinfo[i] != afinfo)
  			continue;
  		RCU_INIT_POINTER(xfrm_policy_afinfo[i], NULL);
  		break;
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
3724
  	}
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
3725

2b61997aa   Florian Westphal   xfrm: policy: xfr...
3726
  	synchronize_rcu();
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
3727

2b61997aa   Florian Westphal   xfrm: policy: xfr...
3728
3729
3730
3731
  	dst_ops->kmem_cachep = NULL;
  	dst_ops->check = NULL;
  	dst_ops->negative_advice = NULL;
  	dst_ops->link_failure = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3732
3733
  }
  EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
f203b76d7   Steffen Klassert   xfrm: Add virtual...
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
  void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb)
  {
  	spin_lock(&xfrm_if_cb_lock);
  	rcu_assign_pointer(xfrm_if_cb, ifcb);
  	spin_unlock(&xfrm_if_cb_lock);
  }
  EXPORT_SYMBOL(xfrm_if_register_cb);
  
  void xfrm_if_unregister_cb(void)
  {
  	RCU_INIT_POINTER(xfrm_if_cb, NULL);
  	synchronize_rcu();
  }
  EXPORT_SYMBOL(xfrm_if_unregister_cb);
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
3748
  #ifdef CONFIG_XFRM_STATISTICS
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3749
  static int __net_init xfrm_statistics_init(struct net *net)
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
3750
  {
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
3751
  	int rv;
698365fa1   WANG Cong   net: clean up snm...
3752
3753
  	net->mib.xfrm_statistics = alloc_percpu(struct linux_xfrm_mib);
  	if (!net->mib.xfrm_statistics)
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
3754
  		return -ENOMEM;
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
3755
3756
  	rv = xfrm_proc_init(net);
  	if (rv < 0)
698365fa1   WANG Cong   net: clean up snm...
3757
  		free_percpu(net->mib.xfrm_statistics);
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
3758
  	return rv;
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
3759
  }
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3760
3761
3762
  
  static void xfrm_statistics_fini(struct net *net)
  {
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
3763
  	xfrm_proc_fini(net);
698365fa1   WANG Cong   net: clean up snm...
3764
  	free_percpu(net->mib.xfrm_statistics);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
  }
  #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...
3775
  #endif
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3776
  static int __net_init xfrm_policy_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3777
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3778
  	unsigned int hmask, sz;
24969facd   Florian Westphal   xfrm: policy: sto...
3779
  	int dir, err;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3780

24969facd   Florian Westphal   xfrm: policy: sto...
3781
  	if (net_eq(net, &init_net)) {
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3782
  		xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3783
  					   sizeof(struct xfrm_dst),
e5d679f33   Alexey Dobriyan   [NET]: Use SLAB_P...
3784
  					   0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
20c2df83d   Paul Mundt   mm: Remove slab d...
3785
  					   NULL);
24969facd   Florian Westphal   xfrm: policy: sto...
3786
3787
3788
3789
  		err = rhashtable_init(&xfrm_policy_inexact_table,
  				      &xfrm_pol_inexact_params);
  		BUG_ON(err);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3790

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3791
3792
  	hmask = 8 - 1;
  	sz = (hmask+1) * sizeof(struct hlist_head);
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
3793
3794
3795
  	net->xfrm.policy_byidx = xfrm_hash_alloc(sz);
  	if (!net->xfrm.policy_byidx)
  		goto out_byidx;
8100bea7d   Alexey Dobriyan   netns xfrm: per-n...
3796
  	net->xfrm.policy_idx_hmask = hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3797

53c2e285f   Herbert Xu   xfrm: Do not hash...
3798
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3799
  		struct xfrm_policy_hash *htab;
dc2caba7b   Alexey Dobriyan   netns xfrm: per-n...
3800
  		net->xfrm.policy_count[dir] = 0;
53c2e285f   Herbert Xu   xfrm: Do not hash...
3801
  		net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
3802
  		INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3803

a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
3804
  		htab = &net->xfrm.policy_bydst[dir];
44e36b42a   David S. Miller   [XFRM]: Extract c...
3805
  		htab->table = xfrm_hash_alloc(sz);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3806
  		if (!htab->table)
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
3807
3808
  			goto out_bydst;
  		htab->hmask = hmask;
b58555f17   Christophe Gouault   xfrm: hash prefix...
3809
3810
3811
3812
  		htab->dbits4 = 32;
  		htab->sbits4 = 32;
  		htab->dbits6 = 128;
  		htab->sbits6 = 128;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3813
  	}
880a6fab8   Christophe Gouault   xfrm: configure p...
3814
3815
3816
3817
3818
3819
  	net->xfrm.policy_hthresh.lbits4 = 32;
  	net->xfrm.policy_hthresh.rbits4 = 32;
  	net->xfrm.policy_hthresh.lbits6 = 128;
  	net->xfrm.policy_hthresh.rbits6 = 128;
  
  	seqlock_init(&net->xfrm.policy_hthresh.lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
3820

adfcf0b27   Alexey Dobriyan   netns xfrm: per-n...
3821
  	INIT_LIST_HEAD(&net->xfrm.policy_all);
24969facd   Florian Westphal   xfrm: policy: sto...
3822
  	INIT_LIST_HEAD(&net->xfrm.inexact_bins);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
3823
  	INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
880a6fab8   Christophe Gouault   xfrm: configure p...
3824
  	INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3825
  	return 0;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
3826

a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
3827
3828
3829
3830
3831
3832
3833
3834
  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...
3835
3836
  out_byidx:
  	return -ENOMEM;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3837
3838
3839
3840
  }
  
  static void xfrm_policy_fini(struct net *net)
  {
6be3b0db6   Florian Westphal   xfrm: policy: add...
3841
  	struct xfrm_pol_inexact_bin *b, *t;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
3842
  	unsigned int sz;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
3843
  	int dir;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
3844

7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
3845
3846
  	flush_work(&net->xfrm.policy_hash_work);
  #ifdef CONFIG_XFRM_SUB_POLICY
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
3847
  	xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false);
7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
3848
  #endif
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
3849
  	xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false);
7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
3850

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

53c2e285f   Herbert Xu   xfrm: Do not hash...
3853
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
3854
  		struct xfrm_policy_hash *htab;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
3855
  		WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
3856
3857
  
  		htab = &net->xfrm.policy_bydst[dir];
5b653b2a1   Michal Kubecek   xfrm: fix freed b...
3858
  		sz = (htab->hmask + 1) * sizeof(struct hlist_head);
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
3859
3860
  		WARN_ON(!hlist_empty(htab->table));
  		xfrm_hash_free(htab->table, sz);
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
3861
  	}
8100bea7d   Alexey Dobriyan   netns xfrm: per-n...
3862
  	sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head);
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
3863
3864
  	WARN_ON(!hlist_empty(net->xfrm.policy_byidx));
  	xfrm_hash_free(net->xfrm.policy_byidx, sz);
24969facd   Florian Westphal   xfrm: policy: sto...
3865

6be3b0db6   Florian Westphal   xfrm: policy: add...
3866
3867
3868
3869
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
  	list_for_each_entry_safe(b, t, &net->xfrm.inexact_bins, inexact_bins)
  		__xfrm_policy_inexact_prune_bin(b, true);
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3870
  }
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3871
3872
3873
  static int __net_init xfrm_net_init(struct net *net)
  {
  	int rv;
c282222a4   Florian Westphal   xfrm: policy: ini...
3874
3875
3876
3877
  	/* Initialize the per-net locks here */
  	spin_lock_init(&net->xfrm.xfrm_state_lock);
  	spin_lock_init(&net->xfrm.xfrm_policy_lock);
  	mutex_init(&net->xfrm.xfrm_cfg_mutex);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3878
3879
3880
  	rv = xfrm_statistics_init(net);
  	if (rv < 0)
  		goto out_statistics;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3881
3882
3883
3884
3885
3886
  	rv = xfrm_state_init(net);
  	if (rv < 0)
  		goto out_state;
  	rv = xfrm_policy_init(net);
  	if (rv < 0)
  		goto out_policy;
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
3887
3888
3889
  	rv = xfrm_sysctl_init(net);
  	if (rv < 0)
  		goto out_sysctl;
283bc9f35   Fan Du   xfrm: Namespacify...
3890

d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3891
  	return 0;
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
3892
3893
  out_sysctl:
  	xfrm_policy_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3894
3895
3896
  out_policy:
  	xfrm_state_fini(net);
  out_state:
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3897
3898
  	xfrm_statistics_fini(net);
  out_statistics:
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3899
3900
3901
3902
3903
  	return rv;
  }
  
  static void __net_exit xfrm_net_exit(struct net *net)
  {
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
3904
  	xfrm_sysctl_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3905
3906
  	xfrm_policy_fini(net);
  	xfrm_state_fini(net);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
3907
  	xfrm_statistics_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3908
3909
3910
3911
3912
3913
  }
  
  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
3914
3915
  void __init xfrm_init(void)
  {
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
3916
  	register_pernet_subsys(&xfrm_net_ops);
e9a441b6e   Kirill Tkhai   xfrm: Register xf...
3917
  	xfrm_dev_init();
77cc278f7   Ahmed S. Darwish   xfrm: policy: Use...
3918
  	seqcount_mutex_init(&xfrm_policy_hash_generation, &hash_resize_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3919
  	xfrm_input_init();
f203b76d7   Steffen Klassert   xfrm: Add virtual...
3920

95a35b42b   Sabrina Dubroca   xfrm: policy: fix...
3921
  #ifdef CONFIG_XFRM_ESPINTCP
e27cca96c   Sabrina Dubroca   xfrm: add espintc...
3922
3923
  	espintcp_init();
  #endif
f203b76d7   Steffen Klassert   xfrm: Add virtual...
3924
3925
  	RCU_INIT_POINTER(xfrm_if_cb, NULL);
  	synchronize_rcu();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3926
  }
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3927
  #ifdef CONFIG_AUDITSYSCALL
1486cbd77   Ilpo Järvinen   [XFRM] xfrm_polic...
3928
3929
  static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
  					 struct audit_buffer *audit_buf)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3930
  {
875179fa6   Paul Moore   [IPSEC]: SPD audi...
3931
3932
3933
3934
  	struct xfrm_sec_ctx *ctx = xp->security;
  	struct xfrm_selector *sel = &xp->selector;
  
  	if (ctx)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3935
  		audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
875179fa6   Paul Moore   [IPSEC]: SPD audi...
3936
  				 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3937

9b7a787d0   Weilong Chen   xfrm: checkpatch ...
3938
  	switch (sel->family) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3939
  	case AF_INET:
21454aaad   Harvey Harrison   net: replace NIPQ...
3940
  		audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
3941
3942
3943
  		if (sel->prefixlen_s != 32)
  			audit_log_format(audit_buf, " src_prefixlen=%d",
  					 sel->prefixlen_s);
21454aaad   Harvey Harrison   net: replace NIPQ...
3944
  		audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
3945
3946
3947
  		if (sel->prefixlen_d != 32)
  			audit_log_format(audit_buf, " dst_prefixlen=%d",
  					 sel->prefixlen_d);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3948
3949
  		break;
  	case AF_INET6:
5b095d989   Harvey Harrison   net: replace %p6 ...
3950
  		audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
3951
3952
3953
  		if (sel->prefixlen_s != 128)
  			audit_log_format(audit_buf, " src_prefixlen=%d",
  					 sel->prefixlen_s);
5b095d989   Harvey Harrison   net: replace %p6 ...
3954
  		audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
3955
3956
3957
  		if (sel->prefixlen_d != 128)
  			audit_log_format(audit_buf, " dst_prefixlen=%d",
  					 sel->prefixlen_d);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3958
3959
3960
  		break;
  	}
  }
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
3961
  void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3962
3963
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3964

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
3965
  	audit_buf = xfrm_audit_start("SPD-add");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3966
3967
  	if (audit_buf == NULL)
  		return;
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
3968
  	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
3969
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3970
3971
3972
3973
  	xfrm_audit_common_policyinfo(xp, audit_buf);
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
68277accb   Paul Moore   [XFRM]: Assorted ...
3974
  void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
3975
  			      bool task_valid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3976
3977
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3978

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
3979
  	audit_buf = xfrm_audit_start("SPD-delete");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3980
3981
  	if (audit_buf == NULL)
  		return;
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
3982
  	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
3983
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
3984
3985
3986
3987
3988
  	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...
3989
  #ifdef CONFIG_XFRM_MIGRATE
bc9b35ad4   David S. Miller   xfrm: Convert sev...
3990
3991
  static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
  					const struct xfrm_selector *sel_tgt)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3992
3993
3994
  {
  	if (sel_cmp->proto == IPSEC_ULPROTO_ANY) {
  		if (sel_tgt->family == sel_cmp->family &&
70e94e66a   YOSHIFUJI Hideaki / 吉藤英明   xfrm: Convert xfr...
3995
3996
3997
3998
  		    xfrm_addr_equal(&sel_tgt->daddr, &sel_cmp->daddr,
  				    sel_cmp->family) &&
  		    xfrm_addr_equal(&sel_tgt->saddr, &sel_cmp->saddr,
  				    sel_cmp->family) &&
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3999
4000
  		    sel_tgt->prefixlen_d == sel_cmp->prefixlen_d &&
  		    sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) {
bc9b35ad4   David S. Miller   xfrm: Convert sev...
4001
  			return true;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4002
4003
4004
  		}
  	} else {
  		if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) {
bc9b35ad4   David S. Miller   xfrm: Convert sev...
4005
  			return true;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4006
4007
  		}
  	}
bc9b35ad4   David S. Miller   xfrm: Convert sev...
4008
  	return false;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4009
  }
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
4010
4011
  static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
  						    u8 dir, u8 type, struct net *net)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4012
4013
  {
  	struct xfrm_policy *pol, *ret = NULL;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4014
4015
  	struct hlist_head *chain;
  	u32 priority = ~0U;
9d0380df6   Florian Westphal   xfrm: policy: con...
4016
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
8d549c4f5   Fan Du   xfrm: Using the r...
4017
  	chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
b67bfe0d4   Sasha Levin   hlist: drop the n...
4018
  	hlist_for_each_entry(pol, chain, bydst) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4019
4020
4021
4022
4023
4024
4025
  		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
  		    pol->type == type) {
  			ret = pol;
  			priority = ret->priority;
  			break;
  		}
  	}
8d549c4f5   Fan Du   xfrm: Using the r...
4026
  	chain = &net->xfrm.policy_inexact[dir];
24969facd   Florian Westphal   xfrm: policy: sto...
4027
  	hlist_for_each_entry(pol, chain, bydst_inexact_list) {
8faf491e6   Li RongQing   xfrm: optimise to...
4028
4029
  		if ((pol->priority >= priority) && ret)
  			break;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4030
  		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
8faf491e6   Li RongQing   xfrm: optimise to...
4031
  		    pol->type == type) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4032
4033
4034
4035
  			ret = pol;
  			break;
  		}
  	}
586f2eb41   Li RongQing   xfrm: remove the ...
4036
  	xfrm_pol_hold(ret);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4037

9d0380df6   Florian Westphal   xfrm: policy: con...
4038
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4039
4040
4041
  
  	return ret;
  }
dd701754e   David S. Miller   xfrm: Const'ify p...
4042
  static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tmpl *t)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4043
4044
4045
4046
4047
4048
4049
4050
  {
  	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:
70e94e66a   YOSHIFUJI Hideaki / 吉藤英明   xfrm: Convert xfr...
4051
4052
4053
4054
  			if (xfrm_addr_equal(&t->id.daddr, &m->old_daddr,
  					    m->old_family) &&
  			    xfrm_addr_equal(&t->saddr, &m->old_saddr,
  					    m->old_family)) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
  				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...
4076
4077
4078
  	int i, j, n = 0;
  
  	write_lock_bh(&pol->lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
4079
  	if (unlikely(pol->walk.dead)) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
  		/* 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...
4090
4091
  			if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL &&
  			    pol->xfrm_vec[i].mode != XFRM_MODE_BEET)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4092
4093
4094
4095
4096
4097
4098
4099
  				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...
4100
  			atomic_inc(&pol->genid);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
  		}
  	}
  
  	write_unlock_bh(&pol->lock);
  
  	if (!n)
  		return -ENODATA;
  
  	return 0;
  }
dd701754e   David S. Miller   xfrm: Const'ify p...
4111
  static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4112
4113
4114
4115
4116
4117
4118
  {
  	int i, j;
  
  	if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH)
  		return -EINVAL;
  
  	for (i = 0; i < num_migrate; i++) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
  		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...
4139
  int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
4140
  		 struct xfrm_migrate *m, int num_migrate,
4ab47d47a   Antony Antony   xfrm: extend MIGR...
4141
4142
  		 struct xfrm_kmaddress *k, struct net *net,
  		 struct xfrm_encap_tmpl *encap)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4143
4144
4145
4146
4147
4148
4149
  {
  	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;
7bab09631   Vladis Dronov   xfrm: policy: che...
4150
  	/* Stage 0 - sanity checks */
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4151
4152
  	if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
  		goto out;
7bab09631   Vladis Dronov   xfrm: policy: che...
4153
4154
4155
4156
  	if (dir >= XFRM_POLICY_MAX) {
  		err = -EINVAL;
  		goto out;
  	}
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4157
  	/* Stage 1 - find policy */
8d549c4f5   Fan Du   xfrm: Using the r...
4158
  	if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4159
4160
4161
4162
4163
4164
  		err = -ENOENT;
  		goto out;
  	}
  
  	/* Stage 2 - find and update state(s) */
  	for (i = 0, mp = m; i < num_migrate; i++, mp++) {
283bc9f35   Fan Du   xfrm: Namespacify...
4165
  		if ((x = xfrm_migrate_state_find(mp, net))) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4166
4167
  			x_cur[nx_cur] = x;
  			nx_cur++;
4ab47d47a   Antony Antony   xfrm: extend MIGR...
4168
4169
  			xc = xfrm_state_migrate(x, mp, encap);
  			if (xc) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
  				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 */
8bafd7309   Antony Antony   xfrm: add UDP enc...
4190
  	km_migrate(sel, dir, type, m, num_migrate, k, encap);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
  
  	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...
4208
  EXPORT_SYMBOL(xfrm_migrate);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
4209
  #endif