Blame view

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

44e36b42a   David S. Miller   [XFRM]: Extract c...
36
  #include "xfrm_hash.h"
a0073fe18   Steffen Klassert   xfrm: Add a state...
37
38
39
  #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...
40
41
42
43
  struct xfrm_flo {
  	struct dst_entry *dst_orig;
  	u8 flags;
  };
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
44
45
  static DEFINE_PER_CPU(struct xfrm_dst *, xfrm_last_dst);
  static struct work_struct *xfrm_pcpu_work __read_mostly;
418a99ac6   Priyanka Jain   Replace rwlock on...
46
  static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
37b103830   Florian Westphal   xfrm: policy: mak...
47
  static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1]
418a99ac6   Priyanka Jain   Replace rwlock on...
48
  						__read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49

e18b890bb   Christoph Lameter   [PATCH] slab: rem...
50
  static struct kmem_cache *xfrm_dst_cache __read_mostly;
30846090a   Florian Westphal   xfrm: policy: add...
51
  static __read_mostly seqcount_t xfrm_policy_hash_generation;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
53
  static void xfrm_init_pmtu(struct dst_entry *dst);
80c802f30   Timo Teräs   xfrm: cache bundl...
54
  static int stale_bundle(struct dst_entry *dst);
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
55
  static int xfrm_bundle_ok(struct xfrm_dst *xdst);
c3aed7095   Kees Cook   xfrm: Convert tim...
56
  static void xfrm_policy_queue_process(struct timer_list *t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

12bfa8bdb   Herbert Xu   xfrm: Use __xfrm_...
58
  static void __xfrm_policy_link(struct xfrm_policy *pol, int dir);
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
59
60
  static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
  						int dir);
e37cc8ade   Florian Westphal   xfrm: policy: use...
61
62
  static inline bool xfrm_pol_hold_rcu(struct xfrm_policy *policy)
  {
850a6212c   Reshetova, Elena   net, xfrm: conver...
63
  	return refcount_inc_not_zero(&policy->refcnt);
e37cc8ade   Florian Westphal   xfrm: policy: use...
64
  }
bc9b35ad4   David S. Miller   xfrm: Convert sev...
65
  static inline bool
200ce96e5   David S. Miller   xfrm: Const'ify s...
66
  __xfrm4_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
776810217   Andrew Morton   [XFRM]: uninline ...
67
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
68
  	const struct flowi4 *fl4 = &fl->u.ip4;
26bff940d   Alexey Dobriyan   xfrm: optimize ip...
69
70
  	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...
71
72
73
74
  		!((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 ...
75
  }
bc9b35ad4   David S. Miller   xfrm: Convert sev...
76
  static inline bool
200ce96e5   David S. Miller   xfrm: Const'ify s...
77
  __xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)
776810217   Andrew Morton   [XFRM]: uninline ...
78
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
79
80
81
82
83
84
85
86
  	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 ...
87
  }
bc9b35ad4   David S. Miller   xfrm: Convert sev...
88
89
  bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl,
  			 unsigned short family)
776810217   Andrew Morton   [XFRM]: uninline ...
90
91
92
93
94
95
96
  {
  	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...
97
  	return false;
776810217   Andrew Morton   [XFRM]: uninline ...
98
  }
a2817d8b2   Florian Westphal   xfrm: policy: rem...
99
  static const struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
100
  {
a2817d8b2   Florian Westphal   xfrm: policy: rem...
101
  	const struct xfrm_policy_afinfo *afinfo;
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
102

a2817d8b2   Florian Westphal   xfrm: policy: rem...
103
  	if (unlikely(family >= ARRAY_SIZE(xfrm_policy_afinfo)))
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
104
105
106
107
108
109
110
  		return NULL;
  	rcu_read_lock();
  	afinfo = rcu_dereference(xfrm_policy_afinfo[family]);
  	if (unlikely(!afinfo))
  		rcu_read_unlock();
  	return afinfo;
  }
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
111
112
113
  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...
114
  				    int family, u32 mark)
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
115
  {
37b103830   Florian Westphal   xfrm: policy: mak...
116
  	const struct xfrm_policy_afinfo *afinfo;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
117
118
119
120
121
  	struct dst_entry *dst;
  
  	afinfo = xfrm_policy_get_afinfo(family);
  	if (unlikely(afinfo == NULL))
  		return ERR_PTR(-EAFNOSUPPORT);
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
122
  	dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
123

bdba9fe01   Florian Westphal   xfrm: policy: rem...
124
  	rcu_read_unlock();
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
125
126
127
  
  	return dst;
  }
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
128
  EXPORT_SYMBOL(__xfrm_dst_lookup);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
129

42a7b32b7   David Ahern   xfrm: Add oif to ...
130
131
  static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
  						int tos, int oif,
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
132
133
  						xfrm_address_t *prev_saddr,
  						xfrm_address_t *prev_daddr,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
134
  						int family, u32 mark)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  {
c5b3cf46e   Alexey Dobriyan   netns xfrm: ->dst...
136
  	struct net *net = xs_net(x);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
137
138
  	xfrm_address_t *saddr = &x->props.saddr;
  	xfrm_address_t *daddr = &x->id.daddr;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
139
  	struct dst_entry *dst;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
140
  	if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
141
  		saddr = x->coaddr;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
142
143
144
145
  		daddr = prev_daddr;
  	}
  	if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
  		saddr = prev_saddr;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
146
  		daddr = x->coaddr;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
147
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

077fbac40   Lorenzo Colitti   net: xfrm: suppor...
149
  	dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family, mark);
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
150
151
152
153
154
155
156
  
  	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
157

66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
158
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
  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...
166
  		return secs*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  }
