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