1 /* 2 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2006 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__ 31 struct 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/ip_compat.h" 74 #include "netinet/ip_fil.h" 75 #include "netinet/ip_pool.h" 76 77 #if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \ 78 ((BSD >= 198911) && !defined(__osf__) && \ 79 !defined(__hpux) && !defined(__sgi)) 80 static int rn_freenode __P((struct radix_node *, void *)); 81 #endif 82 83 /* END OF INCLUDES */ 84 85 #if !defined(lint) 86 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 87 static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.14 2005/06/12 07:18:26 darrenr Exp $"; 88 #endif 89 90 #ifdef IPFILTER_LOOKUP 91 92 ip_pool_stat_t ipoolstat; 93 ipfrwlock_t ip_poolrw; 94 95 /* 96 * Binary tree routines from Sedgewick and enhanced to do ranges of addresses. 97 * NOTE: Insertion *MUST* be from greatest range to least for it to work! 98 * These should be replaced, eventually, by something else - most notably a 99 * interval searching method. The important feature is to be able to find 100 * the best match. 101 * 102 * So why not use a radix tree for this? As the first line implies, it 103 * has been written to work with a _range_ of addresses. A range is not 104 * necessarily a match with any given netmask so what we end up dealing 105 * with is an interval tree. Implementations of these are hard to find 106 * and the one herein is far from bug free. 107 * 108 * Sigh, in the end I became convinced that the bugs the code contained did 109 * not make it worthwhile not using radix trees. For now the radix tree from 110 * 4.4 BSD is used, but this is not viewed as a long term solution. 111 */ 112 ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, 113 NULL, NULL, NULL, NULL }; 114 115 116 #ifdef TEST_POOL 117 void treeprint __P((ip_pool_t *)); 118 119 int 120 main(argc, argv) 121 int argc; 122 char *argv[]; 123 { 124 addrfamily_t a, b; 125 iplookupop_t op; 126 ip_pool_t *ipo; 127 i6addr_t ip; 128 129 RWLOCK_INIT(&ip_poolrw, "poolrw"); 130 ip_pool_init(); 131 132 bzero((char *)&a, sizeof(a)); 133 bzero((char *)&b, sizeof(b)); 134 bzero((char *)&ip, sizeof(ip)); 135 bzero((char *)&op, sizeof(op)); 136 strcpy(op.iplo_name, "0"); 137 138 if (ip_pool_create(&op) == 0) 139 ipo = ip_pool_find(0, "0"); 140 141 a.adf_addr.in4.s_addr = 0x0a010203; 142 b.adf_addr.in4.s_addr = 0xffffffff; 143 ip_pool_insert(ipo, &a, &b, 1); 144 ip_pool_insert(ipo, &a, &b, 1); 145 146 a.adf_addr.in4.s_addr = 0x0a000000; 147 b.adf_addr.in4.s_addr = 0xff000000; 148 ip_pool_insert(ipo, &a, &b, 0); 149 ip_pool_insert(ipo, &a, &b, 0); 150 151 a.adf_addr.in4.s_addr = 0x0a010100; 152 b.adf_addr.in4.s_addr = 0xffffff00; 153 ip_pool_insert(ipo, &a, &b, 1); 154 ip_pool_insert(ipo, &a, &b, 1); 155 156 a.adf_addr.in4.s_addr = 0x0a010200; 157 b.adf_addr.in4.s_addr = 0xffffff00; 158 ip_pool_insert(ipo, &a, &b, 0); 159 ip_pool_insert(ipo, &a, &b, 0); 160 161 a.adf_addr.in4.s_addr = 0x0a010000; 162 b.adf_addr.in4.s_addr = 0xffff0000; 163 ip_pool_insert(ipo, &a, &b, 1); 164 ip_pool_insert(ipo, &a, &b, 1); 165 166 a.adf_addr.in4.s_addr = 0x0a01020f; 167 b.adf_addr.in4.s_addr = 0xffffffff; 168 ip_pool_insert(ipo, &a, &b, 1); 169 ip_pool_insert(ipo, &a, &b, 1); 170 #ifdef DEBUG_POOL 171 treeprint(ipo); 172 #endif 173 ip.in4.s_addr = 0x0a00aabb; 174 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 175 ip_pool_search(ipo, 4, &ip)); 176 177 ip.in4.s_addr = 0x0a000001; 178 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 179 ip_pool_search(ipo, 4, &ip)); 180 181 ip.in4.s_addr = 0x0a000101; 182 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 183 ip_pool_search(ipo, 4, &ip)); 184 185 ip.in4.s_addr = 0x0a010001; 186 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 187 ip_pool_search(ipo, 4, &ip)); 188 189 ip.in4.s_addr = 0x0a010101; 190 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 191 ip_pool_search(ipo, 4, &ip)); 192 193 ip.in4.s_addr = 0x0a010201; 194 printf("search(%#x) = %d (0)\n", ip.in4.s_addr, 195 ip_pool_search(ipo, 4, &ip)); 196 197 ip.in4.s_addr = 0x0a010203; 198 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 199 ip_pool_search(ipo, 4, &ip)); 200 201 ip.in4.s_addr = 0x0a01020f; 202 printf("search(%#x) = %d (1)\n", ip.in4.s_addr, 203 ip_pool_search(ipo, 4, &ip)); 204 205 ip.in4.s_addr = 0x0b00aabb; 206 printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, 207 ip_pool_search(ipo, 4, &ip)); 208 209 #ifdef DEBUG_POOL 210 treeprint(ipo); 211 #endif 212 213 ip_pool_fini(); 214 215 return 0; 216 } 217 218 219 void 220 treeprint(ipo) 221 ip_pool_t *ipo; 222 { 223 ip_pool_node_t *c; 224 225 for (c = ipo->ipo_list; c != NULL; c = c->ipn_next) 226 printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n", 227 c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr, 228 c->ipn_mask.adf_addr.in4.s_addr, 229 c->ipn_info, c->ipn_hits); 230 } 231 #endif /* TEST_POOL */ 232 233 234 /* ------------------------------------------------------------------------ */ 235 /* Function: ip_pool_init */ 236 /* Returns: int - 0 = success, else error */ 237 /* */ 238 /* Initialise the routing table data structures where required. */ 239 /* ------------------------------------------------------------------------ */ 240 int ip_pool_init() 241 { 242 243 bzero((char *)&ipoolstat, sizeof(ipoolstat)); 244 245 #if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10)) 246 rn_init(); 247 #endif 248 return 0; 249 } 250 251 252 /* ------------------------------------------------------------------------ */ 253 /* Function: ip_pool_fini */ 254 /* Returns: int - 0 = success, else error */ 255 /* Locks: WRITE(ipf_global) */ 256 /* */ 257 /* Clean up all the pool data structures allocated and call the cleanup */ 258 /* function for the radix tree that supports the pools. ip_pool_destroy() is*/ 259 /* used to delete the pools one by one to ensure they're properly freed up. */ 260 /* ------------------------------------------------------------------------ */ 261 void ip_pool_fini() 262 { 263 ip_pool_t *p, *q; 264 iplookupop_t op; 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 op.iplo_unit = i; 272 (void)strncpy(op.iplo_name, p->ipo_name, 273 sizeof(op.iplo_name)); 274 q = p->ipo_next; 275 (void) ip_pool_destroy(&op); 276 } 277 } 278 279 #if !defined(_KERNEL) || ((BSD < 199306) && (SOLARIS2 < 10)) 280 rn_fini(); 281 #endif 282 } 283 284 285 /* ------------------------------------------------------------------------ */ 286 /* Function: ip_pool_statistics */ 287 /* Returns: int - 0 = success, else error */ 288 /* Parameters: op(I) - pointer to lookup operation arguments */ 289 /* */ 290 /* Copy the current statistics out into user space, collecting pool list */ 291 /* pointers as appropriate for later use. */ 292 /* ------------------------------------------------------------------------ */ 293 int ip_pool_statistics(op) 294 iplookupop_t *op; 295 { 296 ip_pool_stat_t stats; 297 int unit, i, err = 0; 298 299 if (op->iplo_size != sizeof(ipoolstat)) 300 return EINVAL; 301 302 bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats)); 303 unit = op->iplo_unit; 304 if (unit == IPL_LOGALL) { 305 for (i = 0; i < IPL_LOGSIZE; i++) 306 stats.ipls_list[i] = ip_pool_list[i]; 307 } else if (unit >= 0 && unit < IPL_LOGSIZE) { 308 if (op->iplo_name[0] != '\0') 309 stats.ipls_list[unit] = ip_pool_find(unit, 310 op->iplo_name); 311 else 312 stats.ipls_list[unit] = ip_pool_list[unit]; 313 } else 314 err = EINVAL; 315 if (err == 0) 316 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 317 return err; 318 } 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. */ 329 /* ------------------------------------------------------------------------ */ 330 void *ip_pool_find(unit, name) 331 int unit; 332 char *name; 333 { 334 ip_pool_t *p; 335 336 for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next) 337 if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0) 338 break; 339 return p; 340 } 341 342 343 /* ------------------------------------------------------------------------ */ 344 /* Function: ip_pool_findeq */ 345 /* Returns: int - 0 = success, else error */ 346 /* Parameters: ipo(I) - pointer to the pool getting the new node. */ 347 /* addr(I) - pointer to address information to delete */ 348 /* mask(I) - */ 349 /* */ 350 /* Searches for an exact match of an entry in the pool. */ 351 /* ------------------------------------------------------------------------ */ 352 ip_pool_node_t *ip_pool_findeq(ipo, addr, mask) 353 ip_pool_t *ipo; 354 addrfamily_t *addr, *mask; 355 { 356 struct radix_node *n; 357 SPL_INT(s); 358 359 SPL_NET(s); 360 n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head); 361 SPL_X(s); 362 return (ip_pool_node_t *)n; 363 } 364 365 366 /* ------------------------------------------------------------------------ */ 367 /* Function: ip_pool_search */ 368 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 369 /* Parameters: tptr(I) - pointer to the pool to search */ 370 /* version(I) - IP protocol version (4 or 6) */ 371 /* dptr(I) - pointer to address information */ 372 /* */ 373 /* Search the pool for a given address and return a search result. */ 374 /* ------------------------------------------------------------------------ */ 375 int ip_pool_search(tptr, version, dptr) 376 void *tptr; 377 int version; 378 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 (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(&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(&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 /* ------------------------------------------------------------------------ */ 435 int ip_pool_insert(ipo, addr, mask, info) 436 ip_pool_t *ipo; 437 addrfamily_t *addr, *mask; 438 int info; 439 { 440 struct radix_node *rn; 441 ip_pool_node_t *x; 442 443 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 444 445 KMALLOC(x, ip_pool_node_t *); 446 if (x == NULL) { 447 return ENOMEM; 448 } 449 450 bzero(x, sizeof(*x)); 451 452 x->ipn_info = info; 453 (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name)); 454 455 bcopy(addr, &x->ipn_addr, sizeof(*addr)); 456 x->ipn_addr.adf_len = sizeof(x->ipn_addr); 457 bcopy(mask, &x->ipn_mask, sizeof(*mask)); 458 x->ipn_mask.adf_len = sizeof(x->ipn_mask); 459 460 rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask, 461 ipo->ipo_head, x->ipn_nodes); 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_next = ipo->ipo_list; 472 x->ipn_pnext = &ipo->ipo_list; 473 if (ipo->ipo_list != NULL) 474 ipo->ipo_list->ipn_pnext = &x->ipn_next; 475 ipo->ipo_list = x; 476 477 ipoolstat.ipls_nodes++; 478 479 return 0; 480 } 481 482 483 /* ------------------------------------------------------------------------ */ 484 /* Function: ip_pool_create */ 485 /* Returns: int - 0 = success, else error */ 486 /* Parameters: op(I) - pointer to iplookup struct with call details */ 487 /* Locks: WRITE(ip_poolrw) */ 488 /* */ 489 /* Creates a new group according to the paramters passed in via the */ 490 /* iplookupop structure. Does not check to see if the group already exists */ 491 /* when being inserted - assume this has already been done. If the pool is */ 492 /* marked as being anonymous, give it a new, unique, identifier. Call any */ 493 /* other functions required to initialise the structure. */ 494 /* ------------------------------------------------------------------------ */ 495 int ip_pool_create(op) 496 iplookupop_t *op; 497 { 498 char name[FR_GROUPLEN]; 499 int poolnum, unit; 500 ip_pool_t *h; 501 502 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 503 504 KMALLOC(h, ip_pool_t *); 505 if (h == NULL) 506 return ENOMEM; 507 bzero(h, sizeof(*h)); 508 509 if (rn_inithead((void **)&h->ipo_head, 510 offsetof(addrfamily_t, adf_addr) << 3) == 0) { 511 KFREE(h); 512 return ENOMEM; 513 } 514 515 unit = op->iplo_unit; 516 517 if ((op->iplo_arg & IPOOL_ANON) != 0) { 518 ip_pool_t *p; 519 520 poolnum = IPOOL_ANON; 521 522 #if defined(SNPRINTF) && defined(_KERNEL) 523 (void)SNPRINTF(name, sizeof(name), "%x", poolnum); 524 #else 525 (void)sprintf(name, "%x", poolnum); 526 #endif 527 528 for (p = ip_pool_list[unit]; p != NULL; ) { 529 if (strncmp(name, p->ipo_name, 530 sizeof(p->ipo_name)) == 0) { 531 poolnum++; 532 #if defined(SNPRINTF) && defined(_KERNEL) 533 (void)SNPRINTF(name, sizeof(name), "%x", poolnum); 534 #else 535 (void)sprintf(name, "%x", poolnum); 536 #endif 537 p = ip_pool_list[unit]; 538 } else 539 p = p->ipo_next; 540 } 541 542 (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); 543 } else { 544 (void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); 545 } 546 547 h->ipo_ref = 1; 548 h->ipo_list = NULL; 549 h->ipo_unit = unit; 550 h->ipo_next = ip_pool_list[unit]; 551 if (ip_pool_list[unit] != NULL) 552 ip_pool_list[unit]->ipo_pnext = &h->ipo_next; 553 h->ipo_pnext = &ip_pool_list[unit]; 554 ip_pool_list[unit] = h; 555 556 ipoolstat.ipls_pools++; 557 558 return 0; 559 } 560 561 562 /* ------------------------------------------------------------------------ */ 563 /* Function: ip_pool_remove */ 564 /* Returns: int - 0 = success, else error */ 565 /* Parameters: ipo(I) - pointer to the pool to remove the node from. */ 566 /* ipe(I) - address being deleted as a node */ 567 /* Locks: WRITE(ip_poolrw) */ 568 /* */ 569 /* Add another node to the pool given by ipo. The three parameters passed */ 570 /* in (addr, mask, info) shold all be stored in the node. */ 571 /* ------------------------------------------------------------------------ */ 572 int ip_pool_remove(ipo, ipe) 573 ip_pool_t *ipo; 574 ip_pool_node_t *ipe; 575 { 576 ip_pool_node_t **ipp, *n; 577 578 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 579 580 for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) { 581 if (ipe == n) { 582 *n->ipn_pnext = n->ipn_next; 583 if (n->ipn_next) 584 n->ipn_next->ipn_pnext = n->ipn_pnext; 585 break; 586 } 587 } 588 589 if (n == NULL) 590 return ENOENT; 591 592 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, 593 ipo->ipo_head); 594 KFREE(n); 595 596 ipoolstat.ipls_nodes--; 597 598 return 0; 599 } 600 601 602 /* ------------------------------------------------------------------------ */ 603 /* Function: ip_pool_destroy */ 604 /* Returns: int - 0 = success, else error */ 605 /* Parameters: op(I) - information about the pool to remove */ 606 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 607 /* */ 608 /* Search for a pool using paramters passed in and if it's not otherwise */ 609 /* busy, free it. */ 610 /* */ 611 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 612 /* may not be initialised, we can't use an ASSERT to enforce the locking */ 613 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 614 /* ------------------------------------------------------------------------ */ 615 int ip_pool_destroy(op) 616 iplookupop_t *op; 617 { 618 ip_pool_t *ipo; 619 620 ipo = ip_pool_find(op->iplo_unit, op->iplo_name); 621 if (ipo == NULL) 622 return ESRCH; 623 624 if (ipo->ipo_ref != 1) 625 return EBUSY; 626 627 ip_pool_free(ipo); 628 return 0; 629 } 630 631 632 /* ------------------------------------------------------------------------ */ 633 /* Function: ip_pool_flush */ 634 /* Returns: int - number of pools deleted */ 635 /* Parameters: fp(I) - which pool(s) to flush */ 636 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 637 /* */ 638 /* Free all pools associated with the device that matches the unit number */ 639 /* passed in with operation. */ 640 /* */ 641 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 642 /* may not be initialised, we can't use an ASSERT to enforce the locking */ 643 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 644 /* ------------------------------------------------------------------------ */ 645 int ip_pool_flush(fp) 646 iplookupflush_t *fp; 647 { 648 int i, num = 0, unit, err; 649 ip_pool_t *p, *q; 650 iplookupop_t op; 651 652 unit = fp->iplf_unit; 653 654 for (i = 0; i <= IPL_LOGMAX; i++) { 655 if (unit != IPLT_ALL && i != unit) 656 continue; 657 for (q = ip_pool_list[i]; (p = q) != NULL; ) { 658 op.iplo_unit = i; 659 (void)strncpy(op.iplo_name, p->ipo_name, 660 sizeof(op.iplo_name)); 661 q = p->ipo_next; 662 err = ip_pool_destroy(&op); 663 if (err == 0) 664 num++; 665 else 666 break; 667 } 668 } 669 return num; 670 } 671 672 673 /* ------------------------------------------------------------------------ */ 674 /* Function: ip_pool_free */ 675 /* Returns: void */ 676 /* Parameters: ipo(I) - pointer to pool structure */ 677 /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ 678 /* */ 679 /* Deletes the pool strucutre passed in from the list of pools and deletes */ 680 /* all of the address information stored in it, including any tree data */ 681 /* structures also allocated. */ 682 /* */ 683 /* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ 684 /* may not be initialised, we can't use an ASSERT to enforce the locking */ 685 /* assertion that one of the two (ip_poolrw,ipf_global) is held. */ 686 /* ------------------------------------------------------------------------ */ 687 void ip_pool_free(ipo) 688 ip_pool_t *ipo; 689 { 690 ip_pool_node_t *n; 691 692 while ((n = ipo->ipo_list) != NULL) { 693 ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, 694 ipo->ipo_head); 695 696 *n->ipn_pnext = n->ipn_next; 697 if (n->ipn_next) 698 n->ipn_next->ipn_pnext = n->ipn_pnext; 699 700 KFREE(n); 701 702 ipoolstat.ipls_nodes--; 703 } 704 705 ipo->ipo_list = NULL; 706 if (ipo->ipo_next != NULL) 707 ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; 708 *ipo->ipo_pnext = ipo->ipo_next; 709 rn_freehead(ipo->ipo_head); 710 KFREE(ipo); 711 712 ipoolstat.ipls_pools--; 713 } 714 715 716 /* ------------------------------------------------------------------------ */ 717 /* Function: ip_pool_deref */ 718 /* Returns: void */ 719 /* Parameters: ipo(I) - pointer to pool structure */ 720 /* Locks: WRITE(ip_poolrw) */ 721 /* */ 722 /* Drop the number of known references to this pool structure by one and if */ 723 /* we arrive at zero known references, free it. */ 724 /* ------------------------------------------------------------------------ */ 725 void ip_pool_deref(ipo) 726 ip_pool_t *ipo; 727 { 728 729 ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); 730 731 ipo->ipo_ref--; 732 if (ipo->ipo_ref == 0) 733 ip_pool_free(ipo); 734 } 735 736 737 # if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \ 738 !defined(__hpux) && !defined(__sgi)) 739 static int 740 rn_freenode(struct radix_node *n, void *p) 741 { 742 struct radix_node_head *rnh = p; 743 struct radix_node *d; 744 745 d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); 746 if (d != NULL) { 747 FreeS(d, max_keylen + 2 * sizeof (*d)); 748 } 749 return 0; 750 } 751 752 753 void 754 rn_freehead(rnh) 755 struct radix_node_head *rnh; 756 { 757 758 (*rnh->rnh_walktree)(rnh, rn_freenode, rnh); 759 760 rnh->rnh_addaddr = NULL; 761 rnh->rnh_deladdr = NULL; 762 rnh->rnh_matchaddr = NULL; 763 rnh->rnh_lookup = NULL; 764 rnh->rnh_walktree = NULL; 765 766 Free(rnh); 767 } 768 # endif 769 770 #endif /* IPFILTER_LOOKUP */ 771