1 /* 2 * xfrm6_input.c: based on net/ipv4/xfrm4_input.c 3 * 4 * Authors: 5 * Mitsuru KANDA @USAGI 6 * Kazunori MIYAZAWA @USAGI 7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 8 * YOSHIFUJI Hideaki @USAGI 9 * IPv6 support 10 */ 11 12 #include <linux/module.h> 13 #include <linux/string.h> 14 #include <linux/netfilter.h> 15 #include <linux/netfilter_ipv6.h> 16 #include <net/ipv6.h> 17 #include <net/xfrm.h> 18 19 int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb) 20 { 21 return xfrm6_extract_header(skb); 22 } 23 24 int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) 25 { 26 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 27 XFRM_SPI_SKB_CB(skb)->family = AF_INET6; 28 XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); 29 return xfrm_input(skb, nexthdr, spi, 0); 30 } 31 EXPORT_SYMBOL(xfrm6_rcv_spi); 32 33 int xfrm6_transport_finish(struct sk_buff *skb, int async) 34 { 35 skb_network_header(skb)[IP6CB(skb)->nhoff] = 36 XFRM_MODE_SKB_CB(skb)->protocol; 37 38 #ifndef CONFIG_NETFILTER 39 if (!async) 40 return 1; 41 #endif 42 43 ipv6_hdr(skb)->payload_len = htons(skb->len); 44 __skb_push(skb, skb->data - skb_network_header(skb)); 45 46 NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, 47 dev_net(skb->dev), NULL, skb, skb->dev, NULL, 48 ip6_rcv_finish); 49 return -1; 50 } 51 52 int xfrm6_rcv(struct sk_buff *skb) 53 { 54 return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 55 0); 56 } 57 EXPORT_SYMBOL(xfrm6_rcv); 58 59 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 60 xfrm_address_t *saddr, u8 proto) 61 { 62 struct net *net = dev_net(skb->dev); 63 struct xfrm_state *x = NULL; 64 int i = 0; 65 66 /* Allocate new secpath or COW existing one. */ 67 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 68 struct sec_path *sp; 69 70 sp = secpath_dup(skb->sp); 71 if (!sp) { 72 XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); 73 goto drop; 74 } 75 if (skb->sp) 76 secpath_put(skb->sp); 77 skb->sp = sp; 78 } 79 80 if (1 + skb->sp->len == XFRM_MAX_DEPTH) { 81 XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); 82 goto drop; 83 } 84 85 for (i = 0; i < 3; i++) { 86 xfrm_address_t *dst, *src; 87 88 switch (i) { 89 case 0: 90 dst = daddr; 91 src = saddr; 92 break; 93 case 1: 94 /* lookup state with wild-card source address */ 95 dst = daddr; 96 src = (xfrm_address_t *)&in6addr_any; 97 break; 98 default: 99 /* lookup state with wild-card addresses */ 100 dst = (xfrm_address_t *)&in6addr_any; 101 src = (xfrm_address_t *)&in6addr_any; 102 break; 103 } 104 105 x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); 106 if (!x) 107 continue; 108 109 spin_lock(&x->lock); 110 111 if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) && 112 likely(x->km.state == XFRM_STATE_VALID) && 113 !xfrm_state_check_expire(x)) { 114 spin_unlock(&x->lock); 115 if (x->type->input(x, skb) > 0) { 116 /* found a valid state */ 117 break; 118 } 119 } else 120 spin_unlock(&x->lock); 121 122 xfrm_state_put(x); 123 x = NULL; 124 } 125 126 if (!x) { 127 XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); 128 xfrm_audit_state_notfound_simple(skb, AF_INET6); 129 goto drop; 130 } 131 132 skb->sp->xvec[skb->sp->len++] = x; 133 134 spin_lock(&x->lock); 135 136 x->curlft.bytes += skb->len; 137 x->curlft.packets++; 138 139 spin_unlock(&x->lock); 140 141 return 1; 142 143 drop: 144 return -1; 145 } 146 EXPORT_SYMBOL(xfrm6_input_addr); 147