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 { 367785bba2SSteffen Klassert struct xfrm_offload *xo = xfrm_offload(skb); 377785bba2SSteffen Klassert 3860d5fcfbSHerbert Xu skb_network_header(skb)[IP6CB(skb)->nhoff] = 3960d5fcfbSHerbert Xu XFRM_MODE_SKB_CB(skb)->protocol; 4060d5fcfbSHerbert Xu 410883ae0eSHerbert Xu #ifndef CONFIG_NETFILTER 420883ae0eSHerbert Xu if (!async) 430883ae0eSHerbert Xu return 1; 440883ae0eSHerbert Xu #endif 450883ae0eSHerbert Xu 460660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->payload_len = htons(skb->len); 47d56f90a7SArnaldo Carvalho de Melo __skb_push(skb, skb->data - skb_network_header(skb)); 48b05e1066SPatrick McHardy 497785bba2SSteffen Klassert if (xo && (xo->flags & XFRM_GRO)) { 507785bba2SSteffen Klassert skb_mac_header_rebuild(skb); 517785bba2SSteffen Klassert return -1; 527785bba2SSteffen Klassert } 537785bba2SSteffen Klassert 5429a26a56SEric W. Biederman NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 5529a26a56SEric W. Biederman dev_net(skb->dev), NULL, skb, skb->dev, NULL, 56b05e1066SPatrick McHardy ip6_rcv_finish); 57b05e1066SPatrick McHardy return -1; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 6063c43787SNicolas Dichtel int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t) 611da177e4SLinus Torvalds { 6233b5ecb8SHerbert Xu return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 6363c43787SNicolas Dichtel 0, t); 6463c43787SNicolas Dichtel } 6563c43787SNicolas Dichtel EXPORT_SYMBOL(xfrm6_rcv_tnl); 6663c43787SNicolas Dichtel 6763c43787SNicolas Dichtel int xfrm6_rcv(struct sk_buff *skb) 6863c43787SNicolas Dichtel { 6963c43787SNicolas Dichtel return xfrm6_rcv_tnl(skb, NULL); 701da177e4SLinus Torvalds } 717159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_rcv); 72fbd9a5b4SMasahide NAKAMURA int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 73fbd9a5b4SMasahide NAKAMURA xfrm_address_t *saddr, u8 proto) 74fbd9a5b4SMasahide NAKAMURA { 7559c9940eSAlexey Dobriyan struct net *net = dev_net(skb->dev); 76fbd9a5b4SMasahide NAKAMURA struct xfrm_state *x = NULL; 77fbd9a5b4SMasahide NAKAMURA int i = 0; 78fbd9a5b4SMasahide NAKAMURA 79b0fcee82SSteffen Klassert if (secpath_set(skb)) { 8059c9940eSAlexey Dobriyan XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); 819473e1f6SMasahide NAKAMURA goto drop; 829473e1f6SMasahide NAKAMURA } 839473e1f6SMasahide NAKAMURA 849473e1f6SMasahide NAKAMURA if (1 + skb->sp->len == XFRM_MAX_DEPTH) { 8559c9940eSAlexey Dobriyan XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); 869473e1f6SMasahide NAKAMURA goto drop; 879473e1f6SMasahide NAKAMURA } 889473e1f6SMasahide NAKAMURA 89fbd9a5b4SMasahide NAKAMURA for (i = 0; i < 3; i++) { 90fbd9a5b4SMasahide NAKAMURA xfrm_address_t *dst, *src; 91a002c6fdSYOSHIFUJI Hideaki 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 dst = daddr; 100a002c6fdSYOSHIFUJI Hideaki src = (xfrm_address_t *)&in6addr_any; 101fbd9a5b4SMasahide NAKAMURA break; 102fbd9a5b4SMasahide NAKAMURA default: 103fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card addresses */ 104a002c6fdSYOSHIFUJI Hideaki dst = (xfrm_address_t *)&in6addr_any; 105a002c6fdSYOSHIFUJI Hideaki src = (xfrm_address_t *)&in6addr_any; 106fbd9a5b4SMasahide NAKAMURA break; 107fbd9a5b4SMasahide NAKAMURA } 108fbd9a5b4SMasahide NAKAMURA 109bd55775cSJamal Hadi Salim x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); 110fbd9a5b4SMasahide NAKAMURA if (!x) 111fbd9a5b4SMasahide NAKAMURA continue; 112fbd9a5b4SMasahide NAKAMURA 113fbd9a5b4SMasahide NAKAMURA spin_lock(&x->lock); 114fbd9a5b4SMasahide NAKAMURA 115a002c6fdSYOSHIFUJI Hideaki if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) && 116a002c6fdSYOSHIFUJI Hideaki likely(x->km.state == XFRM_STATE_VALID) && 117a002c6fdSYOSHIFUJI Hideaki !xfrm_state_check_expire(x)) { 118fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 119a002c6fdSYOSHIFUJI Hideaki if (x->type->input(x, skb) > 0) { 120a002c6fdSYOSHIFUJI Hideaki /* found a valid state */ 1219473e1f6SMasahide NAKAMURA break; 1229473e1f6SMasahide NAKAMURA } 123a002c6fdSYOSHIFUJI Hideaki } else 124a002c6fdSYOSHIFUJI Hideaki spin_unlock(&x->lock); 125a002c6fdSYOSHIFUJI Hideaki 126a002c6fdSYOSHIFUJI Hideaki xfrm_state_put(x); 127a002c6fdSYOSHIFUJI Hideaki x = NULL; 128a002c6fdSYOSHIFUJI Hideaki } 1299473e1f6SMasahide NAKAMURA 1309473e1f6SMasahide NAKAMURA if (!x) { 13159c9940eSAlexey Dobriyan XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); 132afeb14b4SPaul Moore xfrm_audit_state_notfound_simple(skb, AF_INET6); 1339473e1f6SMasahide NAKAMURA goto drop; 1349473e1f6SMasahide NAKAMURA } 1359473e1f6SMasahide NAKAMURA 1369473e1f6SMasahide NAKAMURA skb->sp->xvec[skb->sp->len++] = x; 1379473e1f6SMasahide NAKAMURA 1389473e1f6SMasahide NAKAMURA spin_lock(&x->lock); 1399473e1f6SMasahide NAKAMURA 140fbd9a5b4SMasahide NAKAMURA x->curlft.bytes += skb->len; 141fbd9a5b4SMasahide NAKAMURA x->curlft.packets++; 142fbd9a5b4SMasahide NAKAMURA 143fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 144fbd9a5b4SMasahide NAKAMURA 145fbd9a5b4SMasahide NAKAMURA return 1; 1469473e1f6SMasahide NAKAMURA 147fbd9a5b4SMasahide NAKAMURA drop: 148fbd9a5b4SMasahide NAKAMURA return -1; 149fbd9a5b4SMasahide NAKAMURA } 1507159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr); 151