ip_pool.c revision 3448:aaf16568054b
1/* 2 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10#pragma ident "%Z%%M% %I% %E% SMI" 11 12#if defined(KERNEL) || defined(_KERNEL) 13# undef KERNEL 14# undef _KERNEL 15# define KERNEL 1 16# define _KERNEL 1 17#endif 18#if defined(__osf__) 19# define _PROTO_NET_H_ 20#endif 21#include <sys/errno.h> 22#include <sys/types.h> 23#include <sys/param.h> 24#include <sys/file.h> 25#if !defined(_KERNEL) && !defined(__KERNEL__) 26# include <stdio.h> 27# include <stdlib.h> 28# include <string.h> 29# define _KERNEL 30# ifdef __OpenBSD__ 31struct file; 32# endif 33# include <sys/uio.h> 34# undef _KERNEL 35#else 36# include <sys/systm.h> 37# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) 38# include <sys/proc.h> 39# endif 40#endif 41#include <sys/time.h> 42#if !defined(linux) 43# include <sys/protosw.h> 44#endif 45#include <sys/socket.h> 46#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__)) 47# include <sys/mbuf.h> 48#endif 49#if defined(__SVR4) || defined(__svr4__) 50# include <sys/filio.h> 51# include <sys/byteorder.h> 52# ifdef _KERNEL 53# include <sys/dditypes.h> 54# endif 55# include <sys/stream.h> 56# include <sys/kmem.h> 57#endif 58#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 59# include <sys/malloc.h> 60#endif 61 62#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \ 63 defined(__hpux) || defined(__sgi)) 64# ifdef __osf__ 65# include <net/radix.h> 66# endif 67# include "radix_ipf_local.h" 68# define _RADIX_H_ 69#endif 70#include <net/if.h> 71#include <netinet/in.h> 72 73#include "netinet/ipf_stack.h" 74#include "netinet/ip_compat.h" 75#include "netinet/ip_fil.h" 76#include "netinet/ip_pool.h" 77 78#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \ 79 ((BSD >= 198911) && !defined(__osf__) && \ 80 !defined(__hpux) && !defined(__sgi)) 81static int rn_freenode __P((struct radix_node *, void *)); 82#endif 83 84/* END OF INCLUDES */ 85 86#if !defined(lint) 87static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 88static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.14 2005/06/12 07:18:26 darrenr Exp $"; 89#endif 90 91#ifdef IPFILTER_LOOKUP 92 93/* 94 * Binary tree routines from Sedgewick and enhanced to do ranges of addresses. 95 * NOTE: Insertion *MUST* be from greatest range to least for it to work! 96 * These should be replaced, eventually, by something else - most notably a 97 * interval searching method. The important feature is to be able to find 98 * the best match. 99 * 100 * So why not use a radix tree for this? As the first line implies, it 101 * has been written to work with a _range_ of addresses. A range is not 102 * necessarily a match with any given netmask so what we end up dealing 103 * with is an interval tree. Implementations of these are hard to find 104 * and the one herein is far from bug free. 105 * 106 * Sigh, in the end I became convinced that the bugs the code contained did 107 * not make it worthwhile not using radix trees. For now the radix tree from 108 * 4.4 BSD is used, but this is not viewed as a long term solution. 109 */ 110 111#ifdef TEST_POOL 112void treeprint __P((ip_pool_t *)); 113 114int 115main(argc, argv) 116 int argc; 117 char *argv[]; 118{ 119 addrfamily_t a, b; 120 iplookupop_t op; 121 ip_pool_t *ipo; 122 i6addr_t ip; 123 124 RWLOCK_INIT(&ifs->ifs_ip_poolrw, "poolrw"); 125 ip_pool_init(ifs); 126 127 bzero((char *)&a, sizeof(a)); 128 bzero((char *)&b, sizeof(b)); 129 bzero((char *)&ip, sizeof(ip)); 130 bzero((char *)&op, sizeof(op)); 131 strcpy(op.iplo_name, "0"); 132 133 if (ip_pool_create(&op, ifs) == 0) 134 ipo = ip_pool_find(0, "0", ifs); 135 136 a.adf_addr.in4.s_addr = 0x0a010203; 137 b.adf_addr.in4.s_addr = 0xffffffff; 138 ip_pool_insert(ipo, &a, &b, 1, ifs); 139 ip_pool_insert(ipo, &a, &b, 1, ifs); 140 141 a.adf_addr.in4.s_addr = 0x0a000000; 142 b.adf_addr.in4.s_addr = 0xff000000; 143 ip_pool_insert(ipo, &a, &b, 0, ifs); 144 ip_pool_insert(ipo, &a, &b, 0, ifs); 145 146 a.adf_addr.in4.s_addr = 0x0a010100; 147 b.adf_addr.in4.s_addr = 0xffffff00; 148 ip_pool_insert(ipo, &a, &b, 1, ifs); 149 ip_pool_insert(ipo, &a, &b, 1, ifs); 150 151 a.adf_addr.in4.s_addr = 0x0a010200; 152 b.adf_addr.in4.s_addr = 0xffffff00; 153 ip_pool_insert(ipo, &a, &b, 0, ifs); 154 ip_pool_insert(ipo, &a, &b, 0, ifs); 155 156 a.adf_addr.in4.s_addr = 0x0a010000; 157 b.adf_addr.in4.s_addr = 0xffff0000; 158 ip_pool_insert(ipo, &a, &b, 1, ifs); 159 ip_pool_insert(ipo, &a, &b, 1, ifs); 160 161 a.adf_addr.in4.s_addr = 0x0a01020f; 162 b.adf_addr.in4.s_addr = 0xffffffff; 163 ip_pool_insert(ipo, &a, &b, 1, ifs); 164 ip_pool_insert(ipo, &a, &b, 1, ifs); 165#ifdef DEBUG_POOL 166treeprint(ipo); 167#endif 168 ip.in4.s_addr = 0x0a00aabb; 169 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 170 ip_pool_search(ipo, 4, &ip, ifs)); 171 172 ip.in4.s_addr = 0x0a000001; 173 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 174 ip_pool_search(ipo, 4, &ip, ifs)); 175 176 ip.in4.s_addr = 0x0a000101; 177 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 178 ip_pool_search(ipo, 4, &ip, ifs)); 179 180 ip.in4.s_addr = 0x0a010001; 181 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 182 ip_pool_search(ipo, 4, &ip, ifs)); 183 184 ip.in4.s_addr = 0x0a010101; 185 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 186 ip_pool_search(ipo, 4, &ip, ifs)); 187 188 ip.in4.s_addr = 0x0a010201; 189 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 190 ip_pool_search(ipo, 4, &ip, ifs)); 191 192 ip.in4.s_addr = 0x0a010203; 193 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 194 ip_pool_search(ipo, 4, &ip, ifs)); 195 196 ip.in4.s_addr = 0x0a01020f; 197 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 198 ip_pool_search(ipo, 4, &ip, ifs)); 199 200 ip.in4.s_addr = 0x0b00aabb; 201 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, 202 ip_pool_search(ipo, 4, &ip, ifs)); 203 204#ifdef DEBUG_POOL 205treeprint(ipo); 206#endif 207 208 ip_pool_fini(ifs); 209 210 return 0; 211} 212 213 214void 215treeprint(ipo) 216ip_pool_t *ipo; 217{ 218 ip_pool_node_t *c; 219 220 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next) 221 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n", 222 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr, 223 c->ipn_mask.adf_addr.in4.s_addr, 224 c->ipn_info, c->ipn_hits); 225} 226#endif /* TEST_POOL */ 227 228 229/* ------------------------------------------------------------------------ */ 230/* Function: ip_pool_init */ 231/* Returns: int - 0 = success, else error */ 232/* */ 233/* Initialise the routing table data structures where required. */ 234/* ------------------------------------------------------------------------ */ 235int ip_pool_init(ifs) 236ipf_stack_t *ifs; 237{ 238 239 bzero(&ifs->ifs_ipoolstat, sizeof (ip_pool_stat_t)); 240 241#if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10)) 242 rn_init(); 243#endif 244 return 0; 245} 246 247 248/* ------------------------------------------------------------------------ */ 249/* Function: ip_pool_fini */ 250/* Returns: int - 0 = success, else error */ 251/* Locks: WRITE(ipf_global) */ 252/* */ 253/* Clean up all the pool data structures allocated and call the cleanup */ 254/* function for the radix tree that supports the pools. ip_pool_destroy() is*/ 255/* used to delete the pools one by one to ensure they're properly freed up. */ 256/* ------------------------------------------------------------------------ */ 257void ip_pool_fini(ifs) 258ipf_stack_t *ifs; 259{ 260 ip_pool_t *p, *q; 261 iplookupop_t op; 262 int i; 263 264 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 265 266 for (i = 0; i <= IPL_LOGMAX; i++) { 267 for (q = ifs->ifs_ip_pool_list[i]; (p = q) != NULL; ) { 268 op.iplo_unit = i; 269 (void)strncpy(op.iplo_name, p->ipo_name, 270 sizeof(op.iplo_name)); 271 q = p->ipo_next; 272 (void) ip_pool_destroy(&op, ifs); 273 } 274 } 275 276#if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10)) 277 rn_fini(); 278#endif 279} 280 281 282/* ------------------------------------------------------------------------ */ 283/* Function: ip_pool_statistics */ 284/* Returns: int - 0 = success, else error */ 285/* Parameters: op(I) - pointer to lookup operation arguments */ 286/* */ 287/* Copy the current statistics out into user space, collecting pool list */ 288/* pointers as appropriate for later use. */ 289/* ------------------------------------------------------------------------ */ 290int ip_pool_statistics(op, ifs) 291iplookupop_t *op; 292ipf_stack_t *ifs; 293{ 294 ip_pool_stat_t stats; 295 int unit, i, err = 0; 296 297 if (op->iplo_size != sizeof(ip_pool_stat_t)) 298 return EINVAL; 299 300 bcopy((char *)&ifs->ifs_ipoolstat, (char *)&stats, sizeof(stats)); 301 unit = op->iplo_unit; 302 if (unit == IPL_LOGALL) { 303 for (i = 0; i < IPL_LOGSIZE; i++) 304 stats.ipls_list[i] = ifs->ifs_ip_pool_list[i]; 305 } else if (unit >= 0 && unit < IPL_LOGSIZE) { 306 if (op->iplo_name[0] != '\0') 307 stats.ipls_list[unit] = ip_pool_find(unit, 308 op->iplo_name, ifs); 309 else 310 stats.ipls_list[unit] = ifs->ifs_ip_pool_list[unit]; 311 } else 312 err = EINVAL; 313 if (err == 0) 314 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 315 return err; 316} 317 318 319 320/* ------------------------------------------------------------------------ */ 321/* Function: ip_pool_find */ 322/* Returns: int - 0 = success, else error */ 323/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 324/* */ 325/* Find a matching pool inside the collection of pools for a particular */ 326/* device, indicated by the unit number. */ 327/* ------------------------------------------------------------------------ */ 328void *ip_pool_find(unit, name, ifs) 329int unit; 330char *name; 331ipf_stack_t *ifs; 332{ 333 ip_pool_t *p; 334 335 for (p = ifs->ifs_ip_pool_list[unit]; p != NULL; p = p->ipo_next) 336 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0) 337 break; 338 return p; 339} 340 341 342/* ------------------------------------------------------------------------ */ 343/* Function: ip_pool_findeq */ 344/* Returns: int - 0 = success, else error */ 345/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 346/* addr(I) - pointer to address information to delete */ 347/* mask(I) - */ 348/* */ 349/* Searches for an exact match of an entry in the pool. */ 350/* ------------------------------------------------------------------------ */ 351ip_pool_node_t *ip_pool_findeq(ipo, addr, mask) 352ip_pool_t *ipo; 353addrfamily_t *addr, *mask; 354{ 355 struct radix_node *n; 356 SPL_INT(s); 357 358 SPL_NET(s); 359 n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head); 360 SPL_X(s); 361 return (ip_pool_node_t *)n; 362} 363 364 365/* ------------------------------------------------------------------------ */ 366/* Function: ip_pool_search */ 367/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 368/* Parameters: tptr(I) - pointer to the pool to search */ 369/* version(I) - IP protocol version (4 or 6) */ 370/* dptr(I) - pointer to address information */ 371/* */ 372/* Search the pool for a given address and return a search result. */ 373/* ------------------------------------------------------------------------ */ 374int ip_pool_search(tptr, version, dptr, ifs) 375void *tptr; 376int version; 377void *dptr; 378ipf_stack_t *ifs; 379{ 380 struct radix_node *rn; 381 ip_pool_node_t *m; 382 i6addr_t *addr; 383 addrfamily_t v; 384 ip_pool_t *ipo; 385 int rv; 386 387 ipo = tptr; 388 if (ipo == NULL) 389 return -1; 390 391 rv = 1; 392 m = NULL; 393 addr = (i6addr_t *)dptr; 394 bzero(&v, sizeof(v)); 395 v.adf_len = offsetof(addrfamily_t, adf_addr); 396 397 if (version == 4) { 398 v.adf_len += sizeof(addr->in4); 399 v.adf_addr.in4 = addr->in4; 400#ifdef USE_INET6 401 } else if (version == 6) { 402 v.adf_len += sizeof(addr->in6); 403 v.adf_addr.in6 = addr->in6; 404#endif 405 } else 406 return -1; 407 408 READ_ENTER(&ifs->ifs_ip_poolrw); 409 410 rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head); 411 412 if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) { 413 m = (ip_pool_node_t *)rn; 414 ipo->ipo_hits++; 415 m->ipn_hits++; 416 rv = m->ipn_info; 417 } 418 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 419 return rv; 420} 421 422 423/* ------------------------------------------------------------------------ */ 424/* Function: ip_pool_insert */ 425/* Returns: int - 0 = success, else error */ 426/* Parameters: ipo(I) - pointer to the pool getting the new node. */ 427/* addr(I) - IPv4/6 address being added as a node */ 428/* mask(I) - IPv4/6 netmask to with the node being added */ 429/* info(I) - extra information to store in this node. */ 430/* Locks: WRITE(ip_poolrw) */ 431/* */ 432/* Add another node to the pool given by ipo. The three parameters passed */ 433/* in (addr, mask, info) shold all be stored in the node. */ 434/* ------------------------------------------------------------------------ */ 435int ip_pool_insert(ipo, addr, mask, info, ifs) 436ip_pool_t *ipo; 437addrfamily_t *addr, *mask; 438int info; 439ipf_stack_t *ifs; 440{ 441 struct radix_node *rn; 442 ip_pool_node_t *x; 443 444 ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0); 445 446 KMALLOC(x, ip_pool_node_t *); 447 if (x == NULL) { 448 return ENOMEM; 449 } 450 451 bzero(x, sizeof(*x)); 452 453 x->ipn_info = info; 454 (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name)); 455 456 bcopy(addr, &x->ipn_addr, sizeof(*addr)); 457 x->ipn_addr.adf_len = sizeof(x->ipn_addr); 458 bcopy(mask, &x->ipn_mask, sizeof(*mask)); 459 x->ipn_mask.adf_len = sizeof(x->ipn_mask); 460 461 rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask, 462 ipo->ipo_head, x->ipn_nodes); 463#ifdef DEBUG_POOL 464 printf("Added %p at %p\n", x, rn); 465#endif 466 467 if (rn == NULL) { 468 KFREE(x); 469 return ENOMEM; 470 } 471 472 x->ipn_ref = 1; 473 x->ipn_next = ipo->ipo_list; 474 x->ipn_pnext = &ipo->ipo_list; 475 if (ipo->ipo_list != NULL) 476 ipo->ipo_list->ipn_pnext = &x->ipn_next; 477 ipo->ipo_list = x; 478 479 ifs->ifs_ipoolstat.ipls_nodes++; 480 481 return 0; 482} 483 484 485/* ------------------------------------------------------------------------ */ 486/* Function: ip_pool_create */ 487/* Returns: int - 0 = success, else error */ 488/* Parameters: op(I) - pointer to iplookup struct with call details */ 489/* Locks: WRITE(ip_poolrw) */ 490/* */ 491/* Creates a new group according to the paramters passed in via the */ 492/* iplookupop structure. Does not check to see if the group already exists */ 493/* when being inserted - assume this has already been done. If the pool is */ 494/* marked as being anonymous, give it a new, unique, identifier. Call any */ 495/* other functions required to initialise the structure. */ 496/* ------------------------------------------------------------------------ */ 497int ip_pool_create(op, ifs) 498iplookupop_t *op; 499ipf_stack_t *ifs; 500{ 501 char name[FR_GROUPLEN]; 502 int poolnum, unit; 503 ip_pool_t *h; 504 505 ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0); 506 507 KMALLOC(h, ip_pool_t *); 508 if (h == NULL) 509 return ENOMEM; 510 bzero(h, sizeof(*h)); 511 512 if (rn_inithead((void **)&h->ipo_head, 513 offsetof(addrfamily_t, adf_addr) << 3) == 0) { 514 KFREE(h); 515 return ENOMEM; 516 } 517 518 unit = op->iplo_unit; 519 520 if ((op->iplo_arg & IPOOL_ANON) != 0) { 521 ip_pool_t *p; 522 523 poolnum = IPOOL_ANON; 524 525#if defined(SNPRINTF) && defined(_KERNEL) 526 (void)SNPRINTF(name, sizeof(name), "%x", poolnum); 527#else 528 (void)sprintf(name, "%x", poolnum); 529#endif 530 531 for (p = ifs->ifs_ip_pool_list[unit]; p != NULL; ) { 532 if (strncmp(name, p->ipo_name, 533 sizeof(p->ipo_name)) == 0) { 534 poolnum++; 535#if defined(SNPRINTF) && defined(_KERNEL) 536 (void)SNPRINTF(name, sizeof(name), "%x", poolnum); 537#else 538 (void)sprintf(name, "%x", poolnum); 539#endif 540 p = ifs->ifs_ip_pool_list[unit]; 541 } else 542 p = p->ipo_next; 543 } 544 545 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); 546 } else { 547 (void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); 548 } 549 550 h->ipo_ref = 1; 551 h->ipo_list = NULL; 552 h->ipo_unit = unit; 553 h->ipo_next = ifs->ifs_ip_pool_list[unit]; 554 if (ifs->ifs_ip_pool_list[unit] != NULL) 555 ifs->ifs_ip_pool_list[unit]->ipo_pnext = &h->ipo_next; 556 h->ipo_pnext = &ifs->ifs_ip_pool_list[unit]; 557 ifs->ifs_ip_pool_list[unit] = h; 558 559 ifs->ifs_ipoolstat.ipls_pools++; 560 561 return 0; 562} 563 564 565/* ------------------------------------------------------------------------ */ 566/* Function: ip_pool_remove */ 567/* Returns: int - 0 = success, else error */ 568/* Parameters: ipo(I) - pointer to the pool to remove the node from. */ 569/* ipe(I) - address being deleted as a node */ 570/* Locks: WRITE(ip_poolrw) */ 571/* */ 572/* Add another node to the pool given by ipo. The three parameters passed */ 573/* in (addr, mask, info) shold all be stored in the node. */ 574/* ------------------------------------------------------------------------ */ 575int ip_pool_remove(ipo, ipe, ifs) 576ip_pool_t *ipo; 577ip_pool_node_t *ipe; 578ipf_stack_t *ifs; 579{ 580 ip_pool_node_t **ipp, *n; 581 582 ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0); 583 584 for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) { 585 if (ipe == n) { 586 *n->ipn_pnext = n->ipn_next; 587 if (n->ipn_next) 588 n->ipn_next->ipn_pnext = n->ipn_pnext; 589 break; 590 } 591 } 592 593 if (n == NULL) 594 return ENOENT; 595 596 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, 597 ipo->ipo_head); 598 KFREE(n); 599 600 ifs->ifs_ipoolstat.ipls_nodes--; 601 602 return 0; 603} 604 605 606/* ------------------------------------------------------------------------ */ 607/* Function: ip_pool_destroy */ 608/* Returns: int - 0 = success, else error */ 609/* Parameters: op(I) - information about the pool to remove */ 610/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 611/* */ 612/* Search for a pool using paramters passed in and if it's not otherwise */ 613/* busy, free it. */ 614/* */ 615/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 616/* may not be initialised, we can't use an ASSERT to enforce the locking */ 617/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 618/* ------------------------------------------------------------------------ */ 619int ip_pool_destroy(op, ifs) 620iplookupop_t *op; 621ipf_stack_t *ifs; 622{ 623 ip_pool_t *ipo; 624 625 ipo = ip_pool_find(op->iplo_unit, op->iplo_name, ifs); 626 if (ipo == NULL) 627 return ESRCH; 628 629 if (ipo->ipo_ref != 1) 630 return EBUSY; 631 632 ip_pool_free(ipo, ifs); 633 return 0; 634} 635 636 637/* ------------------------------------------------------------------------ */ 638/* Function: ip_pool_flush */ 639/* Returns: int - number of pools deleted */ 640/* Parameters: fp(I) - which pool(s) to flush */ 641/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 642/* */ 643/* Free all pools associated with the device that matches the unit number */ 644/* passed in with operation. */ 645/* */ 646/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 647/* may not be initialised, we can't use an ASSERT to enforce the locking */ 648/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 649/* ------------------------------------------------------------------------ */ 650int ip_pool_flush(fp, ifs) 651iplookupflush_t *fp; 652ipf_stack_t *ifs; 653{ 654 int i, num = 0, unit, err; 655 ip_pool_t *p, *q; 656 iplookupop_t op; 657 658 unit = fp->iplf_unit; 659 660 for (i = 0; i <= IPL_LOGMAX; i++) { 661 if (unit != IPLT_ALL && i != unit) 662 continue; 663 for (q = ifs->ifs_ip_pool_list[i]; (p = q) != NULL; ) { 664 op.iplo_unit = i; 665 (void)strncpy(op.iplo_name, p->ipo_name, 666 sizeof(op.iplo_name)); 667 q = p->ipo_next; 668 err = ip_pool_destroy(&op, ifs); 669 if (err == 0) 670 num++; 671 else 672 break; 673 } 674 } 675 return num; 676} 677 678 679/* ------------------------------------------------------------------------ */ 680/* Function: ip_pool_free */ 681/* Returns: void */ 682/* Parameters: ipo(I) - pointer to pool structure */ 683/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 684/* */ 685/* Deletes the pool strucutre passed in from the list of pools and deletes */ 686/* all of the address information stored in it, including any tree data */ 687/* structures also allocated. */ 688/* */ 689/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 690/* may not be initialised, we can't use an ASSERT to enforce the locking */ 691/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 692/* ------------------------------------------------------------------------ */ 693void ip_pool_free(ipo, ifs) 694ip_pool_t *ipo; 695ipf_stack_t *ifs; 696{ 697 ip_pool_node_t *n; 698 699 while ((n = ipo->ipo_list) != NULL) { 700 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, 701 ipo->ipo_head); 702 703 *n->ipn_pnext = n->ipn_next; 704 if (n->ipn_next) 705 n->ipn_next->ipn_pnext = n->ipn_pnext; 706 707 KFREE(n); 708 709 ifs->ifs_ipoolstat.ipls_nodes--; 710 } 711 712 ipo->ipo_list = NULL; 713 if (ipo->ipo_next != NULL) 714 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; 715 *ipo->ipo_pnext = ipo->ipo_next; 716 rn_freehead(ipo->ipo_head); 717 KFREE(ipo); 718 719 ifs->ifs_ipoolstat.ipls_pools--; 720} 721 722 723/* ------------------------------------------------------------------------ */ 724/* Function: ip_pool_deref */ 725/* Returns: void */ 726/* Parameters: ipo(I) - pointer to pool structure */ 727/* Locks: WRITE(ip_poolrw) */ 728/* */ 729/* Drop the number of known references to this pool structure by one and if */ 730/* we arrive at zero known references, free it. */ 731/* ------------------------------------------------------------------------ */ 732void ip_pool_deref(ipo, ifs) 733ip_pool_t *ipo; 734ipf_stack_t *ifs; 735{ 736 737 ASSERT(rw_read_locked(&ifs->ifs_ip_poolrw.ipf_lk) == 0); 738 739 ipo->ipo_ref--; 740 if (ipo->ipo_ref == 0) 741 ip_pool_free(ipo, ifs); 742} 743 744 745 746void ip_pool_node_deref(ipn, ifs) 747ip_pool_node_t *ipn; 748ipf_stack_t *ifs; 749{ 750 751 ipn->ipn_ref--; 752 753 if (ipn->ipn_ref == 0) { 754 KFREE(ipn); 755 ifs->ifs_ipoolstat.ipls_nodes--; 756 } 757} 758 759 760int ip_pool_getnext(token, ilp, ifs) 761ipftoken_t *token; 762ipflookupiter_t *ilp; 763ipf_stack_t *ifs; 764{ 765 ip_pool_node_t *node, zn, *nextnode; 766 ip_pool_t *ipo, zp, *nextipo; 767 int err; 768 769 err = 0; 770 node = NULL; 771 nextnode = NULL; 772 ipo = NULL; 773 nextipo = NULL; 774 775 READ_ENTER(&ifs->ifs_ip_poolrw); 776 777 switch (ilp->ili_otype) 778 { 779 case IPFLOOKUPITER_LIST : 780 ipo = token->ipt_data; 781 if (ipo == NULL) { 782 nextipo = ifs->ifs_ip_pool_list[(int)ilp->ili_unit]; 783 } else { 784 nextipo = ipo->ipo_next; 785 } 786 787 if (nextipo != NULL) { 788 if (nextipo->ipo_next == NULL) 789 token->ipt_alive = 0; 790 else { 791 ATOMIC_INC(nextipo->ipo_ref); 792 } 793 } else { 794 bzero((char *)&zp, sizeof(zp)); 795 nextipo = &zp; 796 } 797 break; 798 799 case IPFLOOKUPITER_NODE : 800 node = token->ipt_data; 801 if (node == NULL) { 802 ipo = ip_pool_find(ilp->ili_unit, ilp->ili_name, ifs); 803 if (ipo == NULL) 804 err = ESRCH; 805 else { 806 nextnode = ipo->ipo_list; 807 ipo = NULL; 808 } 809 } else { 810 nextnode = node->ipn_next; 811 } 812 813 if (nextnode != NULL) { 814 if (nextnode->ipn_next == NULL) 815 token->ipt_alive = 0; 816 else { 817 ATOMIC_INC(nextnode->ipn_ref); 818 } 819 } else { 820 bzero((char *)&zn, sizeof(zn)); 821 nextnode = &zn; 822 } 823 break; 824 default : 825 err = EINVAL; 826 break; 827 } 828 829 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 830 831 if (err != 0) 832 return err; 833 834 switch (ilp->ili_otype) 835 { 836 case IPFLOOKUPITER_LIST : 837 if (ipo != NULL) { 838 WRITE_ENTER(&ifs->ifs_ip_poolrw); 839 ip_pool_deref(ipo, ifs); 840 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 841 } 842 token->ipt_data = nextipo; 843 err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo)); 844 if (err != 0) 845 err = EFAULT; 846 break; 847 848 case IPFLOOKUPITER_NODE : 849 if (node != NULL) { 850 WRITE_ENTER(&ifs->ifs_ip_poolrw); 851 ip_pool_node_deref(node, ifs); 852 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 853 } 854 token->ipt_data = nextnode; 855 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 856 if (err != 0) 857 err = EFAULT; 858 break; 859 } 860 861 return err; 862} 863 864 865void ip_pool_iterderef(otype, unit, data, ifs) 866u_int otype; 867int unit; 868void *data; 869ipf_stack_t *ifs; 870{ 871 872 if (data == NULL) 873 return; 874 875 if (unit < 0 || unit > IPL_LOGMAX) 876 return; 877 878 switch (otype) 879 { 880 case IPFLOOKUPITER_LIST : 881 WRITE_ENTER(&ifs->ifs_ip_poolrw); 882 ip_pool_deref((ip_pool_t *)data, ifs); 883 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 884 break; 885 886 case IPFLOOKUPITER_NODE : 887 WRITE_ENTER(&ifs->ifs_ip_poolrw); 888 ip_pool_node_deref((ip_pool_node_t *)data, ifs); 889 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 890 break; 891 default : 892 break; 893 } 894} 895 896 897# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \ 898 !defined(__hpux) && !defined(__sgi)) 899static int 900rn_freenode(struct radix_node *n, void *p, ipf_stack_t *ifs) 901{ 902 struct radix_node_head *rnh = p; 903 struct radix_node *d; 904 905 d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); 906 if (d != NULL) { 907 FreeS(d, ifs->ifs_max_keylen + 2 * sizeof (*d)); 908 } 909 return 0; 910} 911 912 913void 914rn_freehead(rnh) 915 struct radix_node_head *rnh; 916{ 917 918 (*rnh->rnh_walktree)(rnh, rn_freenode, rnh); 919 920 rnh->rnh_addaddr = NULL; 921 rnh->rnh_deladdr = NULL; 922 rnh->rnh_matchaddr = NULL; 923 rnh->rnh_lookup = NULL; 924 rnh->rnh_walktree = NULL; 925 926 Free(rnh); 927} 928# endif 929 930#endif /* IPFILTER_LOOKUP */ 931