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