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