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