2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* xfrm_input.c
|
|
|
|
*
|
|
|
|
* Changes:
|
|
|
|
* YOSHIFUJI Hideaki @USAGI
|
|
|
|
* Split up af-specific portion
|
2007-02-09 22:25:29 +08:00
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <net/ip.h>
|
|
|
|
#include <net/xfrm.h>
|
|
|
|
|
2006-12-07 12:33:20 +08:00
|
|
|
static struct kmem_cache *secpath_cachep __read_mostly;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
void __secpath_destroy(struct sec_path *sp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < sp->len; i++)
|
2006-04-01 16:54:16 +08:00
|
|
|
xfrm_state_put(sp->xvec[i]);
|
2005-04-17 06:20:36 +08:00
|
|
|
kmem_cache_free(secpath_cachep, sp);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__secpath_destroy);
|
|
|
|
|
|
|
|
struct sec_path *secpath_dup(struct sec_path *src)
|
|
|
|
{
|
|
|
|
struct sec_path *sp;
|
|
|
|
|
2006-12-07 12:33:16 +08:00
|
|
|
sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!sp)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
sp->len = 0;
|
|
|
|
if (src) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
memcpy(sp, src, sizeof(*sp));
|
|
|
|
for (i = 0; i < sp->len; i++)
|
2006-04-01 16:54:16 +08:00
|
|
|
xfrm_state_hold(sp->xvec[i]);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
atomic_set(&sp->refcnt, 1);
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(secpath_dup);
|
|
|
|
|
|
|
|
/* Fetch spi and seq from ipsec header */
|
|
|
|
|
2006-09-28 09:47:59 +08:00
|
|
|
int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int offset, offset_seq;
|
2007-10-18 12:30:34 +08:00
|
|
|
int hlen;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
switch (nexthdr) {
|
|
|
|
case IPPROTO_AH:
|
2007-10-18 12:30:34 +08:00
|
|
|
hlen = sizeof(struct ip_auth_hdr);
|
2005-04-17 06:20:36 +08:00
|
|
|
offset = offsetof(struct ip_auth_hdr, spi);
|
|
|
|
offset_seq = offsetof(struct ip_auth_hdr, seq_no);
|
|
|
|
break;
|
|
|
|
case IPPROTO_ESP:
|
2007-10-18 12:30:34 +08:00
|
|
|
hlen = sizeof(struct ip_esp_hdr);
|
2005-04-17 06:20:36 +08:00
|
|
|
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;
|
2007-04-26 09:04:18 +08:00
|
|
|
*spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2)));
|
2005-04-17 06:20:36 +08:00
|
|
|
*seq = 0;
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-10-18 12:30:34 +08:00
|
|
|
if (!pskb_may_pull(skb, hlen))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2007-04-26 09:04:18 +08:00
|
|
|
*spi = *(__be32*)(skb_transport_header(skb) + offset);
|
|
|
|
*seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(xfrm_parse_spi);
|
|
|
|
|
|
|
|
void __init xfrm_input_init(void)
|
|
|
|
{
|
|
|
|
secpath_cachep = kmem_cache_create("secpath_cache",
|
|
|
|
sizeof(struct sec_path),
|
2006-08-27 10:25:52 +08:00
|
|
|
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
|
2007-07-20 09:11:58 +08:00
|
|
|
NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|