c3aed7095   Kees Cook   xfrm: Convert tim...
168
  static void xfrm_policy_timer(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  {
c3aed7095   Kees Cook   xfrm: Convert tim...
170
  	struct xfrm_policy *xp = from_timer(xp, t, timer);
9d729f72d   James Morris   [NET]: Convert xt...
171
  	unsigned long now = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
176
  	long next = LONG_MAX;
  	int warn = 0;
  	int dir;
  
  	read_lock(&xp->lock);
ea2dea9da   Timo Teräs   xfrm: remove poli...
177
  	if (unlikely(xp->walk.dead))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  		goto out;
77d8d7a68   Herbert Xu   [IPSEC]: Document...
179
  	dir = xfrm_policy_id2dir(xp->index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  
  	if (xp->lft.hard_add_expires_seconds) {
  		long tmo = xp->lft.hard_add_expires_seconds +
  			xp->curlft.add_time - now;
  		if (tmo <= 0)
  			goto expired;
  		if (tmo < next)
  			next = tmo;
  	}
  	if (xp->lft.hard_use_expires_seconds) {
  		long tmo = xp->lft.hard_use_expires_seconds +
  			(xp->curlft.use_time ? : xp->curlft.add_time) - now;
  		if (tmo <= 0)
  			goto expired;
  		if (tmo < next)
  			next = tmo;
  	}
  	if (xp->lft.soft_add_expires_seconds) {
  		long tmo = xp->lft.soft_add_expires_seconds +
  			xp->curlft.add_time - now;
  		if (tmo <= 0) {
  			warn = 1;
  			tmo = XFRM_KM_TIMEOUT;
  		}
  		if (tmo < next)
  			next = tmo;
  	}
  	if (xp->lft.soft_use_expires_seconds) {
  		long tmo = xp->lft.soft_use_expires_seconds +
  			(xp->curlft.use_time ? : xp->curlft.add_time) - now;
  		if (tmo <= 0) {
  			warn = 1;
  			tmo = XFRM_KM_TIMEOUT;
  		}
  		if (tmo < next)
  			next = tmo;
  	}
  
  	if (warn)
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
219
  		km_policy_expired(xp, dir, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
224
225
226
227
228
229
230
  	if (next != LONG_MAX &&
  	    !mod_timer(&xp->timer, jiffies + make_jiffies(next)))
  		xfrm_pol_hold(xp);
  
  out:
  	read_unlock(&xp->lock);
  	xfrm_pol_put(xp);
  	return;
  
  expired:
  	read_unlock(&xp->lock);
4666faab0   Herbert Xu   [IPSEC] Kill spur...
231
  	if (!xfrm_policy_delete(xp, dir))
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
232
  		km_policy_expired(xp, dir, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
  	xfrm_pol_put(xp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
   * SPD calls.
   */
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
238
  struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  {
  	struct xfrm_policy *policy;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
241
  	policy = kzalloc(sizeof(struct xfrm_policy), gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  
  	if (policy) {
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
244
  		write_pnet(&policy->xp_net, net);
12a169e7d   Herbert Xu   ipsec: Put dumper...
245
  		INIT_LIST_HEAD(&policy->walk.all);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
246
247
  		INIT_HLIST_NODE(&policy->bydst);
  		INIT_HLIST_NODE(&policy->byidx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  		rwlock_init(&policy->lock);
850a6212c   Reshetova, Elena   net, xfrm: conver...
249
  		refcount_set(&policy->refcnt, 1);
a0073fe18   Steffen Klassert   xfrm: Add a state...
250
  		skb_queue_head_init(&policy->polq.hold_queue);
c3aed7095   Kees Cook   xfrm: Convert tim...
251
252
253
  		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
254
255
256
257
  	}
  	return policy;
  }
  EXPORT_SYMBOL(xfrm_policy_alloc);
56f047305   Eric Dumazet   xfrm: add rcu gra...
258
259
260
261
262
263
264
  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
265
  /* Destroy xfrm_policy: descendant resources must be released to this moment. */
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
266
  void xfrm_policy_destroy(struct xfrm_policy *policy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
268
  	BUG_ON(!policy->walk.dead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

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

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

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

e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
286
287
  	if (del_timer(&policy->polq.hold_timer))
  		xfrm_pol_put(policy);
1ee5e6676   Li RongQing   xfrm: remove the ...
288
  	skb_queue_purge(&policy->polq.hold_queue);
a0073fe18   Steffen Klassert   xfrm: Add a state...
289

285ead175   Timo Teräs   xfrm: remove poli...
290
291
292
293
  	if (del_timer(&policy->timer))
  		xfrm_pol_put(policy);
  
  	xfrm_pol_put(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  }
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
295
  static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
e92303f87   Alexey Dobriyan   netns xfrm: propa...
296
  static inline unsigned int idx_hash(struct net *net, u32 index)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
297
  {
e92303f87   Alexey Dobriyan   netns xfrm: propa...
298
  	return __idx_hash(index, net->xfrm.policy_idx_hmask);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
299
  }
b58555f17   Christophe Gouault   xfrm: hash prefix...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  /* 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...
321
322
323
  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...
324
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
325
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
b58555f17   Christophe Gouault   xfrm: hash prefix...
326
327
328
329
330
331
  	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...
332

e1e551bc5   Florian Westphal   xfrm: policy: pre...
333
334
335
336
337
  	if (hash == hmask + 1)
  		return &net->xfrm.policy_inexact[dir];
  
  	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...
338
  }
5f803b58c   David S. Miller   xfrm: Const'ify a...
339
340
341
342
  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...
343
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
344
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
b58555f17   Christophe Gouault   xfrm: hash prefix...
345
346
347
348
349
350
  	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...
351

e1e551bc5   Florian Westphal   xfrm: policy: pre...
352
353
  	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...
354
  }
b58555f17   Christophe Gouault   xfrm: hash prefix...
355
356
  static void xfrm_dst_hash_transfer(struct net *net,
  				   struct hlist_head *list,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
357
  				   struct hlist_head *ndsttable,
b58555f17   Christophe Gouault   xfrm: hash prefix...
358
359
  				   unsigned int nhashmask,
  				   int dir)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
360
  {
b67bfe0d4   Sasha Levin   hlist: drop the n...
361
  	struct hlist_node *tmp, *entry0 = NULL;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
362
  	struct xfrm_policy *pol;
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
363
  	unsigned int h0 = 0;
b58555f17   Christophe Gouault   xfrm: hash prefix...
364
365
  	u8 dbits;
  	u8 sbits;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
366

b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
367
  redo:
b67bfe0d4   Sasha Levin   hlist: drop the n...
368
  	hlist_for_each_entry_safe(pol, tmp, list, bydst) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
369
  		unsigned int h;
b58555f17   Christophe Gouault   xfrm: hash prefix...
370
  		__get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
371
  		h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
b58555f17   Christophe Gouault   xfrm: hash prefix...
372
  				pol->family, nhashmask, dbits, sbits);
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
373
  		if (!entry0) {
a5eefc1df   Florian Westphal   xfrm: policy: use...
374
375
  			hlist_del_rcu(&pol->bydst);
  			hlist_add_head_rcu(&pol->bydst, ndsttable + h);
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
376
377
378
379
  			h0 = h;
  		} else {
  			if (h != h0)
  				continue;
a5eefc1df   Florian Westphal   xfrm: policy: use...
380
381
  			hlist_del_rcu(&pol->bydst);
  			hlist_add_behind_rcu(&pol->bydst, entry0);
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
382
  		}
b67bfe0d4   Sasha Levin   hlist: drop the n...
383
  		entry0 = &pol->bydst;
b791160b5   YOSHIFUJI Hideaki   [XFRM]: Fix order...
384
385
386
387
  	}
  	if (!hlist_empty(list)) {
  		entry0 = NULL;
  		goto redo;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
388
389
390
391
392
393
394
  	}
  }
  
  static void xfrm_idx_hash_transfer(struct hlist_head *list,
  				   struct hlist_head *nidxtable,
  				   unsigned int nhashmask)
  {
b67bfe0d4   Sasha Levin   hlist: drop the n...
395
  	struct hlist_node *tmp;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
396
  	struct xfrm_policy *pol;
b67bfe0d4   Sasha Levin   hlist: drop the n...
397
  	hlist_for_each_entry_safe(pol, tmp, list, byidx) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
398
399
400
401
402
403
404
405
406
407
408
  		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...
409
  static void xfrm_bydst_resize(struct net *net, int dir)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
410
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
411
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
412
413
  	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
  	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
44e36b42a   David S. Miller   [XFRM]: Extract c...
414
  	struct hlist_head *ndst = xfrm_hash_alloc(nsize);
e1e551bc5   Florian Westphal   xfrm: policy: pre...
415
  	struct hlist_head *odst;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
416
417
418
419
  	int i;
  
  	if (!ndst)
  		return;
9d0380df6   Florian Westphal   xfrm: policy: con...
420
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
30846090a   Florian Westphal   xfrm: policy: add...
421
422
423
424
  	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...
425

e1e551bc5   Florian Westphal   xfrm: policy: pre...
426
427
  	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...
428
  	for (i = hmask; i >= 0; i--)
b58555f17   Christophe Gouault   xfrm: hash prefix...
429
  		xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
430

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

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

e1e551bc5   Florian Westphal   xfrm: policy: pre...
437
  	synchronize_rcu();
44e36b42a   David S. Miller   [XFRM]: Extract c...
438
  	xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
439
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
440
  static void xfrm_byidx_resize(struct net *net, int total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
441
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
442
  	unsigned int hmask = net->xfrm.policy_idx_hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
443
444
  	unsigned int nhashmask = xfrm_new_hash_mask(hmask);
  	unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
445
  	struct hlist_head *oidx = net->xfrm.policy_byidx;
44e36b42a   David S. Miller   [XFRM]: Extract c...
446
  	struct hlist_head *nidx = xfrm_hash_alloc(nsize);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
447
448
449
450
  	int i;
  
  	if (!nidx)
  		return;
9d0380df6   Florian Westphal   xfrm: policy: con...
451
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
452
453
454
  
  	for (i = hmask; i >= 0; i--)
  		xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
455
456
  	net->xfrm.policy_byidx = nidx;
  	net->xfrm.policy_idx_hmask = nhashmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
457

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

44e36b42a   David S. Miller   [XFRM]: Extract c...
460
  	xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
461
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
462
  static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
463
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
464
465
  	unsigned int cnt = net->xfrm.policy_count[dir];
  	unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
466
467
468
469
470
471
472
473
474
475
  
  	if (total)
  		*total += cnt;
  
  	if ((hmask + 1) < xfrm_policy_hashmax &&
  	    cnt > hmask)
  		return 1;
  
  	return 0;
  }
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
476
  static inline int xfrm_byidx_should_resize(struct net *net, int total)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
477
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
478
  	unsigned int hmask = net->xfrm.policy_idx_hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
479
480
481
482
483
484
485
  
  	if ((hmask + 1) < xfrm_policy_hashmax &&
  	    total > hmask)
  		return 1;
  
  	return 0;
  }
e071041be   Alexey Dobriyan   netns xfrm: fix "...
486
  void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si)
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
487
  {
e071041be   Alexey Dobriyan   netns xfrm: fix "...
488
489
490
491
492
493
494
  	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...
495
  	si->spdhmcnt = xfrm_policy_hashmax;
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
496
497
  }
  EXPORT_SYMBOL(xfrm_spd_getinfo);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
498

ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
499
  static DEFINE_MUTEX(hash_resize_mutex);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
500
  static void xfrm_hash_resize(struct work_struct *work)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
501
  {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
502
  	struct net *net = container_of(work, struct net, xfrm.policy_hash_work);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
503
504
505
506
507
  	int dir, total;
  
  	mutex_lock(&hash_resize_mutex);
  
  	total = 0;
53c2e285f   Herbert Xu   xfrm: Do not hash...
508
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
509
510
  		if (xfrm_bydst_should_resize(net, dir, &total))
  			xfrm_bydst_resize(net, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
511
  	}
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
512
513
  	if (xfrm_byidx_should_resize(net, total))
  		xfrm_byidx_resize(net, total);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
514
515
516
  
  	mutex_unlock(&hash_resize_mutex);
  }
880a6fab8   Christophe Gouault   xfrm: configure p...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  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...
543
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
880a6fab8   Christophe Gouault   xfrm: configure p...
544
545
  
  	/* reset the bydst and inexact table in all directions */
53c2e285f   Herbert Xu   xfrm: Do not hash...
546
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
880a6fab8   Christophe Gouault   xfrm: configure p...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  		INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
  		hmask = net->xfrm.policy_bydst[dir].hmask;
  		odst = net->xfrm.policy_bydst[dir].table;
  		for (i = hmask; i >= 0; i--)
  			INIT_HLIST_HEAD(odst + i);
  		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) {
6916fb3b1   Tobias Brunner   xfrm: Ignore sock...
569
570
571
572
  		if (xfrm_policy_id2dir(policy->index) >= XFRM_POLICY_MAX) {
  			/* skip socket policies */
  			continue;
  		}
880a6fab8   Christophe Gouault   xfrm: configure p...
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  		newpos = NULL;
  		chain = policy_hash_bysel(net, &policy->selector,
  					  policy->family,
  					  xfrm_policy_id2dir(policy->index));
  		hlist_for_each_entry(pol, chain, bydst) {
  			if (policy->priority >= pol->priority)
  				newpos = &pol->bydst;
  			else
  				break;
  		}
  		if (newpos)
  			hlist_add_behind(&policy->bydst, newpos);
  		else
  			hlist_add_head(&policy->bydst, chain);
  	}
9d0380df6   Florian Westphal   xfrm: policy: con...
588
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
880a6fab8   Christophe Gouault   xfrm: configure p...
589
590
591
592
593
594
595
596
597
  
  	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
598
599
  /* 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...
600
  static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
  	static u32 idx_generator;
  
  	for (;;) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
605
606
607
608
  		struct hlist_head *list;
  		struct xfrm_policy *p;
  		u32 idx;
  		int found;
e682adf02   Fan Du   xfrm: Try to hono...
609
610
611
612
613
614
615
  		if (!index) {
  			idx = (idx_generator | dir);
  			idx_generator += 8;
  		} else {
  			idx = index;
  			index = 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
  		if (idx == 0)
  			idx = 8;
1121994c8   Alexey Dobriyan   netns xfrm: polic...
618
  		list = net->xfrm.policy_byidx + idx_hash(net, idx);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
619
  		found = 0;
b67bfe0d4   Sasha Levin   hlist: drop the n...
620
  		hlist_for_each_entry(p, list, byidx) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
621
622
  			if (p->index == idx) {
  				found = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  				break;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
624
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  		}
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
626
  		if (!found)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
  			return idx;
  	}
  }
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
630
631
632
633
634
635
636
637
638
639
640
641
642
643
  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...
644
645
646
647
648
  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...
649
650
  	if (skb_queue_empty(&pq->hold_queue))
  		return;
a0073fe18   Steffen Klassert   xfrm: Add a state...
651
652
653
654
  	__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...
655
656
  	if (del_timer(&pq->hold_timer))
  		xfrm_pol_put(old);
a0073fe18   Steffen Klassert   xfrm: Add a state...
657
  	spin_unlock_bh(&pq->hold_queue.lock);
a0073fe18   Steffen Klassert   xfrm: Add a state...
658
659
660
661
662
  	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...
663
664
  	if (!mod_timer(&pq->hold_timer, jiffies))
  		xfrm_pol_hold(new);
a0073fe18   Steffen Klassert   xfrm: Add a state...
665
666
  	spin_unlock_bh(&pq->hold_queue.lock);
  }
7cb8a9396   Steffen Klassert   xfrm: Allow inser...
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
  				   struct xfrm_policy *pol)
  {
  	u32 mark = policy->mark.v & policy->mark.m;
  
  	if (policy->mark.v == pol->mark.v && policy->mark.m == pol->mark.m)
  		return true;
  
  	if ((mark & pol->mark.m) == pol->mark.v &&
  	    policy->priority == pol->priority)
  		return true;
  
  	return false;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
  int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
683
  	struct net *net = xp_net(policy);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
684
685
686
  	struct xfrm_policy *pol;
  	struct xfrm_policy *delpol;
  	struct hlist_head *chain;
b67bfe0d4   Sasha Levin   hlist: drop the n...
687
  	struct hlist_node *newpos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688

9d0380df6   Florian Westphal   xfrm: policy: con...
689
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
690
  	chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
691
692
  	delpol = NULL;
  	newpos = NULL;
b67bfe0d4   Sasha Levin   hlist: drop the n...
693
  	hlist_for_each_entry(pol, chain, bydst) {
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
694
  		if (pol->type == policy->type &&
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
695
  		    !selector_cmp(&pol->selector, &policy->selector) &&
7cb8a9396   Steffen Klassert   xfrm: Allow inser...
696
  		    xfrm_policy_mark_match(policy, pol) &&
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
697
698
  		    xfrm_sec_ctx_match(pol->security, policy->security) &&
  		    !WARN_ON(delpol)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
  			if (excl) {
9d0380df6   Florian Westphal   xfrm: policy: con...
700
  				spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
  				return -EEXIST;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
706
  			delpol = pol;
  			if (policy->priority > pol->priority)
  				continue;
  		} else if (policy->priority >= pol->priority) {
a6c7ab55d   Herbert Xu   [IPSEC]: Policy l...
707
  			newpos = &pol->bydst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
711
  		if (delpol)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
  	}
  	if (newpos)
1d023284c   Ken Helias   list: fix order o...
714
  		hlist_add_behind(&policy->bydst, newpos);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
715
716
  	else
  		hlist_add_head(&policy->bydst, chain);
12bfa8bdb   Herbert Xu   xfrm: Use __xfrm_...
717
  	__xfrm_policy_link(policy, dir);
ca4c3fc24   fan.du   net: split rt_gen...
718
719
720
721
722
723
  
  	/* 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...
724
725
  	if (delpol) {
  		xfrm_policy_requeue(delpol, policy);
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
726
  		__xfrm_policy_unlink(delpol, dir);
a0073fe18   Steffen Klassert   xfrm: Add a state...
727
  	}
e682adf02   Fan Du   xfrm: Try to hono...
728
  	policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index);
1121994c8   Alexey Dobriyan   netns xfrm: polic...
729
  	hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index));
9d729f72d   James Morris   [NET]: Convert xt...
730
  	policy->curlft.add_time = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
  	policy->curlft.use_time = 0;
  	if (!mod_timer(&policy->timer, jiffies + HZ))
  		xfrm_pol_hold(policy);
9d0380df6   Florian Westphal   xfrm: policy: con...
734
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_policy_insert);
8ca2e93b5   Jamal Hadi Salim   xfrm: SP lookups ...
744
745
  struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
  					  int dir, struct xfrm_selector *sel,
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
746
747
  					  struct xfrm_sec_ctx *ctx, int delete,
  					  int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
749
750
  	struct xfrm_policy *pol, *ret;
  	struct hlist_head *chain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751

ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
752
  	*err = 0;
9d0380df6   Florian Westphal   xfrm: policy: con...
753
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
8d1211a6a   Alexey Dobriyan   netns xfrm: findi...
754
  	chain = policy_hash_bysel(net, sel, sel->family, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
755
  	ret = NULL;
b67bfe0d4   Sasha Levin   hlist: drop the n...
756
  	hlist_for_each_entry(pol, chain, bydst) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
757
  		if (pol->type == type &&
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
758
  		    (mark & pol->mark.m) == pol->mark.v &&
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
759
760
  		    !selector_cmp(sel, &pol->selector) &&
  		    xfrm_sec_ctx_match(ctx, pol->security)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
  			xfrm_pol_hold(pol);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
762
  			if (delete) {
03e1ad7b5   Paul Moore   LSM: Make the Lab...
763
764
  				*err = security_xfrm_policy_delete(
  								pol->security);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
765
  				if (*err) {
9d0380df6   Florian Westphal   xfrm: policy: con...
766
  					spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
767
768
  					return pol;
  				}
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
769
  				__xfrm_policy_unlink(pol, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
770
771
  			}
  			ret = pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
  			break;
  		}
  	}
9d0380df6   Florian Westphal   xfrm: policy: con...
775
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776

fe1a5f031   Timo Teräs   flow: virtualize ...
777
  	if (ret && delete)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
778
  		xfrm_policy_kill(ret);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
779
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
781
  EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782

8ca2e93b5   Jamal Hadi Salim   xfrm: SP lookups ...
783
784
  struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
  				     int dir, u32 id, int delete, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
786
787
  	struct xfrm_policy *pol, *ret;
  	struct hlist_head *chain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788

b5505c6e1   Herbert Xu   [IPSEC]: Check va...
789
790
791
  	*err = -ENOENT;
  	if (xfrm_policy_id2dir(id) != dir)
  		return NULL;
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
792
  	*err = 0;
9d0380df6   Florian Westphal   xfrm: policy: con...
793
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
8d1211a6a   Alexey Dobriyan   netns xfrm: findi...
794
  	chain = net->xfrm.policy_byidx + idx_hash(net, id);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
795
  	ret = NULL;
b67bfe0d4   Sasha Levin   hlist: drop the n...
796
  	hlist_for_each_entry(pol, chain, byidx) {
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
797
798
  		if (pol->type == type && pol->index == id &&
  		    (mark & pol->mark.m) == pol->mark.v) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  			xfrm_pol_hold(pol);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
800
  			if (delete) {
03e1ad7b5   Paul Moore   LSM: Make the Lab...
801
802
  				*err = security_xfrm_policy_delete(
  								pol->security);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
803
  				if (*err) {
9d0380df6   Florian Westphal   xfrm: policy: con...
804
  					spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
805
806
  					return pol;
  				}
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
807
  				__xfrm_policy_unlink(pol, dir);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
808
809
  			}
  			ret = pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
  			break;
  		}
  	}
9d0380df6   Florian Westphal   xfrm: policy: con...
813
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

fe1a5f031   Timo Teräs   flow: virtualize ...
815
  	if (ret && delete)
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
816
  		xfrm_policy_kill(ret);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
817
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
  }
  EXPORT_SYMBOL(xfrm_policy_byid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
820
821
  #ifdef CONFIG_SECURITY_NETWORK_XFRM
  static inline int
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
822
  xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
  {
4aa2e62c4   Joy Latten   xfrm: Add securit...
824
825
826
827
  	int dir, err = 0;
  
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
  		struct xfrm_policy *pol;
4aa2e62c4   Joy Latten   xfrm: Add securit...
828
  		int i;
b67bfe0d4   Sasha Levin   hlist: drop the n...
829
  		hlist_for_each_entry(pol,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
830
  				     &net->xfrm.policy_inexact[dir], bydst) {
4aa2e62c4   Joy Latten   xfrm: Add securit...
831
832
  			if (pol->type != type)
  				continue;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
833
  			err = security_xfrm_policy_delete(pol->security);
4aa2e62c4   Joy Latten   xfrm: Add securit...
834
  			if (err) {
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
835
  				xfrm_audit_policy_delete(pol, 0, task_valid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
836
837
  				return err;
  			}
7dc12d6dd   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
838
  		}
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
839
  		for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
840
  			hlist_for_each_entry(pol,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
841
  					     net->xfrm.policy_bydst[dir].table + i,
4aa2e62c4   Joy Latten   xfrm: Add securit...
842
843
844
  					     bydst) {
  				if (pol->type != type)
  					continue;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
845
846
  				err = security_xfrm_policy_delete(
  								pol->security);
4aa2e62c4   Joy Latten   xfrm: Add securit...
847
  				if (err) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
848
  					xfrm_audit_policy_delete(pol, 0,
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
849
  								 task_valid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
850
851
852
853
854
855
856
857
858
  					return err;
  				}
  			}
  		}
  	}
  	return err;
  }
  #else
  static inline int
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
859
  xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
4aa2e62c4   Joy Latten   xfrm: Add securit...
860
861
862
863
  {
  	return 0;
  }
  #endif
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
864
  int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
4aa2e62c4   Joy Latten   xfrm: Add securit...
865
  {
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
866
  	int dir, err = 0, cnt = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867

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

2e71029e2   Tetsuo Handa   xfrm: Remove usel...
870
  	err = xfrm_policy_flush_secctx_check(net, type, task_valid);
4aa2e62c4   Joy Latten   xfrm: Add securit...
871
872
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
874
  		struct xfrm_policy *pol;
29fa0b301   Wei Yongjun   xfrm: Cleanup for...
875
  		int i;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
876
877
  
  	again1:
b67bfe0d4   Sasha Levin   hlist: drop the n...
878
  		hlist_for_each_entry(pol,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
879
  				     &net->xfrm.policy_inexact[dir], bydst) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
880
881
  			if (pol->type != type)
  				continue;
ea2dea9da   Timo Teräs   xfrm: remove poli...
882
  			__xfrm_policy_unlink(pol, dir);
9d0380df6   Florian Westphal   xfrm: policy: con...
883
  			spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
ea2dea9da   Timo Teräs   xfrm: remove poli...
884
  			cnt++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885

2e71029e2   Tetsuo Handa   xfrm: Remove usel...
886
  			xfrm_audit_policy_delete(pol, 1, task_valid);
161a09e73   Joy Latten   audit: Add auditi...
887

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
888
  			xfrm_policy_kill(pol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889

4141b36ab   Steffen Klassert   xfrm: Fix xfrm_po...
890
  			spin_lock_bh(&net->xfrm.xfrm_policy_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
891
892
  			goto again1;
  		}
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
893
  		for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
894
  	again2:
b67bfe0d4   Sasha Levin   hlist: drop the n...
895
  			hlist_for_each_entry(pol,
33ffbbd52   Alexey Dobriyan   netns xfrm: polic...
896
  					     net->xfrm.policy_bydst[dir].table + i,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
897
898
899
  					     bydst) {
  				if (pol->type != type)
  					continue;
ea2dea9da   Timo Teräs   xfrm: remove poli...
900
  				__xfrm_policy_unlink(pol, dir);
9d0380df6   Florian Westphal   xfrm: policy: con...
901
  				spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
ea2dea9da   Timo Teräs   xfrm: remove poli...
902
  				cnt++;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
903

2e71029e2   Tetsuo Handa   xfrm: Remove usel...
904
  				xfrm_audit_policy_delete(pol, 1, task_valid);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
905
  				xfrm_policy_kill(pol);
9d0380df6   Florian Westphal   xfrm: policy: con...
906
  				spin_lock_bh(&net->xfrm.xfrm_policy_lock);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
907
908
  				goto again2;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  		}
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
910

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	}
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
912
913
  	if (!cnt)
  		err = -ESRCH;
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
914
915
  	else
  		xfrm_policy_cache_flush();
4aa2e62c4   Joy Latten   xfrm: Add securit...
916
  out:
9d0380df6   Florian Westphal   xfrm: policy: con...
917
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
4aa2e62c4   Joy Latten   xfrm: Add securit...
918
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
920
  }
  EXPORT_SYMBOL(xfrm_policy_flush);
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
921
  int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
4c563f766   Timo Teras   [XFRM]: Speed up ...
922
  		     int (*func)(struct xfrm_policy *, int, int, void*),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
924
  		     void *data)
  {
12a169e7d   Herbert Xu   ipsec: Put dumper...
925
926
  	struct xfrm_policy *pol;
  	struct xfrm_policy_walk_entry *x;
4c563f766   Timo Teras   [XFRM]: Speed up ...
927
928
929
930
931
  	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
932

12a169e7d   Herbert Xu   ipsec: Put dumper...
933
  	if (list_empty(&walk->walk.all) && walk->seq != 0)
4c563f766   Timo Teras   [XFRM]: Speed up ...
934
  		return 0;
9d0380df6   Florian Westphal   xfrm: policy: con...
935
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
936
  	if (list_empty(&walk->walk.all))
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
937
  		x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all);
12a169e7d   Herbert Xu   ipsec: Put dumper...
938
  	else
800777026   Li RongQing   xfrm: optimise th...
939
940
  		x = list_first_entry(&walk->walk.all,
  				     struct xfrm_policy_walk_entry, all);
cdcbca7c1   Alexey Dobriyan   netns xfrm: polic...
941
  	list_for_each_entry_from(x, &net->xfrm.policy_all, all) {
12a169e7d   Herbert Xu   ipsec: Put dumper...
942
  		if (x->dead)
4c563f766   Timo Teras   [XFRM]: Speed up ...
943
  			continue;
12a169e7d   Herbert Xu   ipsec: Put dumper...
944
945
946
947
948
949
950
951
952
  		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...
953
  		}
12a169e7d   Herbert Xu   ipsec: Put dumper...
954
  		walk->seq++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
  	}
12a169e7d   Herbert Xu   ipsec: Put dumper...
956
  	if (walk->seq == 0) {
baf5d743d   Jamal Hadi Salim   [XFRM] Optimize p...
957
958
959
  		error = -ENOENT;
  		goto out;
  	}
12a169e7d   Herbert Xu   ipsec: Put dumper...
960
  	list_del_init(&walk->walk.all);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
  out:
9d0380df6   Florian Westphal   xfrm: policy: con...
962
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
964
965
  	return error;
  }
  EXPORT_SYMBOL(xfrm_policy_walk);
12a169e7d   Herbert Xu   ipsec: Put dumper...
966
967
968
969
970
971
972
973
  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...
974
  void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net)
12a169e7d   Herbert Xu   ipsec: Put dumper...
975
976
977
  {
  	if (list_empty(&walk->walk.all))
  		return;
9d0380df6   Florian Westphal   xfrm: policy: con...
978
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */
12a169e7d   Herbert Xu   ipsec: Put dumper...
979
  	list_del(&walk->walk.all);
9d0380df6   Florian Westphal   xfrm: policy: con...
980
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
981
982
  }
  EXPORT_SYMBOL(xfrm_policy_walk_done);
134b0fc54   James Morris   IPsec: propagate ...
983
984
985
986
987
  /*
   * Find policy to apply to this flow.
   *
   * Returns 0 if policy found, else an -errno.
   */
f299d557c   David S. Miller   xfrm: Const'ify p...
988
989
  static int xfrm_policy_match(const struct xfrm_policy *pol,
  			     const struct flowi *fl,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
990
  			     u8 type, u16 family, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
  {
f299d557c   David S. Miller   xfrm: Const'ify p...
992
  	const struct xfrm_selector *sel = &pol->selector;
bc9b35ad4   David S. Miller   xfrm: Convert sev...
993
994
  	int ret = -ESRCH;
  	bool match;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995

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

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

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

52479b623   Alexey Dobriyan   netns xfrm: looku...
1009
  static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
062cdb43b   David S. Miller   xfrm: Mark flowi ...
1010
  						     const struct flowi *fl,
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1011
1012
  						     u16 family, u8 dir)
  {
134b0fc54   James Morris   IPsec: propagate ...
1013
  	int err;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1014
  	struct xfrm_policy *pol, *ret;
0b597e7ed   David S. Miller   xfrm: Const'ify l...
1015
  	const xfrm_address_t *daddr, *saddr;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1016
  	struct hlist_head *chain;
30846090a   Florian Westphal   xfrm: policy: add...
1017
1018
  	unsigned int sequence;
  	u32 priority;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1019

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1020
1021
1022
1023
  	daddr = xfrm_flowi_daddr(fl, family);
  	saddr = xfrm_flowi_saddr(fl, family);
  	if (unlikely(!daddr || !saddr))
  		return NULL;
a7c44247f   Florian Westphal   xfrm: policy: mak...
1024
  	rcu_read_lock();
30846090a   Florian Westphal   xfrm: policy: add...
1025
1026
1027
1028
1029
1030
1031
   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));
  
  	priority = ~0U;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1032
  	ret = NULL;
a5eefc1df   Florian Westphal   xfrm: policy: use...
1033
  	hlist_for_each_entry_rcu(pol, chain, bydst) {
134b0fc54   James Morris   IPsec: propagate ...
1034
1035
1036
1037
1038
1039
1040
1041
1042
  		err = xfrm_policy_match(pol, fl, type, family, dir);
  		if (err) {
  			if (err == -ESRCH)
  				continue;
  			else {
  				ret = ERR_PTR(err);
  				goto fail;
  			}
  		} else {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1043
  			ret = pol;
acba48e1a   David S. Miller   [XFRM]: Respect p...
1044
  			priority = ret->priority;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1045
1046
1047
  			break;
  		}
  	}
52479b623   Alexey Dobriyan   netns xfrm: looku...
1048
  	chain = &net->xfrm.policy_inexact[dir];
a5eefc1df   Florian Westphal   xfrm: policy: use...
1049
  	hlist_for_each_entry_rcu(pol, chain, bydst) {
8faf491e6   Li RongQing   xfrm: optimise to...
1050
1051
  		if ((pol->priority >= priority) && ret)
  			break;
134b0fc54   James Morris   IPsec: propagate ...
1052
1053
1054
1055
1056
1057
1058
1059
  		err = xfrm_policy_match(pol, fl, type, family, dir);
  		if (err) {
  			if (err == -ESRCH)
  				continue;
  			else {
  				ret = ERR_PTR(err);
  				goto fail;
  			}
8faf491e6   Li RongQing   xfrm: optimise to...
1060
  		} else {
acba48e1a   David S. Miller   [XFRM]: Respect p...
1061
1062
  			ret = pol;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
  		}
  	}
586f2eb41   Li RongQing   xfrm: remove the ...
1065

30846090a   Florian Westphal   xfrm: policy: add...
1066
1067
  	if (read_seqcount_retry(&xfrm_policy_hash_generation, sequence))
  		goto retry;
e37cc8ade   Florian Westphal   xfrm: policy: use...
1068
1069
  	if (ret && !xfrm_pol_hold_rcu(ret))
  		goto retry;
134b0fc54   James Morris   IPsec: propagate ...
1070
  fail:
a7c44247f   Florian Westphal   xfrm: policy: mak...
1071
  	rcu_read_unlock();
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1072

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1073
  	return ret;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1074
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
1075
  static struct xfrm_policy *
86dc8ee0b   Florian Westphal   xfrm_policy: remo...
1076
  xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir)
80c802f30   Timo Teräs   xfrm: cache bundl...
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
  {
  #ifdef CONFIG_XFRM_SUB_POLICY
  	struct xfrm_policy *pol;
  
  	pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
  	if (pol != NULL)
  		return pol;
  #endif
  	return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
  }
6f9c96154   Eric Dumazet   inet: constify ip...
1087
  static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
4c86d7774   Steffen Klassert   xfrm: Don't use s...
1088
  						 const struct flowi *fl, u16 family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
1090
  {
  	struct xfrm_policy *pol;
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
1091
  	rcu_read_lock();
ae33786f7   Florian Westphal   xfrm: policy: onl...
1092
   again:
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
1093
1094
  	pol = rcu_dereference(sk->sk_policy[dir]);
  	if (pol != NULL) {
ddc47e440   Steffen Klassert   xfrm: Fix stack-o...
1095
  		bool match;
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
1096
  		int err = 0;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1097

ddc47e440   Steffen Klassert   xfrm: Fix stack-o...
1098
1099
1100
1101
1102
1103
  		if (pol->family != family) {
  			pol = NULL;
  			goto out;
  		}
  
  		match = xfrm_selector_match(&pol->selector, fl, family);
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1104
  		if (match) {
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
1105
1106
1107
1108
  			if ((sk->sk_mark & pol->mark.m) != pol->mark.v) {
  				pol = NULL;
  				goto out;
  			}
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1109
  			err = security_xfrm_policy_lookup(pol->security,
1d28f42c1   David S. Miller   net: Put flowi_* ...
1110
  						      fl->flowi_secid,
aff669bc2   Florian Westphal   xfrm_policy: kill...
1111
  						      dir);
330e832ab   Florian Westphal   xfrm: unbreak xfr...
1112
1113
1114
1115
  			if (!err) {
  				if (!xfrm_pol_hold_rcu(pol))
  					goto again;
  			} else if (err == -ESRCH) {
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1116
  				pol = NULL;
330e832ab   Florian Westphal   xfrm: unbreak xfr...
1117
  			} else {
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1118
  				pol = ERR_PTR(err);
330e832ab   Florian Westphal   xfrm: unbreak xfr...
1119
  			}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
1120
  		} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
1122
  			pol = NULL;
  	}
34f8d8846   Jamal Hadi Salim   xfrm: SP lookups ...
1123
  out:
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
1124
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
1126
1127
1128
1129
  	return pol;
  }
  
  static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
  {
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
1130
  	struct net *net = xp_net(pol);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1131

98806f75b   Alexey Dobriyan   netns xfrm: trivi...
1132
  	list_add(&pol->walk.all, &net->xfrm.policy_all);
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
1133
  	net->xfrm.policy_count[dir]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
1135
1136
1137
1138
1139
  	xfrm_pol_hold(pol);
  }
  
  static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
  						int dir)
  {
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
1140
  	struct net *net = xp_net(pol);
53c2e285f   Herbert Xu   xfrm: Do not hash...
1141
  	if (list_empty(&pol->walk.all))
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1142
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143

53c2e285f   Herbert Xu   xfrm: Do not hash...
1144
1145
  	/* Socket policies are not hashed. */
  	if (!hlist_unhashed(&pol->bydst)) {
a5eefc1df   Florian Westphal   xfrm: policy: use...
1146
  		hlist_del_rcu(&pol->bydst);
53c2e285f   Herbert Xu   xfrm: Do not hash...
1147
1148
1149
1150
  		hlist_del(&pol->byidx);
  	}
  
  	list_del_init(&pol->walk.all);
98806f75b   Alexey Dobriyan   netns xfrm: trivi...
1151
  	net->xfrm.policy_count[dir]--;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
1152
1153
  
  	return pol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
  }
53c2e285f   Herbert Xu   xfrm: Do not hash...
1155
1156
1157
1158
1159
1160
1161
1162
1163
  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...
1164
  int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
  {
283bc9f35   Fan Du   xfrm: Namespacify...
1166
  	struct net *net = xp_net(pol);
9d0380df6   Florian Westphal   xfrm: policy: con...
1167
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
  	pol = __xfrm_policy_unlink(pol, dir);
9d0380df6   Florian Westphal   xfrm: policy: con...
1169
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
  	if (pol) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
  		xfrm_policy_kill(pol);
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1172
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
  	}
4666faab0   Herbert Xu   [IPSEC] Kill spur...
1174
  	return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
  }
a70fcb0ba   David S. Miller   [XFRM]: Add some ...
1176
  EXPORT_SYMBOL(xfrm_policy_delete);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
1178
1179
  
  int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
  {
1121994c8   Alexey Dobriyan   netns xfrm: polic...
1180
  	struct net *net = xp_net(pol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
  	struct xfrm_policy *old_pol;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1182
1183
1184
1185
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pol && pol->type != XFRM_POLICY_TYPE_MAIN)
  		return -EINVAL;
  #endif
9d0380df6   Florian Westphal   xfrm: policy: con...
1186
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
1187
1188
  	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
1189
  	if (pol) {
9d729f72d   James Morris   [NET]: Convert xt...
1190
  		pol->curlft.add_time = get_seconds();
e682adf02   Fan Du   xfrm: Try to hono...
1191
  		pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
53c2e285f   Herbert Xu   xfrm: Do not hash...
1192
  		xfrm_sk_policy_link(pol, dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  	}
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
1194
  	rcu_assign_pointer(sk->sk_policy[dir], pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1195
1196
1197
  	if (old_pol) {
  		if (pol)
  			xfrm_policy_requeue(old_pol, pol);
ea2dea9da   Timo Teräs   xfrm: remove poli...
1198
1199
1200
  		/* Unlinking succeeds always. This is the only function
  		 * allowed to delete or replace socket policy.
  		 */
53c2e285f   Herbert Xu   xfrm: Do not hash...
1201
  		xfrm_sk_policy_unlink(old_pol, dir);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1202
  	}
9d0380df6   Florian Westphal   xfrm: policy: con...
1203
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
1207
1208
1209
  
  	if (old_pol) {
  		xfrm_policy_kill(old_pol);
  	}
  	return 0;
  }
d3e40a9f5   David S. Miller   xfrm: Const'ify p...
1210
  static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
  {
0331b1f38   Alexey Dobriyan   netns xfrm: add s...
1212
  	struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC);
283bc9f35   Fan Du   xfrm: Namespacify...
1213
  	struct net *net = xp_net(old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
1216
  
  	if (newp) {
  		newp->selector = old->selector;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1217
1218
  		if (security_xfrm_policy_clone(old->security,
  					       &newp->security)) {
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1219
1220
1221
  			kfree(newp);
  			return NULL;  /* ENOMEM */
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
  		newp->lft = old->lft;
  		newp->curlft = old->curlft;
fb977e2ca   Jamal Hadi Salim   xfrm: clone mark ...
1224
  		newp->mark = old->mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
1227
1228
  		newp->action = old->action;
  		newp->flags = old->flags;
  		newp->xfrm_nr = old->xfrm_nr;
  		newp->index = old->index;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1229
  		newp->type = old->type;
0e74aa1d7   Herbert Xu   xfrm: Copy policy...
1230
  		newp->family = old->family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
1232
  		memcpy(newp->xfrm_vec, old->xfrm_vec,
  		       newp->xfrm_nr*sizeof(struct xfrm_tmpl));
9d0380df6   Florian Westphal   xfrm: policy: con...
1233
  		spin_lock_bh(&net->xfrm.xfrm_policy_lock);
53c2e285f   Herbert Xu   xfrm: Do not hash...
1234
  		xfrm_sk_policy_link(newp, dir);
9d0380df6   Florian Westphal   xfrm: policy: con...
1235
  		spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
1237
1238
1239
  		xfrm_pol_put(newp);
  	}
  	return newp;
  }
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
1240
  int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
  {
d188ba86d   Eric Dumazet   xfrm: add rcu pro...
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
  	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
1260
  }
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1261
  static int
42a7b32b7   David Ahern   xfrm: Add oif to ...
1262
  xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
1263
  	       xfrm_address_t *remote, unsigned short family, u32 mark)
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1264
1265
  {
  	int err;
37b103830   Florian Westphal   xfrm: policy: mak...
1266
  	const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1267
1268
1269
  
  	if (unlikely(afinfo == NULL))
  		return -EINVAL;
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
1270
  	err = afinfo->get_saddr(net, oif, local, remote, mark);
bdba9fe01   Florian Westphal   xfrm: policy: rem...
1271
  	rcu_read_unlock();
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1272
1273
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
1275
1276
  /* Resolve list of templates for the flow, given policy. */
  
  static int
a6c2e6111   David S. Miller   xfrm: Mark flowi ...
1277
1278
  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
1279
  {
fbda33b2b   Alexey Dobriyan   netns xfrm: ->get...
1280
  	struct net *net = xp_net(policy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
  	int nx;
  	int i, error;
948021518   Steffen Klassert   Revert "xfrm: Fix...
1283
1284
  	xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
  	xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
1285
  	xfrm_address_t tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286

9b7a787d0   Weilong Chen   xfrm: checkpatch ...
1287
  	for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
  		struct xfrm_state *x;
948021518   Steffen Klassert   Revert "xfrm: Fix...
1289
1290
  		xfrm_address_t *remote = daddr;
  		xfrm_address_t *local  = saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
  		struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
948021518   Steffen Klassert   Revert "xfrm: Fix...
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  		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
1304
1305
1306
1307
1308
1309
  		}
  
  		x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
  
  		if (x && x->km.state == XFRM_STATE_VALID) {
  			xfrm[nx++] = x;
948021518   Steffen Klassert   Revert "xfrm: Fix...
1310
1311
  			daddr = remote;
  			saddr = local;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1312
1313
1314
1315
1316
1317
  			continue;
  		}
  		if (x) {
  			error = (x->km.state == XFRM_STATE_ERROR ?
  				 -EINVAL : -EAGAIN);
  			xfrm_state_put(x);
42054569f   Weilong Chen   xfrm: fix checkpa...
1318
  		} else if (error == -ESRCH) {
a43222661   fernando@oss.ntt.co   xfrm: do not leak...
1319
  			error = -EAGAIN;
42054569f   Weilong Chen   xfrm: fix checkpa...
1320
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
1322
1323
1324
1325
1326
1327
  
  		if (!tmpl->optional)
  			goto fail;
  	}
  	return nx;
  
  fail:
9b7a787d0   Weilong Chen   xfrm: checkpatch ...
1328
  	for (nx--; nx >= 0; nx--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329
1330
1331
  		xfrm_state_put(xfrm[nx]);
  	return error;
  }
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1332
  static int
a6c2e6111   David S. Miller   xfrm: Mark flowi ...
1333
1334
  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...
1335
  {
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1336
1337
  	struct xfrm_state *tp[XFRM_MAX_DEPTH];
  	struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
  	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...
1348
1349
  
  		ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1350
1351
1352
1353
1354
1355
  		if (ret < 0) {
  			error = ret;
  			goto fail;
  		} else
  			cnx += ret;
  	}
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1356
1357
1358
  	/* found states are sorted for outbound processing */
  	if (npols > 1)
  		xfrm_state_sort(xfrm, tpp, cnx, family);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1359
1360
1361
  	return cnx;
  
   fail:
9b7a787d0   Weilong Chen   xfrm: checkpatch ...
1362
  	for (cnx--; cnx >= 0; cnx--)
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
1363
  		xfrm_state_put(tpp[cnx]);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
1364
1365
1366
  	return error;
  
  }
f5e2bb4f5   Florian Westphal   xfrm: policy: xfr...
1367
  static int xfrm_get_tos(const struct flowi *fl, int family)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1368
  {
37b103830   Florian Westphal   xfrm: policy: mak...
1369
  	const struct xfrm_policy_afinfo *afinfo;
f5e2bb4f5   Florian Westphal   xfrm: policy: xfr...
1370
  	int tos = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371

f5e2bb4f5   Florian Westphal   xfrm: policy: xfr...
1372
1373
  	afinfo = xfrm_policy_get_afinfo(family);
  	tos = afinfo ? afinfo->get_tos(fl) : 0;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1374

bdba9fe01   Florian Westphal   xfrm: policy: rem...
1375
  	rcu_read_unlock();
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1376
1377
1378
  
  	return tos;
  }
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1379
  static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
  {
37b103830   Florian Westphal   xfrm: policy: mak...
1381
  	const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1382
  	struct dst_ops *dst_ops;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1383
1384
1385
1386
  	struct xfrm_dst *xdst;
  
  	if (!afinfo)
  		return ERR_PTR(-EINVAL);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1387
1388
1389
1390
  	switch (family) {
  	case AF_INET:
  		dst_ops = &net->xfrm.xfrm4_dst_ops;
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1391
  #if IS_ENABLED(CONFIG_IPV6)
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1392
1393
1394
1395
1396
1397
1398
  	case AF_INET6:
  		dst_ops = &net->xfrm.xfrm6_dst_ops;
  		break;
  #endif
  	default:
  		BUG();
  	}
b2a9c0ed7   Wei Wang   net: remove DST_N...
1399
  	xdst = dst_alloc(dst_ops, NULL, 1, DST_OBSOLETE_NONE, 0);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1400

d4cae5621   Madalin Bucur   net: check return...
1401
  	if (likely(xdst)) {
141e369de   Steffen Klassert   xfrm: Initialize ...
1402
1403
1404
  		struct dst_entry *dst = &xdst->u.dst;
  
  		memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst));
d4cae5621   Madalin Bucur   net: check return...
1405
  	} else
0b1509321   Hiroaki SHIMODA   xfrm: avoid possi...
1406
  		xdst = ERR_PTR(-ENOBUFS);
80c802f30   Timo Teräs   xfrm: cache bundl...
1407

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

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1410
1411
  	return xdst;
  }
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1412
1413
1414
  static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst,
  				 int nfheader_len)
  {
37b103830   Florian Westphal   xfrm: policy: mak...
1415
  	const struct xfrm_policy_afinfo *afinfo =
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1416
1417
1418
1419
1420
1421
1422
  		xfrm_policy_get_afinfo(dst->ops->family);
  	int err;
  
  	if (!afinfo)
  		return -EINVAL;
  
  	err = afinfo->init_path(path, dst, nfheader_len);
bdba9fe01   Florian Westphal   xfrm: policy: rem...
1423
  	rcu_read_unlock();
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1424
1425
1426
  
  	return err;
  }
87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
1427
  static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
0c7b3eefb   David S. Miller   xfrm: Mark flowi ...
1428
  				const struct flowi *fl)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1429
  {
37b103830   Florian Westphal   xfrm: policy: mak...
1430
  	const struct xfrm_policy_afinfo *afinfo =
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1431
1432
1433
1434
  		xfrm_policy_get_afinfo(xdst->u.dst.ops->family);
  	int err;
  
  	if (!afinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
  		return -EINVAL;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1436

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1441
1442
  	return err;
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
1443

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1444
1445
1446
1447
1448
1449
  /* Allocate chain of dst_entry's, attach known xfrm's, calculate
   * all the metrics... Shortly, bundle a bundle.
   */
  
  static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
  					    struct xfrm_state **xfrm, int nx,
98313adaa   David S. Miller   xfrm: Mark flowi ...
1450
  					    const struct flowi *fl,
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1451
1452
  					    struct dst_entry *dst)
  {
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1453
  	struct net *net = xp_net(policy);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1454
1455
  	unsigned long now = jiffies;
  	struct net_device *dev;
43a4dea4c   Steffen Klassert   xfrm: Assign the ...
1456
  	struct xfrm_mode *inner_mode;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1457
1458
1459
1460
1461
  	struct dst_entry *dst_prev = NULL;
  	struct dst_entry *dst0 = NULL;
  	int i = 0;
  	int err;
  	int header_len = 0;
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1462
  	int nfheader_len = 0;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1463
1464
1465
  	int trailer_len = 0;
  	int tos;
  	int family = policy->selector.family;
9bb182a70   YOSHIFUJI Hideaki   [XFRM] MIP6: Fix ...
1466
1467
1468
  	xfrm_address_t saddr, daddr;
  
  	xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1469
1470
  
  	tos = xfrm_get_tos(fl, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1471
1472
1473
1474
  
  	dst_hold(dst);
  
  	for (; i < nx; i++) {
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
1475
  		struct xfrm_dst *xdst = xfrm_alloc_dst(net, family);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1476
1477
1478
1479
1480
1481
1482
  		struct dst_entry *dst1 = &xdst->u.dst;
  
  		err = PTR_ERR(xdst);
  		if (IS_ERR(xdst)) {
  			dst_release(dst);
  			goto put_states;
  		}
10a7ef336   David Miller   ipsec: Fix dst le...
1483
1484
1485
1486
1487
1488
1489
  		if (!dst_prev)
  			dst0 = dst1;
  		else
  			/* Ref count is taken during xfrm_alloc_dst()
  			 * No need to do dst_clone() on dst1
  			 */
  			dst_prev->child = dst1;
43a4dea4c   Steffen Klassert   xfrm: Assign the ...
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
  		if (xfrm[i]->sel.family == AF_UNSPEC) {
  			inner_mode = xfrm_ip2inner_mode(xfrm[i],
  							xfrm_af2proto(family));
  			if (!inner_mode) {
  				err = -EAFNOSUPPORT;
  				dst_release(dst);
  				goto put_states;
  			}
  		} else
  			inner_mode = xfrm[i]->inner_mode;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1500
  		xdst->route = dst;
defb3519a   David S. Miller   net: Abstract awa...
1501
  		dst_copy_metrics(dst1, dst);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1502
1503
1504
  
  		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
  			family = xfrm[i]->props.family;
42a7b32b7   David Ahern   xfrm: Add oif to ...
1505
  			dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
1506
1507
  					      &saddr, &daddr, family,
  					      xfrm[i]->props.output_mark);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1508
1509
1510
1511
1512
1513
1514
  			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...
1515
  		xdst->xfrm_genid = xfrm[i]->genid;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1516

f5b0a8743   David S. Miller   net: Document dst...
1517
  		dst1->obsolete = DST_OBSOLETE_FORCE_CHK;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1518
1519
1520
1521
  		dst1->flags |= DST_HOST;
  		dst1->lastuse = now;
  
  		dst1->input = dst_discard;
43a4dea4c   Steffen Klassert   xfrm: Assign the ...
1522
  		dst1->output = inner_mode->afinfo->output;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1523
1524
1525
1526
1527
  
  		dst1->next = dst_prev;
  		dst_prev = dst1;
  
  		header_len += xfrm[i]->props.header_len;
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1528
1529
  		if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
  			nfheader_len += xfrm[i]->props.header_len;
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
  		trailer_len += xfrm[i]->props.trailer_len;
  	}
  
  	dst_prev->child = dst;
  	dst0->path = dst;
  
  	err = -ENODEV;
  	dev = dst->dev;
  	if (!dev)
  		goto free_dst;
a1b051405   Masahide NAKAMURA   [XFRM] IPv6: Fix ...
1540
  	xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1541
1542
1543
1544
  	xfrm_init_pmtu(dst_prev);
  
  	for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) {
  		struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev;
87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
1545
  		err = xfrm_fill_dst(xdst, dev, fl);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
  		if (err)
  			goto free_dst;
  
  		dst_prev->header_len = header_len;
  		dst_prev->trailer_len = trailer_len;
  		header_len -= xdst->u.dst.xfrm->props.header_len;
  		trailer_len -= xdst->u.dst.xfrm->props.trailer_len;
  	}
  
  out:
  	return dst0;
  
  put_states:
  	for (; i < nx; i++)
  		xfrm_state_put(xfrm[i]);
  free_dst:
  	if (dst0)
52df157f1   Wei Wang   xfrm: take refcnt...
1563
  		dst_release_immediate(dst0);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
1564
1565
1566
  	dst0 = ERR_PTR(err);
  	goto out;
  }
73ff93cd0   David S. Miller   xfrm: Mark flowi ...
1567
  static int xfrm_expand_policies(const struct flowi *fl, u16 family,
80c802f30   Timo Teräs   xfrm: cache bundl...
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
  				struct xfrm_policy **pols,
  				int *num_pols, int *num_xfrms)
  {
  	int i;
  
  	if (*num_pols == 0 || !pols[0]) {
  		*num_pols = 0;
  		*num_xfrms = 0;
  		return 0;
  	}
  	if (IS_ERR(pols[0]))
  		return PTR_ERR(pols[0]);
  
  	*num_xfrms = pols[0]->xfrm_nr;
  
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pols[0] && pols[0]->action == XFRM_POLICY_ALLOW &&
  	    pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
  		pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]),
  						    XFRM_POLICY_TYPE_MAIN,
  						    fl, family,
  						    XFRM_POLICY_OUT);
  		if (pols[1]) {
  			if (IS_ERR(pols[1])) {
  				xfrm_pols_put(pols, *num_pols);
  				return PTR_ERR(pols[1]);
  			}
02d0892f9   Weilong Chen   xfrm: checkpatch ...
1595
  			(*num_pols)++;
80c802f30   Timo Teräs   xfrm: cache bundl...
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
  			(*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;
  
  }
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
  static void xfrm_last_dst_update(struct xfrm_dst *xdst, struct xfrm_dst *old)
  {
  	this_cpu_write(xfrm_last_dst, xdst);
  	if (old)
  		dst_release(&old->u.dst);
  }
  
  static void __xfrm_pcpu_work_fn(void)
  {
  	struct xfrm_dst *old;
  
  	old = this_cpu_read(xfrm_last_dst);
  	if (old && !xfrm_bundle_ok(old))
  		xfrm_last_dst_update(NULL, old);
  }
  
  static void xfrm_pcpu_work_fn(struct work_struct *work)
  {
  	local_bh_disable();
  	rcu_read_lock();
  	__xfrm_pcpu_work_fn();
  	rcu_read_unlock();
  	local_bh_enable();
  }
  
  void xfrm_policy_cache_flush(void)
  {
  	struct xfrm_dst *old;
  	bool found = 0;
  	int cpu;
  
  	local_bh_disable();
  	rcu_read_lock();
  	for_each_possible_cpu(cpu) {
  		old = per_cpu(xfrm_last_dst, cpu);
  		if (old && !xfrm_bundle_ok(old)) {
  			if (smp_processor_id() == cpu) {
  				__xfrm_pcpu_work_fn();
  				continue;
  			}
  			found = true;
  			break;
  		}
  	}
  
  	rcu_read_unlock();
  	local_bh_enable();
  
  	if (!found)
  		return;
  
  	get_online_cpus();
  
  	for_each_possible_cpu(cpu) {
  		bool bundle_release;
  
  		rcu_read_lock();
  		old = per_cpu(xfrm_last_dst, cpu);
  		bundle_release = old && !xfrm_bundle_ok(old);
  		rcu_read_unlock();
  
  		if (!bundle_release)
  			continue;
  
  		if (cpu_online(cpu)) {
  			schedule_work_on(cpu, &xfrm_pcpu_work[cpu]);
  			continue;
  		}
  
  		rcu_read_lock();
  		old = per_cpu(xfrm_last_dst, cpu);
  		if (old && !xfrm_bundle_ok(old)) {
  			per_cpu(xfrm_last_dst, cpu) = NULL;
  			dst_release(&old->u.dst);
  		}
  		rcu_read_unlock();
  	}
  
  	put_online_cpus();
  }
cf3796675   Florian Westphal   xfrm: do uncondit...
1690
1691
1692
  static bool xfrm_xdst_can_reuse(struct xfrm_dst *xdst,
  				struct xfrm_state * const xfrm[],
  				int num)
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1693
  {
cf3796675   Florian Westphal   xfrm: do uncondit...
1694
1695
  	const struct dst_entry *dst = &xdst->u.dst;
  	int i;
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1696

cf3796675   Florian Westphal   xfrm: do uncondit...
1697
1698
  	if (xdst->num_xfrms != num)
  		return false;
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1699

cf3796675   Florian Westphal   xfrm: do uncondit...
1700
1701
1702
1703
1704
  	for (i = 0; i < num; i++) {
  		if (!dst || dst->xfrm != xfrm[i])
  			return false;
  		dst = dst->child;
  	}
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1705

cf3796675   Florian Westphal   xfrm: do uncondit...
1706
  	return xfrm_bundle_ok(xdst);
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1707
  }
80c802f30   Timo Teräs   xfrm: cache bundl...
1708
1709
  static struct xfrm_dst *
  xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
4ca2e6851   David S. Miller   xfrm: Mark flowi ...
1710
  			       const struct flowi *fl, u16 family,
80c802f30   Timo Teräs   xfrm: cache bundl...
1711
1712
1713
1714
  			       struct dst_entry *dst_orig)
  {
  	struct net *net = xp_net(pols[0]);
  	struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1715
  	struct xfrm_dst *xdst, *old;
80c802f30   Timo Teräs   xfrm: cache bundl...
1716
  	struct dst_entry *dst;
80c802f30   Timo Teräs   xfrm: cache bundl...
1717
  	int err;
cf3796675   Florian Westphal   xfrm: do uncondit...
1718
1719
1720
1721
1722
1723
1724
  	/* Try to instantiate a bundle */
  	err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
  	if (err <= 0) {
  		if (err != 0 && err != -EAGAIN)
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
  		return ERR_PTR(err);
  	}
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1725
1726
1727
1728
  	xdst = this_cpu_read(xfrm_last_dst);
  	if (xdst &&
  	    xdst->u.dst.dev == dst_orig->dev &&
  	    xdst->num_pols == num_pols &&
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1729
  	    memcmp(xdst->pols, pols,
13ead5c4f   Florian Westphal   xfrm: check that ...
1730
  		   sizeof(struct xfrm_policy *) * num_pols) == 0 &&
cf3796675   Florian Westphal   xfrm: do uncondit...
1731
  	    xfrm_xdst_can_reuse(xdst, xfrm, err)) {
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1732
  		dst_hold(&xdst->u.dst);
d2950278d   Florian Westphal   xfrm: put policie...
1733
  		xfrm_pols_put(pols, num_pols);
cf3796675   Florian Westphal   xfrm: do uncondit...
1734
1735
  		while (err > 0)
  			xfrm_state_put(xfrm[--err]);
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1736
1737
1738
1739
  		return xdst;
  	}
  
  	old = xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
1740
1741
1742
1743
1744
1745
1746
1747
1748
  
  	dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
  	if (IS_ERR(dst)) {
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
  		return ERR_CAST(dst);
  	}
  
  	xdst = (struct xfrm_dst *)dst;
  	xdst->num_xfrms = err;
80c802f30   Timo Teräs   xfrm: cache bundl...
1749
  	xdst->num_pols = num_pols;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
1750
  	memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
1751
  	xdst->policy_genid = atomic_read(&pols[0]->genid);
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
1752
1753
  	atomic_set(&xdst->u.dst.__refcnt, 2);
  	xfrm_last_dst_update(xdst, old);
80c802f30   Timo Teräs   xfrm: cache bundl...
1754
1755
  	return xdst;
  }
c3aed7095   Kees Cook   xfrm: Convert tim...
1756
  static void xfrm_policy_queue_process(struct timer_list *t)
a0073fe18   Steffen Klassert   xfrm: Add a state...
1757
  {
a0073fe18   Steffen Klassert   xfrm: Add a state...
1758
1759
1760
  	struct sk_buff *skb;
  	struct sock *sk;
  	struct dst_entry *dst;
c3aed7095   Kees Cook   xfrm: Convert tim...
1761
  	struct xfrm_policy *pol = from_timer(pol, t, polq.hold_timer);
3f5312ae6   Eric W. Biederman   xfrm: Only comput...
1762
  	struct net *net = xp_net(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1763
1764
1765
1766
1767
1768
  	struct xfrm_policy_queue *pq = &pol->polq;
  	struct flowi fl;
  	struct sk_buff_head list;
  
  	spin_lock(&pq->hold_queue.lock);
  	skb = skb_peek(&pq->hold_queue);
2bb53e255   Steffen Klassert   xfrm: check for a...
1769
1770
1771
1772
  	if (!skb) {
  		spin_unlock(&pq->hold_queue.lock);
  		goto out;
  	}
a0073fe18   Steffen Klassert   xfrm: Add a state...
1773
1774
1775
1776
1777
1778
  	dst = skb_dst(skb);
  	sk = skb->sk;
  	xfrm_decode_session(skb, &fl, dst->ops->family);
  	spin_unlock(&pq->hold_queue.lock);
  
  	dst_hold(dst->path);
3f5312ae6   Eric W. Biederman   xfrm: Only comput...
1779
  	dst = xfrm_lookup(net, dst->path, &fl, sk, 0);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
  	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...
1790
1791
1792
  		if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout))
  			xfrm_pol_hold(pol);
  	goto out;
a0073fe18   Steffen Klassert   xfrm: Add a state...
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
  	}
  
  	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);
  
  		xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family);
  		dst_hold(skb_dst(skb)->path);
