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 sec_decap_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, &(xfrm_vec[xfrm_nr].decap), 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++].xvec = 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->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state)); 122 skb->sp->len += xfrm_nr; 123 skb->ip_summed = CHECKSUM_NONE; 124 125 nf_reset(skb); 126 127 if (decaps) { 128 if (!(skb->dev->flags&IFF_LOOPBACK)) { 129 dst_release(skb->dst); 130 skb->dst = NULL; 131 } 132 netif_rx(skb); 133 return -1; 134 } else { 135 #ifdef CONFIG_NETFILTER 136 skb->nh.ipv6h->payload_len = htons(skb->len); 137 __skb_push(skb, skb->data - skb->nh.raw); 138 139 NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, 140 ip6_rcv_finish); 141 return -1; 142 #else 143 return 1; 144 #endif 145 } 146 147 drop_unlock: 148 spin_unlock(&x->lock); 149 xfrm_state_put(x); 150 drop: 151 while (--xfrm_nr >= 0) 152 xfrm_state_put(xfrm_vec[xfrm_nr].xvec); 153 kfree_skb(skb); 154 return -1; 155 } 156 157 EXPORT_SYMBOL(xfrm6_rcv_spi); 158 159 int xfrm6_rcv(struct sk_buff **pskb) 160 { 161 return xfrm6_rcv_spi(*pskb, 0); 162 } 163