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