Blame view

net/xfrm/xfrm_input.c 12.5 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
  /*
   * xfrm_input.c
   *
   * Changes:
   * 	YOSHIFUJI Hideaki @USAGI
   * 		Split up af-specific portion
a716c1197   YOSHIFUJI Hideaki   [NET] XFRM: Fix w...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   */
acf568ee8   Herbert Xu   xfrm: Reinject tr...
10
11
  #include <linux/bottom_half.h>
  #include <linux/interrupt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  #include <linux/slab.h>
  #include <linux/module.h>
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
14
  #include <linux/netdevice.h>
acf568ee8   Herbert Xu   xfrm: Reinject tr...
15
  #include <linux/percpu.h>
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
16
  #include <net/dst.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <net/ip.h>
  #include <net/xfrm.h>
049f8e2e2   Alexander Duyck   xfrm: Override sk...
19
20
  #include <net/ip_tunnels.h>
  #include <net/ip6_tunnel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

acf568ee8   Herbert Xu   xfrm: Reinject tr...
22
23
24
25
26
27
28
29
30
31
  struct xfrm_trans_tasklet {
  	struct tasklet_struct tasklet;
  	struct sk_buff_head queue;
  };
  
  struct xfrm_trans_cb {
  	int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);
  };
  
  #define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0]))
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
32
  static struct kmem_cache *secpath_cachep __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

2f32b51b6   Steffen Klassert   xfrm: Introduce x...
34
  static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
960fdfdeb   Florian Westphal   xfrm: input: cons...
35
  static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[AF_INET6 + 1];
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
36

1995876a0   Steffen Klassert   xfrm: Add a dummy...
37
38
  static struct gro_cells gro_cells;
  static struct net_device xfrm_napi_dev;
acf568ee8   Herbert Xu   xfrm: Reinject tr...
39
  static DEFINE_PER_CPU(struct xfrm_trans_tasklet, xfrm_trans_tasklet);
960fdfdeb   Florian Westphal   xfrm: input: cons...
40
  int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo)
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
41
42
  {
  	int err = 0;
960fdfdeb   Florian Westphal   xfrm: input: cons...
43
  	if (WARN_ON(afinfo->family >= ARRAY_SIZE(xfrm_input_afinfo)))
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
44
  		return -EAFNOSUPPORT;
960fdfdeb   Florian Westphal   xfrm: input: cons...
45

2f32b51b6   Steffen Klassert   xfrm: Introduce x...
46
47
  	spin_lock_bh(&xfrm_input_afinfo_lock);
  	if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL))
f31e8d4f7   Li RongQing   xfrm: fix the ret...
48
  		err = -EEXIST;
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
49
50
51
52
53
54
  	else
  		rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo);
  	spin_unlock_bh(&xfrm_input_afinfo_lock);
  	return err;
  }
  EXPORT_SYMBOL(xfrm_input_register_afinfo);
960fdfdeb   Florian Westphal   xfrm: input: cons...
55
  int xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo)
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
56
57
  {
  	int err = 0;
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
58
59
60
61
62
63
64
65
66
67
68
69
  	spin_lock_bh(&xfrm_input_afinfo_lock);
  	if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) {
  		if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo))
  			err = -EINVAL;
  		else
  			RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL);
  	}
  	spin_unlock_bh(&xfrm_input_afinfo_lock);
  	synchronize_rcu();
  	return err;
  }
  EXPORT_SYMBOL(xfrm_input_unregister_afinfo);
