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