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