3f5312ae6   Eric W. Biederman   xfrm: Only comput...
1809
  		dst = xfrm_lookup(net, skb_dst(skb)->path, &fl, skb->sk, 0);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1810
  		if (IS_ERR(dst)) {
a0073fe18   Steffen Klassert   xfrm: Add a state...
1811
1812
1813
1814
1815
1816
1817
  			kfree_skb(skb);
  			continue;
  		}
  
  		nf_reset(skb);
  		skb_dst_drop(skb);
  		skb_dst_set(skb, dst);
13206b6bf   Eric W. Biederman   net: Pass net int...
1818
  		dst_output(net, skb->sk, skb);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1819
  	}
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
1820
1821
  out:
  	xfrm_pol_put(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1822
1823
1824
1825
  	return;
  
  purge_queue:
  	pq->timeout = 0;
1ee5e6676   Li RongQing   xfrm: remove the ...
1826
  	skb_queue_purge(&pq->hold_queue);
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
1827
  	xfrm_pol_put(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1828
  }
ede2059db   Eric W. Biederman   dst: Pass net int...
1829
  static int xdst_queue_output(struct net *net, struct sock *sk, struct sk_buff *skb)
a0073fe18   Steffen Klassert   xfrm: Add a state...
1830
1831
1832
1833
  {
  	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...
1834
1835
  	struct xfrm_policy *pol = xdst->pols[0];
  	struct xfrm_policy_queue *pq = &pol->polq;
4d53eff48   Steffen Klassert   xfrm: Don't queue...
1836

39bb5e628   Eric Dumazet   net: skb_fclone_b...
1837
  	if (unlikely(skb_fclone_busy(sk, skb))) {
4d53eff48   Steffen Klassert   xfrm: Don't queue...
1838
1839
1840
  		kfree_skb(skb);
  		return 0;
  	}
a0073fe18   Steffen Klassert   xfrm: Add a state...
1841
1842
1843
1844
1845
1846
1847
  
  	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...
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
  
  	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...
1859
  		xfrm_pol_put(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1860
1861
1862
  	}
  
  	__skb_queue_tail(&pq->hold_queue, skb);
e7d8f6cb2   Steffen Klassert   xfrm: Add refcoun...
1863
1864
  	if (!mod_timer(&pq->hold_timer, sched_next))
  		xfrm_pol_hold(pol);
a0073fe18   Steffen Klassert   xfrm: Add a state...
1865
1866
1867
1868
1869
1870
1871
  
  	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...
1872
  						 struct xfrm_flo *xflo,
a0073fe18   Steffen Klassert   xfrm: Add a state...
1873
1874
1875
1876
1877
1878
  						 const struct flowi *fl,
  						 int num_xfrms,
  						 u16 family)
  {
  	int err;
  	struct net_device *dev;
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
1879
  	struct dst_entry *dst;
a0073fe18   Steffen Klassert   xfrm: Add a state...
1880
1881
1882
1883
1884
1885
  	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...
1886
1887
1888
  	if (!(xflo->flags & XFRM_LOOKUP_QUEUE) ||
  	    net->xfrm.sysctl_larval_drop ||
  	    num_xfrms <= 0)
a0073fe18   Steffen Klassert   xfrm: Add a state...
1889
  		return xdst;
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
1890
  	dst = xflo->dst_orig;
a0073fe18   Steffen Klassert   xfrm: Add a state...
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
  	dst1 = &xdst->u.dst;
  	dst_hold(dst);
  	xdst->route = dst;
  
  	dst_copy_metrics(dst1, dst);
  
  	dst1->obsolete = DST_OBSOLETE_FORCE_CHK;
  	dst1->flags |= DST_HOST | DST_XFRM_QUEUE;
  	dst1->lastuse = jiffies;
  
  	dst1->input = dst_discard;
  	dst1->output = xdst_queue_output;
  
  	dst_hold(dst);
  	dst1->child = dst;
  	dst1->path = dst;
  
  	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;
  }
bd45c539b   Florian Westphal   xfrm_policy: make...
1927
  static struct xfrm_dst *
3ca28286e   Florian Westphal   xfrm_policy: bypa...
1928
  xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, struct xfrm_flo *xflo)
