| /* |
| * 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 kmem_cache_t *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->h.raw + 2))); |
| *seq = 0; |
| return 0; |
| default: |
| return 1; |
| } |
| |
| if (!pskb_may_pull(skb, 16)) |
| return -EINVAL; |
| |
| *spi = *(__be32*)(skb->h.raw + offset); |
| *seq = *(__be32*)(skb->h.raw + 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); |
| } |