ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / xfrm / xfrm_input.c
1 /*
2  * xfrm_input.c
3  *
4  * Changes:
5  *      YOSHIFUJI Hideaki @USAGI
6  *              Split up af-specific portion
7  *      
8  */
9
10 #include <linux/slab.h>
11 #include <net/ip.h>
12 #include <net/xfrm.h>
13
14 static kmem_cache_t *secpath_cachep;
15
16 void __secpath_destroy(struct sec_path *sp)
17 {
18         int i;
19         for (i = 0; i < sp->len; i++)
20                 xfrm_state_put(sp->x[i].xvec);
21         kmem_cache_free(secpath_cachep, sp);
22 }
23
24 struct sec_path *secpath_dup(struct sec_path *src)
25 {
26         struct sec_path *sp;
27
28         sp = kmem_cache_alloc(secpath_cachep, SLAB_ATOMIC);
29         if (!sp)
30                 return NULL;
31
32         sp->len = 0;
33         if (src) {
34                 int i;
35
36                 memcpy(sp, src, sizeof(*sp));
37                 for (i = 0; i < sp->len; i++)
38                         xfrm_state_hold(sp->x[i].xvec);
39         }
40         atomic_set(&sp->refcnt, 1);
41         return sp;
42 }
43
44 /* Fetch spi and seq from ipsec header */
45
46 int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
47 {
48         int offset, offset_seq;
49
50         switch (nexthdr) {
51         case IPPROTO_AH:
52                 offset = offsetof(struct ip_auth_hdr, spi);
53                 offset_seq = offsetof(struct ip_auth_hdr, seq_no);
54                 break;
55         case IPPROTO_ESP:
56                 offset = offsetof(struct ip_esp_hdr, spi);
57                 offset_seq = offsetof(struct ip_esp_hdr, seq_no);
58                 break;
59         case IPPROTO_COMP:
60                 if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
61                         return -EINVAL;
62                 *spi = ntohl(ntohs(*(u16*)(skb->h.raw + 2)));
63                 *seq = 0;
64                 return 0;
65         default:
66                 return 1;
67         }
68
69         if (!pskb_may_pull(skb, 16))
70                 return -EINVAL;
71
72         *spi = *(u32*)(skb->h.raw + offset);
73         *seq = *(u32*)(skb->h.raw + offset_seq);
74         return 0;
75 }
76
77 void __init xfrm_input_init(void)
78 {
79         secpath_cachep = kmem_cache_create("secpath_cache",
80                                            sizeof(struct sec_path),
81                                            0, SLAB_HWCACHE_ALIGN,
82                                            NULL, NULL);
83         if (!secpath_cachep)
84                 panic("XFRM: failed to allocate secpath_cache\n");
85 }