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) { 759473e1f6SMasahide NAKAMURA goto drop; 769473e1f6SMasahide NAKAMURA } 779473e1f6SMasahide NAKAMURA if (skb->sp) 789473e1f6SMasahide NAKAMURA secpath_put(skb->sp); 799473e1f6SMasahide NAKAMURA skb->sp = sp; 809473e1f6SMasahide NAKAMURA } 819473e1f6SMasahide NAKAMURA 829473e1f6SMasahide NAKAMURA if (1 + skb->sp->len == XFRM_MAX_DEPTH) { 839473e1f6SMasahide NAKAMURA goto drop; 849473e1f6SMasahide NAKAMURA } 859473e1f6SMasahide NAKAMURA 86c53b3590SYOSHIFUJI Hideaki xany = (xfrm_address_t *)&in6addr_any; 87fbd9a5b4SMasahide NAKAMURA 88fbd9a5b4SMasahide NAKAMURA for (i = 0; i < 3; i++) { 89fbd9a5b4SMasahide NAKAMURA xfrm_address_t *dst, *src; 90fbd9a5b4SMasahide NAKAMURA switch (i) { 91fbd9a5b4SMasahide NAKAMURA case 0: 92fbd9a5b4SMasahide NAKAMURA dst = daddr; 93fbd9a5b4SMasahide NAKAMURA src = saddr; 94fbd9a5b4SMasahide NAKAMURA break; 95fbd9a5b4SMasahide NAKAMURA case 1: 96fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card source address */ 97fbd9a5b4SMasahide NAKAMURA wildcard = 1; 98fbd9a5b4SMasahide NAKAMURA dst = daddr; 99fbd9a5b4SMasahide NAKAMURA src = xany; 100fbd9a5b4SMasahide NAKAMURA break; 101fbd9a5b4SMasahide NAKAMURA case 2: 102fbd9a5b4SMasahide NAKAMURA default: 103fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card addresses */ 104fbd9a5b4SMasahide NAKAMURA wildcard = 1; /* XXX */ 105fbd9a5b4SMasahide NAKAMURA dst = xany; 106fbd9a5b4SMasahide NAKAMURA src = xany; 107fbd9a5b4SMasahide NAKAMURA break; 108fbd9a5b4SMasahide NAKAMURA } 109fbd9a5b4SMasahide NAKAMURA 110fbd9a5b4SMasahide NAKAMURA x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); 111fbd9a5b4SMasahide NAKAMURA if (!x) 112fbd9a5b4SMasahide NAKAMURA continue; 113fbd9a5b4SMasahide NAKAMURA 114fbd9a5b4SMasahide NAKAMURA spin_lock(&x->lock); 115fbd9a5b4SMasahide NAKAMURA 116fbd9a5b4SMasahide NAKAMURA if (wildcard) { 117fbd9a5b4SMasahide NAKAMURA if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { 118fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 119fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 120fbd9a5b4SMasahide NAKAMURA x = NULL; 121fbd9a5b4SMasahide NAKAMURA continue; 122fbd9a5b4SMasahide NAKAMURA } 123fbd9a5b4SMasahide NAKAMURA } 124fbd9a5b4SMasahide NAKAMURA 125fbd9a5b4SMasahide NAKAMURA if (unlikely(x->km.state != XFRM_STATE_VALID)) { 126fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 127fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 128fbd9a5b4SMasahide NAKAMURA x = NULL; 129fbd9a5b4SMasahide NAKAMURA continue; 130fbd9a5b4SMasahide NAKAMURA } 131fbd9a5b4SMasahide NAKAMURA if (xfrm_state_check_expire(x)) { 132fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 133fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 134fbd9a5b4SMasahide NAKAMURA x = NULL; 135fbd9a5b4SMasahide NAKAMURA continue; 136fbd9a5b4SMasahide NAKAMURA } 137fbd9a5b4SMasahide NAKAMURA 1389473e1f6SMasahide NAKAMURA spin_unlock(&x->lock); 1399473e1f6SMasahide NAKAMURA 140fbd9a5b4SMasahide NAKAMURA nh = x->type->input(x, skb); 141fbd9a5b4SMasahide NAKAMURA if (nh <= 0) { 142fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 143fbd9a5b4SMasahide NAKAMURA x = NULL; 144fbd9a5b4SMasahide NAKAMURA continue; 145fbd9a5b4SMasahide NAKAMURA } 146fbd9a5b4SMasahide NAKAMURA 1479473e1f6SMasahide NAKAMURA /* Found a state */ 1489473e1f6SMasahide NAKAMURA break; 1499473e1f6SMasahide NAKAMURA } 1509473e1f6SMasahide NAKAMURA 1519473e1f6SMasahide NAKAMURA if (!x) { 1529473e1f6SMasahide NAKAMURA goto drop; 1539473e1f6SMasahide NAKAMURA } 1549473e1f6SMasahide NAKAMURA 1559473e1f6SMasahide NAKAMURA skb->sp->xvec[skb->sp->len++] = x; 1569473e1f6SMasahide NAKAMURA 1579473e1f6SMasahide NAKAMURA spin_lock(&x->lock); 1589473e1f6SMasahide NAKAMURA 159fbd9a5b4SMasahide NAKAMURA x->curlft.bytes += skb->len; 160fbd9a5b4SMasahide NAKAMURA x->curlft.packets++; 161fbd9a5b4SMasahide NAKAMURA 162fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 163fbd9a5b4SMasahide NAKAMURA 164fbd9a5b4SMasahide NAKAMURA return 1; 1659473e1f6SMasahide NAKAMURA 166fbd9a5b4SMasahide NAKAMURA drop: 167fbd9a5b4SMasahide NAKAMURA return -1; 168fbd9a5b4SMasahide NAKAMURA } 1697159039aSYOSHIFUJI Hideaki 1707159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr); 171