1 /* $NetBSD: ip_pool.c,v 1.5 2016/06/09 04:43:46 pgoyette Exp $ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8 #if defined(KERNEL) || defined(_KERNEL) 9 # undef KERNEL 10 # undef _KERNEL 11 # define KERNEL 1 12 # define _KERNEL 1 13 #endif 14 #if defined(__osf__) 15 # define _PROTO_NET_H_ 16 #endif 17 #include <sys/errno.h> 18 #include <sys/types.h> 19 #include <sys/param.h> 20 #if defined(__NetBSD__) 21 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) 22 # if (__NetBSD_Version__ >= 799003000) 23 # if defined(_KERNEL_OPT) 24 # include "opt_ipfilter.h" 25 # endif 26 # else 27 # include "opt_ipfilter.h" 28 # endif 29 # endif 30 #endif 31 #include <sys/file.h> 32 #if !defined(_KERNEL) && !defined(__KERNEL__) 33 # include <stdio.h> 34 # include <stdlib.h> 35 # include <string.h> 36 # define _KERNEL 37 # ifdef __OpenBSD__ 38 struct file; 39 # endif 40 # include <sys/uio.h> 41 # undef _KERNEL 42 #else 43 # include <sys/systm.h> 44 # if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) 45 # include <sys/proc.h> 46 # endif 47 #endif 48 #include <sys/time.h> 49 #if defined(_KERNEL) && !defined(SOLARIS2) 50 # include <sys/mbuf.h> 51 #endif 52 #if defined(__SVR4) || defined(__svr4__) 53 # include <sys/byteorder.h> 54 # ifdef _KERNEL 55 # include <sys/dditypes.h> 56 # endif 57 # include <sys/stream.h> 58 # include <sys/kmem.h> 59 #endif 60 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 61 # include <sys/malloc.h> 62 #endif 63 64 #include <sys/socket.h> 65 #include <net/if.h> 66 #include <netinet/in.h> 67 #if !defined(_KERNEL) 68 # include "ipf.h" 69 #endif 70 71 #include "netinet/ip_compat.h" 72 #include "netinet/ip_fil.h" 73 #include "netinet/ip_pool.h" 74 #include "netinet/radix_ipf.h" 75 76 /* END OF INCLUDES */ 77 78 #if !defined(lint) 79 #if defined(__NetBSD__) 80 #include <sys/cdefs.h> 81 __KERNEL_RCSID(0, "$NetBSD: ip_pool.c,v 1.5 2016/06/09 04:43:46 pgoyette Exp $"); 82 #else 83 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 84 static const char rcsid[] = "@(#)Id: ip_pool.c,v 1.1.1.2 2012/07/22 13:45:31 darrenr Exp"; 85 #endif 86 #endif 87 88 typedef struct ipf_pool_softc_s { 89 void *ipf_radix; 90 ip_pool_t *ipf_pool_list[LOOKUP_POOL_SZ]; 91 ipf_pool_stat_t ipf_pool_stats; 92 ip_pool_node_t *ipf_node_explist; 93 } ipf_pool_softc_t; 94 95 96 static void ipf_pool_clearnodes(ipf_main_softc_t *, ipf_pool_softc_t *, 97 ip_pool_t *); 98 static int ipf_pool_create(ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *); 99 static int ipf_pool_deref(ipf_main_softc_t *, void *, void *); 100 static int ipf_pool_destroy(ipf_main_softc_t *, ipf_pool_softc_t *, int, char *); 101 static void *ipf_pool_exists(ipf_pool_softc_t *, int, char *); 102 static void *ipf_pool_find(void *, int, char *); 103 static ip_pool_node_t *ipf_pool_findeq(ipf_pool_softc_t *, ip_pool_t *, 104 addrfamily_t *, addrfamily_t *); 105 static void ipf_pool_free(ipf_main_softc_t *, ipf_pool_softc_t *, ip_pool_t *); 106 static int ipf_pool_insert_node(ipf_main_softc_t *, ipf_pool_softc_t *, 107 ip_pool_t *, struct ip_pool_node *); 108 static int ipf_pool_iter_deref(ipf_main_softc_t *, void *, int, int, void *); 109 static int ipf_pool_iter_next(ipf_main_softc_t *, void *, ipftoken_t *, 110 ipflookupiter_t *); 111 static size_t ipf_pool_flush(ipf_main_softc_t *, void *, iplookupflush_t *); 112 static int ipf_pool_node_add(ipf_main_softc_t *, void *, iplookupop_t *, 113 int); 114 static int ipf_pool_node_del(ipf_main_softc_t *, void *, iplookupop_t *, 115 int); 116 static void ipf_pool_node_deref(ipf_pool_softc_t *, ip_pool_node_t *); 117 static int ipf_pool_remove_node(ipf_main_softc_t *, ipf_pool_softc_t *, 118 ip_pool_t *, ip_pool_node_t *); 119 static int ipf_pool_search(ipf_main_softc_t *, void *, int, 120 void *, u_int); 121 static void *ipf_pool_soft_create(ipf_main_softc_t *); 122 static void ipf_pool_soft_destroy(ipf_main_softc_t *, void *); 123 static void ipf_pool_soft_fini(ipf_main_softc_t *, void *); 124 static int ipf_pool_soft_init(ipf_main_softc_t *, void *); 125 static int ipf_pool_stats_get(ipf_main_softc_t *, void *, iplookupop_t *); 126 static int ipf_pool_table_add(ipf_main_softc_t *, void *, iplookupop_t *); 127 static int ipf_pool_table_del(ipf_main_softc_t *, void *, iplookupop_t *); 128 static void *ipf_pool_select_add_ref(void *, int, char *); 129 static void ipf_pool_expire(ipf_main_softc_t *, void *); 130 131 ipf_lookup_t ipf_pool_backend = { 132 IPLT_POOL, 133 ipf_pool_soft_create, 134 ipf_pool_soft_destroy, 135 ipf_pool_soft_init, 136 ipf_pool_soft_fini, 137 ipf_pool_search, 138 ipf_pool_flush, 139 ipf_pool_iter_deref, 140 ipf_pool_iter_next, 141 ipf_pool_node_add, 142 ipf_pool_node_del, 143 ipf_pool_stats_get, 144 ipf_pool_table_add, 145 ipf_pool_table_del, 146 ipf_pool_deref, 147 ipf_pool_find, 148 ipf_pool_select_add_ref, 149 NULL, 150 ipf_pool_expire, 151 NULL 152 }; 153 154 155 #ifdef TEST_POOL 156 void treeprint(ip_pool_t *); 157 158 int 159 main(argc, argv) 160 int argc; 161 char *argv[]; 162 { 163 ip_pool_node_t node; 164 addrfamily_t a, b; 165 iplookupop_t op; 166 ip_pool_t *ipo; 167 i6addr_t ip; 168 169 RWLOCK_INIT(softc->ipf_poolrw, "poolrw"); 170 ipf_pool_init(); 171 172 bzero((char *)&ip, sizeof(ip)); 173 bzero((char *)&op, sizeof(op)); 174 bzero((char *)&node, sizeof(node)); 175 strlcpy(op.iplo_name, "0", sizeof(op.iplo_name)); 176 177 if (ipf_pool_create(&op) == 0) 178 ipo = ipf_pool_exists(0, "0"); 179 180 node.ipn_addr.adf_family = AF_INET; 181 182 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203; 183 node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff; 184 node.ipn_info = 1; 185 ipf_pool_insert_node(ipo, &node); 186 187 node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000; 188 node.ipn_mask.adf_addr.in4.s_addr = 0xff000000; 189 node.ipn_info = 0; 190 ipf_pool_insert_node(ipo, &node); 191 192 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100; 193 node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00; 194 node.ipn_info = 1; 195 ipf_pool_insert_node(ipo, &node); 196 197 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200; 198 node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00; 199 node.ipn_info = 0; 200 ipf_pool_insert_node(ipo, &node); 201 202 node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000; 203 node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000; 204 node.ipn_info = 1; 205 ipf_pool_insert_node(ipo, &node); 206 207 node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f; 208 node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff; 209 node.ipn_info = 1; 210 ipf_pool_insert_node(ipo, &node); 211 #ifdef DEBUG_POOL 212 treeprint(ipo); 213 #endif 214 ip.in4.s_addr = 0x0a00aabb; 215 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 216 ipf_pool_search(ipo, 4, &ip, 1)); 217 218 ip.in4.s_addr = 0x0a000001; 219 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 220 ipf_pool_search(ipo, 4, &ip, 1)); 221 222 ip.in4.s_addr = 0x0a000101; 223 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 224 ipf_pool_search(ipo, 4, &ip, 1)); 225 226 ip.in4.s_addr = 0x0a010001; 227 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 228 ipf_pool_search(ipo, 4, &ip, 1)); 229 230 ip.in4.s_addr = 0x0a010101; 231 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 232 ipf_pool_search(ipo, 4, &ip, 1)); 233 234 ip.in4.s_addr = 0x0a010201; 235 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 236 ipf_pool_search(ipo, 4, &ip, 1)); 237 238 ip.in4.s_addr = 0x0a010203; 239 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 240 ipf_pool_search(ipo, 4, &ip, 1)); 241 242 ip.in4.s_addr = 0x0a01020f; 243 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 244 ipf_pool_search(ipo, 4, &ip, 1)); 245 246 ip.in4.s_addr = 0x0b00aabb; 247 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, 248 ipf_pool_search(ipo, 4, &ip, 1)); 249 250 #ifdef DEBUG_POOL 251 treeprint(ipo); 252 #endif 253 254 ipf_pool_fini(); 255 256 return 0; 257 } 258 259 260 void 261 treeprint(ipo) 262 ip_pool_t *ipo; 263 { 264 ip_pool_node_t *c; 265 266 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next) 267 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n", 268 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr, 269 c->ipn_mask.adf_addr.in4.s_addr, 270 c->ipn_info, c->ipn_hits); 271 } 272 #endif /* TEST_POOL */ 273 274 275 /* ------------------------------------------------------------------------ */ 276 /* Function: ipf_pool_soft_create */ 277 /* Returns: void * - NULL = failure, else pointer to local context */ 278 /* Parameters: softc(I) - pointer to soft context main structure */ 279 /* */ 280 /* Initialise the routing table data structures where required. */ 281 /* ------------------------------------------------------------------------ */ 282 static void * 283 ipf_pool_soft_create(ipf_main_softc_t *softc) 284 { 285 ipf_pool_softc_t *softp; 286 287 KMALLOC(softp, ipf_pool_softc_t *); 288 if (softp == NULL) { 289 IPFERROR(70032); 290 return NULL; 291 } 292 293 bzero((char *)softp, sizeof(*softp)); 294 295 softp->ipf_radix = ipf_rx_create(); 296 if (softp->ipf_radix == NULL) { 297 IPFERROR(70033); 298 KFREE(softp); 299 return NULL; 300 } 301 302 return softp; 303 } 304 305 306 /* ------------------------------------------------------------------------ */ 307 /* Function: ipf_pool_soft_init */ 308 /* Returns: int - 0 = success, else error */ 309 /* Parameters: softc(I) - pointer to soft context main structure */ 310 /* arg(I) - pointer to local context to use */ 311 /* */ 312 /* Initialise the routing table data structures where required. */ 313 /* ------------------------------------------------------------------------ */ 314 static int 315 ipf_pool_soft_init(ipf_main_softc_t *softc, void *arg) 316 { 317 ipf_pool_softc_t *softp = arg; 318 319 ipf_rx_init(softp->ipf_radix); 320 321 return 0; 322 } 323 324 325 /* ------------------------------------------------------------------------ */ 326 /* Function: ipf_pool_soft_fini */ 327 /* Returns: Nil */ 328 /* Parameters: softc(I) - pointer to soft context main structure */ 329 /* arg(I) - pointer to local context to use */ 330 /* Locks: WRITE(ipf_global) */ 331 /* */ 332 /* Clean up all the pool data structures allocated and call the cleanup */ 333 /* function for the radix tree that supports the pools. ipf_pool_destroy is */ 334 /* used to delete the pools one by one to ensure they're properly freed up. */ 335 /* ------------------------------------------------------------------------ */ 336 static void 337 ipf_pool_soft_fini(ipf_main_softc_t *softc, void *arg) 338 { 339 ipf_pool_softc_t *softp = arg; 340 ip_pool_t *p, *q; 341 int i; 342 343 softc = arg; 344 345 for (i = -1; i <= IPL_LOGMAX; i++) { 346 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) { 347 q = p->ipo_next; 348 (void) ipf_pool_destroy(softc, arg, i, p->ipo_name); 349 } 350 } 351 } 352 353 354 /* ------------------------------------------------------------------------ */ 355 /* Function: ipf_pool_soft_destroy */ 356 /* Returns: Nil */ 357 /* Parameters: softc(I) - pointer to soft context main structure */ 358 /* arg(I) - pointer to local context to use */ 359 /* */ 360 /* Clean up the pool by free'ing the radix tree associated with it and free */ 361 /* up the pool context too. */ 362 /* ------------------------------------------------------------------------ */ 363 static void 364 ipf_pool_soft_destroy(ipf_main_softc_t *softc, void *arg) 365 { 366 ipf_pool_softc_t *softp = arg; 367 368 ipf_rx_destroy(softp->ipf_radix); 369 370 KFREE(softp); 371 } 372 373 374 /* ------------------------------------------------------------------------ */ 375 /* Function: ipf_pool_node_add */ 376 /* Returns: int - 0 = success, else error */ 377 /* Parameters: softc(I) - pointer to soft context main structure */ 378 /* arg(I) - pointer to local context to use */ 379 /* op(I) - pointer to lookup operatin data */ 380 /* */ 381 /* When adding a new node, a check is made to ensure that the address/mask */ 382 /* pair supplied has been appropriately prepared by applying the mask to */ 383 /* the address prior to calling for the pair to be added. */ 384 /* ------------------------------------------------------------------------ */ 385 static int 386 ipf_pool_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op, int uid) 387 { 388 ip_pool_node_t node, *m; 389 ip_pool_t *p; 390 int err; 391 392 if (op->iplo_size != sizeof(node)) { 393 IPFERROR(70014); 394 return EINVAL; 395 } 396 397 err = COPYIN(op->iplo_struct, &node, sizeof(node)); 398 if (err != 0) { 399 IPFERROR(70015); 400 return EFAULT; 401 } 402 403 p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name); 404 if (p == NULL) { 405 IPFERROR(70017); 406 return ESRCH; 407 } 408 409 if (node.ipn_addr.adf_family == AF_INET) { 410 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + 411 sizeof(struct in_addr)) { 412 IPFERROR(70028); 413 return EINVAL; 414 } 415 } 416 #ifdef USE_INET6 417 else if (node.ipn_addr.adf_family == AF_INET6) { 418 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + 419 sizeof(struct in6_addr)) { 420 IPFERROR(70034); 421 return EINVAL; 422 } 423 } 424 #endif 425 if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) { 426 IPFERROR(70029); 427 return EINVAL; 428 } 429 430 /* 431 * Check that the address/mask pair works. 432 */ 433 if (node.ipn_addr.adf_family == AF_INET) { 434 if ((node.ipn_addr.adf_addr.in4.s_addr & 435 node.ipn_mask.adf_addr.in4.s_addr) != 436 node.ipn_addr.adf_addr.in4.s_addr) { 437 IPFERROR(70035); 438 return EINVAL; 439 } 440 } 441 #ifdef USE_INET6 442 else if (node.ipn_addr.adf_family == AF_INET6) { 443 if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6, 444 &node.ipn_mask.adf_addr.in6, 445 &node.ipn_addr.adf_addr.in6)) { 446 IPFERROR(70036); 447 return EINVAL; 448 } 449 } 450 #endif 451 452 /* 453 * add an entry to a pool - return an error if it already 454 * exists remove an entry from a pool - if it exists 455 * - in both cases, the pool *must* exist! 456 */ 457 m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask); 458 if (m != NULL) { 459 IPFERROR(70018); 460 return EEXIST; 461 } 462 err = ipf_pool_insert_node(softc, arg, p, &node); 463 464 return err; 465 } 466 467 468 /* ------------------------------------------------------------------------ */ 469 /* Function: ipf_pool_node_del */ 470 /* Returns: int - 0 = success, else error */ 471 /* Parameters: softc(I) - pointer to soft context main structure */ 472 /* arg(I) - pointer to local context to use */ 473 /* op(I) - pointer to lookup operatin data */ 474 /* */ 475 /* ------------------------------------------------------------------------ */ 476 static int 477 ipf_pool_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op, int uid) 478 { 479 ip_pool_node_t node, *m; 480 ip_pool_t *p; 481 int err; 482 483 484 if (op->iplo_size != sizeof(node)) { 485 IPFERROR(70019); 486 return EINVAL; 487 } 488 node.ipn_uid = uid; 489 490 err = COPYIN(op->iplo_struct, &node, sizeof(node)); 491 if (err != 0) { 492 IPFERROR(70020); 493 return EFAULT; 494 } 495 496 if (node.ipn_addr.adf_family == AF_INET) { 497 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + 498 sizeof(struct in_addr)) { 499 IPFERROR(70030); 500 return EINVAL; 501 } 502 } 503 #ifdef USE_INET6 504 else if (node.ipn_addr.adf_family == AF_INET6) { 505 if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) + 506 sizeof(struct in6_addr)) { 507 IPFERROR(70037); 508 return EINVAL; 509 } 510 } 511 #endif 512 if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) { 513 IPFERROR(70031); 514 return EINVAL; 515 } 516 517 p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name); 518 if (p == NULL) { 519 IPFERROR(70021); 520 return ESRCH; 521 } 522 523 m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask); 524 if (m == NULL) { 525 IPFERROR(70022); 526 return ENOENT; 527 } 528 529 if ((uid != 0) && (uid != m->ipn_uid)) { 530 IPFERROR(70024); 531 return EACCES; 532 } 533 534 err = ipf_pool_remove_node(softc, arg, p, m); 535 536 return err; 537 } 538 539 540 /* ------------------------------------------------------------------------ */ 541 /* Function: ipf_pool_table_add */ 542 /* Returns: int - 0 = success, else error */ 543 /* Parameters: softc(I) - pointer to soft context main structure */ 544 /* arg(I) - pointer to local context to use */ 545 /* op(I) - pointer to lookup operatin data */ 546 /* */ 547 /* ------------------------------------------------------------------------ */ 548 static int 549 ipf_pool_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) 550 { 551 int err; 552 553 if (((op->iplo_arg & LOOKUP_ANON) == 0) && 554 (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) { 555 IPFERROR(70023); 556 err = EEXIST; 557 } else { 558 err = ipf_pool_create(softc, arg, op); 559 } 560 561 return err; 562 } 563 564 565 /* ------------------------------------------------------------------------ */ 566 /* Function: ipf_pool_table_del */ 567 /* Returns: int - 0 = success, else error */ 568 /* Parameters: softc(I) - pointer to soft context main structure */ 569 /* arg(I) - pointer to local context to use */ 570 /* op(I) - pointer to lookup operatin data */ 571 /* */ 572 /* ------------------------------------------------------------------------ */ 573 static int 574 ipf_pool_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) 575 { 576 return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name); 577 } 578 579 580 /* ------------------------------------------------------------------------ */ 581 /* Function: ipf_pool_statistics */ 582 /* Returns: int - 0 = success, else error */ 583 /* Parameters: softc(I) - pointer to soft context main structure */ 584 /* arg(I) - pointer to local context to use */ 585 /* op(I) - pointer to lookup operatin data */ 586 /* */ 587 /* Copy the current statistics out into user space, collecting pool list */ 588 /* pointers as appropriate for later use. */ 589 /* ------------------------------------------------------------------------ */ 590 static int 591 ipf_pool_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) 592 { 593 ipf_pool_softc_t *softp = arg; 594 ipf_pool_stat_t stats; 595 int unit, i, err = 0; 596 597 if (op->iplo_size != sizeof(ipf_pool_stat_t)) { 598 IPFERROR(70001); 599 return EINVAL; 600 } 601 602 bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats)); 603 unit = op->iplo_unit; 604 if (unit == IPL_LOGALL) { 605 for (i = 0; i <= LOOKUP_POOL_MAX; i++) 606 stats.ipls_list[i] = softp->ipf_pool_list[i]; 607 } else if (unit >= 0 && unit <= IPL_LOGMAX) { 608 unit++; /* -1 => 0 */ 609 if (op->iplo_name[0] != '\0') 610 stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1, 611 op->iplo_name); 612 else 613 stats.ipls_list[unit] = softp->ipf_pool_list[unit]; 614 } else { 615 IPFERROR(70025); 616 err = EINVAL; 617 } 618 if (err == 0) { 619 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 620 if (err != 0) { 621 IPFERROR(70026); 622 return EFAULT; 623 } 624 } 625 return 0; 626 } 627 628 629 /* ------------------------------------------------------------------------ */ 630 /* Function: ipf_pool_exists */ 631 /* Returns: int - 0 = success, else error */ 632 /* Parameters: softp(I) - pointer to soft context pool information */ 633 /* unit(I) - ipfilter device to which we are working on */ 634 /* name(I) - name of the pool */ 635 /* */ 636 /* Find a matching pool inside the collection of pools for a particular */ 637 /* device, indicated by the unit number. */ 638 /* ------------------------------------------------------------------------ */ 639 static void * 640 ipf_pool_exists(ipf_pool_softc_t *softp, int unit, char *name) 641 { 642 ip_pool_t *p; 643 int i; 644 645 if (unit == IPL_LOGALL) { 646 for (i = 0; i <= LOOKUP_POOL_MAX; i++) { 647 for (p = softp->ipf_pool_list[i]; p != NULL; 648 p = p->ipo_next) { 649 if (strncmp(p->ipo_name, name, 650 sizeof(p->ipo_name)) == 0) 651 break; 652 } 653 if (p != NULL) 654 break; 655 } 656 } else { 657 for (p = softp->ipf_pool_list[unit + 1]; p != NULL; 658 p = p->ipo_next) 659 if (strncmp(p->ipo_name, name, 660 sizeof(p->ipo_name)) == 0) 661 break; 662 } 663 return p; 664 } 665 666 667 /* ------------------------------------------------------------------------ */ 668 /* Function: ipf_pool_find */ 669 /* Returns: int - 0 = success, else error */ 670 /* Parameters: arg(I) - pointer to local context to use */ 671 /* unit(I) - ipfilter device to which we are working on */ 672 /* name(I) - name of the pool */ 673 /* */ 674 /* Find a matching pool inside the collection of pools for a particular */ 675 /* device, indicated by the unit number. If it is marked for deletion then */ 676 /* pretend it does not exist. */ 677 /* ------------------------------------------------------------------------ */ 678 static void * 679 ipf_pool_find(void *arg, int unit, char *name) 680 { 681 ipf_pool_softc_t *softp = arg; 682 ip_pool_t *p; 683 684 p = ipf_pool_exists(softp, unit, name); 685 if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE)) 686 return NULL; 687 688 return p; 689 } 690 691 692 /* ------------------------------------------------------------------------ */ 693 /* Function: ipf_pool_select_add_ref */ 694 /* Returns: int - 0 = success, else error */ 695 /* Parameters: arg(I) - pointer to local context to use */ 696 /* unit(I) - ipfilter device to which we are working on */ 697 /* name(I) - name of the pool */ 698 /* */ 699 /* ------------------------------------------------------------------------ */ 700 static void * 701 ipf_pool_select_add_ref(void *arg, int unit, char *name) 702 { 703 ip_pool_t *p; 704 705 p = ipf_pool_find(arg, -1, name); 706 if (p == NULL) 707 p = ipf_pool_find(arg, unit, name); 708 if (p != NULL) { 709 ATOMIC_INC32(p->ipo_ref); 710 } 711 return p; 712 } 713 714 715 /* ------------------------------------------------------------------------ */ 716 /* Function: ipf_pool_findeq */ 717 /* Returns: int - 0 = success, else error */ 718 /* Parameters: softp(I) - pointer to soft context pool information */ 719 /* ipo(I) - pointer to the pool getting the new node. */ 720 /* addr(I) - pointer to address information to match on */ 721 /* mask(I) - pointer to the address mask to match */ 722 /* */ 723 /* Searches for an exact match of an entry in the pool. */ 724 /* ------------------------------------------------------------------------ */ 725 extern void printhostmask(int, u_32_t *, u_32_t *); 726 static ip_pool_node_t * 727 ipf_pool_findeq(ipf_pool_softc_t *softp, ip_pool_t *ipo, addrfamily_t *addr, 728 addrfamily_t *mask) 729 { 730 ipf_rdx_node_t *n; 731 732 n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask); 733 return (ip_pool_node_t *)n; 734 } 735 736 737 /* ------------------------------------------------------------------------ */ 738 /* Function: ipf_pool_search */ 739 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 740 /* Parameters: softc(I) - pointer to soft context main structure */ 741 /* tptr(I) - pointer to the pool to search */ 742 /* version(I) - IP protocol version (4 or 6) */ 743 /* dptr(I) - pointer to address information */ 744 /* bytes(I) - length of packet */ 745 /* */ 746 /* Search the pool for a given address and return a search result. */ 747 /* ------------------------------------------------------------------------ */ 748 static int 749 ipf_pool_search(ipf_main_softc_t *softc, void *tptr, int ipversion, void *dptr, 750 u_int bytes) 751 { 752 ipf_rdx_node_t *rn; 753 ip_pool_node_t *m; 754 i6addr_t *addr; 755 addrfamily_t v; 756 ip_pool_t *ipo; 757 int rv; 758 759 ipo = tptr; 760 if (ipo == NULL) 761 return -1; 762 763 rv = 1; 764 m = NULL; 765 addr = (i6addr_t *)dptr; 766 bzero(&v, sizeof(v)); 767 768 if (ipversion == 4) { 769 v.adf_family = AF_INET; 770 v.adf_len = offsetof(addrfamily_t, adf_addr) + 771 sizeof(struct in_addr); 772 v.adf_addr.in4 = addr->in4; 773 #ifdef USE_INET6 774 } else if (ipversion == 6) { 775 v.adf_family = AF_INET6; 776 v.adf_len = offsetof(addrfamily_t, adf_addr) + 777 sizeof(struct in6_addr); 778 v.adf_addr.in6 = addr->in6; 779 #endif 780 } else 781 return -1; 782 783 READ_ENTER(&softc->ipf_poolrw); 784 785 rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v); 786 787 if ((rn != NULL) && (rn->root == 0)) { 788 m = (ip_pool_node_t *)rn; 789 ipo->ipo_hits++; 790 m->ipn_bytes += bytes; 791 m->ipn_hits++; 792 rv = m->ipn_info; 793 } 794 RWLOCK_EXIT(&softc->ipf_poolrw); 795 return rv; 796 } 797 798 799 /* ------------------------------------------------------------------------ */ 800 /* Function: ipf_pool_insert_node */ 801 /* Returns: int - 0 = success, else error */ 802 /* Parameters: softc(I) - pointer to soft context main structure */ 803 /* softp(I) - pointer to soft context pool information */ 804 /* ipo(I) - pointer to the pool getting the new node. */ 805 /* node(I) - structure with address/mask to add */ 806 /* Locks: WRITE(ipf_poolrw) */ 807 /* */ 808 /* Add another node to the pool given by ipo. The three parameters passed */ 809 /* in (addr, mask, info) shold all be stored in the node. */ 810 /* ------------------------------------------------------------------------ */ 811 static int 812 ipf_pool_insert_node(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, 813 ip_pool_t *ipo, struct ip_pool_node *node) 814 { 815 ipf_rdx_node_t *rn; 816 ip_pool_node_t *x; 817 818 if ((node->ipn_addr.adf_len > sizeof(*rn)) || 819 (node->ipn_addr.adf_len < 4)) { 820 IPFERROR(70003); 821 return EINVAL; 822 } 823 824 if ((node->ipn_mask.adf_len > sizeof(*rn)) || 825 (node->ipn_mask.adf_len < 4)) { 826 IPFERROR(70004); 827 return EINVAL; 828 } 829 830 KMALLOC(x, ip_pool_node_t *); 831 if (x == NULL) { 832 IPFERROR(70002); 833 return ENOMEM; 834 } 835 836 *x = *node; 837 bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes)); 838 x->ipn_owner = ipo; 839 x->ipn_hits = 0; 840 x->ipn_next = NULL; 841 x->ipn_pnext = NULL; 842 x->ipn_dnext = NULL; 843 x->ipn_pdnext = NULL; 844 845 if (x->ipn_die != 0) { 846 /* 847 * If the new node has a given expiration time, insert it 848 * into the list of expiring nodes with the ones to be 849 * removed first added to the front of the list. The 850 * insertion is O(n) but it is kept sorted for quick scans 851 * at expiration interval checks. 852 */ 853 ip_pool_node_t *n; 854 855 x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die); 856 for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) { 857 if (x->ipn_die < n->ipn_die) 858 break; 859 if (n->ipn_dnext == NULL) { 860 /* 861 * We've got to the last node and everything 862 * wanted to be expired before this new node, 863 * so we have to tack it on the end... 864 */ 865 n->ipn_dnext = x; 866 x->ipn_pdnext = &n->ipn_dnext; 867 n = NULL; 868 break; 869 } 870 } 871 872 if (softp->ipf_node_explist == NULL) { 873 softp->ipf_node_explist = x; 874 x->ipn_pdnext = &softp->ipf_node_explist; 875 } else if (n != NULL) { 876 x->ipn_dnext = n; 877 x->ipn_pdnext = n->ipn_pdnext; 878 n->ipn_pdnext = &x->ipn_dnext; 879 } 880 } 881 882 rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask, 883 x->ipn_nodes); 884 #ifdef DEBUG_POOL 885 printf("Added %p at %p\n", x, rn); 886 #endif 887 888 if (rn == NULL) { 889 KFREE(x); 890 IPFERROR(70005); 891 return ENOMEM; 892 } 893 894 x->ipn_ref = 1; 895 x->ipn_pnext = ipo->ipo_tail; 896 *ipo->ipo_tail = x; 897 ipo->ipo_tail = &x->ipn_next; 898 899 softp->ipf_pool_stats.ipls_nodes++; 900 901 return 0; 902 } 903 904 905 /* ------------------------------------------------------------------------ */ 906 /* Function: ipf_pool_create */ 907 /* Returns: int - 0 = success, else error */ 908 /* Parameters: softc(I) - pointer to soft context main structure */ 909 /* softp(I) - pointer to soft context pool information */ 910 /* op(I) - pointer to iplookup struct with call details */ 911 /* Locks: WRITE(ipf_poolrw) */ 912 /* */ 913 /* Creates a new group according to the paramters passed in via the */ 914 /* iplookupop structure. Does not check to see if the group already exists */ 915 /* when being inserted - assume this has already been done. If the pool is */ 916 /* marked as being anonymous, give it a new, unique, identifier. Call any */ 917 /* other functions required to initialise the structure. */ 918 /* */ 919 /* If the structure is flagged for deletion then reset the flag and return, */ 920 /* as this likely means we've tried to free a pool that is in use (flush) */ 921 /* and now want to repopulate it with "new" data. */ 922 /* ------------------------------------------------------------------------ */ 923 static int 924 ipf_pool_create(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, 925 iplookupop_t *op) 926 { 927 char name[FR_GROUPLEN]; 928 int poolnum, unit; 929 ip_pool_t *h; 930 931 unit = op->iplo_unit; 932 933 if ((op->iplo_arg & LOOKUP_ANON) == 0) { 934 h = ipf_pool_exists(softp, unit, op->iplo_name); 935 if (h != NULL) { 936 if ((h->ipo_flags & IPOOL_DELETE) == 0) { 937 IPFERROR(70006); 938 return EEXIST; 939 } 940 h->ipo_flags &= ~IPOOL_DELETE; 941 return 0; 942 } 943 } 944 945 KMALLOC(h, ip_pool_t *); 946 if (h == NULL) { 947 IPFERROR(70007); 948 return ENOMEM; 949 } 950 bzero(h, sizeof(*h)); 951 952 if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) { 953 KFREE(h); 954 IPFERROR(70008); 955 return ENOMEM; 956 } 957 958 if ((op->iplo_arg & LOOKUP_ANON) != 0) { 959 ip_pool_t *p; 960 961 h->ipo_flags |= IPOOL_ANON; 962 poolnum = LOOKUP_ANON; 963 964 snprintf(name, sizeof(name), "%x", poolnum); 965 966 for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) { 967 if (strncmp(name, p->ipo_name, 968 sizeof(p->ipo_name)) == 0) { 969 poolnum++; 970 snprintf(name, sizeof(name), "%x", poolnum); 971 p = softp->ipf_pool_list[unit + 1]; 972 } else 973 p = p->ipo_next; 974 } 975 976 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); 977 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); 978 } else { 979 (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); 980 } 981 982 h->ipo_radix = softp->ipf_radix; 983 h->ipo_ref = 1; 984 h->ipo_list = NULL; 985 h->ipo_tail = &h->ipo_list; 986 h->ipo_unit = unit; 987 h->ipo_next = softp->ipf_pool_list[unit + 1]; 988 if (softp->ipf_pool_list[unit + 1] != NULL) 989 softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next; 990 h->ipo_pnext = &softp->ipf_pool_list[unit + 1]; 991 softp->ipf_pool_list[unit + 1] = h; 992 993 softp->ipf_pool_stats.ipls_pools++; 994 995 return 0; 996 } 997 998 999 /* ------------------------------------------------------------------------ */ 1000 /* Function: ipf_pool_remove_node */ 1001 /* Returns: int - 0 = success, else error */ 1002 /* Parameters: softc(I) - pointer to soft context main structure */ 1003 /* ipo(I) - pointer to the pool to remove the node from. */ 1004 /* ipe(I) - address being deleted as a node */ 1005 /* Locks: WRITE(ipf_poolrw) */ 1006 /* */ 1007 /* Remove a node from the pool given by ipo. */ 1008 /* ------------------------------------------------------------------------ */ 1009 static int 1010 ipf_pool_remove_node(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, 1011 ip_pool_t *ipo, ip_pool_node_t *ipe) 1012 { 1013 void *ptr; 1014 1015 if (ipo->ipo_tail == &ipe->ipn_next) 1016 ipo->ipo_tail = ipe->ipn_pnext; 1017 1018 if (ipe->ipn_pnext != NULL) 1019 *ipe->ipn_pnext = ipe->ipn_next; 1020 if (ipe->ipn_next != NULL) 1021 ipe->ipn_next->ipn_pnext = ipe->ipn_pnext; 1022 1023 if (ipe->ipn_pdnext != NULL) 1024 *ipe->ipn_pdnext = ipe->ipn_dnext; 1025 if (ipe->ipn_dnext != NULL) 1026 ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext; 1027 1028 ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr, 1029 &ipe->ipn_mask); 1030 1031 if (ptr != NULL) { 1032 ipf_pool_node_deref(softp, ipe); 1033 return 0; 1034 } 1035 IPFERROR(70027); 1036 return ESRCH; 1037 } 1038 1039 1040 /* ------------------------------------------------------------------------ */ 1041 /* Function: ipf_pool_destroy */ 1042 /* Returns: int - 0 = success, else error */ 1043 /* Parameters: softc(I) - pointer to soft context main structure */ 1044 /* softp(I) - pointer to soft context pool information */ 1045 /* unit(I) - ipfilter device to which we are working on */ 1046 /* name(I) - name of the pool */ 1047 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ 1048 /* */ 1049 /* Search for a pool using paramters passed in and if it's not otherwise */ 1050 /* busy, free it. If it is busy, clear all of its nodes, mark it for being */ 1051 /* deleted and return an error saying it is busy. */ 1052 /* */ 1053 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/ 1054 /* may not be initialised, we can't use an ASSERT to enforce the locking */ 1055 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */ 1056 /* ------------------------------------------------------------------------ */ 1057 static int 1058 ipf_pool_destroy(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, int unit, 1059 char *name) 1060 { 1061 ip_pool_t *ipo; 1062 1063 ipo = ipf_pool_exists(softp, unit, name); 1064 if (ipo == NULL) { 1065 IPFERROR(70009); 1066 return ESRCH; 1067 } 1068 1069 if (ipo->ipo_ref != 1) { 1070 ipf_pool_clearnodes(softc, softp, ipo); 1071 ipo->ipo_flags |= IPOOL_DELETE; 1072 return 0; 1073 } 1074 1075 ipf_pool_free(softc, softp, ipo); 1076 return 0; 1077 } 1078 1079 1080 /* ------------------------------------------------------------------------ */ 1081 /* Function: ipf_pool_flush */ 1082 /* Returns: int - number of pools deleted */ 1083 /* Parameters: softc(I) - pointer to soft context main structure */ 1084 /* arg(I) - pointer to local context to use */ 1085 /* fp(I) - which pool(s) to flush */ 1086 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ 1087 /* */ 1088 /* Free all pools associated with the device that matches the unit number */ 1089 /* passed in with operation. */ 1090 /* */ 1091 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/ 1092 /* may not be initialised, we can't use an ASSERT to enforce the locking */ 1093 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */ 1094 /* ------------------------------------------------------------------------ */ 1095 static size_t 1096 ipf_pool_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *fp) 1097 { 1098 ipf_pool_softc_t *softp = arg; 1099 int i, num = 0, unit, err; 1100 ip_pool_t *p, *q; 1101 1102 unit = fp->iplf_unit; 1103 for (i = -1; i <= IPL_LOGMAX; i++) { 1104 if (unit != IPLT_ALL && i != unit) 1105 continue; 1106 for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) { 1107 q = p->ipo_next; 1108 err = ipf_pool_destroy(softc, softp, i, p->ipo_name); 1109 if (err == 0) 1110 num++; 1111 } 1112 } 1113 return num; 1114 } 1115 1116 1117 /* ------------------------------------------------------------------------ */ 1118 /* Function: ipf_pool_free */ 1119 /* Returns: void */ 1120 /* Parameters: softc(I) - pointer to soft context main structure */ 1121 /* softp(I) - pointer to soft context pool information */ 1122 /* ipo(I) - pointer to pool structure */ 1123 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ 1124 /* */ 1125 /* Deletes the pool strucutre passed in from the list of pools and deletes */ 1126 /* all of the address information stored in it, including any tree data */ 1127 /* structures also allocated. */ 1128 /* */ 1129 /* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/ 1130 /* may not be initialised, we can't use an ASSERT to enforce the locking */ 1131 /* assertion that one of the two (ipf_poolrw,ipf_global) is held. */ 1132 /* ------------------------------------------------------------------------ */ 1133 static void 1134 ipf_pool_free(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, ip_pool_t *ipo) 1135 { 1136 1137 ipf_pool_clearnodes(softc, softp, ipo); 1138 1139 if (ipo->ipo_next != NULL) 1140 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; 1141 *ipo->ipo_pnext = ipo->ipo_next; 1142 ipf_rx_freehead(ipo->ipo_head); 1143 KFREE(ipo); 1144 1145 softp->ipf_pool_stats.ipls_pools--; 1146 } 1147 1148 1149 /* ------------------------------------------------------------------------ */ 1150 /* Function: ipf_pool_clearnodes */ 1151 /* Returns: void */ 1152 /* Parameters: softc(I) - pointer to soft context main structure */ 1153 /* softp(I) - pointer to soft context pool information */ 1154 /* ipo(I) - pointer to pool structure */ 1155 /* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */ 1156 /* */ 1157 /* Deletes all nodes stored in a pool structure. */ 1158 /* ------------------------------------------------------------------------ */ 1159 static void 1160 ipf_pool_clearnodes(ipf_main_softc_t *softc, ipf_pool_softc_t *softp, 1161 ip_pool_t *ipo) 1162 { 1163 ip_pool_node_t *n, **next; 1164 1165 for (next = &ipo->ipo_list; (n = *next) != NULL; ) 1166 ipf_pool_remove_node(softc, softp, ipo, n); 1167 1168 ipo->ipo_list = NULL; 1169 } 1170 1171 1172 /* ------------------------------------------------------------------------ */ 1173 /* Function: ipf_pool_deref */ 1174 /* Returns: void */ 1175 /* Parameters: softc(I) - pointer to soft context main structure */ 1176 /* arg(I) - pointer to local context to use */ 1177 /* pool(I) - pointer to pool structure */ 1178 /* Locks: WRITE(ipf_poolrw) */ 1179 /* */ 1180 /* Drop the number of known references to this pool structure by one and if */ 1181 /* we arrive at zero known references, free it. */ 1182 /* ------------------------------------------------------------------------ */ 1183 static int 1184 ipf_pool_deref(ipf_main_softc_t *softc, void *arg, void *pool) 1185 { 1186 ip_pool_t *ipo = pool; 1187 1188 ipo->ipo_ref--; 1189 1190 if (ipo->ipo_ref == 0) 1191 ipf_pool_free(softc, arg, ipo); 1192 1193 else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE)) 1194 ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name); 1195 1196 return 0; 1197 } 1198 1199 1200 /* ------------------------------------------------------------------------ */ 1201 /* Function: ipf_pool_node_deref */ 1202 /* Returns: void */ 1203 /* Parameters: softp(I) - pointer to soft context pool information */ 1204 /* ipn(I) - pointer to pool structure */ 1205 /* Locks: WRITE(ipf_poolrw) */ 1206 /* */ 1207 /* Drop a reference to the pool node passed in and if we're the last, free */ 1208 /* it all up and adjust the stats accordingly. */ 1209 /* ------------------------------------------------------------------------ */ 1210 static void 1211 ipf_pool_node_deref(ipf_pool_softc_t *softp, ip_pool_node_t *ipn) 1212 { 1213 1214 ipn->ipn_ref--; 1215 1216 if (ipn->ipn_ref == 0) { 1217 KFREE(ipn); 1218 softp->ipf_pool_stats.ipls_nodes--; 1219 } 1220 } 1221 1222 1223 /* ------------------------------------------------------------------------ */ 1224 /* Function: ipf_pool_iter_next */ 1225 /* Returns: void */ 1226 /* Parameters: softc(I) - pointer to soft context main structure */ 1227 /* arg(I) - pointer to local context to use */ 1228 /* token(I) - pointer to pool structure */ 1229 /* ilp(IO) - pointer to pool iterating structure */ 1230 /* */ 1231 /* ------------------------------------------------------------------------ */ 1232 static int 1233 ipf_pool_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token, 1234 ipflookupiter_t *ilp) 1235 { 1236 ipf_pool_softc_t *softp = arg; 1237 ip_pool_node_t *node, zn, *nextnode; 1238 ip_pool_t *ipo, zp, *nextipo; 1239 void *pnext; 1240 int err; 1241 1242 err = 0; 1243 node = NULL; 1244 nextnode = NULL; 1245 ipo = NULL; 1246 nextipo = NULL; 1247 1248 READ_ENTER(&softc->ipf_poolrw); 1249 1250 switch (ilp->ili_otype) 1251 { 1252 case IPFLOOKUPITER_LIST : 1253 ipo = token->ipt_data; 1254 if (ipo == NULL) { 1255 nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1]; 1256 } else { 1257 nextipo = ipo->ipo_next; 1258 } 1259 1260 if (nextipo != NULL) { 1261 ATOMIC_INC32(nextipo->ipo_ref); 1262 token->ipt_data = nextipo; 1263 } else { 1264 bzero((char *)&zp, sizeof(zp)); 1265 nextipo = &zp; 1266 token->ipt_data = NULL; 1267 } 1268 pnext = nextipo->ipo_next; 1269 break; 1270 1271 case IPFLOOKUPITER_NODE : 1272 node = token->ipt_data; 1273 if (node == NULL) { 1274 ipo = ipf_pool_exists(arg, ilp->ili_unit, 1275 ilp->ili_name); 1276 if (ipo == NULL) { 1277 IPFERROR(70010); 1278 err = ESRCH; 1279 } else { 1280 nextnode = ipo->ipo_list; 1281 ipo = NULL; 1282 } 1283 } else { 1284 nextnode = node->ipn_next; 1285 } 1286 1287 if (nextnode != NULL) { 1288 ATOMIC_INC32(nextnode->ipn_ref); 1289 token->ipt_data = nextnode; 1290 } else { 1291 bzero((char *)&zn, sizeof(zn)); 1292 nextnode = &zn; 1293 token->ipt_data = NULL; 1294 } 1295 pnext = nextnode->ipn_next; 1296 break; 1297 1298 default : 1299 IPFERROR(70011); 1300 pnext = NULL; 1301 err = EINVAL; 1302 break; 1303 } 1304 1305 RWLOCK_EXIT(&softc->ipf_poolrw); 1306 if (err != 0) 1307 return err; 1308 1309 switch (ilp->ili_otype) 1310 { 1311 case IPFLOOKUPITER_LIST : 1312 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo)); 1313 if (err != 0) { 1314 IPFERROR(70012); 1315 err = EFAULT; 1316 } 1317 if (ipo != NULL) { 1318 WRITE_ENTER(&softc->ipf_poolrw); 1319 ipf_pool_deref(softc, softp, ipo); 1320 RWLOCK_EXIT(&softc->ipf_poolrw); 1321 } 1322 break; 1323 1324 case IPFLOOKUPITER_NODE : 1325 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 1326 if (err != 0) { 1327 IPFERROR(70013); 1328 err = EFAULT; 1329 } 1330 if (node != NULL) { 1331 WRITE_ENTER(&softc->ipf_poolrw); 1332 ipf_pool_node_deref(softp, node); 1333 RWLOCK_EXIT(&softc->ipf_poolrw); 1334 } 1335 break; 1336 } 1337 if (pnext == NULL) 1338 ipf_token_mark_complete(token); 1339 1340 return err; 1341 } 1342 1343 1344 /* ------------------------------------------------------------------------ */ 1345 /* Function: ipf_pool_iterderef */ 1346 /* Returns: void */ 1347 /* Parameters: softc(I) - pointer to soft context main structure */ 1348 /* arg(I) - pointer to local context to use */ 1349 /* unit(I) - ipfilter device to which we are working on */ 1350 /* Locks: WRITE(ipf_poolrw) */ 1351 /* */ 1352 /* ------------------------------------------------------------------------ */ 1353 static int 1354 ipf_pool_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit, 1355 void *data) 1356 { 1357 ipf_pool_softc_t *softp = arg; 1358 1359 if (data == NULL) 1360 return EINVAL; 1361 1362 if (unit < 0 || unit > IPL_LOGMAX) 1363 return EINVAL; 1364 1365 switch (otype) 1366 { 1367 case IPFLOOKUPITER_LIST : 1368 ipf_pool_deref(softc, softp, (ip_pool_t *)data); 1369 break; 1370 1371 case IPFLOOKUPITER_NODE : 1372 ipf_pool_node_deref(softp, (ip_pool_node_t *)data); 1373 break; 1374 default : 1375 break; 1376 } 1377 1378 return 0; 1379 } 1380 1381 1382 /* ------------------------------------------------------------------------ */ 1383 /* Function: ipf_pool_expire */ 1384 /* Returns: Nil */ 1385 /* Parameters: softc(I) - pointer to soft context main structure */ 1386 /* arg(I) - pointer to local context to use */ 1387 /* */ 1388 /* At present this function exists just to support temporary addition of */ 1389 /* nodes to the address pool. */ 1390 /* ------------------------------------------------------------------------ */ 1391 static void 1392 ipf_pool_expire(ipf_main_softc_t *softc, void *arg) 1393 { 1394 ipf_pool_softc_t *softp = arg; 1395 ip_pool_node_t *n; 1396 1397 while ((n = softp->ipf_node_explist) != NULL) { 1398 /* 1399 * Because the list is kept sorted on insertion, the fist 1400 * one that dies in the future means no more work to do. 1401 */ 1402 if (n->ipn_die > softc->ipf_ticks) 1403 break; 1404 ipf_pool_remove_node(softc, softp, n->ipn_owner, n); 1405 } 1406 } 1407 1408 1409 1410 1411 #ifndef _KERNEL 1412 void 1413 ipf_pool_dump(softc, arg) 1414 ipf_main_softc_t *softc; 1415 void *arg; 1416 { 1417 ipf_pool_softc_t *softp = arg; 1418 ip_pool_t *ipl; 1419 int i; 1420 1421 printf("List of configured pools\n"); 1422 for (i = 0; i <= LOOKUP_POOL_MAX; i++) 1423 for (ipl = softp->ipf_pool_list[i]; ipl != NULL; 1424 ipl = ipl->ipo_next) 1425 printpool(ipl, bcopywrap, NULL, opts, NULL); 1426 } 1427 #endif 1428