1 /* 2 * Copyright (C)2003,2004 USAGI/WIDE Project 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * 18 * Authors Mitsuru KANDA <mk@linux-ipv6.org> 19 * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> 20 * 21 * Based on net/ipv4/xfrm4_tunnel.c 22 * 23 */ 24 #include <linux/module.h> 25 #include <linux/xfrm.h> 26 #include <linux/list.h> 27 #include <net/ip.h> 28 #include <net/xfrm.h> 29 #include <net/ipv6.h> 30 #include <linux/ipv6.h> 31 #include <linux/icmpv6.h> 32 #include <linux/mutex.h> 33 34 #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG 35 # define X6TDEBUG 3 36 #else 37 # define X6TDEBUG 1 38 #endif 39 40 #define X6TPRINTK(fmt, args...) printk(fmt, ## args) 41 #define X6TNOPRINTK(fmt, args...) do { ; } while(0) 42 43 #if X6TDEBUG >= 1 44 # define X6TPRINTK1 X6TPRINTK 45 #else 46 # define X6TPRINTK1 X6TNOPRINTK 47 #endif 48 49 #if X6TDEBUG >= 3 50 # define X6TPRINTK3 X6TPRINTK 51 #else 52 # define X6TPRINTK3 X6TNOPRINTK 53 #endif 54 55 /* 56 * xfrm_tunnel_spi things are for allocating unique id ("spi") 57 * per xfrm_address_t. 58 */ 59 struct xfrm6_tunnel_spi { 60 struct hlist_node list_byaddr; 61 struct hlist_node list_byspi; 62 xfrm_address_t addr; 63 u32 spi; 64 atomic_t refcnt; 65 #ifdef XFRM6_TUNNEL_SPI_MAGIC 66 u32 magic; 67 #endif 68 }; 69 70 #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG 71 # define XFRM6_TUNNEL_SPI_MAGIC 0xdeadbeef 72 #endif 73 74 static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); 75 76 static u32 xfrm6_tunnel_spi; 77 78 #define XFRM6_TUNNEL_SPI_MIN 1 79 #define XFRM6_TUNNEL_SPI_MAX 0xffffffff 80 81 static kmem_cache_t *xfrm6_tunnel_spi_kmem __read_mostly; 82 83 #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 84 #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 85 86 static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; 87 static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; 88 89 #ifdef XFRM6_TUNNEL_SPI_MAGIC 90 static int x6spi_check_magic(const struct xfrm6_tunnel_spi *x6spi, 91 const char *name) 92 { 93 if (unlikely(x6spi->magic != XFRM6_TUNNEL_SPI_MAGIC)) { 94 X6TPRINTK3(KERN_DEBUG "%s(): x6spi object " 95 "at %p has corrupted magic %08x " 96 "(should be %08x)\n", 97 name, x6spi, x6spi->magic, XFRM6_TUNNEL_SPI_MAGIC); 98 return -1; 99 } 100 return 0; 101 } 102 #else 103 static int inline x6spi_check_magic(const struct xfrm6_tunnel_spi *x6spi, 104 const char *name) 105 { 106 return 0; 107 } 108 #endif 109 110 #define X6SPI_CHECK_MAGIC(x6spi) x6spi_check_magic((x6spi), __FUNCTION__) 111 112 113 static unsigned inline xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) 114 { 115 unsigned h; 116 117 X6TPRINTK3(KERN_DEBUG "%s(addr=%p)\n", __FUNCTION__, addr); 118 119 h = addr->a6[0] ^ addr->a6[1] ^ addr->a6[2] ^ addr->a6[3]; 120 h ^= h >> 16; 121 h ^= h >> 8; 122 h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; 123 124 X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, h); 125 126 return h; 127 } 128 129 static unsigned inline xfrm6_tunnel_spi_hash_byspi(u32 spi) 130 { 131 return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; 132 } 133 134 135 static int xfrm6_tunnel_spi_init(void) 136 { 137 int i; 138 139 X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); 140 141 xfrm6_tunnel_spi = 0; 142 xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", 143 sizeof(struct xfrm6_tunnel_spi), 144 0, SLAB_HWCACHE_ALIGN, 145 NULL, NULL); 146 if (!xfrm6_tunnel_spi_kmem) { 147 X6TPRINTK1(KERN_ERR 148 "%s(): failed to allocate xfrm6_tunnel_spi_kmem\n", 149 __FUNCTION__); 150 return -ENOMEM; 151 } 152 153 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) 154 INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); 155 for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) 156 INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]); 157 return 0; 158 } 159 160 static void xfrm6_tunnel_spi_fini(void) 161 { 162 int i; 163 164 X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); 165 166 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { 167 if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) 168 goto err; 169 } 170 for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { 171 if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) 172 goto err; 173 } 174 kmem_cache_destroy(xfrm6_tunnel_spi_kmem); 175 xfrm6_tunnel_spi_kmem = NULL; 176 return; 177 err: 178 X6TPRINTK1(KERN_ERR "%s(): table is not empty\n", __FUNCTION__); 179 return; 180 } 181 182 static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) 183 { 184 struct xfrm6_tunnel_spi *x6spi; 185 struct hlist_node *pos; 186 187 X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); 188 189 hlist_for_each_entry(x6spi, pos, 190 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], 191 list_byaddr) { 192 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { 193 X6SPI_CHECK_MAGIC(x6spi); 194 X6TPRINTK3(KERN_DEBUG "%s() = %p(%u)\n", __FUNCTION__, x6spi, x6spi->spi); 195 return x6spi; 196 } 197 } 198 199 X6TPRINTK3(KERN_DEBUG "%s() = NULL(0)\n", __FUNCTION__); 200 return NULL; 201 } 202 203 u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) 204 { 205 struct xfrm6_tunnel_spi *x6spi; 206 u32 spi; 207 208 X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); 209 210 read_lock_bh(&xfrm6_tunnel_spi_lock); 211 x6spi = __xfrm6_tunnel_spi_lookup(saddr); 212 spi = x6spi ? x6spi->spi : 0; 213 read_unlock_bh(&xfrm6_tunnel_spi_lock); 214 return spi; 215 } 216 217 EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); 218 219 static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) 220 { 221 u32 spi; 222 struct xfrm6_tunnel_spi *x6spi; 223 struct hlist_node *pos; 224 unsigned index; 225 226 X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); 227 228 if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || 229 xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) 230 xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; 231 else 232 xfrm6_tunnel_spi++; 233 234 for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { 235 index = xfrm6_tunnel_spi_hash_byspi(spi); 236 hlist_for_each_entry(x6spi, pos, 237 &xfrm6_tunnel_spi_byspi[index], 238 list_byspi) { 239 if (x6spi->spi == spi) 240 goto try_next_1; 241 } 242 xfrm6_tunnel_spi = spi; 243 goto alloc_spi; 244 try_next_1:; 245 } 246 for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { 247 index = xfrm6_tunnel_spi_hash_byspi(spi); 248 hlist_for_each_entry(x6spi, pos, 249 &xfrm6_tunnel_spi_byspi[index], 250 list_byspi) { 251 if (x6spi->spi == spi) 252 goto try_next_2; 253 } 254 xfrm6_tunnel_spi = spi; 255 goto alloc_spi; 256 try_next_2:; 257 } 258 spi = 0; 259 goto out; 260 alloc_spi: 261 X6TPRINTK3(KERN_DEBUG "%s(): allocate new spi for " NIP6_FMT "\n", 262 __FUNCTION__, 263 NIP6(*(struct in6_addr *)saddr)); 264 x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, SLAB_ATOMIC); 265 if (!x6spi) { 266 X6TPRINTK1(KERN_ERR "%s(): kmem_cache_alloc() failed\n", 267 __FUNCTION__); 268 goto out; 269 } 270 #ifdef XFRM6_TUNNEL_SPI_MAGIC 271 x6spi->magic = XFRM6_TUNNEL_SPI_MAGIC; 272 #endif 273 memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); 274 x6spi->spi = spi; 275 atomic_set(&x6spi->refcnt, 1); 276 277 hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); 278 279 index = xfrm6_tunnel_spi_hash_byaddr(saddr); 280 hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); 281 X6SPI_CHECK_MAGIC(x6spi); 282 out: 283 X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, spi); 284 return spi; 285 } 286 287 u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) 288 { 289 struct xfrm6_tunnel_spi *x6spi; 290 u32 spi; 291 292 X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); 293 294 write_lock_bh(&xfrm6_tunnel_spi_lock); 295 x6spi = __xfrm6_tunnel_spi_lookup(saddr); 296 if (x6spi) { 297 atomic_inc(&x6spi->refcnt); 298 spi = x6spi->spi; 299 } else 300 spi = __xfrm6_tunnel_alloc_spi(saddr); 301 write_unlock_bh(&xfrm6_tunnel_spi_lock); 302 303 X6TPRINTK3(KERN_DEBUG "%s() = %u\n", __FUNCTION__, spi); 304 305 return spi; 306 } 307 308 EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); 309 310 void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) 311 { 312 struct xfrm6_tunnel_spi *x6spi; 313 struct hlist_node *pos, *n; 314 315 X6TPRINTK3(KERN_DEBUG "%s(saddr=%p)\n", __FUNCTION__, saddr); 316 317 write_lock_bh(&xfrm6_tunnel_spi_lock); 318 319 hlist_for_each_entry_safe(x6spi, pos, n, 320 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], 321 list_byaddr) 322 { 323 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { 324 X6TPRINTK3(KERN_DEBUG "%s(): x6spi object for " NIP6_FMT 325 " found at %p\n", 326 __FUNCTION__, 327 NIP6(*(struct in6_addr *)saddr), 328 x6spi); 329 X6SPI_CHECK_MAGIC(x6spi); 330 if (atomic_dec_and_test(&x6spi->refcnt)) { 331 hlist_del(&x6spi->list_byaddr); 332 hlist_del(&x6spi->list_byspi); 333 kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi); 334 break; 335 } 336 } 337 } 338 write_unlock_bh(&xfrm6_tunnel_spi_lock); 339 } 340 341 EXPORT_SYMBOL(xfrm6_tunnel_free_spi); 342 343 static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) 344 { 345 struct ipv6hdr *top_iph; 346 347 top_iph = (struct ipv6hdr *)skb->data; 348 top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); 349 350 return 0; 351 } 352 353 static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) 354 { 355 return 0; 356 } 357 358 static int xfrm6_tunnel_rcv(struct sk_buff *skb) 359 { 360 struct ipv6hdr *iph = skb->nh.ipv6h; 361 u32 spi; 362 363 spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); 364 return xfrm6_rcv_spi(skb, spi); 365 } 366 367 static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 368 int type, int code, int offset, __u32 info) 369 { 370 /* xfrm6_tunnel native err handling */ 371 switch (type) { 372 case ICMPV6_DEST_UNREACH: 373 switch (code) { 374 case ICMPV6_NOROUTE: 375 case ICMPV6_ADM_PROHIBITED: 376 case ICMPV6_NOT_NEIGHBOUR: 377 case ICMPV6_ADDR_UNREACH: 378 case ICMPV6_PORT_UNREACH: 379 default: 380 X6TPRINTK3(KERN_DEBUG 381 "xfrm6_tunnel: Destination Unreach.\n"); 382 break; 383 } 384 break; 385 case ICMPV6_PKT_TOOBIG: 386 X6TPRINTK3(KERN_DEBUG 387 "xfrm6_tunnel: Packet Too Big.\n"); 388 break; 389 case ICMPV6_TIME_EXCEED: 390 switch (code) { 391 case ICMPV6_EXC_HOPLIMIT: 392 X6TPRINTK3(KERN_DEBUG 393 "xfrm6_tunnel: Too small Hoplimit.\n"); 394 break; 395 case ICMPV6_EXC_FRAGTIME: 396 default: 397 break; 398 } 399 break; 400 case ICMPV6_PARAMPROB: 401 switch (code) { 402 case ICMPV6_HDR_FIELD: break; 403 case ICMPV6_UNK_NEXTHDR: break; 404 case ICMPV6_UNK_OPTION: break; 405 } 406 break; 407 default: 408 break; 409 } 410 411 return 0; 412 } 413 414 static int xfrm6_tunnel_init_state(struct xfrm_state *x) 415 { 416 if (!x->props.mode) 417 return -EINVAL; 418 419 if (x->encap) 420 return -EINVAL; 421 422 x->props.header_len = sizeof(struct ipv6hdr); 423 424 return 0; 425 } 426 427 static void xfrm6_tunnel_destroy(struct xfrm_state *x) 428 { 429 xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); 430 } 431 432 static struct xfrm_type xfrm6_tunnel_type = { 433 .description = "IP6IP6", 434 .owner = THIS_MODULE, 435 .proto = IPPROTO_IPV6, 436 .init_state = xfrm6_tunnel_init_state, 437 .destructor = xfrm6_tunnel_destroy, 438 .input = xfrm6_tunnel_input, 439 .output = xfrm6_tunnel_output, 440 }; 441 442 static struct xfrm6_tunnel xfrm6_tunnel_handler = { 443 .handler = xfrm6_tunnel_rcv, 444 .err_handler = xfrm6_tunnel_err, 445 .priority = 2, 446 }; 447 448 static int __init xfrm6_tunnel_init(void) 449 { 450 X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); 451 452 if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) { 453 X6TPRINTK1(KERN_ERR 454 "xfrm6_tunnel init: can't add xfrm type\n"); 455 return -EAGAIN; 456 } 457 if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) { 458 X6TPRINTK1(KERN_ERR 459 "xfrm6_tunnel init(): can't add handler\n"); 460 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); 461 return -EAGAIN; 462 } 463 if (xfrm6_tunnel_spi_init() < 0) { 464 X6TPRINTK1(KERN_ERR 465 "xfrm6_tunnel init: failed to initialize spi\n"); 466 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); 467 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); 468 return -EAGAIN; 469 } 470 return 0; 471 } 472 473 static void __exit xfrm6_tunnel_fini(void) 474 { 475 X6TPRINTK3(KERN_DEBUG "%s()\n", __FUNCTION__); 476 477 xfrm6_tunnel_spi_fini(); 478 if (xfrm6_tunnel_deregister(&xfrm6_tunnel_handler)) 479 X6TPRINTK1(KERN_ERR 480 "xfrm6_tunnel close: can't remove handler\n"); 481 if (xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6) < 0) 482 X6TPRINTK1(KERN_ERR 483 "xfrm6_tunnel close: can't remove xfrm type\n"); 484 } 485 486 module_init(xfrm6_tunnel_init); 487 module_exit(xfrm6_tunnel_fini); 488 MODULE_LICENSE("GPL"); 489