80c802f30   Timo Teräs   xfrm: cache bundl...
1929
  {
80c802f30   Timo Teräs   xfrm: cache bundl...
1930
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
855dad99c   Florian Westphal   xfrm_policy: remo...
1931
  	int num_pols = 0, num_xfrms = 0, err;
bd45c539b   Florian Westphal   xfrm_policy: make...
1932
  	struct xfrm_dst *xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
1933

80c802f30   Timo Teräs   xfrm: cache bundl...
1934
1935
  	/* Resolve policies to use if we couldn't get them from
  	 * previous cache entry */
855dad99c   Florian Westphal   xfrm_policy: remo...
1936
  	num_pols = 1;
86dc8ee0b   Florian Westphal   xfrm_policy: remo...
1937
  	pols[0] = xfrm_policy_lookup(net, fl, family, dir);
855dad99c   Florian Westphal   xfrm_policy: remo...
1938
  	err = xfrm_expand_policies(fl, family, pols,
80c802f30   Timo Teräs   xfrm: cache bundl...
1939
  					   &num_pols, &num_xfrms);
855dad99c   Florian Westphal   xfrm_policy: remo...
1940
1941
1942
1943
1944
1945
  	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...
1946

bd45c539b   Florian Westphal   xfrm_policy: make...
1947
  	xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family,
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
1948
  						  xflo->dst_orig);
