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