Blame view

net/xfrm/xfrm_input.c 18.8 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
  #include <linux/bottom_half.h>
f8c3d0dda   Alexey Dobriyan   xfrm: mark kmem_c...
11
  #include <linux/cache.h>
acf568ee8   Herbert Xu   xfrm: Reinject tr...
12
  #include <linux/interrupt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
  #include <linux/slab.h>
  #include <linux/module.h>
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
15
  #include <linux/netdevice.h>
acf568ee8   Herbert Xu   xfrm: Reinject tr...
16
  #include <linux/percpu.h>
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
17
  #include <net/dst.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include <net/ip.h>
  #include <net/xfrm.h>
049f8e2e2   Alexander Duyck   xfrm: Override sk...
20
21
  #include <net/ip_tunnels.h>
  #include <net/ip6_tunnel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

b3284df1c   Florian Westphal   xfrm: remove inpu...
23
  #include "xfrm_inout.h"
acf568ee8   Herbert Xu   xfrm: Reinject tr...
24
25
26
27
28
29
  struct xfrm_trans_tasklet {
  	struct tasklet_struct tasklet;
  	struct sk_buff_head queue;
  };
  
  struct xfrm_trans_cb {
9a3fb9fb8   Steffen Klassert   xfrm: Fix transpo...
30
31
32
33
34
35
  	union {
  		struct inet_skb_parm	h4;
  #if IS_ENABLED(CONFIG_IPV6)
  		struct inet6_skb_parm	h6;
  #endif
  	} header;
acf568ee8   Herbert Xu   xfrm: Reinject tr...
36
  	int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);
7b3801927   Sabrina Dubroca   xfrm: introduce x...
37
  	struct net *net;
acf568ee8   Herbert Xu   xfrm: Reinject tr...
38
39
40
  };
  
  #define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0]))
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
41
  static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
960fdfdeb   Florian Westphal   xfrm: input: cons...
42
  static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[AF_INET6 + 1];
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
43

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

2f32b51b6   Steffen Klassert   xfrm: Introduce x...
53
54
  	spin_lock_bh(&xfrm_input_afinfo_lock);
  	if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL))
f31e8d4f7   Li RongQing   xfrm: fix the ret...
55
  		err = -EEXIST;
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
56
57
58
59
60
61
  	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...
62
  int xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo)
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
63
64
  {
  	int err = 0;
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
65
66
67
68
69
70
71
72
73
74
75
76
  	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...
77
  static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family)
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
78
  {
960fdfdeb   Florian Westphal   xfrm: input: cons...
79
  	const struct xfrm_input_afinfo *afinfo;
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
80

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

2f32b51b6   Steffen Klassert   xfrm: Introduce x...
84
85
86
87
88
89
  	rcu_read_lock();
  	afinfo = rcu_dereference(xfrm_input_afinfo[family]);
  	if (unlikely(!afinfo))
  		rcu_read_unlock();
  	return afinfo;
  }
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
90
91
92
93
  static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
  		       int err)
  {
  	int ret;
960fdfdeb   Florian Westphal   xfrm: input: cons...
94
  	const struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family);
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
95
96
97
98
99
  
  	if (!afinfo)
  		return -EAFNOSUPPORT;
  
  	ret = afinfo->callback(skb, protocol, err);
960fdfdeb   Florian Westphal   xfrm: input: cons...
100
  	rcu_read_unlock();
2f32b51b6   Steffen Klassert   xfrm: Introduce x...
101
102
103
  
  	return ret;
  }