bd45c539b   Florian Westphal   xfrm_policy: make...
1949
1950
  	if (IS_ERR(xdst)) {
  		err = PTR_ERR(xdst);
80c802f30   Timo Teräs   xfrm: cache bundl...
1951
1952
  		if (err != -EAGAIN)
  			goto error;
855dad99c   Florian Westphal   xfrm_policy: remo...
1953
  		goto make_dummy_bundle;
bd45c539b   Florian Westphal   xfrm_policy: make...
1954
  	} else if (xdst == NULL) {
d809ec895   Timo Teräs   xfrm: do not assu...
1955
  		num_xfrms = 0;
855dad99c   Florian Westphal   xfrm_policy: remo...
1956
  		goto make_dummy_bundle;
80c802f30   Timo Teräs   xfrm: cache bundl...
1957
  	}
bd45c539b   Florian Westphal   xfrm_policy: make...
1958
  	return xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
1959
1960
1961
1962
1963
  
  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...
1964
  	xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family);
80c802f30   Timo Teräs   xfrm: cache bundl...
1965
1966
1967
1968
1969
1970
  	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 ...
1971
  	memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
1972

bd45c539b   Florian Westphal   xfrm_policy: make...
1973
  	return xdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
1974
1975
1976
1977
  
  inc_error:
  	XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
  error:
