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 2463c43787SNicolas Dichtel int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi, 2563c43787SNicolas Dichtel struct ip6_tnl *t) 261da177e4SLinus Torvalds { 2763c43787SNicolas Dichtel XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; 282fcb45b6SHerbert Xu XFRM_SPI_SKB_CB(skb)->family = AF_INET6; 29716062fdSHerbert Xu XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); 30716062fdSHerbert Xu return xfrm_input(skb, nexthdr, spi, 0); 311da177e4SLinus Torvalds } 32716062fdSHerbert Xu EXPORT_SYMBOL(xfrm6_rcv_spi); 331da177e4SLinus Torvalds 34716062fdSHerbert Xu int xfrm6_transport_finish(struct sk_buff *skb, int async) 35716062fdSHerbert Xu { 3660d5fcfbSHerbert Xu skb_network_header(skb)[IP6CB(skb)->nhoff] = 3760d5fcfbSHerbert Xu XFRM_MODE_SKB_CB(skb)->protocol; 3860d5fcfbSHerbert Xu 390883ae0eSHerbert Xu #ifndef CONFIG_NETFILTER 400883ae0eSHerbert Xu if (!async) 410883ae0eSHerbert Xu return 1; 420883ae0eSHerbert Xu #endif 430883ae0eSHerbert Xu 440660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->payload_len = htons(skb->len); 45d56f90a7SArnaldo Carvalho de Melo __skb_push(skb, skb->data - skb_network_header(skb)); 46b05e1066SPatrick McHardy 4729a26a56SEric W. Biederman NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 4829a26a56SEric W. Biederman dev_net(skb->dev), NULL, skb, skb->dev, NULL, 49b05e1066SPatrick McHardy ip6_rcv_finish); 50b05e1066SPatrick McHardy return -1; 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds 5363c43787SNicolas Dichtel int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t) 541da177e4SLinus Torvalds { 5533b5ecb8SHerbert Xu return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 5663c43787SNicolas Dichtel 0, t); 5763c43787SNicolas Dichtel } 5863c43787SNicolas Dichtel EXPORT_SYMBOL(xfrm6_rcv_tnl); 5963c43787SNicolas Dichtel 6063c43787SNicolas Dichtel int xfrm6_rcv(struct sk_buff *skb) 6163c43787SNicolas Dichtel { 6263c43787SNicolas Dichtel return xfrm6_rcv_tnl(skb, NULL); 631da177e4SLinus Torvalds } 647159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_rcv); 65fbd9a5b4SMasahide NAKAMURA int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 66fbd9a5b4SMasahide NAKAMURA xfrm_address_t *saddr, u8 proto) 67fbd9a5b4SMasahide NAKAMURA { 6859c9940eSAlexey Dobriyan struct net *net = dev_net(skb->dev); 69fbd9a5b4SMasahide NAKAMURA struct xfrm_state *x = NULL; 70fbd9a5b4SMasahide NAKAMURA int i = 0; 71fbd9a5b4SMasahide NAKAMURA 72b0fcee82SSteffen Klassert if (secpath_set(skb)) { 7359c9940eSAlexey Dobriyan XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); 749473e1f6SMasahide NAKAMURA goto drop; 759473e1f6SMasahide NAKAMURA } 769473e1f6SMasahide NAKAMURA 779473e1f6SMasahide NAKAMURA if (1 + skb->sp->len == XFRM_MAX_DEPTH) { 7859c9940eSAlexey Dobriyan XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); 799473e1f6SMasahide NAKAMURA goto drop; 809473e1f6SMasahide NAKAMURA } 819473e1f6SMasahide NAKAMURA 82fbd9a5b4SMasahide NAKAMURA for (i = 0; i < 3; i++) { 83fbd9a5b4SMasahide NAKAMURA xfrm_address_t *dst, *src; 84a002c6fdSYOSHIFUJI Hideaki 85fbd9a5b4SMasahide NAKAMURA switch (i) { 86fbd9a5b4SMasahide NAKAMURA case 0: 87fbd9a5b4SMasahide NAKAMURA dst = daddr; 88fbd9a5b4SMasahide NAKAMURA src = saddr; 89fbd9a5b4SMasahide NAKAMURA break; 90fbd9a5b4SMasahide NAKAMURA case 1: 91fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card source address */ 92fbd9a5b4SMasahide NAKAMURA dst = daddr; 93a002c6fdSYOSHIFUJI Hideaki src = (xfrm_address_t *)&in6addr_any; 94fbd9a5b4SMasahide NAKAMURA break; 95fbd9a5b4SMasahide NAKAMURA default: 96fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card addresses */ 97a002c6fdSYOSHIFUJI Hideaki dst = (xfrm_address_t *)&in6addr_any; 98a002c6fdSYOSHIFUJI Hideaki src = (xfrm_address_t *)&in6addr_any; 99fbd9a5b4SMasahide NAKAMURA break; 100fbd9a5b4SMasahide NAKAMURA } 101fbd9a5b4SMasahide NAKAMURA 102bd55775cSJamal Hadi Salim x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); 103fbd9a5b4SMasahide NAKAMURA if (!x) 104fbd9a5b4SMasahide NAKAMURA continue; 105fbd9a5b4SMasahide NAKAMURA 106fbd9a5b4SMasahide NAKAMURA spin_lock(&x->lock); 107fbd9a5b4SMasahide NAKAMURA 108a002c6fdSYOSHIFUJI Hideaki if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) && 109a002c6fdSYOSHIFUJI Hideaki likely(x->km.state == XFRM_STATE_VALID) && 110a002c6fdSYOSHIFUJI Hideaki !xfrm_state_check_expire(x)) { 111fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 112a002c6fdSYOSHIFUJI Hideaki if (x->type->input(x, skb) > 0) { 113a002c6fdSYOSHIFUJI Hideaki /* found a valid state */ 1149473e1f6SMasahide NAKAMURA break; 1159473e1f6SMasahide NAKAMURA } 116a002c6fdSYOSHIFUJI Hideaki } else 117a002c6fdSYOSHIFUJI Hideaki spin_unlock(&x->lock); 118a002c6fdSYOSHIFUJI Hideaki 119a002c6fdSYOSHIFUJI Hideaki xfrm_state_put(x); 120a002c6fdSYOSHIFUJI Hideaki x = NULL; 121a002c6fdSYOSHIFUJI Hideaki } 1229473e1f6SMasahide NAKAMURA 1239473e1f6SMasahide NAKAMURA if (!x) { 12459c9940eSAlexey Dobriyan XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); 125afeb14b4SPaul Moore xfrm_audit_state_notfound_simple(skb, AF_INET6); 1269473e1f6SMasahide NAKAMURA goto drop; 1279473e1f6SMasahide NAKAMURA } 1289473e1f6SMasahide NAKAMURA 1299473e1f6SMasahide NAKAMURA skb->sp->xvec[skb->sp->len++] = x; 1309473e1f6SMasahide NAKAMURA 1319473e1f6SMasahide NAKAMURA spin_lock(&x->lock); 1329473e1f6SMasahide NAKAMURA 133fbd9a5b4SMasahide NAKAMURA x->curlft.bytes += skb->len; 134fbd9a5b4SMasahide NAKAMURA x->curlft.packets++; 135fbd9a5b4SMasahide NAKAMURA 136fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 137fbd9a5b4SMasahide NAKAMURA 138fbd9a5b4SMasahide NAKAMURA return 1; 1399473e1f6SMasahide NAKAMURA 140fbd9a5b4SMasahide NAKAMURA drop: 141fbd9a5b4SMasahide NAKAMURA return -1; 142fbd9a5b4SMasahide NAKAMURA } 1437159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr); 144