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/ipv6.h> 17 #include <net/xfrm.h> 18 19 int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) 20 { 21 int err; 22 __be32 seq; 23 struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; 24 struct xfrm_state *x; 25 int xfrm_nr = 0; 26 int decaps = 0; 27 int nexthdr; 28 unsigned int nhoff; 29 30 nhoff = IP6CB(skb)->nhoff; 31 nexthdr = skb->nh.raw[nhoff]; 32 33 seq = 0; 34 if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) 35 goto drop; 36 37 do { 38 struct ipv6hdr *iph = skb->nh.ipv6h; 39 40 if (xfrm_nr == XFRM_MAX_DEPTH) 41 goto drop; 42 43 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, 44 nexthdr != IPPROTO_IPIP ? nexthdr : IPPROTO_IPV6, AF_INET6); 45 if (x == NULL) 46 goto drop; 47 spin_lock(&x->lock); 48 if (unlikely(x->km.state != XFRM_STATE_VALID)) 49 goto drop_unlock; 50 51 if (x->props.replay_window && xfrm_replay_check(x, seq)) 52 goto drop_unlock; 53 54 if (xfrm_state_check_expire(x)) 55 goto drop_unlock; 56 57 nexthdr = x->type->input(x, skb); 58 if (nexthdr <= 0) 59 goto drop_unlock; 60 61 skb->nh.raw[nhoff] = nexthdr; 62 63 if (x->props.replay_window) 64 xfrm_replay_advance(x, seq); 65 66 x->curlft.bytes += skb->len; 67 x->curlft.packets++; 68 69 spin_unlock(&x->lock); 70 71 xfrm_vec[xfrm_nr++] = x; 72 73 if (x->mode->input(x, skb)) 74 goto drop; 75 76 if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */ 77 decaps = 1; 78 break; 79 } 80 81 if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) 82 goto drop; 83 } while (!err); 84 85 /* Allocate new secpath or COW existing one. */ 86 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 87 struct sec_path *sp; 88 sp = secpath_dup(skb->sp); 89 if (!sp) 90 goto drop; 91 if (skb->sp) 92 secpath_put(skb->sp); 93 skb->sp = sp; 94 } 95 96 if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) 97 goto drop; 98 99 memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, 100 xfrm_nr * sizeof(xfrm_vec[0])); 101 skb->sp->len += xfrm_nr; 102 skb->ip_summed = CHECKSUM_NONE; 103 104 nf_reset(skb); 105 106 if (decaps) { 107 if (!(skb->dev->flags&IFF_LOOPBACK)) { 108 dst_release(skb->dst); 109 skb->dst = NULL; 110 } 111 netif_rx(skb); 112 return -1; 113 } else { 114 #ifdef CONFIG_NETFILTER 115 skb->nh.ipv6h->payload_len = htons(skb->len); 116 __skb_push(skb, skb->data - skb->nh.raw); 117 118 NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, 119 ip6_rcv_finish); 120 return -1; 121 #else 122 return 1; 123 #endif 124 } 125 126 drop_unlock: 127 spin_unlock(&x->lock); 128 xfrm_state_put(x); 129 drop: 130 while (--xfrm_nr >= 0) 131 xfrm_state_put(xfrm_vec[xfrm_nr]); 132 kfree_skb(skb); 133 return -1; 134 } 135 136 EXPORT_SYMBOL(xfrm6_rcv_spi); 137 138 int xfrm6_rcv(struct sk_buff **pskb) 139 { 140 return xfrm6_rcv_spi(*pskb, 0); 141 } 142 143 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 144 xfrm_address_t *saddr, u8 proto) 145 { 146 struct xfrm_state *x = NULL; 147 int wildcard = 0; 148 struct in6_addr any; 149 xfrm_address_t *xany; 150 struct xfrm_state *xfrm_vec_one = NULL; 151 int nh = 0; 152 int i = 0; 153 154 ipv6_addr_set(&any, 0, 0, 0, 0); 155 xany = (xfrm_address_t *)&any; 156 157 for (i = 0; i < 3; i++) { 158 xfrm_address_t *dst, *src; 159 switch (i) { 160 case 0: 161 dst = daddr; 162 src = saddr; 163 break; 164 case 1: 165 /* lookup state with wild-card source address */ 166 wildcard = 1; 167 dst = daddr; 168 src = xany; 169 break; 170 case 2: 171 default: 172 /* lookup state with wild-card addresses */ 173 wildcard = 1; /* XXX */ 174 dst = xany; 175 src = xany; 176 break; 177 } 178 179 x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); 180 if (!x) 181 continue; 182 183 spin_lock(&x->lock); 184 185 if (wildcard) { 186 if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { 187 spin_unlock(&x->lock); 188 xfrm_state_put(x); 189 x = NULL; 190 continue; 191 } 192 } 193 194 if (unlikely(x->km.state != XFRM_STATE_VALID)) { 195 spin_unlock(&x->lock); 196 xfrm_state_put(x); 197 x = NULL; 198 continue; 199 } 200 if (xfrm_state_check_expire(x)) { 201 spin_unlock(&x->lock); 202 xfrm_state_put(x); 203 x = NULL; 204 continue; 205 } 206 207 nh = x->type->input(x, skb); 208 if (nh <= 0) { 209 spin_unlock(&x->lock); 210 xfrm_state_put(x); 211 x = NULL; 212 continue; 213 } 214 215 x->curlft.bytes += skb->len; 216 x->curlft.packets++; 217 218 spin_unlock(&x->lock); 219 220 xfrm_vec_one = x; 221 break; 222 } 223 224 if (!xfrm_vec_one) 225 goto drop; 226 227 /* Allocate new secpath or COW existing one. */ 228 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 229 struct sec_path *sp; 230 sp = secpath_dup(skb->sp); 231 if (!sp) 232 goto drop; 233 if (skb->sp) 234 secpath_put(skb->sp); 235 skb->sp = sp; 236 } 237 238 if (1 + skb->sp->len > XFRM_MAX_DEPTH) 239 goto drop; 240 241 skb->sp->xvec[skb->sp->len] = xfrm_vec_one; 242 skb->sp->len ++; 243 244 return 1; 245 drop: 246 if (xfrm_vec_one) 247 xfrm_state_put(xfrm_vec_one); 248 return -1; 249 } 250