4165079ba   Florian Westphal   net: switch secpa...
104
  struct sec_path *secpath_set(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
4165079ba   Florian Westphal   net: switch secpa...
106
  	struct sec_path *sp, *tmp = skb_ext_find(skb, SKB_EXT_SEC_PATH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107

4165079ba   Florian Westphal   net: switch secpa...
108
  	sp = skb_ext_add(skb, SKB_EXT_SEC_PATH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
  	if (!sp)
  		return NULL;
4165079ba   Florian Westphal   net: switch secpa...
111
112
  	if (tmp) /* reused existing one (was COW'd if needed) */
  		return sp;
54ef207ac   Steffen Klassert   xfrm: Extend the ...
113

4165079ba   Florian Westphal   net: switch secpa...
114
  	/* allocated new secpath */
f1193e915   Li RongQing   xfrm: use correct...
115
  	memset(sp->ovec, 0, sizeof(sp->ovec));
4165079ba   Florian Westphal   net: switch secpa...
116
117
  	sp->olen = 0;
  	sp->len = 0;
0ca64da12   Florian Westphal   xfrm: change secp...
118
119
  
  	return sp;
b0fcee825   Steffen Klassert   xfrm: Add a secpa...
120
121
  }
  EXPORT_SYMBOL(secpath_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  /* Fetch spi and seq from ipsec header */
6067b2bab   Al Viro   [XFRM]: xfrm_pars...
123
  int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
  {
  	int offset, offset_seq;
440725000   Herbert Xu   [IPSEC]: Fix leng...
126
  	int hlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
  
  	switch (nexthdr) {
  	case IPPROTO_AH:
440725000   Herbert Xu   [IPSEC]: Fix leng...
130
  		hlen = sizeof(struct ip_auth_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
  		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...
135
  		hlen = sizeof(struct ip_esp_hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
141
  		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 ...
142
  		*spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
  		*seq = 0;
  		return 0;
  	default:
  		return 1;
  	}
440725000   Herbert Xu   [IPSEC]: Fix leng...
148
  	if (!pskb_may_pull(skb, hlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  		return -EINVAL;
3e94c2dcf   Weilong Chen   xfrm: checkpatch ...
150
151
  	*spi = *(__be32 *)(skb_transport_header(skb) + offset);
  	*seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
  	return 0;
  }
1e2953703   Steffen Klassert   xfrm: Export xfrm...
154
  EXPORT_SYMBOL(xfrm_parse_spi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155

b3284df1c   Florian Westphal   xfrm: remove inpu...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  static int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
  {
  	struct iphdr *iph;
  	int optlen = 0;
  	int err = -EINVAL;
  
  	if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
  		struct ip_beet_phdr *ph;
  		int phlen;
  
  		if (!pskb_may_pull(skb, sizeof(*ph)))
  			goto out;
  
  		ph = (struct ip_beet_phdr *)skb->data;
  
  		phlen = sizeof(*ph) + ph->padlen;
  		optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
  		if (optlen < 0 || optlen & 3 || optlen > 250)
  			goto out;
  
  		XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
  
  		if (!pskb_may_pull(skb, phlen))
  			goto out;
  		__skb_pull(skb, phlen);
  	}
  
  	skb_push(skb, sizeof(*iph));
  	skb_reset_network_header(skb);
  	skb_mac_header_rebuild(skb);
  
  	xfrm4_beet_make_header(skb);
  
  	iph = ip_hdr(skb);
  
  	iph->ihl += optlen / 4;
  	iph->tot_len = htons(skb->len);
  	iph->daddr = x->sel.daddr.a4;
  	iph->saddr = x->sel.saddr.a4;
  	iph->check = 0;
  	iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
  	err = 0;
  out:
  	return err;
  }
  
  static void ipip_ecn_decapsulate(struct sk_buff *skb)
  {
  	struct iphdr *inner_iph = ipip_hdr(skb);
  
  	if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
  		IP_ECN_set_ce(inner_iph);
  }
  
  static int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
  {
  	int err = -EINVAL;
  
  	if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
  		goto out;
  
  	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  		goto out;
  
  	err = skb_unclone(skb, GFP_ATOMIC);
  	if (err)
  		goto out;
  
  	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
  		ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb));
  	if (!(x->props.flags & XFRM_STATE_NOECN))
  		ipip_ecn_decapsulate(skb);
  
  	skb_reset_network_header(skb);
  	skb_mac_header_rebuild(skb);
  	if (skb->mac_len)
  		eth_hdr(skb)->h_proto = skb->protocol;
  
  	err = 0;
  
  out:
  	return err;
  }
  
  static void ipip6_ecn_decapsulate(struct sk_buff *skb)
  {
  	struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
  
  	if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
  		IP6_ECN_set_ce(skb, inner_iph);
  }
  
  static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
  {
  	int err = -EINVAL;
  
  	if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
  		goto out;
  	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
  		goto out;
  
  	err = skb_unclone(skb, GFP_ATOMIC);
  	if (err)
  		goto out;
  
  	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
  		ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)),
  			       ipipv6_hdr(skb));
  	if (!(x->props.flags & XFRM_STATE_NOECN))
  		ipip6_ecn_decapsulate(skb);
  
  	skb_reset_network_header(skb);
  	skb_mac_header_rebuild(skb);
  	if (skb->mac_len)
  		eth_hdr(skb)->h_proto = skb->protocol;
  
  	err = 0;
  
  out:
  	return err;
  }
  
  static int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
  {
  	struct ipv6hdr *ip6h;
  	int size = sizeof(struct ipv6hdr);
  	int err;
  
  	err = skb_cow_head(skb, size + skb->mac_len);
  	if (err)
  		goto out;
  
  	__skb_push(skb, size);
  	skb_reset_network_header(skb);
  	skb_mac_header_rebuild(skb);
  
  	xfrm6_beet_make_header(skb);
  
  	ip6h = ipv6_hdr(skb);
  	ip6h->payload_len = htons(skb->len - size);
  	ip6h->daddr = x->sel.daddr.in6;
  	ip6h->saddr = x->sel.saddr.in6;
  	err = 0;
  out:
  	return err;
  }
  
  /* Remove encapsulation header.
   *
   * The IP header will be moved over the top of the encapsulation
   * header.
   *
   * On entry, the transport header shall point to where the IP header
   * should be and the network header shall be set to where the IP
   * header currently is.  skb->data shall point to the start of the
   * payload.
   */
  static int
  xfrm_inner_mode_encap_remove(struct xfrm_state *x,
  			     const struct xfrm_mode *inner_mode,
  			     struct sk_buff *skb)
  {
  	switch (inner_mode->encap) {
  	case XFRM_MODE_BEET:
  		if (inner_mode->family == AF_INET)
  			return xfrm4_remove_beet_encap(x, skb);
  		if (inner_mode->family == AF_INET6)
  			return xfrm6_remove_beet_encap(x, skb);
  		break;
  	case XFRM_MODE_TUNNEL:
  		if (inner_mode->family == AF_INET)
  			return xfrm4_remove_tunnel_encap(x, skb);
  		if (inner_mode->family == AF_INET6)
  			return xfrm6_remove_tunnel_encap(x, skb);
  		break;
  	}
  
  	WARN_ON_ONCE(1);
  	return -EOPNOTSUPP;
  }
c2d305e51   Florian Westphal   xfrm: remove inpu...
336
  static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
227620e29   Herbert Xu   [IPSEC]: Separate...
337
  {
c9500d7b7   Florian Westphal   xfrm: store xfrm_...
338
  	const struct xfrm_mode *inner_mode = &x->inner_mode;
733a5fac2   Florian Westphal   xfrm: remove afin...
339
340
  	const struct xfrm_state_afinfo *afinfo;
  	int err = -EAFNOSUPPORT;
227620e29   Herbert Xu   [IPSEC]: Separate...
341

733a5fac2   Florian Westphal   xfrm: remove afin...
342
  	rcu_read_lock();
c9500d7b7   Florian Westphal   xfrm: store xfrm_...
343
  	afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode.family);
733a5fac2   Florian Westphal   xfrm: remove afin...
344
345
  	if (likely(afinfo))
  		err = afinfo->extract_input(x, skb);
4c203b045   Florian Westphal   xfrm: remove eth_...
346
  	rcu_read_unlock();
733a5fac2   Florian Westphal   xfrm: remove afin...
347

4c203b045   Florian Westphal   xfrm: remove eth_...
348
  	if (err)
227620e29   Herbert Xu   [IPSEC]: Separate...
349
  		return err;
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
350
351
  	if (x->sel.family == AF_UNSPEC) {
  		inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
4c203b045   Florian Westphal   xfrm: remove eth_...
352
  		if (!inner_mode)
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
353
354
  			return -EAFNOSUPPORT;
  	}
4c203b045   Florian Westphal   xfrm: remove eth_...
355
356
357
358
359
360
  	switch (inner_mode->family) {
  	case AF_INET:
  		skb->protocol = htons(ETH_P_IP);
  		break;
  	case AF_INET6:
  		skb->protocol = htons(ETH_P_IPV6);
1be451d99   Florian Westphal   xfrm: fix bogus W...
361
  		break;
4c203b045   Florian Westphal   xfrm: remove eth_...
362
363
364
  	default:
  		WARN_ON_ONCE(1);
  		break;
733a5fac2   Florian Westphal   xfrm: remove afin...
365
  	}
b3284df1c   Florian Westphal   xfrm: remove inpu...
366
  	return xfrm_inner_mode_encap_remove(x, inner_mode, skb);
227620e29   Herbert Xu   [IPSEC]: Separate...
367
  }
c2d305e51   Florian Westphal   xfrm: remove inpu...
368
369
370
371
372
373
374
375
376
377
378
  
  /* Remove encapsulation header.
   *
   * The IP header will be moved over the top of the encapsulation header.
   *
   * On entry, skb_transport_header() shall point to where the IP header
   * should be and skb_network_header() shall be set to where the IP header
   * currently is.  skb->data shall point to the start of the payload.
   */
  static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
  {
c2d305e51   Florian Westphal   xfrm: remove inpu...
379
380
381
382
383
384
385
386
387
388
  	int ihl = skb->data - skb_transport_header(skb);
  
  	if (skb->transport_header != skb->network_header) {
  		memmove(skb_transport_header(skb),
  			skb_network_header(skb), ihl);
  		skb->network_header = skb->transport_header;
  	}
  	ip_hdr(skb)->tot_len = htons(skb->len + ihl);
  	skb_reset_transport_header(skb);
  	return 0;
c2d305e51   Florian Westphal   xfrm: remove inpu...
389
390
391
392
  }
  
  static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
  {
4c145dce2   Florian Westphal   xfrm: make xfrm m...
393
  #if IS_ENABLED(CONFIG_IPV6)
c2d305e51   Florian Westphal   xfrm: remove inpu...
394
395
396
397
398
399
400
401
402
403
404
405
  	int ihl = skb->data - skb_transport_header(skb);
  
  	if (skb->transport_header != skb->network_header) {
  		memmove(skb_transport_header(skb),
  			skb_network_header(skb), ihl);
  		skb->network_header = skb->transport_header;
  	}
  	ipv6_hdr(skb)->payload_len = htons(skb->len + ihl -
  					   sizeof(struct ipv6hdr));
  	skb_reset_transport_header(skb);
  	return 0;
  #else
4c145dce2   Florian Westphal   xfrm: make xfrm m...
406
407
  	WARN_ON_ONCE(1);
  	return -EAFNOSUPPORT;
c2d305e51   Florian Westphal   xfrm: remove inpu...
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  #endif
  }
  
  static int xfrm_inner_mode_input(struct xfrm_state *x,
  				 const struct xfrm_mode *inner_mode,
  				 struct sk_buff *skb)
  {
  	switch (inner_mode->encap) {
  	case XFRM_MODE_BEET:
  	case XFRM_MODE_TUNNEL:
  		return xfrm_prepare_input(x, skb);
  	case XFRM_MODE_TRANSPORT:
  		if (inner_mode->family == AF_INET)
  			return xfrm4_transport_input(x, skb);
  		if (inner_mode->family == AF_INET6)
  			return xfrm6_transport_input(x, skb);
  		break;
  	case XFRM_MODE_ROUTEOPTIMIZATION:
  		WARN_ON_ONCE(1);
  		break;
  	default:
  		WARN_ON_ONCE(1);
  		break;
  	}
  
  	return -EOPNOTSUPP;
  }
227620e29   Herbert Xu   [IPSEC]: Separate...
435

716062fd4   Herbert Xu   [IPSEC]: Merge mo...
436
437
  int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
  {
733a5fac2   Florian Westphal   xfrm: remove afin...
438
  	const struct xfrm_state_afinfo *afinfo;
bd235e3cf   Alexey Dobriyan   netns xfrm: xfrm_...
439
  	struct net *net = dev_net(skb->dev);
4c145dce2   Florian Westphal   xfrm: make xfrm m...
440
  	const struct xfrm_mode *inner_mode;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
441
442
  	int err;
  	__be32 seq;
2cd084678   Steffen Klassert   xfrm: Add support...
443
  	__be32 seq_hi;
3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
444
  	struct xfrm_state *x = NULL;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
445
  	xfrm_address_t *daddr;
049f8e2e2   Alexander Duyck   xfrm: Override sk...
446
  	u32 mark = skb->mark;
4ce3dbe39   Aviv Heller   xfrm: Fix xfrm_in...
447
  	unsigned int family = AF_UNSPEC;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
448
  	int decaps = 0;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
449
  	int async = 0;
7785bba29   Steffen Klassert   esp: Add a softwa...
450
  	bool xfrm_gro = false;
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
451
452
  	bool crypto_done = false;
  	struct xfrm_offload *xo = xfrm_offload(skb);
0ca64da12   Florian Westphal   xfrm: change secp...
453
  	struct sec_path *sp;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
454

1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
455
  	if (encap_type < 0) {
005011211   Herbert Xu   [IPSEC]: Add xfrm...
456
  		x = xfrm_input_state(skb);
4ce3dbe39   Aviv Heller   xfrm: Fix xfrm_in...
457
458
459
460
461
462
463
  
  		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);
4944a4b10   Xiaodong Xu   xfrm: release dev...
464
465
466
  
  			if (encap_type == -1)
  				dev_put(skb->dev);
4ce3dbe39   Aviv Heller   xfrm: Fix xfrm_in...
467
468
  			goto drop;
  		}
c9500d7b7   Florian Westphal   xfrm: store xfrm_...
469
  		family = x->outer_mode.family;
7785bba29   Steffen Klassert   esp: Add a softwa...
470
471
472
473
474
475
476
  
  		/* 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...
477

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

bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
482
483
  		if (xo && (xo->flags & CRYPTO_DONE)) {
  			crypto_done = true;
bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  			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...
499
500
501
502
  				if (xo->status & CRYPTO_INVALID_PROTOCOL) {
  					XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
  					goto drop;
  				}
bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
503
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
504
505
  				goto drop;
  			}
bcd1f8a45   Steffen Klassert   xfrm: Prepare the...
506
507
508
509
  			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...
510
  		}
7785bba29   Steffen Klassert   esp: Add a softwa...
511
  		goto lock;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
512
  	}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
513

3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
514
  	family = XFRM_SPI_SKB_CB(skb)->family;
049f8e2e2   Alexander Duyck   xfrm: Override sk...
515
  	/* if tunnel is present override skb->mark value with tunnel i_key */
1625f4529   Alexey Kodanev   net/xfrm_input: f...
516
517
518
  	switch (family) {
  	case AF_INET:
  		if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4)
049f8e2e2   Alexander Duyck   xfrm: Override sk...
519
  			mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key);
