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