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 60 typedef 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 68 static void ipf_pool_clearnodes(ipf_main_softc_t *, ipf_pool_softc_t *, 69 ip_pool_t *); 70 static int ipf_pool_create(ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *); 71 static int ipf_pool_deref(ipf_main_softc_t *, void *, void *); 72 static int ipf_pool_destroy(ipf_main_softc_t *, ipf_pool_softc_t *, int, char *); 73 static void *ipf_pool_exists(ipf_pool_softc_t *, int, char *); 74 static void *ipf_pool_find(void *, int, char *); 75 static ip_pool_node_t *ipf_pool_findeq(ipf_pool_softc_t *, ip_pool_t *, 76 addrfamily_t *, addrfamily_t *); 77 static void ipf_pool_free(ipf_main_softc_t *, ipf_pool_softc_t *, 78 ip_pool_t *); 79 static int ipf_pool_insert_node(ipf_main_softc_t *, ipf_pool_softc_t *, 80 ip_pool_t *, struct ip_pool_node *); 81 static int ipf_pool_iter_deref(ipf_main_softc_t *, void *, int, int, void *); 82 static int ipf_pool_iter_next(ipf_main_softc_t *, void *, ipftoken_t *, 83 ipflookupiter_t *); 84 static size_t ipf_pool_flush(ipf_main_softc_t *, void *, iplookupflush_t *); 85 static int ipf_pool_node_add(ipf_main_softc_t *, void *, iplookupop_t *, 86 int); 87 static int ipf_pool_node_del(ipf_main_softc_t *, void *, iplookupop_t *, 88 int); 89 static void ipf_pool_node_deref(ipf_pool_softc_t *, ip_pool_node_t *); 90 static int ipf_pool_remove_node(ipf_main_softc_t *, ipf_pool_softc_t *, 91 ip_pool_t *, ip_pool_node_t *); 92 static int ipf_pool_search(ipf_main_softc_t *, void *, int, 93 void *, u_int); 94 static void *ipf_pool_soft_create(ipf_main_softc_t *); 95 static void ipf_pool_soft_destroy(ipf_main_softc_t *, void *); 96 static void ipf_pool_soft_fini(ipf_main_softc_t *, void *); 97 static int ipf_pool_soft_init(ipf_main_softc_t *, void *); 98 static int ipf_pool_stats_get(ipf_main_softc_t *, void *, iplookupop_t *); 99 static int ipf_pool_table_add(ipf_main_softc_t *, void *, iplookupop_t *); 100 static int ipf_pool_table_del(ipf_main_softc_t *, void *, iplookupop_t *); 101 static void *ipf_pool_select_add_ref(void *, int, char *); 102 static void ipf_pool_expire(ipf_main_softc_t *, void *); 103 104 ipf_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 129 void treeprint(ip_pool_t *); 130 131 int 132 main(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 231 void 232 treeprint(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 /* ------------------------------------------------------------------------ */ 252 static void * 253 ipf_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 /* ------------------------------------------------------------------------ */ 284 static int 285 ipf_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 /* ------------------------------------------------------------------------ */ 306 static void 307 ipf_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 /* ------------------------------------------------------------------------ */ 333 static void 334 ipf_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 /* ------------------------------------------------------------------------ */ 355 static int 356 ipf_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 /* ------------------------------------------------------------------------ */ 447 static int 448 ipf_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 /* ------------------------------------------------------------------------ */ 520 static int 521 ipf_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 /* ------------------------------------------------------------------------ */ 545 static int 546 ipf_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 /* ------------------------------------------------------------------------ */ 562 static int 563 ipf_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 /* ------------------------------------------------------------------------ */ 611 static void * 612 ipf_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 /* ------------------------------------------------------------------------ */ 650 static void * 651 ipf_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 /* ------------------------------------------------------------------------ */ 672 static void * 673 ipf_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 /* ------------------------------------------------------------------------ */ 697 extern void printhostmask(int, u_32_t *, u_32_t *); 698 static ip_pool_node_t * 699 ipf_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 /* ------------------------------------------------------------------------ */ 720 static int 721 ipf_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 /* ------------------------------------------------------------------------ */ 783 static int 784 ipf_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 /* ------------------------------------------------------------------------ */ 895 static int 896 ipf_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 /* ------------------------------------------------------------------------ */ 981 static int 982 ipf_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 /* ------------------------------------------------------------------------ */ 1029 static int 1030 ipf_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 /* ------------------------------------------------------------------------ */ 1067 static size_t 1068 ipf_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 /* ------------------------------------------------------------------------ */ 1105 static void 1106 ipf_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 /* ------------------------------------------------------------------------ */ 1131 static void 1132 ipf_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 /* ------------------------------------------------------------------------ */ 1155 static int 1156 ipf_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 /* ------------------------------------------------------------------------ */ 1182 static void 1183 ipf_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 /* ------------------------------------------------------------------------ */ 1204 static int 1205 ipf_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 /* ------------------------------------------------------------------------ */ 1325 static int 1326 ipf_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 /* ------------------------------------------------------------------------ */ 1363 static void 1364 ipf_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 1384 void 1385 ipf_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