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