[IPSEC]: Fix length check in xfrm_parse_spi
[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 <linux/module.h>
12 #include <net/ip.h>
13 #include <net/xfrm.h>
14
15 static struct kmem_cache *secpath_cachep __read_mostly;
16
17 void __secpath_destroy(struct sec_path *sp)
18 {
19         int i;
20         for (i = 0; i < sp->len; i++)
21                 xfrm_state_put(sp->xvec[i]);
22         kmem_cache_free(secpath_cachep, sp);
23 }
24 EXPORT_SYMBOL(__secpath_destroy);
25
26 struct sec_path *secpath_dup(struct sec_path *src)
27 {
28         struct sec_path *sp;
29
30         sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC);
31         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++)
40                         xfrm_state_hold(sp->xvec[i]);
41         }
42         atomic_set(&sp->refcnt, 1);
43         return sp;
44 }
45 EXPORT_SYMBOL(secpath_dup);
46
47 /* Fetch spi and seq from ipsec header */
48
49 int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
50 {
51         int offset, offset_seq;
52         int hlen;
53
54         switch (nexthdr) {
55         case IPPROTO_AH:
56                 hlen = sizeof(struct ip_auth_hdr);
57                 offset = offsetof(struct ip_auth_hdr, spi);
58                 offset_seq = offsetof(struct ip_auth_hdr, seq_no);
59                 break;
60         case IPPROTO_ESP:
61                 hlen = sizeof(struct ip_esp_hdr);
62                 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;
68                 *spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2)));
69                 *seq = 0;
70                 return 0;
71         default:
72                 return 1;
73         }
74
75         if (!pskb_may_pull(skb, hlen))
76                 return -EINVAL;
77
78         *spi = *(__be32*)(skb_transport_header(skb) + offset);
79         *seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
80         return 0;
81 }
82 EXPORT_SYMBOL(xfrm_parse_spi);
83
84 void __init xfrm_input_init(void)
85 {
86         secpath_cachep = kmem_cache_create("secpath_cache",
87                                            sizeof(struct sec_path),
88                                            0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
89                                            NULL);
90 }