960fdfdeb   Florian Westphal   xfrm: input: cons...
70
  static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family)
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
71
  {
960fdfdeb   Florian Westphal   xfrm: input: cons...
72
  	const struct xfrm_input_afinfo *afinfo;
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
73

960fdfdeb   Florian Westphal   xfrm: input: cons...
74
  	if (WARN_ON_ONCE(family >= ARRAY_SIZE(xfrm_input_afinfo)))
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
75
  		return NULL;
960fdfdeb   Florian Westphal   xfrm: input: cons...
76

2f32b51b6   Steffen Klassert   xfrm: Introduce x...
77
78
79
80
81
82
  	rcu_read_lock();
  	afinfo = rcu_dereference(xfrm_input_afinfo[family]);
  	if (unlikely(!afinfo))
  		rcu_read_unlock();
  	return afinfo;
  }
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
83
84
85
86
  static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
  		       int err)
  {
  	int ret;
960fdfdeb   Florian Westphal   xfrm: input: cons...
87
  	const struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family);
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
88
89
90
91
92
  
  	if (!afinfo)
  		return -EAFNOSUPPORT;
  
  	ret = afinfo->callback(skb, protocol, err);
960fdfdeb   Florian Westphal   xfrm: input: cons...
93
  	rcu_read_unlock();
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
94
95
96
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
  void __secpath_destroy(struct sec_path *sp)
  {
  	int i;
  	for (i = 0; i < sp->len; i++)
dbe5b4aaa   Herbert Xu   [IPSEC]: Kill unu...
101
  		xfrm_state_put(sp->xvec[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
  	kmem_cache_free(secpath_cachep, sp);
  }
  EXPORT_SYMBOL(__secpath_destroy);
  
  struct sec_path *secpath_dup(struct sec_path *src)
  {
  	struct sec_path *sp;
54e6ecb23   Christoph Lameter   [PATCH] slab: rem...
109
  	sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
  	if (!sp)
  		return NULL;
  
  	sp->len = 0;
54ef207ac   Steffen Klassert   xfrm: Extend the ...
114
  	sp->olen = 0;
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
115
  	memset(sp->ovec, 0, sizeof(sp->ovec[XFRM_MAX_OFFLOAD_DEPTH]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
  	if (src) {
  		int i;
  
  		memcpy(sp, src, sizeof(*sp));
  		for (i = 0; i < sp->len; i++)
dbe5b4aaa   Herbert Xu   [IPSEC]: Kill unu...
121
  			xfrm_state_hold(sp->xvec[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  	}
55eabed60   Reshetova, Elena   net, xfrm: conver...
123
  	refcount_set(&sp->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
  	return sp;
  }
  EXPORT_SYMBOL(secpath_dup);
b0fcee825   Steffen Klassert   xfrm: Add a secpa...
127
128
129
130
131
  int secpath_set(struct sk_buff *skb)
  {
  	struct sec_path *sp;
  
  	/* Allocate new secpath or COW existing one. */
55eabed60   Reshetova, Elena   net, xfrm: conver...
132
  	if (!skb->sp || refcount_read(&skb->sp->refcnt) != 1) {
b0fcee825   Steffen Klassert   xfrm: Add a secpa...
133
134
135
136
137
138
139
140
141
142
143
  		sp = secpath_dup(skb->sp);
  		if (!sp)
  			return -ENOMEM;
  
  		if (skb->sp)
  			secpath_put(skb->sp);
  		skb->sp = sp;
  	}
  	return 0;
  }
  EXPORT_SYMBOL(secpath_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  /* Fetch spi and seq from ipsec header */
6067b2bab   Al Viro   [XFRM]: xfrm_pars...
145
  int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  {
  	int offset, offset_seq;
440725000   Herbert Xu   [IPSEC]: Fix leng...
148
  	int hlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
  
  	switch (nexthdr) {
  	case IPPROTO_AH:
440725000   Herbert Xu   [IPSEC]: Fix leng...
152
  		hlen = sizeof(struct ip_auth_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
  		offset = offsetof(struct ip_auth_hdr, spi);
  		offset_seq = offsetof(struct ip_auth_hdr, seq_no);
  		break;
  	case IPPROTO_ESP:
440725000   Herbert Xu   [IPSEC]: Fix leng...
157
  		hlen = sizeof(struct ip_esp_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
162
163
  		offset = offsetof(struct ip_esp_hdr, spi);
  		offset_seq = offsetof(struct ip_esp_hdr, seq_no);
  		break;
  	case IPPROTO_COMP:
  		if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
  			return -EINVAL;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
164
  		*spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
  		*seq = 0;
  		return 0;
  	default:
  		return 1;
  	}
440725000   Herbert Xu   [IPSEC]: Fix leng...
170
  	if (!pskb_may_pull(skb, hlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		return -EINVAL;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
172
173
  	*spi = *(__be32 *)(skb_transport_header(skb) + offset);
  	*seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  	return 0;
  }
1e2953703   Steffen Klassert   xfrm: Export xfrm...
176
  EXPORT_SYMBOL(xfrm_parse_spi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

227620e29   Herbert Xu   [IPSEC]: Separate...
178
179
  int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
  {
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
180
  	struct xfrm_mode *inner_mode = x->inner_mode;
227620e29   Herbert Xu   [IPSEC]: Separate...
181
182
183
184
185
  	int err;
  
  	err = x->outer_mode->afinfo->extract_input(x, skb);
  	if (err)
  		return err;
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
186
187
188
189
190
191
192
193
  	if (x->sel.family == AF_UNSPEC) {
  		inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
  		if (inner_mode == NULL)
  			return -EAFNOSUPPORT;
  	}
  
  	skb->protocol = inner_mode->afinfo->eth_proto;
  	return inner_mode->input2(x, skb);
227620e29   Herbert Xu   [IPSEC]: Separate...
194
195
  }
  EXPORT_SYMBOL(xfrm_prepare_input);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
196
197
  int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
  {
bd235e3cf   Alexey Dobriyan   netns xfrm: xfrm_...
198
  	struct net *net = dev_net(skb->dev);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
199
200
  	int err;
  	__be32 seq;
2cd084678   Steffen Klassert   xfrm: Add support...
201
  	__be32 seq_hi;
3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
202
  	struct xfrm_state *x = NULL;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
203
  	xfrm_address_t *daddr;
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
204
  	struct xfrm_mode *inner_mode;
049f8e2e2   Alexander Duyck   xfrm: Override sk...
205
  	u32 mark = skb->mark;
4ce3dbe39   Aviv Heller   xfrm: Fix xfrm_in...
206
  	unsigned int family = AF_UNSPEC;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
207
  	int decaps = 0;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
208
  	int async = 0;
7785bba29   Steffen Klassert   esp: Add a softwa...
209
  	bool xfrm_gro = false;
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
210
211
  	bool crypto_done = false;
  	struct xfrm_offload *xo = xfrm_offload(skb);
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
212

1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
213
  	if (encap_type < 0) {
005011211   Herbert Xu   [IPSEC]: Add xfrm...
214
  		x = xfrm_input_state(skb);
4ce3dbe39   Aviv Heller   xfrm: Fix xfrm_in...
215
216
217
218
219
220
221
222
223
  
  		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
  			if (x->km.state == XFRM_STATE_ACQ)
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
  			else
  				XFRM_INC_STATS(net,
  					       LINUX_MIB_XFRMINSTATEINVALID);
  			goto drop;
  		}
3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
224
  		family = x->outer_mode->afinfo->family;
7785bba29   Steffen Klassert   esp: Add a softwa...
225
226
227
228
229
230
231
  
  		/* An encap_type of -1 indicates async resumption. */
  		if (encap_type == -1) {
  			async = 1;
  			seq = XFRM_SKB_CB(skb)->seq.input.low;
  			goto resume;
  		}
bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
232

7785bba29   Steffen Klassert   esp: Add a softwa...
233
234
235
  		/* encap_type < -1 indicates a GRO call. */
  		encap_type = 0;
  		seq = XFRM_SPI_SKB_CB(skb)->seq;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
236

bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  		if (xo && (xo->flags & CRYPTO_DONE)) {
  			crypto_done = true;
  			x = xfrm_input_state(skb);
  			family = XFRM_SPI_SKB_CB(skb)->family;
  
  			if (!(xo->status & CRYPTO_SUCCESS)) {
  				if (xo->status &
  				    (CRYPTO_TRANSPORT_AH_AUTH_FAILED |
  				     CRYPTO_TRANSPORT_ESP_AUTH_FAILED |
  				     CRYPTO_TUNNEL_AH_AUTH_FAILED |
  				     CRYPTO_TUNNEL_ESP_AUTH_FAILED)) {
  
  					xfrm_audit_state_icvfail(x, skb,
  								 x->type->proto);
  					x->stats.integrity_failed++;
  					XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
  					goto drop;
  				}
47ebcc0bb   Yossi Kuperman   xfrm: Add support...
255
256
257
258
  				if (xo->status & CRYPTO_INVALID_PROTOCOL) {
  					XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
  					goto drop;
  				}
bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
259
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
260
261
  				goto drop;
  			}
bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
262
263
264
265
  			if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
  				goto drop;
  			}
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
266
  		}
7785bba29   Steffen Klassert   esp: Add a softwa...
267
  		goto lock;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
268
  	}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
269

3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
270
  	family = XFRM_SPI_SKB_CB(skb)->family;
049f8e2e2   Alexander Duyck   xfrm: Override sk...
271
  	/* if tunnel is present override skb->mark value with tunnel i_key */
1625f4529   Alexey Kodanev   net/xfrm_input: f...
272
273
274
  	switch (family) {
  	case AF_INET:
  		if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4)
049f8e2e2   Alexander Duyck   xfrm: Override sk...
275
  			mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key);
1625f4529   Alexey Kodanev   net/xfrm_input: f...
276
277
278
  		break;
  	case AF_INET6:
  		if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6)
049f8e2e2   Alexander Duyck   xfrm: Override sk...
279
  			mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key);
1625f4529   Alexey Kodanev   net/xfrm_input: f...
280
  		break;
049f8e2e2   Alexander Duyck   xfrm: Override sk...
281
  	}
b0fcee825   Steffen Klassert   xfrm: Add a secpa...
282
283
284
285
  	err = secpath_set(skb);
  	if (err) {
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
  		goto drop;
b2aa5e9d4   Herbert Xu   [IPSEC]: Store xf...
286
  	}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
287
  	seq = 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
288
  	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
289
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
290
  		goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
291
  	}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
292

cb79a180f   Florian Westphal   xfrm: defer daddr...
293
294
  	daddr = (xfrm_address_t *)(skb_network_header(skb) +
  				   XFRM_SPI_SKB_CB(skb)->daddroff);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
295
  	do {
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
296
  		if (skb->sp->len == XFRM_MAX_DEPTH) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
297
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
298
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
299
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
300

049f8e2e2   Alexander Duyck   xfrm: Override sk...
301
  		x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
302
  		if (x == NULL) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
303
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
304
  			xfrm_audit_state_notfound(skb, family, spi, seq);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
305
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
306
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
307

b2aa5e9d4   Herbert Xu   [IPSEC]: Store xf...
308
  		skb->sp->xvec[skb->sp->len++] = x;
7785bba29   Steffen Klassert   esp: Add a softwa...
309
  lock:
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
310
  		spin_lock(&x->lock);
4c4d41f20   Fan Du   xfrm: add LINUX_M...
311

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
312
  		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
dc0565ce6   Li RongQing   xfrm: slightly op...
313
314
315
316
317
  			if (x->km.state == XFRM_STATE_ACQ)
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
  			else
  				XFRM_INC_STATS(net,
  					       LINUX_MIB_XFRMINSTATEINVALID);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
318
  			goto drop_unlock;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
319
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
320

3de77cf23   David S. Miller   Revert "xfrm: Acc...
321
322
323
324
  		if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
  			goto drop_unlock;
  		}
36ae0148d   Steffen Klassert   xfrm: Move the te...
325
  		if (x->repl->check(x, skb, seq)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
326
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
327
  			goto drop_unlock;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
328
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
329

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
330
  		if (xfrm_state_check_expire(x)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
331
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
332
  			goto drop_unlock;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
333
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
334

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
335
  		spin_unlock(&x->lock);
68c11e98e   Alexey Dobriyan   xfrm: fix xfrm_in...
336
337
338
339
  		if (xfrm_tunnel_check(skb, x, family)) {
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
  			goto drop;
  		}
2cd084678   Steffen Klassert   xfrm: Add support...
340
  		seq_hi = htonl(xfrm_replay_seqhi(x, seq));
1ce3644ad   Steffen Klassert   xfrm: Use separat...
341
  		XFRM_SKB_CB(skb)->seq.input.low = seq;
2cd084678   Steffen Klassert   xfrm: Add support...
342
  		XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
343

3bc07321c   Steffen Klassert   xfrm: Force a dst...
344
  		skb_dst_force(skb);
071d36bf2   subashab@codeaurora.org   xfrm: Fix crash o...
345
  		dev_hold(skb->dev);
3bc07321c   Steffen Klassert   xfrm: Force a dst...
346

d77e38e61   Steffen Klassert   xfrm: Add an IPse...
347
348
349
350
  		if (crypto_done)
  			nexthdr = x->type_offload->input_tail(x, skb);
  		else
  			nexthdr = x->type->input(x, skb);
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
351

1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
352
353
  		if (nexthdr == -EINPROGRESS)
  			return 0;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
354
  resume:
071d36bf2   subashab@codeaurora.org   xfrm: Fix crash o...
355
  		dev_put(skb->dev);
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
356
  		spin_lock(&x->lock);
668dc8af3   Herbert Xu   [IPSEC]: Move int...
357
  		if (nexthdr <= 0) {
9dd3245a2   Herbert Xu   [IPSEC]: Move all...
358
359
360
  			if (nexthdr == -EBADMSG) {
  				xfrm_audit_state_icvfail(x, skb,
  							 x->type->proto);
668dc8af3   Herbert Xu   [IPSEC]: Move int...
361
  				x->stats.integrity_failed++;
9dd3245a2   Herbert Xu   [IPSEC]: Move all...
362
  			}
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
363
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
364
  			goto drop_unlock;
668dc8af3   Herbert Xu   [IPSEC]: Move int...
365
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
366

716062fd4   Herbert Xu   [IPSEC]: Merge mo...
367
368
  		/* only the first xfrm gets the encap type */
  		encap_type = 0;
3b59df46a   Steffen Klassert   xfrm: Workaround ...
369
  		if (async && x->repl->recheck(x, skb, seq)) {
bcf66bf54   Steffen Klassert   xfrm: Perform a r...
370
371
372
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
  			goto drop_unlock;
  		}
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
373
  		x->repl->advance(x, seq);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
374
375
376
377
378
  
  		x->curlft.bytes += skb->len;
  		x->curlft.packets++;
  
  		spin_unlock(&x->lock);
60d5fcfb1   Herbert Xu   [IPSEC]: Remove n...
379
  		XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
380
381
382
383
  		inner_mode = x->inner_mode;
  
  		if (x->sel.family == AF_UNSPEC) {
  			inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
cb866e329   Steffen Klassert   xfrm: Increment s...
384
385
  			if (inner_mode == NULL) {
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
386
  				goto drop;
cb866e329   Steffen Klassert   xfrm: Increment s...
387
  			}
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
388
389
390
  		}
  
  		if (inner_mode->input(x, skb)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
391
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
392
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
393
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
394
395
396
397
398
  
  		if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
  			decaps = 1;
  			break;
  		}
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
399
400
401
402
403
  		/*
  		 * We need the inner address.  However, we only get here for
  		 * transport mode so the outer address is identical.
  		 */
  		daddr = &x->id.daddr;
2fcb45b6b   Herbert Xu   [IPSEC]: Use the ...
404
  		family = x->outer_mode->afinfo->family;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
405

716062fd4   Herbert Xu   [IPSEC]: Merge mo...
406
  		err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
407
  		if (err < 0) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
408
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
409
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
410
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
411
  	} while (!err);
3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
412
413
414
  	err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
  	if (err)
  		goto drop;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
415
416
417
  	nf_reset(skb);
  
  	if (decaps) {
23e9fcfef   Alexey Kodanev   vti: fix NULL der...
418
419
  		if (skb->sp)
  			skb->sp->olen = 0;
adf30907d   Eric Dumazet   net: skb->dst acc...
420
  		skb_dst_drop(skb);
1995876a0   Steffen Klassert   xfrm: Add a dummy...
421
  		gro_cells_receive(&gro_cells, skb);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
422
423
  		return 0;
  	} else {
7785bba29   Steffen Klassert   esp: Add a softwa...
424
425
426
  		xo = xfrm_offload(skb);
  		if (xo)
  			xfrm_gro = xo->flags & XFRM_GRO;
cfcf99f98   Sabrina Dubroca   xfrm: fix GRO for...
427
  		err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
7785bba29   Steffen Klassert   esp: Add a softwa...
428
  		if (xfrm_gro) {
23e9fcfef   Alexey Kodanev   vti: fix NULL der...
429
430
  			if (skb->sp)
  				skb->sp->olen = 0;
7785bba29   Steffen Klassert   esp: Add a softwa...
431
432
433
434
435
436
  			skb_dst_drop(skb);
  			gro_cells_receive(&gro_cells, skb);
  			return err;
  		}
  
  		return err;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
437
438
439
440
  	}
  
  drop_unlock:
  	spin_unlock(&x->lock);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
441
  drop:
3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
442
  	xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
443
444
445
446
  	kfree_skb(skb);
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_input);
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
447
448
449
450
451
  int xfrm_input_resume(struct sk_buff *skb, int nexthdr)
  {
  	return xfrm_input(skb, nexthdr, 0, -1);
  }
  EXPORT_SYMBOL(xfrm_input_resume);
acf568ee8   Herbert Xu   xfrm: Reinject tr...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  static void xfrm_trans_reinject(unsigned long data)
  {
  	struct xfrm_trans_tasklet *trans = (void *)data;
  	struct sk_buff_head queue;
  	struct sk_buff *skb;
  
  	__skb_queue_head_init(&queue);
  	skb_queue_splice_init(&trans->queue, &queue);
  
  	while ((skb = __skb_dequeue(&queue)))
  		XFRM_TRANS_SKB_CB(skb)->finish(dev_net(skb->dev), NULL, skb);
  }
  
  int xfrm_trans_queue(struct sk_buff *skb,
  		     int (*finish)(struct net *, struct sock *,
  				   struct sk_buff *))
  {
  	struct xfrm_trans_tasklet *trans;
  
  	trans = this_cpu_ptr(&xfrm_trans_tasklet);
  
  	if (skb_queue_len(&trans->queue) >= netdev_max_backlog)
  		return -ENOBUFS;
  
  	XFRM_TRANS_SKB_CB(skb)->finish = finish;
  	skb_queue_tail(&trans->queue, skb);
  	tasklet_schedule(&trans->tasklet);
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_trans_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  void __init xfrm_input_init(void)
  {
1995876a0   Steffen Klassert   xfrm: Add a dummy...
484
  	int err;
acf568ee8   Herbert Xu   xfrm: Reinject tr...
485
  	int i;
1995876a0   Steffen Klassert   xfrm: Add a dummy...
486
487
488
489
490
  
  	init_dummy_netdev(&xfrm_napi_dev);
  	err = gro_cells_init(&gro_cells, &xfrm_napi_dev);
  	if (err)
  		gro_cells.cells = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
  	secpath_cachep = kmem_cache_create("secpath_cache",
  					   sizeof(struct sec_path),
e5d679f33   Alexey Dobriyan   [NET]: Use SLAB_P...
493
  					   0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
20c2df83d   Paul Mundt   mm: Remove slab d...
494
  					   NULL);
acf568ee8   Herbert Xu   xfrm: Reinject tr...
495
496
497
498
499
500
501
502
503
  
  	for_each_possible_cpu(i) {
  		struct xfrm_trans_tasklet *trans;
  
  		trans = &per_cpu(xfrm_trans_tasklet, i);
  		__skb_queue_head_init(&trans->queue);
  		tasklet_init(&trans->tasklet, xfrm_trans_reinject,
  			     (unsigned long)trans);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  }