1625f4529   Alexey Kodanev   net/xfrm_input: f...
520
521
522
  		break;
  	case AF_INET6:
  		if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6)
049f8e2e2   Alexander Duyck   xfrm: Override sk...
523
  			mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key);
1625f4529   Alexey Kodanev   net/xfrm_input: f...
524
  		break;
049f8e2e2   Alexander Duyck   xfrm: Override sk...
525
  	}
0ca64da12   Florian Westphal   xfrm: change secp...
526
527
  	sp = secpath_set(skb);
  	if (!sp) {
b0fcee825   Steffen Klassert   xfrm: Add a secpa...
528
529
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
  		goto drop;
b2aa5e9d4   Herbert Xu   [IPSEC]: Store xf...
530
  	}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
531
  	seq = 0;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
532
  	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
f203b76d7   Steffen Klassert   xfrm: Add virtual...
533
  		secpath_reset(skb);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
534
  		XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
535
  		goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
536
  	}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
537

cb79a180f   Florian Westphal   xfrm: defer daddr...
538
539
  	daddr = (xfrm_address_t *)(skb_network_header(skb) +
  				   XFRM_SPI_SKB_CB(skb)->daddroff);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
540
  	do {
2294be0f1   Florian Westphal   net: use skb_sec_...
541
542
543
  		sp = skb_sec_path(skb);
  
  		if (sp->len == XFRM_MAX_DEPTH) {
f203b76d7   Steffen Klassert   xfrm: Add virtual...
544
  			secpath_reset(skb);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
545
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
546
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
547
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
548

049f8e2e2   Alexander Duyck   xfrm: Override sk...
549
  		x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
550
  		if (x == NULL) {
f203b76d7   Steffen Klassert   xfrm: Add virtual...
551
  			secpath_reset(skb);
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
552
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
afeb14b49   Paul Moore   [XFRM]: RFC4303 c...
553
  			xfrm_audit_state_notfound(skb, family, spi, seq);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
554
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
555
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
556

9b42c1f17   Steffen Klassert   xfrm: Extend the ...
557
  		skb->mark = xfrm_smark_get(skb->mark, x);
2294be0f1   Florian Westphal   net: use skb_sec_...
558
  		sp->xvec[sp->len++] = x;
b2aa5e9d4   Herbert Xu   [IPSEC]: Store xf...
559

0152eee6f   Steffen Klassert   xfrm: Fix NULL po...
560
561
562
563
564
  		skb_dst_force(skb);
  		if (!skb_dst(skb)) {
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
  			goto drop;
  		}
7785bba29   Steffen Klassert   esp: Add a softwa...
565
  lock:
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
566
  		spin_lock(&x->lock);
4c4d41f20   Fan Du   xfrm: add LINUX_M...
567

0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
568
  		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
dc0565ce6   Li RongQing   xfrm: slightly op...
569
570
571
572
573
  			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...
574
  			goto drop_unlock;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
575
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
576

3de77cf23   David S. Miller   Revert "xfrm: Acc...
577
578
579
580
  		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...
581
  		if (x->repl->check(x, skb, seq)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
582
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
583
  			goto drop_unlock;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
584
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
585

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

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
591
  		spin_unlock(&x->lock);
68c11e98e   Alexey Dobriyan   xfrm: fix xfrm_in...
592
593
594
595
  		if (xfrm_tunnel_check(skb, x, family)) {
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
  			goto drop;
  		}
2cd084678   Steffen Klassert   xfrm: Add support...
596
  		seq_hi = htonl(xfrm_replay_seqhi(x, seq));
1ce3644ad   Steffen Klassert   xfrm: Use separat...
597
  		XFRM_SKB_CB(skb)->seq.input.low = seq;
2cd084678   Steffen Klassert   xfrm: Add support...
598
  		XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
599

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

d77e38e61   Steffen Klassert   xfrm: Add an IPse...
602
603
604
605
  		if (crypto_done)
  			nexthdr = x->type_offload->input_tail(x, skb);
  		else
  			nexthdr = x->type->input(x, skb);
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
606

1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
607
608
  		if (nexthdr == -EINPROGRESS)
  			return 0;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
609
  resume:
071d36bf2   subashab@codeaurora.org   xfrm: Fix crash o...
610
  		dev_put(skb->dev);
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
611
  		spin_lock(&x->lock);
668dc8af3   Herbert Xu   [IPSEC]: Move int...
612
  		if (nexthdr <= 0) {
9dd3245a2   Herbert Xu   [IPSEC]: Move all...
613
614
615
  			if (nexthdr == -EBADMSG) {
  				xfrm_audit_state_icvfail(x, skb,
  							 x->type->proto);
668dc8af3   Herbert Xu   [IPSEC]: Move int...
616
  				x->stats.integrity_failed++;
9dd3245a2   Herbert Xu   [IPSEC]: Move all...
617
  			}
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
618
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
619
  			goto drop_unlock;
668dc8af3   Herbert Xu   [IPSEC]: Move int...
620
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
621

716062fd4   Herbert Xu   [IPSEC]: Merge mo...
622
623
  		/* only the first xfrm gets the encap type */
  		encap_type = 0;
3b59df46a   Steffen Klassert   xfrm: Workaround ...
624
  		if (async && x->repl->recheck(x, skb, seq)) {
bcf66bf54   Steffen Klassert   xfrm: Perform a r...
625
626
627
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
  			goto drop_unlock;
  		}
9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
628
  		x->repl->advance(x, seq);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
629
630
631
632
633
  
  		x->curlft.bytes += skb->len;
  		x->curlft.packets++;
  
  		spin_unlock(&x->lock);
60d5fcfb1   Herbert Xu   [IPSEC]: Remove n...
634
  		XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
c9500d7b7   Florian Westphal   xfrm: store xfrm_...
635
  		inner_mode = &x->inner_mode;
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
636
637
638
  
  		if (x->sel.family == AF_UNSPEC) {
  			inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
cb866e329   Steffen Klassert   xfrm: Increment s...
639
640
  			if (inner_mode == NULL) {
  				XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
641
  				goto drop;
cb866e329   Steffen Klassert   xfrm: Increment s...
642
  			}
df9dcb458   Kazunori MIYAZAWA   [IPSEC]: Fix inte...
643
  		}
c2d305e51   Florian Westphal   xfrm: remove inpu...
644
  		if (xfrm_inner_mode_input(x, inner_mode, skb)) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
645
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
646
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
647
  		}
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
648

c9500d7b7   Florian Westphal   xfrm: store xfrm_...
649
  		if (x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL) {
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
650
651
652
  			decaps = 1;
  			break;
  		}
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
653
654
655
656
657
  		/*
  		 * We need the inner address.  However, we only get here for
  		 * transport mode so the outer address is identical.
  		 */
  		daddr = &x->id.daddr;
c9500d7b7   Florian Westphal   xfrm: store xfrm_...
658
  		family = x->outer_mode.family;
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
659

716062fd4   Herbert Xu   [IPSEC]: Merge mo...
660
  		err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
661
  		if (err < 0) {
59c9940ed   Alexey Dobriyan   netns xfrm: per-n...
662
  			XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
663
  			goto drop;
0aa647746   Masahide NAKAMURA   [XFRM]: Support t...
664
  		}
782710e33   Sowmini Varadhan   xfrm: reset crypt...
665
  		crypto_done = false;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
666
  	} while (!err);
3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
667
668
669
  	err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
  	if (err)
  		goto drop;
895b5c9f2   Florian Westphal   netfilter: drop b...
670
  	nf_reset_ct(skb);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
671
672
  
  	if (decaps) {
2294be0f1   Florian Westphal   net: use skb_sec_...
673
674
675
  		sp = skb_sec_path(skb);
  		if (sp)
  			sp->olen = 0;
adf30907d   Eric Dumazet   net: skb->dst acc...
676
  		skb_dst_drop(skb);
1995876a0   Steffen Klassert   xfrm: Add a dummy...
677
  		gro_cells_receive(&gro_cells, skb);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
678
679
  		return 0;
  	} else {
7785bba29   Steffen Klassert   esp: Add a softwa...
680
681
682
  		xo = xfrm_offload(skb);
  		if (xo)
  			xfrm_gro = xo->flags & XFRM_GRO;
733a5fac2   Florian Westphal   xfrm: remove afin...
683
684
  		err = -EAFNOSUPPORT;
  		rcu_read_lock();
c9500d7b7   Florian Westphal   xfrm: store xfrm_...
685
  		afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode.family);
733a5fac2   Florian Westphal   xfrm: remove afin...
686
687
688
  		if (likely(afinfo))
  			err = afinfo->transport_finish(skb, xfrm_gro || async);
  		rcu_read_unlock();
7785bba29   Steffen Klassert   esp: Add a softwa...
689
  		if (xfrm_gro) {
2294be0f1   Florian Westphal   net: use skb_sec_...
690
691
692
  			sp = skb_sec_path(skb);
  			if (sp)
  				sp->olen = 0;
7785bba29   Steffen Klassert   esp: Add a softwa...
693
694
695
696
697
698
  			skb_dst_drop(skb);
  			gro_cells_receive(&gro_cells, skb);
  			return err;
  		}
  
  		return err;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
699
700
701
702
  	}
  
  drop_unlock:
  	spin_unlock(&x->lock);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
703
  drop:
3328715e6   Steffen Klassert   xfrm4: Add IPsec ...
704
  	xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
705
706
707
708
  	kfree_skb(skb);
  	return 0;
  }
  EXPORT_SYMBOL(xfrm_input);
1bf06cd2e   Herbert Xu   [IPSEC]: Add asyn...
709
710
711
712
713
  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...
714
715
716
717
718
719
720
721
722
723
  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)))
