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 { 26716062fdSHerbert Xu XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); 27716062fdSHerbert Xu return xfrm_input(skb, nexthdr, spi, 0); 281da177e4SLinus Torvalds } 29716062fdSHerbert Xu EXPORT_SYMBOL(xfrm6_rcv_spi); 301da177e4SLinus Torvalds 31716062fdSHerbert Xu int xfrm6_transport_finish(struct sk_buff *skb, int async) 32716062fdSHerbert Xu { 3360d5fcfbSHerbert Xu skb_network_header(skb)[IP6CB(skb)->nhoff] = 3460d5fcfbSHerbert Xu XFRM_MODE_SKB_CB(skb)->protocol; 3560d5fcfbSHerbert Xu 36b05e1066SPatrick McHardy #ifdef CONFIG_NETFILTER 370660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->payload_len = htons(skb->len); 38d56f90a7SArnaldo Carvalho de Melo __skb_push(skb, skb->data - skb_network_header(skb)); 39b05e1066SPatrick McHardy 40b05e1066SPatrick McHardy NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, 41b05e1066SPatrick McHardy ip6_rcv_finish); 42b05e1066SPatrick McHardy return -1; 43b05e1066SPatrick McHardy #else 441bf06cd2SHerbert Xu if (async) 451bf06cd2SHerbert Xu return ip6_rcv_finish(skb); 461bf06cd2SHerbert Xu 471da177e4SLinus Torvalds return 1; 48b05e1066SPatrick McHardy #endif 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 51e5bbef20SHerbert Xu int xfrm6_rcv(struct sk_buff *skb) 521da177e4SLinus Torvalds { 5333b5ecb8SHerbert Xu return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 5433b5ecb8SHerbert Xu 0); 551da177e4SLinus Torvalds } 56fbd9a5b4SMasahide NAKAMURA 577159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_rcv); 587159039aSYOSHIFUJI Hideaki 59fbd9a5b4SMasahide NAKAMURA int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 60fbd9a5b4SMasahide NAKAMURA xfrm_address_t *saddr, u8 proto) 61fbd9a5b4SMasahide NAKAMURA { 62fbd9a5b4SMasahide NAKAMURA struct xfrm_state *x = NULL; 63fbd9a5b4SMasahide NAKAMURA int wildcard = 0; 64fbd9a5b4SMasahide NAKAMURA xfrm_address_t *xany; 65fbd9a5b4SMasahide NAKAMURA struct xfrm_state *xfrm_vec_one = NULL; 66fbd9a5b4SMasahide NAKAMURA int nh = 0; 67fbd9a5b4SMasahide NAKAMURA int i = 0; 68fbd9a5b4SMasahide NAKAMURA 69c53b3590SYOSHIFUJI Hideaki xany = (xfrm_address_t *)&in6addr_any; 70fbd9a5b4SMasahide NAKAMURA 71fbd9a5b4SMasahide NAKAMURA for (i = 0; i < 3; i++) { 72fbd9a5b4SMasahide NAKAMURA xfrm_address_t *dst, *src; 73fbd9a5b4SMasahide NAKAMURA switch (i) { 74fbd9a5b4SMasahide NAKAMURA case 0: 75fbd9a5b4SMasahide NAKAMURA dst = daddr; 76fbd9a5b4SMasahide NAKAMURA src = saddr; 77fbd9a5b4SMasahide NAKAMURA break; 78fbd9a5b4SMasahide NAKAMURA case 1: 79fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card source address */ 80fbd9a5b4SMasahide NAKAMURA wildcard = 1; 81fbd9a5b4SMasahide NAKAMURA dst = daddr; 82fbd9a5b4SMasahide NAKAMURA src = xany; 83fbd9a5b4SMasahide NAKAMURA break; 84fbd9a5b4SMasahide NAKAMURA case 2: 85fbd9a5b4SMasahide NAKAMURA default: 86fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card addresses */ 87fbd9a5b4SMasahide NAKAMURA wildcard = 1; /* XXX */ 88fbd9a5b4SMasahide NAKAMURA dst = xany; 89fbd9a5b4SMasahide NAKAMURA src = xany; 90fbd9a5b4SMasahide NAKAMURA break; 91fbd9a5b4SMasahide NAKAMURA } 92fbd9a5b4SMasahide NAKAMURA 93fbd9a5b4SMasahide NAKAMURA x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); 94fbd9a5b4SMasahide NAKAMURA if (!x) 95fbd9a5b4SMasahide NAKAMURA continue; 96fbd9a5b4SMasahide NAKAMURA 97fbd9a5b4SMasahide NAKAMURA spin_lock(&x->lock); 98fbd9a5b4SMasahide NAKAMURA 99fbd9a5b4SMasahide NAKAMURA if (wildcard) { 100fbd9a5b4SMasahide NAKAMURA if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { 101fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 102fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 103fbd9a5b4SMasahide NAKAMURA x = NULL; 104fbd9a5b4SMasahide NAKAMURA continue; 105fbd9a5b4SMasahide NAKAMURA } 106fbd9a5b4SMasahide NAKAMURA } 107fbd9a5b4SMasahide NAKAMURA 108fbd9a5b4SMasahide NAKAMURA if (unlikely(x->km.state != XFRM_STATE_VALID)) { 109fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 110fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 111fbd9a5b4SMasahide NAKAMURA x = NULL; 112fbd9a5b4SMasahide NAKAMURA continue; 113fbd9a5b4SMasahide NAKAMURA } 114fbd9a5b4SMasahide NAKAMURA if (xfrm_state_check_expire(x)) { 115fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 116fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 117fbd9a5b4SMasahide NAKAMURA x = NULL; 118fbd9a5b4SMasahide NAKAMURA continue; 119fbd9a5b4SMasahide NAKAMURA } 120fbd9a5b4SMasahide NAKAMURA 121fbd9a5b4SMasahide NAKAMURA nh = x->type->input(x, skb); 122fbd9a5b4SMasahide NAKAMURA if (nh <= 0) { 123fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 124fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 125fbd9a5b4SMasahide NAKAMURA x = NULL; 126fbd9a5b4SMasahide NAKAMURA continue; 127fbd9a5b4SMasahide NAKAMURA } 128fbd9a5b4SMasahide NAKAMURA 129fbd9a5b4SMasahide NAKAMURA x->curlft.bytes += skb->len; 130fbd9a5b4SMasahide NAKAMURA x->curlft.packets++; 131fbd9a5b4SMasahide NAKAMURA 132fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 133fbd9a5b4SMasahide NAKAMURA 134fbd9a5b4SMasahide NAKAMURA xfrm_vec_one = x; 135fbd9a5b4SMasahide NAKAMURA break; 136fbd9a5b4SMasahide NAKAMURA } 137fbd9a5b4SMasahide NAKAMURA 138fbd9a5b4SMasahide NAKAMURA if (!xfrm_vec_one) 139fbd9a5b4SMasahide NAKAMURA goto drop; 140fbd9a5b4SMasahide NAKAMURA 141fbd9a5b4SMasahide NAKAMURA /* Allocate new secpath or COW existing one. */ 142fbd9a5b4SMasahide NAKAMURA if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 143fbd9a5b4SMasahide NAKAMURA struct sec_path *sp; 144fbd9a5b4SMasahide NAKAMURA sp = secpath_dup(skb->sp); 145fbd9a5b4SMasahide NAKAMURA if (!sp) 146fbd9a5b4SMasahide NAKAMURA goto drop; 147fbd9a5b4SMasahide NAKAMURA if (skb->sp) 148fbd9a5b4SMasahide NAKAMURA secpath_put(skb->sp); 149fbd9a5b4SMasahide NAKAMURA skb->sp = sp; 150fbd9a5b4SMasahide NAKAMURA } 151fbd9a5b4SMasahide NAKAMURA 152fbd9a5b4SMasahide NAKAMURA if (1 + skb->sp->len > XFRM_MAX_DEPTH) 153fbd9a5b4SMasahide NAKAMURA goto drop; 154fbd9a5b4SMasahide NAKAMURA 155fbd9a5b4SMasahide NAKAMURA skb->sp->xvec[skb->sp->len] = xfrm_vec_one; 156fbd9a5b4SMasahide NAKAMURA skb->sp->len ++; 157fbd9a5b4SMasahide NAKAMURA 158fbd9a5b4SMasahide NAKAMURA return 1; 159fbd9a5b4SMasahide NAKAMURA drop: 160fbd9a5b4SMasahide NAKAMURA if (xfrm_vec_one) 161fbd9a5b4SMasahide NAKAMURA xfrm_state_put(xfrm_vec_one); 162fbd9a5b4SMasahide NAKAMURA return -1; 163fbd9a5b4SMasahide NAKAMURA } 1647159039aSYOSHIFUJI Hideaki 1657159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr); 166