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