blob: 4c803f7e74e530f46185230118ccc0fd645acf15 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * xfrm_input.c
3 *
4 * Changes:
5 * YOSHIFUJI Hideaki @USAGI
6 * Split up af-specific portion
YOSHIFUJI Hideakia716c112007-02-09 23:25:29 +09007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
10#include <linux/slab.h>
11#include <linux/module.h>
12#include <net/ip.h>
13#include <net/xfrm.h>
14
Christoph Lametere18b8902006-12-06 20:33:20 -080015static struct kmem_cache *secpath_cachep __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17void __secpath_destroy(struct sec_path *sp)
18{
19 int i;
20 for (i = 0; i < sp->len; i++)
Herbert Xudbe5b4a2006-04-01 00:54:16 -080021 xfrm_state_put(sp->xvec[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 kmem_cache_free(secpath_cachep, sp);
23}
24EXPORT_SYMBOL(__secpath_destroy);
25
26struct sec_path *secpath_dup(struct sec_path *src)
27{
28 struct sec_path *sp;
29
Christoph Lameter54e6ecb2006-12-06 20:33:16 -080030 sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 if (!sp)
32 return NULL;
33
34 sp->len = 0;
35 if (src) {
36 int i;
37
38 memcpy(sp, src, sizeof(*sp));
39 for (i = 0; i < sp->len; i++)
Herbert Xudbe5b4a2006-04-01 00:54:16 -080040 xfrm_state_hold(sp->xvec[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 }
42 atomic_set(&sp->refcnt, 1);
43 return sp;
44}
45EXPORT_SYMBOL(secpath_dup);
46
47/* Fetch spi and seq from ipsec header */
48
Al Viro6067b2b2006-09-27 18:47:59 -070049int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
51 int offset, offset_seq;
Herbert Xu44072502007-10-17 21:30:34 -070052 int hlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54 switch (nexthdr) {
55 case IPPROTO_AH:
Herbert Xu44072502007-10-17 21:30:34 -070056 hlen = sizeof(struct ip_auth_hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 offset = offsetof(struct ip_auth_hdr, spi);
58 offset_seq = offsetof(struct ip_auth_hdr, seq_no);
59 break;
60 case IPPROTO_ESP:
Herbert Xu44072502007-10-17 21:30:34 -070061 hlen = sizeof(struct ip_esp_hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 offset = offsetof(struct ip_esp_hdr, spi);
63 offset_seq = offsetof(struct ip_esp_hdr, seq_no);
64 break;
65 case IPPROTO_COMP:
66 if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
67 return -EINVAL;
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -070068 *spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 *seq = 0;
70 return 0;
71 default:
72 return 1;
73 }
74
Herbert Xu44072502007-10-17 21:30:34 -070075 if (!pskb_may_pull(skb, hlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 return -EINVAL;
77
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -070078 *spi = *(__be32*)(skb_transport_header(skb) + offset);
79 *seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 return 0;
81}
82EXPORT_SYMBOL(xfrm_parse_spi);
83
Herbert Xu227620e2007-11-13 21:41:28 -080084int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
85{
86 int err;
87
88 err = x->outer_mode->afinfo->extract_input(x, skb);
89 if (err)
90 return err;
91
92 skb->protocol = x->inner_mode->afinfo->eth_proto;
93 return x->inner_mode->input2(x, skb);
94}
95EXPORT_SYMBOL(xfrm_prepare_input);
96
Linus Torvalds1da177e2005-04-16 15:20:36 -070097void __init xfrm_input_init(void)
98{
99 secpath_cachep = kmem_cache_create("secpath_cache",
100 sizeof(struct sec_path),
Alexey Dobriyane5d679f332006-08-26 19:25:52 -0700101 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +0900102 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}