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 **pskb, u32 spi) 32 { 33 struct sk_buff *skb = *pskb; 34 int err; 35 u32 seq; 36 struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH]; 37 struct xfrm_state *x; 38 int xfrm_nr = 0; 39 int decaps = 0; 40 int nexthdr; 41 unsigned int nhoff; 42 43 nhoff = IP6CB(skb)->nhoff; 44 nexthdr = skb->nh.raw[nhoff]; 45 46 seq = 0; 47 if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) 48 goto drop; 49 50 do { 51 struct ipv6hdr *iph = skb->nh.ipv6h; 52 53 if (xfrm_nr == XFRM_MAX_DEPTH) 54 goto drop; 55 56 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6); 57 if (x == NULL) 58 goto drop; 59 spin_lock(&x->lock); 60 if (unlikely(x->km.state != XFRM_STATE_VALID)) 61 goto drop_unlock; 62 63 if (x->props.replay_window && xfrm_replay_check(x, seq)) 64 goto drop_unlock; 65 66 if (xfrm_state_check_expire(x)) 67 goto drop_unlock; 68 69 nexthdr = x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb); 70 if (nexthdr <= 0) 71 goto drop_unlock; 72 73 skb->nh.raw[nhoff] = nexthdr; 74 75 if (x->props.replay_window) 76 xfrm_replay_advance(x, seq); 77 78 x->curlft.bytes += skb->len; 79 x->curlft.packets++; 80 81 spin_unlock(&x->lock); 82 83 xfrm_vec[xfrm_nr++].xvec = x; 84 85 if (x->props.mode) { /* XXX */ 86 if (nexthdr != IPPROTO_IPV6) 87 goto drop; 88 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 89 goto drop; 90 if (skb_cloned(skb) && 91 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 92 goto drop; 93 if (x->props.flags & XFRM_STATE_DECAP_DSCP) 94 ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); 95 if (!(x->props.flags & XFRM_STATE_NOECN)) 96 ipip6_ecn_decapsulate(skb); 97 skb->mac.raw = memmove(skb->data - skb->mac_len, 98 skb->mac.raw, skb->mac_len); 99 skb->nh.raw = skb->data; 100 decaps = 1; 101 break; 102 } 103 104 if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) 105 goto drop; 106 } while (!err); 107 108 /* Allocate new secpath or COW existing one. */ 109 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 110 struct sec_path *sp; 111 sp = secpath_dup(skb->sp); 112 if (!sp) 113 goto drop; 114 if (skb->sp) 115 secpath_put(skb->sp); 116 skb->sp = sp; 117 } 118 119 if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) 120 goto drop; 121 122 memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state)); 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].xvec); 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