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