7b3801927   Sabrina Dubroca   xfrm: introduce x...
724
725
  		XFRM_TRANS_SKB_CB(skb)->finish(XFRM_TRANS_SKB_CB(skb)->net,
  					       NULL, skb);
acf568ee8   Herbert Xu   xfrm: Reinject tr...
726
  }
7b3801927   Sabrina Dubroca   xfrm: introduce x...
727
728
729
  int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb,
  			 int (*finish)(struct net *, struct sock *,
  				       struct sk_buff *))
acf568ee8   Herbert Xu   xfrm: Reinject tr...
730
731
732
733
734
735
736
  {
  	struct xfrm_trans_tasklet *trans;
  
  	trans = this_cpu_ptr(&xfrm_trans_tasklet);
  
  	if (skb_queue_len(&trans->queue) >= netdev_max_backlog)
  		return -ENOBUFS;
7b3801927   Sabrina Dubroca   xfrm: introduce x...
737
  	BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb));
acf568ee8   Herbert Xu   xfrm: Reinject tr...
738
  	XFRM_TRANS_SKB_CB(skb)->finish = finish;
7b3801927   Sabrina Dubroca   xfrm: introduce x...
739
  	XFRM_TRANS_SKB_CB(skb)->net = net;
d16b46e4f   Herbert Xu   xfrm: Use __skb_q...
740
  	__skb_queue_tail(&trans->queue, skb);
