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