855dad99c   Florian Westphal   xfrm_policy: remo...
1978
  	xfrm_pols_put(pols, num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
1979
1980
  	return ERR_PTR(err);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981

2774c131b   David S. Miller   xfrm: Handle blac...
1982
1983
1984
  static struct dst_entry *make_blackhole(struct net *net, u16 family,
  					struct dst_entry *dst_orig)
  {
37b103830   Florian Westphal   xfrm: policy: mak...
1985
  	const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
2774c131b   David S. Miller   xfrm: Handle blac...
1986
1987
1988
1989
  	struct dst_entry *ret;
  
  	if (!afinfo) {
  		dst_release(dst_orig);
433a19548   Li RongQing   xfrm: fix a read ...
1990
  		return ERR_PTR(-EINVAL);
2774c131b   David S. Miller   xfrm: Handle blac...
1991
1992
1993
  	} else {
  		ret = afinfo->blackhole_route(net, dst_orig);
  	}
bdba9fe01   Florian Westphal   xfrm: policy: rem...
1994
  	rcu_read_unlock();
2774c131b   David S. Miller   xfrm: Handle blac...
1995
1996
1997
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
1999
2000
2001
2002
  /* Main function: finds/creates a bundle for given flow.
   *
   * At the moment we eat a raw IP route. Mostly to speed up lookups
   * on interfaces with disabled IPsec.
   */
452edd598   David S. Miller   xfrm: Return dst ...
2003
2004
  struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
  			      const struct flowi *fl,
6f9c96154   Eric Dumazet   inet: constify ip...
2005
  			      const struct sock *sk, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2006
  {
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2007
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
80c802f30   Timo Teräs   xfrm: cache bundl...
2008
  	struct xfrm_dst *xdst;
452edd598   David S. Miller   xfrm: Return dst ...
2009
  	struct dst_entry *dst, *route;
80c802f30   Timo Teräs   xfrm: cache bundl...
2010
  	u16 family = dst_orig->ops->family;
aff669bc2   Florian Westphal   xfrm_policy: kill...
2011
  	u8 dir = XFRM_POLICY_OUT;
4b021628b   Changli Gao   xfrm: potential u...
2012
  	int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
2013

80c802f30   Timo Teräs   xfrm: cache bundl...
2014
2015
2016
  	dst = NULL;
  	xdst = NULL;
  	route = NULL;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2017

bd5eb35f1   Eric Dumazet   xfrm: take care o...
2018
  	sk = sk_const_to_full_sk(sk);
f7944fb19   Thomas Graf   [XFRM] policy: Re...
2019
  	if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
80c802f30   Timo Teräs   xfrm: cache bundl...
2020
  		num_pols = 1;
4c86d7774   Steffen Klassert   xfrm: Don't use s...
2021
  		pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family);
80c802f30   Timo Teräs   xfrm: cache bundl...
2022
2023
2024
  		err = xfrm_expand_policies(fl, family, pols,
  					   &num_pols, &num_xfrms);
  		if (err < 0)
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
2025
  			goto dropdst;
80c802f30   Timo Teräs   xfrm: cache bundl...
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
  
  		if (num_pols) {
  			if (num_xfrms <= 0) {
  				drop_pols = num_pols;
  				goto no_transform;
  			}
  
  			xdst = xfrm_resolve_and_create_bundle(
  					pols, num_pols, fl,
  					family, dst_orig);
  			if (IS_ERR(xdst)) {
  				xfrm_pols_put(pols, num_pols);
  				err = PTR_ERR(xdst);
  				goto dropdst;
d809ec895   Timo Teräs   xfrm: do not assu...
2040
2041
2042
2043
  			} else if (xdst == NULL) {
  				num_xfrms = 0;
  				drop_pols = num_pols;
  				goto no_transform;
80c802f30   Timo Teräs   xfrm: cache bundl...
2044
  			}
80c802f30   Timo Teräs   xfrm: cache bundl...
2045
  			route = xdst->route;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2046
  		}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2047
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2048

80c802f30   Timo Teräs   xfrm: cache bundl...
2049
  	if (xdst == NULL) {
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2050
2051
2052
2053
  		struct xfrm_flo xflo;
  
  		xflo.dst_orig = dst_orig;
  		xflo.flags = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
  		/* To accelerate a bit...  */
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2055
  		if ((dst_orig->flags & DST_NOXFRM) ||
52479b623   Alexey Dobriyan   netns xfrm: looku...
2056
  		    !net->xfrm.policy_count[XFRM_POLICY_OUT])
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2057
  			goto nopol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058

bd45c539b   Florian Westphal   xfrm_policy: make...
2059
2060
  		xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo);
  		if (xdst == NULL)
80c802f30   Timo Teräs   xfrm: cache bundl...
2061
  			goto nopol;
bd45c539b   Florian Westphal   xfrm_policy: make...
2062
2063
  		if (IS_ERR(xdst)) {
  			err = PTR_ERR(xdst);
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
2064
  			goto dropdst;
d66e37a99   Masahide NAKAMURA   [XFRM] Statistics...
2065
  		}
80c802f30   Timo Teräs   xfrm: cache bundl...
2066
2067
2068
  
  		num_pols = xdst->num_pols;
  		num_xfrms = xdst->num_xfrms;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
2069
  		memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols);
80c802f30   Timo Teräs   xfrm: cache bundl...
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
  		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...
2082
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
ac37e2515   huaibin Wang   xfrm: release dst...
2083
2084
  			err = -EREMOTE;
  			goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
2085
  		}
80c802f30   Timo Teräs   xfrm: cache bundl...
2086

5b8ef3415   Steffen Klassert   xfrm: Remove anci...
2087
  		err = -EAGAIN;
80c802f30   Timo Teräs   xfrm: cache bundl...
2088
2089
2090
  
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
2092
2093
  no_transform:
  	if (num_pols == 0)
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2094
  		goto nopol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2095

80c802f30   Timo Teräs   xfrm: cache bundl...
2096
2097
2098
  	if ((flags & XFRM_LOOKUP_ICMP) &&
  	    !(pols[0]->flags & XFRM_POLICY_ICMP)) {
  		err = -ENOENT;
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2099
  		goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
2100
  	}
8b7817f3a   Herbert Xu   [IPSEC]: Add ICMP...
2101

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

80c802f30   Timo Teräs   xfrm: cache bundl...
2105
  	if (num_xfrms < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2106
  		/* Prohibit the flow */
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2107
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
e104411b8   Patrick McHardy   [XFRM]: Always re...
2108
2109
  		err = -EPERM;
  		goto error;
80c802f30   Timo Teräs   xfrm: cache bundl...
2110
2111
  	} else if (num_xfrms > 0) {
  		/* Flow transformed */
80c802f30   Timo Teräs   xfrm: cache bundl...
2112
2113
2114
2115
  		dst_release(dst_orig);
  	} else {
  		/* Flow passes untransformed */
  		dst_release(dst);
452edd598   David S. Miller   xfrm: Return dst ...
2116
  		dst = dst_orig;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
2118
2119
  ok:
  	xfrm_pols_put(pols, drop_pols);
0c1833797   Gao feng   ipv6: fix incorre...
2120
2121
2122
  	if (dst && dst->xfrm &&
  	    dst->xfrm->props.mode == XFRM_MODE_TUNNEL)
  		dst->flags |= DST_XFRM_TUNNEL;
452edd598   David S. Miller   xfrm: Return dst ...
2123
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2124

80c802f30   Timo Teräs   xfrm: cache bundl...
2125
  nopol:
452edd598   David S. Miller   xfrm: Return dst ...
2126
2127
  	if (!(flags & XFRM_LOOKUP_ICMP)) {
  		dst = dst_orig;
80c802f30   Timo Teräs   xfrm: cache bundl...
2128
  		goto ok;
452edd598   David S. Miller   xfrm: Return dst ...
2129
  	}
80c802f30   Timo Teräs   xfrm: cache bundl...
2130
  	err = -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2131
  error:
80c802f30   Timo Teräs   xfrm: cache bundl...
2132
  	dst_release(dst);
75b8c1332   Herbert Xu   [IPSEC]: Fix pote...
2133
  dropdst:
ac37e2515   huaibin Wang   xfrm: release dst...
2134
2135
  	if (!(flags & XFRM_LOOKUP_KEEP_DST_REF))
  		dst_release(dst_orig);
80c802f30   Timo Teräs   xfrm: cache bundl...
2136
  	xfrm_pols_put(pols, drop_pols);
452edd598   David S. Miller   xfrm: Return dst ...
2137
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2138
2139
  }
  EXPORT_SYMBOL(xfrm_lookup);
f92ee6198   Steffen Klassert   xfrm: Generate bl...
2140
2141
2142
2143
2144
  /* 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...
2145
  				    const struct sock *sk, int flags)
f92ee6198   Steffen Klassert   xfrm: Generate bl...
2146
  {
b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2147
  	struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
ac37e2515   huaibin Wang   xfrm: release dst...
2148
2149
  					    flags | XFRM_LOOKUP_QUEUE |
  					    XFRM_LOOKUP_KEEP_DST_REF);
f92ee6198   Steffen Klassert   xfrm: Generate bl...
2150
2151
2152
2153
2154
2155
2156
  
  	if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
  		return make_blackhole(net, dst_orig->ops->family, dst_orig);
  
  	return dst;
  }
  EXPORT_SYMBOL(xfrm_lookup_route);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2157
  static inline int
8f029de28   David S. Miller   xfrm: Mark flowi ...
2158
  xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl)
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2159
2160
  {
  	struct xfrm_state *x;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2161
2162
2163
2164
2165
2166
  
  	if (!skb->sp || idx < 0 || idx >= skb->sp->len)
  		return 0;
  	x = skb->sp->xvec[idx];
  	if (!x->type->reject)
  		return 0;
1ecafede8   Herbert Xu   [IPSEC]: Remove b...
2167
  	return x->type->reject(x, skb, fl);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2168
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2169
2170
2171
2172
2173
2174
2175
  /* 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...
2176
  xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2177
2178
2179
  	      unsigned short family)
  {
  	if (xfrm_state_kern(x))
928ba4169   Kazunori MIYAZAWA   [IPSEC]: Fix the ...
2180
  		return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2181
2182
2183
2184
  	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...
2185
  		(tmpl->allalgs || (tmpl->aalgos & (1<<x->props.aalgo)) ||
f3bd48402   Masahide NAKAMURA   [XFRM]: Restrict ...
2186
  		 !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) &&
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
2187
2188
  		!(x->props.mode != XFRM_MODE_TRANSPORT &&
  		  xfrm_state_addr_cmp(tmpl, x, family));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189
  }
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2190
2191
2192
2193
2194
2195
2196
  /*
   * 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
2197
  static inline int
22cccb7e0   David S. Miller   xfrm: Const'ify p...
2198
  xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
2200
2201
2202
2203
  	       unsigned short family)
  {
  	int idx = start;
  
  	if (tmpl->optional) {
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
2204
  		if (tmpl->mode == XFRM_MODE_TRANSPORT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205
2206
2207
2208
  			return start;
  	} else
  		start = -1;
  	for (; idx < sp->len; idx++) {
dbe5b4aaa   Herbert Xu   [IPSEC]: Kill unu...
2209
  		if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
  			return ++idx;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2211
2212
2213
  		if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
  			if (start == -1)
  				start = -2-idx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2214
  			break;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2215
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2216
2217
2218
  	}
  	return start;
  }
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
2219
2220
  int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
  			  unsigned int family, int reverse)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221
  {
37b103830   Florian Westphal   xfrm: policy: mak...
2222
  	const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
2223
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2224
2225
2226
  
  	if (unlikely(afinfo == NULL))
  		return -EAFNOSUPPORT;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
2227
  	afinfo->decode_session(skb, fl, reverse);
1d28f42c1   David S. Miller   net: Put flowi_* ...
2228
  	err = security_xfrm_decode_session(skb, &fl->flowi_secid);
bdba9fe01   Florian Westphal   xfrm: policy: rem...
2229
  	rcu_read_unlock();
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
2230
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2231
  }
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
2232
  EXPORT_SYMBOL(__xfrm_decode_session);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2233

9a7386ec9   David S. Miller   xfrm: Const'ify s...
2234
  static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int *idxp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
2236
  {
  	for (; k < sp->len; k++) {
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2237
  		if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) {
d1d9facfd   James Morris   [XFRM]: remove xe...
2238
  			*idxp = k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2239
  			return 1;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2240
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2241
2242
2243
2244
  	}
  
  	return 0;
  }
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
2245
  int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2246
2247
  			unsigned short family)
  {
f6e1e25d7   Alexey Dobriyan   netns xfrm: xfrm_...
2248
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2249
  	struct xfrm_policy *pol;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2250
2251
2252
2253
  	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
  	int npols = 0;
  	int xfrm_nr;
  	int pi;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
2254
  	int reverse;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2255
  	struct flowi fl;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2256
  	int xerr_idx = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2257

d5422efe6   Herbert Xu   [IPSEC]: Added xf...
2258
2259
  	reverse = dir & ~XFRM_POLICY_MASK;
  	dir &= XFRM_POLICY_MASK;
d5422efe6   Herbert Xu   [IPSEC]: Added xf...
2260

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2261
  	if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2262
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2263
  		return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2264
  	}
eb9c7ebe6   Patrick McHardy   [NETFILTER]: Hand...
2265
  	nf_nat_decode_session(skb, &fl, family);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
2267
2268
2269
  
  	/* First, check used SA against their selectors. */
  	if (skb->sp) {
  		int i;
9b7a787d0   Weilong Chen   xfrm: checkpatch ...
2270
  		for (i = skb->sp->len-1; i >= 0; i--) {
dbe5b4aaa   Herbert Xu   [IPSEC]: Kill unu...
2271
  			struct xfrm_state *x = skb->sp->xvec[i];
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2272
  			if (!xfrm_selector_match(&x->sel, &fl, family)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2273
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
  				return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2275
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2276
2277
2278
2279
  		}
  	}
  
  	pol = NULL;
bd5eb35f1   Eric Dumazet   xfrm: take care o...
2280
  	sk = sk_to_full_sk(sk);
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2281
  	if (sk && sk->sk_policy[dir]) {
4c86d7774   Steffen Klassert   xfrm: Don't use s...
2282
  		pol = xfrm_sk_policy_lookup(sk, dir, &fl, family);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2283
  		if (IS_ERR(pol)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2284
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2285
  			return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2286
  		}
3bccfbc7a   Venkat Yekkirala   IPsec: fix handli...
2287
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2288

86dc8ee0b   Florian Westphal   xfrm_policy: remo...
2289
2290
  	if (!pol)
  		pol = xfrm_policy_lookup(net, &fl, family, dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2291

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2292
  	if (IS_ERR(pol)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2293
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
134b0fc54   James Morris   IPsec: propagate ...
2294
  		return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2295
  	}
134b0fc54   James Morris   IPsec: propagate ...
2296

df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2297
  	if (!pol) {
d1d9facfd   James Morris   [XFRM]: remove xe...
2298
  		if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2299
  			xfrm_secpath_reject(xerr_idx, skb, &fl);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2300
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2301
2302
2303
2304
  			return 0;
  		}
  		return 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305

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

4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2308
  	pols[0] = pol;
02d0892f9   Weilong Chen   xfrm: checkpatch ...
2309
  	npols++;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2310
2311
  #ifdef CONFIG_XFRM_SUB_POLICY
  	if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
f6e1e25d7   Alexey Dobriyan   netns xfrm: xfrm_...
2312
  		pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2313
2314
2315
  						    &fl, family,
  						    XFRM_POLICY_IN);
  		if (pols[1]) {
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2316
  			if (IS_ERR(pols[1])) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2317
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
134b0fc54   James Morris   IPsec: propagate ...
2318
  				return 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2319
  			}
9d729f72d   James Morris   [NET]: Convert xt...
2320
  			pols[1]->curlft.use_time = get_seconds();
02d0892f9   Weilong Chen   xfrm: checkpatch ...
2321
  			npols++;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2322
2323
2324
  		}
  	}
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2325
2326
2327
  	if (pol->action == XFRM_POLICY_ALLOW) {
  		struct sec_path *sp;
  		static struct sec_path dummy;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2328
  		struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
2329
  		struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2330
2331
  		struct xfrm_tmpl **tpp = tp;
  		int ti = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2332
2333
2334
2335
  		int i, k;
  
  		if ((sp = skb->sp) == NULL)
  			sp = &dummy;
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2336
2337
  		for (pi = 0; pi < npols; pi++) {
  			if (pols[pi] != pol &&
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2338
  			    pols[pi]->action != XFRM_POLICY_ALLOW) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2339
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2340
  				goto reject;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2341
2342
  			}
  			if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2343
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2344
  				goto reject_error;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2345
  			}
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2346
2347
2348
2349
  			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...
