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_network_header(skb)[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 = ipv6_hdr(skb); 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_network_header(skb)[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 dst_release(skb->dst); 108 skb->dst = NULL; 109 netif_rx(skb); 110 return -1; 111 } else { 112 #ifdef CONFIG_NETFILTER 113 ipv6_hdr(skb)->payload_len = htons(skb->len); 114 __skb_push(skb, skb->data - skb_network_header(skb)); 115 116 NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, 117 ip6_rcv_finish); 118 return -1; 119 #else 120 return 1; 121 #endif 122 } 123 124 drop_unlock: 125 spin_unlock(&x->lock); 126 xfrm_state_put(x); 127 drop: 128 while (--xfrm_nr >= 0) 129 xfrm_state_put(xfrm_vec[xfrm_nr]); 130 kfree_skb(skb); 131 return -1; 132 } 133 134 EXPORT_SYMBOL(xfrm6_rcv_spi); 135 136 int xfrm6_rcv(struct sk_buff **pskb) 137 { 138 return xfrm6_rcv_spi(*pskb, 0); 139 } 140 141 EXPORT_SYMBOL(xfrm6_rcv); 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 xfrm_address_t *xany; 149 struct xfrm_state *xfrm_vec_one = NULL; 150 int nh = 0; 151 int i = 0; 152 153 xany = (xfrm_address_t *)&in6addr_any; 154 155 for (i = 0; i < 3; i++) { 156 xfrm_address_t *dst, *src; 157 switch (i) { 158 case 0: 159 dst = daddr; 160 src = saddr; 161 break; 162 case 1: 163 /* lookup state with wild-card source address */ 164 wildcard = 1; 165 dst = daddr; 166 src = xany; 167 break; 168 case 2: 169 default: 170 /* lookup state with wild-card addresses */ 171 wildcard = 1; /* XXX */ 172 dst = xany; 173 src = xany; 174 break; 175 } 176 177 x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); 178 if (!x) 179 continue; 180 181 spin_lock(&x->lock); 182 183 if (wildcard) { 184 if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { 185 spin_unlock(&x->lock); 186 xfrm_state_put(x); 187 x = NULL; 188 continue; 189 } 190 } 191 192 if (unlikely(x->km.state != XFRM_STATE_VALID)) { 193 spin_unlock(&x->lock); 194 xfrm_state_put(x); 195 x = NULL; 196 continue; 197 } 198 if (xfrm_state_check_expire(x)) { 199 spin_unlock(&x->lock); 200 xfrm_state_put(x); 201 x = NULL; 202 continue; 203 } 204 205 nh = x->type->input(x, skb); 206 if (nh <= 0) { 207 spin_unlock(&x->lock); 208 xfrm_state_put(x); 209 x = NULL; 210 continue; 211 } 212 213 x->curlft.bytes += skb->len; 214 x->curlft.packets++; 215 216 spin_unlock(&x->lock); 217 218 xfrm_vec_one = x; 219 break; 220 } 221 222 if (!xfrm_vec_one) 223 goto drop; 224 225 /* Allocate new secpath or COW existing one. */ 226 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 227 struct sec_path *sp; 228 sp = secpath_dup(skb->sp); 229 if (!sp) 230 goto drop; 231 if (skb->sp) 232 secpath_put(skb->sp); 233 skb->sp = sp; 234 } 235 236 if (1 + skb->sp->len > XFRM_MAX_DEPTH) 237 goto drop; 238 239 skb->sp->xvec[skb->sp->len] = xfrm_vec_one; 240 skb->sp->len ++; 241 242 return 1; 243 drop: 244 if (xfrm_vec_one) 245 xfrm_state_put(xfrm_vec_one); 246 return -1; 247 } 248 249 EXPORT_SYMBOL(xfrm6_input_addr); 250