/* * xfrm_input.c * * Changes: * YOSHIFUJI Hideaki @USAGI * Split up af-specific portion * */ #include <linux/slab.h> #include <linux/module.h> #include <net/ip.h> #include <net/xfrm.h> static struct kmem_cache *secpath_cachep __read_mostly; void __secpath_destroy(struct sec_path *sp) { int i; for (i = 0; i < sp->len; i++) xfrm_state_put(sp->xvec[i]); kmem_cache_free(secpath_cachep, sp); } EXPORT_SYMBOL(__secpath_destroy); struct sec_path *secpath_dup(struct sec_path *src) { struct sec_path *sp; sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC); if (!sp) return NULL; sp->len = 0; if (src) { int i; memcpy(sp, src, sizeof(*sp)); for (i = 0; i < sp->len; i++) xfrm_state_hold(sp->xvec[i]); } atomic_set(&sp->refcnt, 1); return sp; } EXPORT_SYMBOL(secpath_dup); /* Fetch spi and seq from ipsec header */ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) { int offset, offset_seq; switch (nexthdr) { case IPPROTO_AH: offset = offsetof(struct ip_auth_hdr, spi); offset_seq = offsetof(struct ip_auth_hdr, seq_no); break; case IPPROTO_ESP: 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; *spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2))); *seq = 0; return 0; default: return 1; } if (!pskb_may_pull(skb, 16)) return -EINVAL; *spi = *(__be32*)(skb_transport_header(skb) + offset); *seq = *(__be32*)(skb_transport_header(skb) + offset_seq); return 0; } EXPORT_SYMBOL(xfrm_parse_spi); void __init xfrm_input_init(void) { secpath_cachep = kmem_cache_create("secpath_cache", sizeof(struct sec_path), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); }