2350
  		if (npols > 1) {
283bc9f35   Fan Du   xfrm: Namespacify...
2351
  			xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net);
41a49cc3c   Masahide NAKAMURA   [XFRM]: Add sorti...
2352
2353
  			tpp = stp;
  		}
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2354

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355
2356
2357
2358
2359
2360
  		/* 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...
2361
2362
  		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...
2363
  			if (k < 0) {
d1d9facfd   James Morris   [XFRM]: remove xe...
2364
2365
2366
  				if (k < -1)
  					/* "-2 - errored_index" returned */
  					xerr_idx = -(2+k);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2367
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368
  				goto reject;
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2369
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2370
  		}
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2371
  		if (secpath_has_nontransport(sp, k, &xerr_idx)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2372
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2373
  			goto reject;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
2374
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2375

4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2376
  		xfrm_pols_put(pols, npols);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2377
2378
  		return 1;
  	}
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2379
  	XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2380
2381
  
  reject:
df0ba92a9   Masahide NAKAMURA   [XFRM]: Trace whi...
2382
  	xfrm_secpath_reject(xerr_idx, skb, &fl);
4e81bb833   Masahide NAKAMURA   [XFRM] POLICY: su...
2383
2384
  reject_error:
  	xfrm_pols_put(pols, npols);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2385
2386
2387
2388
2389
2390
  	return 0;
  }
  EXPORT_SYMBOL(__xfrm_policy_check);
  
  int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
  {
99a66657b   Alexey Dobriyan   netns xfrm: xfrm_...
2391
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2392
  	struct flowi fl;
adf30907d   Eric Dumazet   net: skb->dst acc...
2393
  	struct dst_entry *dst;
731371477   Eric Dumazet   xfrm: fix __xfrm_...
2394
  	int res = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2395

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

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

b8c203b2d   Steffen Klassert   xfrm: Generate qu...
2403
  	dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE);
452edd598   David S. Miller   xfrm: Return dst ...
2404
  	if (IS_ERR(dst)) {
731371477   Eric Dumazet   xfrm: fix __xfrm_...
2405
  		res = 0;
452edd598   David S. Miller   xfrm: Return dst ...
2406
2407
  		dst = NULL;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
2408
2409
  	skb_dst_set(skb, dst);
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
2411
  }
  EXPORT_SYMBOL(__xfrm_route_forward);
d49c73c72   David S. Miller   [IPSEC]: Validate...
2412
  /* Optimize later using cookies and generation ids. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2413
2414
  static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
  {
d49c73c72   David S. Miller   [IPSEC]: Validate...
2415
  	/* Code (such as __xfrm4_bundle_create()) sets dst->obsolete
f5b0a8743   David S. Miller   net: Document dst...
2416
2417
2418
2419
2420
2421
2422
  	 * 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...
2423
2424
2425
2426
2427
2428
2429
2430
  	 *
  	 *	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...
2431
2432
  	 * When a dst is removed from the fib tree, DST_OBSOLETE_DEAD will
  	 * be marked on it.
09c757048   Florian Westphal   xfrm: remove flow...
2433
  	 * This will force stale_bundle() to fail on any xdst bundle with
52df157f1   Wei Wang   xfrm: take refcnt...
2434
  	 * this dst linked in it.
399c180ac   David S. Miller   [IPSEC]: Perform ...
2435
  	 */
d49c73c72   David S. Miller   [IPSEC]: Validate...
2436
2437
  	if (dst->obsolete < 0 && !stale_bundle(dst))
  		return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2438
