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