acf568ee8   Herbert Xu   xfrm: Reinject tr...
741
742
743
  	tasklet_schedule(&trans->tasklet);
  	return 0;
  }
7b3801927   Sabrina Dubroca   xfrm: introduce x...
744
745
746
747
748
749
750
751
  EXPORT_SYMBOL(xfrm_trans_queue_net);
  
  int xfrm_trans_queue(struct sk_buff *skb,
  		     int (*finish)(struct net *, struct sock *,
  				   struct sk_buff *))
  {
  	return xfrm_trans_queue_net(dev_net(skb->dev), skb, finish);
  }
acf568ee8   Herbert Xu   xfrm: Reinject tr...
752
  EXPORT_SYMBOL(xfrm_trans_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
  void __init xfrm_input_init(void)
  {
1995876a0   Steffen Klassert   xfrm: Add a dummy...
755
  	int err;
acf568ee8   Herbert Xu   xfrm: Reinject tr...
756
  	int i;
1995876a0   Steffen Klassert   xfrm: Add a dummy...
757
758
759
760
761
  
  	init_dummy_netdev(&xfrm_napi_dev);
  	err = gro_cells_init(&gro_cells, &xfrm_napi_dev);
  	if (err)
  		gro_cells.cells = NULL;
acf568ee8   Herbert Xu   xfrm: Reinject tr...
762
763
764
765
766
767
768
769
  	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
770
  }