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/dsfield.h> 17 #include <net/inet_ecn.h> 18 #include <net/ip.h> 19 #include <net/ipv6.h> 20 #include <net/xfrm.h> 21 22 static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) 23 { 24 struct ipv6hdr *outer_iph = skb->nh.ipv6h; 25 struct ipv6hdr *inner_iph = skb->h.ipv6h; 26 27 if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) 28 IP6_ECN_set_ce(inner_iph); 29 } 30 31 int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) 32 { 33 int err; 34 u32 seq; 35 struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; 36 struct xfrm_state *x; 37 int xfrm_nr = 0; 38 int decaps = 0; 39 int nexthdr; 40 unsigned int nhoff; 41 42 nhoff = IP6CB(skb)->nhoff; 43 nexthdr = skb->nh.raw[nhoff]; 44 45 seq = 0; 46 if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) 47 goto drop; 48 49 do { 50 struct ipv6hdr *iph = skb->nh.ipv6h; 51 52 if (xfrm_nr == XFRM_MAX_DEPTH) 53 goto drop; 54 55 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6); 56 if (x == NULL) 57 goto drop; 58 spin_lock(&x->lock); 59 if (unlikely(x->km.state != XFRM_STATE_VALID)) 60 goto drop_unlock; 61 62 if (x->props.replay_window && xfrm_replay_check(x, seq)) 63 goto drop_unlock; 64 65 if (xfrm_state_check_expire(x)) 66 goto drop_unlock; 67 68 nexthdr = x->type->input(x, skb); 69 if (nexthdr <= 0) 70 goto drop_unlock; 71 72 skb->nh.raw[nhoff] = nexthdr; 73 74 if (x->props.replay_window) 75 xfrm_replay_advance(x, seq); 76 77 x->curlft.bytes += skb->len; 78 x->curlft.packets++; 79 80 spin_unlock(&x->lock); 81 82 xfrm_vec[xfrm_nr++] = x; 83 84 if (x->props.mode) { /* XXX */ 85 if (nexthdr != IPPROTO_IPV6) 86 goto drop; 87 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 88 goto drop; 89 if (skb_cloned(skb) && 90 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 91 goto drop; 92 if (x->props.flags & XFRM_STATE_DECAP_DSCP) 93 ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); 94 if (!(x->props.flags & XFRM_STATE_NOECN)) 95 ipip6_ecn_decapsulate(skb); 96 skb->mac.raw = memmove(skb->data - skb->mac_len, 97 skb->mac.raw, skb->mac_len); 98 skb->nh.raw = skb->data; 99 decaps = 1; 100 break; 101 } 102 103 if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) 104 goto drop; 105 } while (!err); 106 107 /* Allocate new secpath or COW existing one. */ 108 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 109 struct sec_path *sp; 110 sp = secpath_dup(skb->sp); 111 if (!sp) 112 goto drop; 113 if (skb->sp) 114 secpath_put(skb->sp); 115 skb->sp = sp; 116 } 117 118 if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) 119 goto drop; 120 121 memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, 122 xfrm_nr * sizeof(xfrm_vec[0])); 123 skb->sp->len += xfrm_nr; 124 skb->ip_summed = CHECKSUM_NONE; 125 126 nf_reset(skb); 127 128 if (decaps) { 129 if (!(skb->dev->flags&IFF_LOOPBACK)) { 130 dst_release(skb->dst); 131 skb->dst = NULL; 132 } 133 netif_rx(skb); 134 return -1; 135 } else { 136 #ifdef CONFIG_NETFILTER 137 skb->nh.ipv6h->payload_len = htons(skb->len); 138 __skb_push(skb, skb->data - skb->nh.raw); 139 140 NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, 141 ip6_rcv_finish); 142 return -1; 143 #else 144 return 1; 145 #endif 146 } 147 148 drop_unlock: 149 spin_unlock(&x->lock); 150 xfrm_state_put(x); 151 drop: 152 while (--xfrm_nr >= 0) 153 xfrm_state_put(xfrm_vec[xfrm_nr]); 154 kfree_skb(skb); 155 return -1; 156 } 157 158 EXPORT_SYMBOL(xfrm6_rcv_spi); 159 160 int xfrm6_rcv(struct sk_buff **pskb) 161 { 162 return xfrm6_rcv_spi(*pskb, 0); 163 } 164