2 * xfrm6_input.c: based on net/ipv4/xfrm4_input.c
6 * Kazunori MIYAZAWA @USAGI
7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
8 * YOSHIFUJI Hideaki @USAGI
12 #include <net/inet_ecn.h>
17 static inline void ipip6_ecn_decapsulate(struct ipv6hdr *iph,
20 if (INET_ECN_is_ce(ip6_get_dsfield(iph)) &&
21 INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h)))
22 IP6_ECN_set_ce(skb->nh.ipv6h);
25 int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
27 struct sk_buff *skb = *pskb;
30 struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
37 ip6_find_1stfragopt(skb, &prevhdr);
39 *nhoffp = prevhdr - skb->nh.raw;
41 if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
45 struct ipv6hdr *iph = skb->nh.ipv6h;
47 if (xfrm_nr == XFRM_MAX_DEPTH)
50 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6);
54 if (unlikely(x->km.state != XFRM_STATE_VALID))
57 if (x->props.replay_window && xfrm_replay_check(x, seq))
60 if (xfrm_state_check_expire(x))
63 nexthdr = x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb);
67 if (x->props.replay_window)
68 xfrm_replay_advance(x, seq);
70 x->curlft.bytes += skb->len;
73 spin_unlock(&x->lock);
75 xfrm_vec[xfrm_nr++].xvec = x;
77 if (x->props.mode) { /* XXX */
78 if (nexthdr != IPPROTO_IPV6)
80 skb->nh.raw = skb->data;
81 if (!(x->props.flags & XFRM_STATE_NOECN))
82 ipip6_ecn_decapsulate(iph, skb);
88 if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
92 /* Allocate new secpath or COW existing one. */
93 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
95 sp = secpath_dup(skb->sp);
103 if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
106 memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
107 skb->sp->len += xfrm_nr;
108 skb->ip_summed = CHECKSUM_NONE;
111 if (!(skb->dev->flags&IFF_LOOPBACK)) {
112 dst_release(skb->dst);
122 spin_unlock(&x->lock);
125 while (--xfrm_nr >= 0)
126 xfrm_state_put(xfrm_vec[xfrm_nr].xvec);