2439
2440
2441
2442
  	return NULL;
  }
  
  static int stale_bundle(struct dst_entry *dst)
  {
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
2443
  	return !xfrm_bundle_ok((struct xfrm_dst *)dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2444
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
2445
  void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2446
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2447
  	while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2448
  		dst->dev = dev_net(dev)->loopback_dev;
de3cb747f   Daniel Lezcano   [NET]: Dynamicall...
2449
  		dev_hold(dst->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
2451
2452
  		dev_put(dev);
  	}
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
2453
  EXPORT_SYMBOL(xfrm_dst_ifdown);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2454
2455
2456
2457
  
  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
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
  }
  
  static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
  {
  	if (dst) {
  		if (dst->obsolete) {
  			dst_release(dst);
  			dst = NULL;
  		}
  	}
  	return dst;
  }
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
2470
  static void xfrm_init_pmtu(struct dst_entry *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
  {
  	do {
  		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  		u32 pmtu, route_mtu_cached;
  
  		pmtu = dst_mtu(dst->child);
  		xdst->child_mtu_cached = pmtu;
  
  		pmtu = xfrm_state_mtu(dst->xfrm, pmtu);
  
  		route_mtu_cached = dst_mtu(xdst->route);
  		xdst->route_mtu_cached = route_mtu_cached;
  
  		if (pmtu > route_mtu_cached)
  			pmtu = route_mtu_cached;
defb3519a   David S. Miller   net: Abstract awa...
2486
  		dst_metric_set(dst, RTAX_MTU, pmtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2487
2488
  	} while ((dst = dst->next));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2489
2490
2491
  /* Check that the bundle accepts the flow and its components are
   * still valid.
   */
12fdb4d3b   Steffen Klassert   xfrm: Remove fami...
2492
  static int xfrm_bundle_ok(struct xfrm_dst *first)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2493
2494
2495
2496
  {
  	struct dst_entry *dst = &first->u.dst;
  	struct xfrm_dst *last;
  	u32 mtu;
92d63decc   Hideaki YOSHIFUJI   From: Kazunori Mi...
2497
  	if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2498
2499
  	    (dst->dev && !netif_running(dst->dev)))
  		return 0;
a0073fe18   Steffen Klassert   xfrm: Add a state...
2500
2501
  	if (dst->flags & DST_XFRM_QUEUE)
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2502
2503
2504
2505
  	last = NULL;
  
  	do {
  		struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2506
2507
  		if (dst->xfrm->km.state != XFRM_STATE_VALID)
  			return 0;
80c802f30   Timo Teräs   xfrm: cache bundl...
2508
2509
  		if (xdst->xfrm_genid != dst->xfrm->genid)
  			return 0;
b1312c89f   Timo Teräs   xfrm: check bundl...
2510
2511
  		if (xdst->num_pols > 0 &&
  		    xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))
9d4a706d8   David S. Miller   [XFRM]: Add gener...
2512
  			return 0;
e53820de0   Masahide NAKAMURA   [XFRM] IPV6: Rest...
2513

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2514
2515
2516
2517
2518
  		mtu = dst_mtu(dst->child);
  		if (xdst->child_mtu_cached != mtu) {
  			last = xdst;
  			xdst->child_mtu_cached = mtu;
  		}
92d63decc   Hideaki YOSHIFUJI   From: Kazunori Mi...
2519
  		if (!dst_check(xdst->route, xdst->route_cookie))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
  			return 0;
  		mtu = dst_mtu(xdst->route);
  		if (xdst->route_mtu_cached != mtu) {
  			last = xdst;
  			xdst->route_mtu_cached = mtu;
  		}
  
  		dst = dst->child;
  	} while (dst->xfrm);
  
  	if (likely(!last))
  		return 1;
  
  	mtu = last->child_mtu_cached;
  	for (;;) {
  		dst = &last->u.dst;
  
  		mtu = xfrm_state_mtu(dst->xfrm, mtu);
  		if (mtu > last->route_mtu_cached)
  			mtu = last->route_mtu_cached;
defb3519a   David S. Miller   net: Abstract awa...
2540
  		dst_metric_set(dst, RTAX_MTU, mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2541
2542
2543
  
  		if (last == first)
  			break;
bd0bf0765   Patrick McHardy   [XFRM]: Fix crash...
2544
  		last = (struct xfrm_dst *)last->u.dst.next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
2546
2547
2548
2549
  		last->child_mtu_cached = mtu;
  	}
  
  	return 1;
  }
0dbaee3b3   David S. Miller   net: Abstract def...
2550
2551
2552
2553
  static unsigned int xfrm_default_advmss(const struct dst_entry *dst)
  {
  	return dst_metric_advmss(dst->path);
  }
ebb762f27   Steffen Klassert   net: Rename the d...
2554
  static unsigned int xfrm_mtu(const struct dst_entry *dst)
d33e45533   David S. Miller   net: Abstract def...
2555
  {
618f9bc74   Steffen Klassert   net: Move mtu han...
2556
2557
2558
  	unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
  
  	return mtu ? : dst_mtu(dst->path);
d33e45533   David S. Miller   net: Abstract def...
2559
  }
1ecc9ad02   Julian Anastasov   xfrm: provide cor...
2560
2561
  static const void *xfrm_get_dst_nexthop(const struct dst_entry *dst,
  					const void *daddr)
63fca65d0   Julian Anastasov   net: add confirm_...
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
  {
  	const struct dst_entry *path = dst->path;
  
  	for (; dst != path; dst = dst->child) {
  		const struct xfrm_state *xfrm = dst->xfrm;
  
  		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...
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
  	return daddr;
  }
  
  static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
  					   struct sk_buff *skb,
  					   const void *daddr)
  {
  	const struct dst_entry *path = dst->path;
  
  	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)
  {
  	const struct dst_entry *path = dst->path;
  
  	daddr = xfrm_get_dst_nexthop(dst, daddr);
63fca65d0   Julian Anastasov   net: add confirm_...
2594
2595
  	path->ops->confirm_neigh(path, daddr);
  }
a2817d8b2   Florian Westphal   xfrm: policy: rem...
2596
  int xfrm_policy_register_afinfo(const struct xfrm_policy_afinfo *afinfo, int family)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2597
2598
  {
  	int err = 0;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
2599
2600
  
  	if (WARN_ON(family >= ARRAY_SIZE(xfrm_policy_afinfo)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2601
  		return -EAFNOSUPPORT;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
2602

ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
2603
  	spin_lock(&xfrm_policy_afinfo_lock);
a2817d8b2   Florian Westphal   xfrm: policy: rem...
2604
  	if (unlikely(xfrm_policy_afinfo[family] != NULL))
f31e8d4f7   Li RongQing   xfrm: fix the ret...
2605
  		err = -EEXIST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2606
2607
2608
2609
2610
2611
  	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...
2612
2613
  		if (likely(dst_ops->default_advmss == NULL))
  			dst_ops->default_advmss = xfrm_default_advmss;
ebb762f27   Steffen Klassert   net: Rename the d...
2614
2615
  		if (likely(dst_ops->mtu == NULL))
  			dst_ops->mtu = xfrm_mtu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2616
2617
2618
2619
  		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_...
2620
2621
  		if (likely(dst_ops->neigh_lookup == NULL))
  			dst_ops->neigh_lookup = xfrm_neigh_lookup;
63fca65d0   Julian Anastasov   net: add confirm_...
2622
2623
  		if (likely(!dst_ops->confirm_neigh))
  			dst_ops->confirm_neigh = xfrm_confirm_neigh;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
2624
  		rcu_assign_pointer(xfrm_policy_afinfo[family], afinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2625
  	}
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
2626
  	spin_unlock(&xfrm_policy_afinfo_lock);
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
2627

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2628
2629
2630
  	return err;
  }
  EXPORT_SYMBOL(xfrm_policy_register_afinfo);
a2817d8b2   Florian Westphal   xfrm: policy: rem...
2631
  void xfrm_policy_unregister_afinfo(const struct xfrm_policy_afinfo *afinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2632
  {
2b61997aa   Florian Westphal   xfrm: policy: xfr...
2633
  	struct dst_ops *dst_ops = afinfo->dst_ops;
a2817d8b2   Florian Westphal   xfrm: policy: rem...
2634
  	int i;
2b61997aa   Florian Westphal   xfrm: policy: xfr...
2635

a2817d8b2   Florian Westphal   xfrm: policy: rem...
2636
2637
2638
2639
2640
  	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
2641
  	}
ef8531b64   Eric Dumazet   xfrm: fix RCU bugs
2642

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

2b61997aa   Florian Westphal   xfrm: policy: xfr...
2645
2646
2647
2648
  	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
2649
2650
  }
  EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2651
  #ifdef CONFIG_XFRM_STATISTICS
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2652
  static int __net_init xfrm_statistics_init(struct net *net)
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2653
  {
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2654
  	int rv;
698365fa1   WANG Cong   net: clean up snm...
2655
2656
  	net->mib.xfrm_statistics = alloc_percpu(struct linux_xfrm_mib);
  	if (!net->mib.xfrm_statistics)
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2657
  		return -ENOMEM;
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2658
2659
  	rv = xfrm_proc_init(net);
  	if (rv < 0)
698365fa1   WANG Cong   net: clean up snm...
2660
  		free_percpu(net->mib.xfrm_statistics);
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2661
  	return rv;
558f82ef6   Masahide NAKAMURA   [XFRM]: Define pa...
2662
  }
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2663
2664
2665
  
  static void xfrm_statistics_fini(struct net *net)
  {
c68cd1a01   Alexey Dobriyan   netns xfrm: /proc...
2666
  	xfrm_proc_fini(net);
698365fa1   WANG Cong   net: clean up snm...
2667
  	free_percpu(net->mib.xfrm_statistics);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
  }
  #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...
2678
  #endif
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2679
  static int __net_init xfrm_policy_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2680
  {
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2681
2682
  	unsigned int hmask, sz;
  	int dir;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2683
2684
  	if (net_eq(net, &init_net))
  		xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2685
  					   sizeof(struct xfrm_dst),
e5d679f33   Alexey Dobriyan   [NET]: Use SLAB_P...
2686
  					   0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
20c2df83d   Paul Mundt   mm: Remove slab d...
2687
  					   NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2688

2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2689
2690
  	hmask = 8 - 1;
  	sz = (hmask+1) * sizeof(struct hlist_head);
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2691
2692
2693
  	net->xfrm.policy_byidx = xfrm_hash_alloc(sz);
  	if (!net->xfrm.policy_byidx)
  		goto out_byidx;
8100bea7d   Alexey Dobriyan   netns xfrm: per-n...
2694
  	net->xfrm.policy_idx_hmask = hmask;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2695

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

a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2702
  		htab = &net->xfrm.policy_bydst[dir];
44e36b42a   David S. Miller   [XFRM]: Extract c...
2703
  		htab->table = xfrm_hash_alloc(sz);
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2704
  		if (!htab->table)
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2705
2706
  			goto out_bydst;
  		htab->hmask = hmask;
b58555f17   Christophe Gouault   xfrm: hash prefix...
2707
2708
2709
2710
  		htab->dbits4 = 32;
  		htab->sbits4 = 32;
  		htab->dbits6 = 128;
  		htab->sbits6 = 128;
2518c7c2b   David S. Miller   [XFRM]: Hash poli...
2711
  	}
880a6fab8   Christophe Gouault   xfrm: configure p...
2712
2713
2714
2715
2716
2717
  	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...
2718

adfcf0b27   Alexey Dobriyan   netns xfrm: per-n...
2719
  	INIT_LIST_HEAD(&net->xfrm.policy_all);
66caf628c   Alexey Dobriyan   netns xfrm: per-n...
2720
  	INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
880a6fab8   Christophe Gouault   xfrm: configure p...
2721
  	INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2722
  	if (net_eq(net, &init_net))
21f42cc95   Steffen Klassert   xfrm: Move device...
2723
  		xfrm_dev_init();
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2724
  	return 0;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2725

a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2726
2727
2728
2729
2730
2731
2732
2733
  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...
2734
2735
  out_byidx:
  	return -ENOMEM;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2736
2737
2738
2739
  }
  
  static void xfrm_policy_fini(struct net *net)
  {
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2740
  	unsigned int sz;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2741
  	int dir;
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2742

7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
2743
2744
  	flush_work(&net->xfrm.policy_hash_work);
  #ifdef CONFIG_XFRM_SUB_POLICY
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
2745
  	xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false);
7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
2746
  #endif
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
2747
  	xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false);
7c2776ee2   Alexey Dobriyan   netns xfrm: flush...
2748

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

53c2e285f   Herbert Xu   xfrm: Do not hash...
2751
  	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2752
  		struct xfrm_policy_hash *htab;
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2753
  		WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2754
2755
  
  		htab = &net->xfrm.policy_bydst[dir];
5b653b2a1   Michal Kubecek   xfrm: fix freed b...
2756
  		sz = (htab->hmask + 1) * sizeof(struct hlist_head);
a35f6c5de   Alexey Dobriyan   netns xfrm: per-n...
2757
2758
  		WARN_ON(!hlist_empty(htab->table));
  		xfrm_hash_free(htab->table, sz);
8b18f8eaf   Alexey Dobriyan   netns xfrm: per-n...
2759
  	}
8100bea7d   Alexey Dobriyan   netns xfrm: per-n...
2760
  	sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head);
93b851c1c   Alexey Dobriyan   netns xfrm: per-n...
2761
2762
  	WARN_ON(!hlist_empty(net->xfrm.policy_byidx));
  	xfrm_hash_free(net->xfrm.policy_byidx, sz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2763
  }
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2764
2765
2766
  static int __net_init xfrm_net_init(struct net *net)
  {
  	int rv;
c282222a4   Florian Westphal   xfrm: policy: ini...
2767
2768
2769
2770
  	/* 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...
2771
2772
2773
  	rv = xfrm_statistics_init(net);
  	if (rv < 0)
  		goto out_statistics;
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2774
2775
2776
2777
2778
2779
  	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...
2780
2781
2782
  	rv = xfrm_sysctl_init(net);
  	if (rv < 0)
  		goto out_sysctl;
283bc9f35   Fan Du   xfrm: Namespacify...
2783

d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2784
  	return 0;
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
2785
2786
  out_sysctl:
  	xfrm_policy_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2787
2788
2789
  out_policy:
  	xfrm_state_fini(net);
  out_state:
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2790
2791
  	xfrm_statistics_fini(net);
  out_statistics:
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2792
2793
2794
2795
2796
  	return rv;
  }
  
  static void __net_exit xfrm_net_exit(struct net *net)
  {
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
2797
  	xfrm_sysctl_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2798
2799
  	xfrm_policy_fini(net);
  	xfrm_state_fini(net);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
2800
  	xfrm_statistics_fini(net);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2801
2802
2803
2804
2805
2806
  }
  
  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
2807
2808
  void __init xfrm_init(void)
  {
ec30d78c1   Florian Westphal   xfrm: add xdst pc...
2809
2810
2811
2812
2813
2814
2815
2816
  	int i;
  
  	xfrm_pcpu_work = kmalloc_array(NR_CPUS, sizeof(*xfrm_pcpu_work),
  				       GFP_KERNEL);
  	BUG_ON(!xfrm_pcpu_work);
  
  	for (i = 0; i < NR_CPUS; i++)
  		INIT_WORK(&xfrm_pcpu_work[i], xfrm_pcpu_work_fn);
d62ddc21b   Alexey Dobriyan   netns xfrm: add n...
2817
  	register_pernet_subsys(&xfrm_net_ops);
30846090a   Florian Westphal   xfrm: policy: add...
2818
  	seqcount_init(&xfrm_policy_hash_generation);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2819
2820
  	xfrm_input_init();
  }
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2821
  #ifdef CONFIG_AUDITSYSCALL
1486cbd77   Ilpo Järvinen   [XFRM] xfrm_polic...
2822
2823
  static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
  					 struct audit_buffer *audit_buf)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2824
  {
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2825
2826
2827
2828
  	struct xfrm_sec_ctx *ctx = xp->security;
  	struct xfrm_selector *sel = &xp->selector;
  
  	if (ctx)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2829
  		audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2830
  				 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2831

9b7a787d0   Weilong Chen   xfrm: checkpatch ...
2832
  	switch (sel->family) {
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2833
  	case AF_INET:
21454aaad   Harvey Harrison   net: replace NIPQ...
2834
  		audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2835
2836
2837
  		if (sel->prefixlen_s != 32)
  			audit_log_format(audit_buf, " src_prefixlen=%d",
  					 sel->prefixlen_s);
21454aaad   Harvey Harrison   net: replace NIPQ...
2838
  		audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2839
2840
2841
  		if (sel->prefixlen_d != 32)
  			audit_log_format(audit_buf, " dst_prefixlen=%d",
  					 sel->prefixlen_d);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2842
2843
  		break;
  	case AF_INET6:
5b095d989   Harvey Harrison   net: replace %p6 ...
2844
  		audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2845
2846
2847
  		if (sel->prefixlen_s != 128)
  			audit_log_format(audit_buf, " src_prefixlen=%d",
  					 sel->prefixlen_s);
5b095d989   Harvey Harrison   net: replace %p6 ...
2848
  		audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6);
875179fa6   Paul Moore   [IPSEC]: SPD audi...
2849
2850
2851
  		if (sel->prefixlen_d != 128)
  			audit_log_format(audit_buf, " dst_prefixlen=%d",
  					 sel->prefixlen_d);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2852
2853
2854
  		break;
  	}
  }
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
2855
  void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2856
2857
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2858

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2859
  	audit_buf = xfrm_audit_start("SPD-add");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2860
2861
  	if (audit_buf == NULL)
  		return;
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
2862
  	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2863
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2864
2865
2866
2867
  	xfrm_audit_common_policyinfo(xp, audit_buf);
  	audit_log_end(audit_buf);
  }
  EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
68277accb   Paul Moore   [XFRM]: Assorted ...
2868
  void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
2869
  			      bool task_valid)
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2870
2871
  {
  	struct audit_buffer *audit_buf;
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2872

afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2873
  	audit_buf = xfrm_audit_start("SPD-delete");
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2874
2875
  	if (audit_buf == NULL)
  		return;
2e71029e2   Tetsuo Handa   xfrm: Remove usel...
2876
  	xfrm_audit_helper_usrinfo(task_valid, audit_buf);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
2877
  	audit_log_format(audit_buf, " res=%u", result);
ab5f5e8b1   Joy Latten   [XFRM]: xfrm audi...
2878
2879
2880
2881
2882
  	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...
2883
  #ifdef CONFIG_XFRM_MIGRATE
bc9b35ad4   David S. Miller   xfrm: Convert sev...
2884
2885
  static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
  					const struct xfrm_selector *sel_tgt)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2886
2887
2888
  {
  	if (sel_cmp->proto == IPSEC_ULPROTO_ANY) {
  		if (sel_tgt->family == sel_cmp->family &&
70e94e66a   YOSHIFUJI Hideaki / 吉藤英明   xfrm: Convert xfr...
2889
2890
2891
2892
  		    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...
2893
2894
  		    sel_tgt->prefixlen_d == sel_cmp->prefixlen_d &&
  		    sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) {
bc9b35ad4   David S. Miller   xfrm: Convert sev...
2895
  			return true;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2896
2897
2898
  		}
  	} else {
  		if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) {
bc9b35ad4   David S. Miller   xfrm: Convert sev...
2899
  			return true;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2900
2901
  		}
  	}
bc9b35ad4   David S. Miller   xfrm: Convert sev...
2902
  	return false;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2903
  }
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
2904
2905
  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...
2906
2907
  {
  	struct xfrm_policy *pol, *ret = NULL;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2908
2909
  	struct hlist_head *chain;
  	u32 priority = ~0U;
9d0380df6   Florian Westphal   xfrm: policy: con...
2910
  	spin_lock_bh(&net->xfrm.xfrm_policy_lock);
8d549c4f5   Fan Du   xfrm: Using the r...
2911
  	chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
b67bfe0d4   Sasha Levin   hlist: drop the n...
2912
  	hlist_for_each_entry(pol, chain, bydst) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2913
2914
2915
2916
2917
2918
2919
  		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
  		    pol->type == type) {
  			ret = pol;
  			priority = ret->priority;
  			break;
  		}
  	}
8d549c4f5   Fan Du   xfrm: Using the r...
2920
  	chain = &net->xfrm.policy_inexact[dir];
b67bfe0d4   Sasha Levin   hlist: drop the n...
2921
  	hlist_for_each_entry(pol, chain, bydst) {
8faf491e6   Li RongQing   xfrm: optimise to...
2922
2923
  		if ((pol->priority >= priority) && ret)
  			break;
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2924
  		if (xfrm_migrate_selector_match(sel, &pol->selector) &&
8faf491e6   Li RongQing   xfrm: optimise to...
2925
  		    pol->type == type) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2926
2927
2928
2929
  			ret = pol;
  			break;
  		}
  	}
586f2eb41   Li RongQing   xfrm: remove the ...
2930
  	xfrm_pol_hold(ret);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2931

9d0380df6   Florian Westphal   xfrm: policy: con...
2932
  	spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2933
2934
2935
  
  	return ret;
  }
dd701754e   David S. Miller   xfrm: Const'ify p...
2936
  static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tmpl *t)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2937
2938
2939
2940
2941
2942
2943
2944
  {
  	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...
2945
2946
2947
2948
  			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...
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
  				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...
2970
2971
2972
  	int i, j, n = 0;
  
  	write_lock_bh(&pol->lock);
12a169e7d   Herbert Xu   ipsec: Put dumper...
2973
  	if (unlikely(pol->walk.dead)) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
  		/* 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...
2984
2985
  			if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL &&
  			    pol->xfrm_vec[i].mode != XFRM_MODE_BEET)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2986
2987
2988
2989
2990
2991
2992
2993
  				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...
2994
  			atomic_inc(&pol->genid);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
  		}
  	}
  
  	write_unlock_bh(&pol->lock);
  
  	if (!n)
  		return -ENODATA;
  
  	return 0;
  }
dd701754e   David S. Miller   xfrm: Const'ify p...
3005
  static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3006
3007
3008
3009
3010
3011
3012
  {
  	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...
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
  		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...
3033
  int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
3034
  		 struct xfrm_migrate *m, int num_migrate,
4ab47d47a   Antony Antony   xfrm: extend MIGR...
3035
3036
  		 struct xfrm_kmaddress *k, struct net *net,
  		 struct xfrm_encap_tmpl *encap)
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3037
3038
3039
3040
3041
3042
3043
  {
  	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...
3044
  	/* Stage 0 - sanity checks */
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3045
3046
  	if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
  		goto out;
7bab09631   Vladis Dronov   xfrm: policy: che...
3047
3048
3049
3050
  	if (dir >= XFRM_POLICY_MAX) {
  		err = -EINVAL;
  		goto out;
  	}
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3051
  	/* Stage 1 - find policy */
8d549c4f5   Fan Du   xfrm: Using the r...
3052
  	if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3053
3054
3055
3056
3057
3058
  		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...
3059
  		if ((x = xfrm_migrate_state_find(mp, net))) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3060
3061
  			x_cur[nx_cur] = x;
  			nx_cur++;
4ab47d47a   Antony Antony   xfrm: extend MIGR...
3062
3063
  			xc = xfrm_state_migrate(x, mp, encap);
  			if (xc) {
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
  				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...
3084
  	km_migrate(sel, dir, type, m, num_migrate, k, encap);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
  
  	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...
3102
  EXPORT_SYMBOL(xfrm_migrate);
80c9abaab   Shinta Sugimoto   [XFRM]: Extension...
3103
  #endif