11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * xfrm6_input.c: based on net/ipv4/xfrm4_input.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors: 51da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 61da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 71da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 81da177e4SLinus Torvalds * YOSHIFUJI Hideaki @USAGI 91da177e4SLinus Torvalds * IPv6 support 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/string.h> 14b05e1066SPatrick McHardy #include <linux/netfilter.h> 15b05e1066SPatrick McHardy #include <linux/netfilter_ipv6.h> 161da177e4SLinus Torvalds #include <net/ipv6.h> 171da177e4SLinus Torvalds #include <net/xfrm.h> 181da177e4SLinus Torvalds 19227620e2SHerbert Xu int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb) 20227620e2SHerbert Xu { 21227620e2SHerbert Xu return xfrm6_extract_header(skb); 22227620e2SHerbert Xu } 23227620e2SHerbert Xu 2433b5ecb8SHerbert Xu int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) 251da177e4SLinus Torvalds { 262fcb45b6SHerbert Xu XFRM_SPI_SKB_CB(skb)->family = AF_INET6; 27716062fdSHerbert Xu XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); 28716062fdSHerbert Xu return xfrm_input(skb, nexthdr, spi, 0); 291da177e4SLinus Torvalds } 30716062fdSHerbert Xu EXPORT_SYMBOL(xfrm6_rcv_spi); 311da177e4SLinus Torvalds 32716062fdSHerbert Xu int xfrm6_transport_finish(struct sk_buff *skb, int async) 33716062fdSHerbert Xu { 3460d5fcfbSHerbert Xu skb_network_header(skb)[IP6CB(skb)->nhoff] = 3560d5fcfbSHerbert Xu XFRM_MODE_SKB_CB(skb)->protocol; 3660d5fcfbSHerbert Xu 37b05e1066SPatrick McHardy #ifdef CONFIG_NETFILTER 380660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->payload_len = htons(skb->len); 39d56f90a7SArnaldo Carvalho de Melo __skb_push(skb, skb->data - skb_network_header(skb)); 40b05e1066SPatrick McHardy 416e23ae2aSPatrick McHardy NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, 42b05e1066SPatrick McHardy ip6_rcv_finish); 43b05e1066SPatrick McHardy return -1; 44b05e1066SPatrick McHardy #else 451bf06cd2SHerbert Xu if (async) 461bf06cd2SHerbert Xu return ip6_rcv_finish(skb); 471bf06cd2SHerbert Xu 481da177e4SLinus Torvalds return 1; 49b05e1066SPatrick McHardy #endif 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 52e5bbef20SHerbert Xu int xfrm6_rcv(struct sk_buff *skb) 531da177e4SLinus Torvalds { 5433b5ecb8SHerbert Xu return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 5533b5ecb8SHerbert Xu 0); 561da177e4SLinus Torvalds } 57fbd9a5b4SMasahide NAKAMURA 587159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_rcv); 597159039aSYOSHIFUJI Hideaki 60fbd9a5b4SMasahide NAKAMURA int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 61fbd9a5b4SMasahide NAKAMURA xfrm_address_t *saddr, u8 proto) 62fbd9a5b4SMasahide NAKAMURA { 63fbd9a5b4SMasahide NAKAMURA struct xfrm_state *x = NULL; 64fbd9a5b4SMasahide NAKAMURA int wildcard = 0; 65fbd9a5b4SMasahide NAKAMURA xfrm_address_t *xany; 66fbd9a5b4SMasahide NAKAMURA int nh = 0; 67fbd9a5b4SMasahide NAKAMURA int i = 0; 68fbd9a5b4SMasahide NAKAMURA 699473e1f6SMasahide NAKAMURA /* Allocate new secpath or COW existing one. */ 709473e1f6SMasahide NAKAMURA if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 719473e1f6SMasahide NAKAMURA struct sec_path *sp; 729473e1f6SMasahide NAKAMURA 739473e1f6SMasahide NAKAMURA sp = secpath_dup(skb->sp); 749473e1f6SMasahide NAKAMURA if (!sp) { 750aa64774SMasahide NAKAMURA XFRM_INC_STATS(LINUX_MIB_XFRMINERROR); 769473e1f6SMasahide NAKAMURA goto drop; 779473e1f6SMasahide NAKAMURA } 789473e1f6SMasahide NAKAMURA if (skb->sp) 799473e1f6SMasahide NAKAMURA secpath_put(skb->sp); 809473e1f6SMasahide NAKAMURA skb->sp = sp; 819473e1f6SMasahide NAKAMURA } 829473e1f6SMasahide NAKAMURA 839473e1f6SMasahide NAKAMURA if (1 + skb->sp->len == XFRM_MAX_DEPTH) { 840aa64774SMasahide NAKAMURA XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); 859473e1f6SMasahide NAKAMURA goto drop; 869473e1f6SMasahide NAKAMURA } 879473e1f6SMasahide NAKAMURA 88c53b3590SYOSHIFUJI Hideaki xany = (xfrm_address_t *)&in6addr_any; 89fbd9a5b4SMasahide NAKAMURA 90fbd9a5b4SMasahide NAKAMURA for (i = 0; i < 3; i++) { 91fbd9a5b4SMasahide NAKAMURA xfrm_address_t *dst, *src; 92fbd9a5b4SMasahide NAKAMURA switch (i) { 93fbd9a5b4SMasahide NAKAMURA case 0: 94fbd9a5b4SMasahide NAKAMURA dst = daddr; 95fbd9a5b4SMasahide NAKAMURA src = saddr; 96fbd9a5b4SMasahide NAKAMURA break; 97fbd9a5b4SMasahide NAKAMURA case 1: 98fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card source address */ 99fbd9a5b4SMasahide NAKAMURA wildcard = 1; 100fbd9a5b4SMasahide NAKAMURA dst = daddr; 101fbd9a5b4SMasahide NAKAMURA src = xany; 102fbd9a5b4SMasahide NAKAMURA break; 103fbd9a5b4SMasahide NAKAMURA case 2: 104fbd9a5b4SMasahide NAKAMURA default: 105fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card addresses */ 106fbd9a5b4SMasahide NAKAMURA wildcard = 1; /* XXX */ 107fbd9a5b4SMasahide NAKAMURA dst = xany; 108fbd9a5b4SMasahide NAKAMURA src = xany; 109fbd9a5b4SMasahide NAKAMURA break; 110fbd9a5b4SMasahide NAKAMURA } 111fbd9a5b4SMasahide NAKAMURA 112fbd9a5b4SMasahide NAKAMURA x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); 113fbd9a5b4SMasahide NAKAMURA if (!x) 114fbd9a5b4SMasahide NAKAMURA continue; 115fbd9a5b4SMasahide NAKAMURA 116fbd9a5b4SMasahide NAKAMURA spin_lock(&x->lock); 117fbd9a5b4SMasahide NAKAMURA 118fbd9a5b4SMasahide NAKAMURA if (wildcard) { 119fbd9a5b4SMasahide NAKAMURA if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { 120fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 121fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 122fbd9a5b4SMasahide NAKAMURA x = NULL; 123fbd9a5b4SMasahide NAKAMURA continue; 124fbd9a5b4SMasahide NAKAMURA } 125fbd9a5b4SMasahide NAKAMURA } 126fbd9a5b4SMasahide NAKAMURA 127fbd9a5b4SMasahide NAKAMURA if (unlikely(x->km.state != XFRM_STATE_VALID)) { 128fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 129fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 130fbd9a5b4SMasahide NAKAMURA x = NULL; 131fbd9a5b4SMasahide NAKAMURA continue; 132fbd9a5b4SMasahide NAKAMURA } 133fbd9a5b4SMasahide NAKAMURA if (xfrm_state_check_expire(x)) { 134fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 135fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 136fbd9a5b4SMasahide NAKAMURA x = NULL; 137fbd9a5b4SMasahide NAKAMURA continue; 138fbd9a5b4SMasahide NAKAMURA } 139fbd9a5b4SMasahide NAKAMURA 1409473e1f6SMasahide NAKAMURA spin_unlock(&x->lock); 1419473e1f6SMasahide NAKAMURA 142fbd9a5b4SMasahide NAKAMURA nh = x->type->input(x, skb); 143fbd9a5b4SMasahide NAKAMURA if (nh <= 0) { 144fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 145fbd9a5b4SMasahide NAKAMURA x = NULL; 146fbd9a5b4SMasahide NAKAMURA continue; 147fbd9a5b4SMasahide NAKAMURA } 148fbd9a5b4SMasahide NAKAMURA 1499473e1f6SMasahide NAKAMURA /* Found a state */ 1509473e1f6SMasahide NAKAMURA break; 1519473e1f6SMasahide NAKAMURA } 1529473e1f6SMasahide NAKAMURA 1539473e1f6SMasahide NAKAMURA if (!x) { 1540aa64774SMasahide NAKAMURA XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); 155afeb14b4SPaul Moore xfrm_audit_state_notfound_simple(skb, AF_INET6); 1569473e1f6SMasahide NAKAMURA goto drop; 1579473e1f6SMasahide NAKAMURA } 1589473e1f6SMasahide NAKAMURA 1599473e1f6SMasahide NAKAMURA skb->sp->xvec[skb->sp->len++] = x; 1609473e1f6SMasahide NAKAMURA 1619473e1f6SMasahide NAKAMURA spin_lock(&x->lock); 1629473e1f6SMasahide NAKAMURA 163fbd9a5b4SMasahide NAKAMURA x->curlft.bytes += skb->len; 164fbd9a5b4SMasahide NAKAMURA x->curlft.packets++; 165fbd9a5b4SMasahide NAKAMURA 166fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 167fbd9a5b4SMasahide NAKAMURA 168fbd9a5b4SMasahide NAKAMURA return 1; 1699473e1f6SMasahide NAKAMURA 170fbd9a5b4SMasahide NAKAMURA drop: 171fbd9a5b4SMasahide NAKAMURA return -1; 172fbd9a5b4SMasahide NAKAMURA } 1737159039aSYOSHIFUJI Hideaki 1747159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr); 175