11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * xfrm6_input.c: based on net/ipv4/xfrm4_input.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors: 51da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 61da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 71da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 81da177e4SLinus Torvalds * YOSHIFUJI Hideaki @USAGI 91da177e4SLinus Torvalds * IPv6 support 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/string.h> 14b05e1066SPatrick McHardy #include <linux/netfilter.h> 15b05e1066SPatrick McHardy #include <linux/netfilter_ipv6.h> 161da177e4SLinus Torvalds #include <net/ipv6.h> 171da177e4SLinus Torvalds #include <net/xfrm.h> 181da177e4SLinus Torvalds 1933b5ecb8SHerbert Xu int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) 201da177e4SLinus Torvalds { 211da177e4SLinus Torvalds int err; 226067b2baSAl Viro __be32 seq; 23dbe5b4aaSHerbert Xu struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; 241da177e4SLinus Torvalds struct xfrm_state *x; 251da177e4SLinus Torvalds int xfrm_nr = 0; 261da177e4SLinus Torvalds int decaps = 0; 271da177e4SLinus Torvalds unsigned int nhoff; 281da177e4SLinus Torvalds 29951dbc8aSPatrick McHardy nhoff = IP6CB(skb)->nhoff; 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds seq = 0; 321da177e4SLinus Torvalds if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) 331da177e4SLinus Torvalds goto drop; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds do { 360660e03fSArnaldo Carvalho de Melo struct ipv6hdr *iph = ipv6_hdr(skb); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds if (xfrm_nr == XFRM_MAX_DEPTH) 391da177e4SLinus Torvalds goto drop; 401da177e4SLinus Torvalds 4173d605d1SKazunori MIYAZAWA x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, 4233b5ecb8SHerbert Xu nexthdr, AF_INET6); 431da177e4SLinus Torvalds if (x == NULL) 441da177e4SLinus Torvalds goto drop; 451da177e4SLinus Torvalds spin_lock(&x->lock); 461da177e4SLinus Torvalds if (unlikely(x->km.state != XFRM_STATE_VALID)) 471da177e4SLinus Torvalds goto drop_unlock; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds if (x->props.replay_window && xfrm_replay_check(x, seq)) 501da177e4SLinus Torvalds goto drop_unlock; 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds if (xfrm_state_check_expire(x)) 531da177e4SLinus Torvalds goto drop_unlock; 541da177e4SLinus Torvalds 55e695633eSHerbert Xu nexthdr = x->type->input(x, skb); 561da177e4SLinus Torvalds if (nexthdr <= 0) 571da177e4SLinus Torvalds goto drop_unlock; 581da177e4SLinus Torvalds 59d56f90a7SArnaldo Carvalho de Melo skb_network_header(skb)[nhoff] = nexthdr; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds if (x->props.replay_window) 621da177e4SLinus Torvalds xfrm_replay_advance(x, seq); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds x->curlft.bytes += skb->len; 651da177e4SLinus Torvalds x->curlft.packets++; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds spin_unlock(&x->lock); 681da177e4SLinus Torvalds 69dbe5b4aaSHerbert Xu xfrm_vec[xfrm_nr++] = x; 701da177e4SLinus Torvalds 7113996378SHerbert Xu if (x->outer_mode->input(x, skb)) 72b59f45d0SHerbert Xu goto drop; 73b59f45d0SHerbert Xu 7413996378SHerbert Xu if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { 751da177e4SLinus Torvalds decaps = 1; 761da177e4SLinus Torvalds break; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) 801da177e4SLinus Torvalds goto drop; 811da177e4SLinus Torvalds } while (!err); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* Allocate new secpath or COW existing one. */ 841da177e4SLinus Torvalds if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 851da177e4SLinus Torvalds struct sec_path *sp; 861da177e4SLinus Torvalds sp = secpath_dup(skb->sp); 871da177e4SLinus Torvalds if (!sp) 881da177e4SLinus Torvalds goto drop; 891da177e4SLinus Torvalds if (skb->sp) 901da177e4SLinus Torvalds secpath_put(skb->sp); 911da177e4SLinus Torvalds skb->sp = sp; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) 951da177e4SLinus Torvalds goto drop; 961da177e4SLinus Torvalds 97dbe5b4aaSHerbert Xu memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, 98dbe5b4aaSHerbert Xu xfrm_nr * sizeof(xfrm_vec[0])); 991da177e4SLinus Torvalds skb->sp->len += xfrm_nr; 1001da177e4SLinus Torvalds 101b05e1066SPatrick McHardy nf_reset(skb); 102b05e1066SPatrick McHardy 1031da177e4SLinus Torvalds if (decaps) { 1041da177e4SLinus Torvalds dst_release(skb->dst); 1051da177e4SLinus Torvalds skb->dst = NULL; 1061da177e4SLinus Torvalds netif_rx(skb); 1071da177e4SLinus Torvalds return -1; 1081da177e4SLinus Torvalds } else { 109b05e1066SPatrick McHardy #ifdef CONFIG_NETFILTER 1100660e03fSArnaldo Carvalho de Melo ipv6_hdr(skb)->payload_len = htons(skb->len); 111d56f90a7SArnaldo Carvalho de Melo __skb_push(skb, skb->data - skb_network_header(skb)); 112b05e1066SPatrick McHardy 113b05e1066SPatrick McHardy NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, 114b05e1066SPatrick McHardy ip6_rcv_finish); 115b05e1066SPatrick McHardy return -1; 116b05e1066SPatrick McHardy #else 1171da177e4SLinus Torvalds return 1; 118b05e1066SPatrick McHardy #endif 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds drop_unlock: 1221da177e4SLinus Torvalds spin_unlock(&x->lock); 1231da177e4SLinus Torvalds xfrm_state_put(x); 1241da177e4SLinus Torvalds drop: 1251da177e4SLinus Torvalds while (--xfrm_nr >= 0) 126dbe5b4aaSHerbert Xu xfrm_state_put(xfrm_vec[xfrm_nr]); 1271da177e4SLinus Torvalds kfree_skb(skb); 1281da177e4SLinus Torvalds return -1; 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm6_rcv_spi); 1321da177e4SLinus Torvalds 133e5bbef20SHerbert Xu int xfrm6_rcv(struct sk_buff *skb) 1341da177e4SLinus Torvalds { 13533b5ecb8SHerbert Xu return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 13633b5ecb8SHerbert Xu 0); 1371da177e4SLinus Torvalds } 138fbd9a5b4SMasahide NAKAMURA 1397159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_rcv); 1407159039aSYOSHIFUJI Hideaki 141fbd9a5b4SMasahide NAKAMURA int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 142fbd9a5b4SMasahide NAKAMURA xfrm_address_t *saddr, u8 proto) 143fbd9a5b4SMasahide NAKAMURA { 144fbd9a5b4SMasahide NAKAMURA struct xfrm_state *x = NULL; 145fbd9a5b4SMasahide NAKAMURA int wildcard = 0; 146fbd9a5b4SMasahide NAKAMURA xfrm_address_t *xany; 147fbd9a5b4SMasahide NAKAMURA struct xfrm_state *xfrm_vec_one = NULL; 148fbd9a5b4SMasahide NAKAMURA int nh = 0; 149fbd9a5b4SMasahide NAKAMURA int i = 0; 150fbd9a5b4SMasahide NAKAMURA 151c53b3590SYOSHIFUJI Hideaki xany = (xfrm_address_t *)&in6addr_any; 152fbd9a5b4SMasahide NAKAMURA 153fbd9a5b4SMasahide NAKAMURA for (i = 0; i < 3; i++) { 154fbd9a5b4SMasahide NAKAMURA xfrm_address_t *dst, *src; 155fbd9a5b4SMasahide NAKAMURA switch (i) { 156fbd9a5b4SMasahide NAKAMURA case 0: 157fbd9a5b4SMasahide NAKAMURA dst = daddr; 158fbd9a5b4SMasahide NAKAMURA src = saddr; 159fbd9a5b4SMasahide NAKAMURA break; 160fbd9a5b4SMasahide NAKAMURA case 1: 161fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card source address */ 162fbd9a5b4SMasahide NAKAMURA wildcard = 1; 163fbd9a5b4SMasahide NAKAMURA dst = daddr; 164fbd9a5b4SMasahide NAKAMURA src = xany; 165fbd9a5b4SMasahide NAKAMURA break; 166fbd9a5b4SMasahide NAKAMURA case 2: 167fbd9a5b4SMasahide NAKAMURA default: 168fbd9a5b4SMasahide NAKAMURA /* lookup state with wild-card addresses */ 169fbd9a5b4SMasahide NAKAMURA wildcard = 1; /* XXX */ 170fbd9a5b4SMasahide NAKAMURA dst = xany; 171fbd9a5b4SMasahide NAKAMURA src = xany; 172fbd9a5b4SMasahide NAKAMURA break; 173fbd9a5b4SMasahide NAKAMURA } 174fbd9a5b4SMasahide NAKAMURA 175fbd9a5b4SMasahide NAKAMURA x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); 176fbd9a5b4SMasahide NAKAMURA if (!x) 177fbd9a5b4SMasahide NAKAMURA continue; 178fbd9a5b4SMasahide NAKAMURA 179fbd9a5b4SMasahide NAKAMURA spin_lock(&x->lock); 180fbd9a5b4SMasahide NAKAMURA 181fbd9a5b4SMasahide NAKAMURA if (wildcard) { 182fbd9a5b4SMasahide NAKAMURA if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { 183fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 184fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 185fbd9a5b4SMasahide NAKAMURA x = NULL; 186fbd9a5b4SMasahide NAKAMURA continue; 187fbd9a5b4SMasahide NAKAMURA } 188fbd9a5b4SMasahide NAKAMURA } 189fbd9a5b4SMasahide NAKAMURA 190fbd9a5b4SMasahide NAKAMURA if (unlikely(x->km.state != XFRM_STATE_VALID)) { 191fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 192fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 193fbd9a5b4SMasahide NAKAMURA x = NULL; 194fbd9a5b4SMasahide NAKAMURA continue; 195fbd9a5b4SMasahide NAKAMURA } 196fbd9a5b4SMasahide NAKAMURA if (xfrm_state_check_expire(x)) { 197fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 198fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 199fbd9a5b4SMasahide NAKAMURA x = NULL; 200fbd9a5b4SMasahide NAKAMURA continue; 201fbd9a5b4SMasahide NAKAMURA } 202fbd9a5b4SMasahide NAKAMURA 203fbd9a5b4SMasahide NAKAMURA nh = x->type->input(x, skb); 204fbd9a5b4SMasahide NAKAMURA if (nh <= 0) { 205fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 206fbd9a5b4SMasahide NAKAMURA xfrm_state_put(x); 207fbd9a5b4SMasahide NAKAMURA x = NULL; 208fbd9a5b4SMasahide NAKAMURA continue; 209fbd9a5b4SMasahide NAKAMURA } 210fbd9a5b4SMasahide NAKAMURA 211fbd9a5b4SMasahide NAKAMURA x->curlft.bytes += skb->len; 212fbd9a5b4SMasahide NAKAMURA x->curlft.packets++; 213fbd9a5b4SMasahide NAKAMURA 214fbd9a5b4SMasahide NAKAMURA spin_unlock(&x->lock); 215fbd9a5b4SMasahide NAKAMURA 216fbd9a5b4SMasahide NAKAMURA xfrm_vec_one = x; 217fbd9a5b4SMasahide NAKAMURA break; 218fbd9a5b4SMasahide NAKAMURA } 219fbd9a5b4SMasahide NAKAMURA 220fbd9a5b4SMasahide NAKAMURA if (!xfrm_vec_one) 221fbd9a5b4SMasahide NAKAMURA goto drop; 222fbd9a5b4SMasahide NAKAMURA 223fbd9a5b4SMasahide NAKAMURA /* Allocate new secpath or COW existing one. */ 224fbd9a5b4SMasahide NAKAMURA if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 225fbd9a5b4SMasahide NAKAMURA struct sec_path *sp; 226fbd9a5b4SMasahide NAKAMURA sp = secpath_dup(skb->sp); 227fbd9a5b4SMasahide NAKAMURA if (!sp) 228fbd9a5b4SMasahide NAKAMURA goto drop; 229fbd9a5b4SMasahide NAKAMURA if (skb->sp) 230fbd9a5b4SMasahide NAKAMURA secpath_put(skb->sp); 231fbd9a5b4SMasahide NAKAMURA skb->sp = sp; 232fbd9a5b4SMasahide NAKAMURA } 233fbd9a5b4SMasahide NAKAMURA 234fbd9a5b4SMasahide NAKAMURA if (1 + skb->sp->len > XFRM_MAX_DEPTH) 235fbd9a5b4SMasahide NAKAMURA goto drop; 236fbd9a5b4SMasahide NAKAMURA 237fbd9a5b4SMasahide NAKAMURA skb->sp->xvec[skb->sp->len] = xfrm_vec_one; 238fbd9a5b4SMasahide NAKAMURA skb->sp->len ++; 239fbd9a5b4SMasahide NAKAMURA 240fbd9a5b4SMasahide NAKAMURA return 1; 241fbd9a5b4SMasahide NAKAMURA drop: 242fbd9a5b4SMasahide NAKAMURA if (xfrm_vec_one) 243fbd9a5b4SMasahide NAKAMURA xfrm_state_put(xfrm_vec_one); 244fbd9a5b4SMasahide NAKAMURA return -1; 245fbd9a5b4SMasahide NAKAMURA } 2467159039aSYOSHIFUJI Hideaki 2477159039aSYOSHIFUJI Hideaki EXPORT_SYMBOL(xfrm6_input_addr); 248