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 #include <sys/param.h> 19 #include <sys/types.h> 20 #include <sys/errno.h> 21 #include <sys/time.h> 22 #include <sys/file.h> 23 #if !defined(_KERNEL) 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 #endif 33 #include <sys/socket.h> 34 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 35 # include <sys/malloc.h> 36 #endif 37 #if defined(__FreeBSD__) 38 # include <sys/cdefs.h> 39 # include <sys/proc.h> 40 #endif 41 #if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \ 42 !defined(linux) 43 # include <sys/mbuf.h> 44 #endif 45 #if defined(_KERNEL) 46 # include <sys/systm.h> 47 #else 48 # include <stdio.h> 49 #endif 50 #include <netinet/in.h> 51 #include <net/if.h> 52 53 #include "netinet/ip_compat.h" 54 #include "netinet/ip_fil.h" 55 #include "netinet/ip_lookup.h" 56 #include "netinet/ip_htable.h" 57 #include "netinet/ipf_stack.h" 58 /* END OF INCLUDES */ 59 60 #if !defined(lint) 61 static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.3 2005/05/14 05:11:38 darrenr Exp $"; 62 #endif 63 64 #ifdef IPFILTER_LOOKUP 65 static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *)); 66 #ifdef USE_INET6 67 static iphtent_t *fr_iphmfind6 __P((iphtable_t *, struct in6_addr *)); 68 static uint32_t sum4(uint32_t *); 69 static void left_shift_ipv6 __P((char *)); 70 #endif 71 72 void fr_htable_unload(ifs) 73 ipf_stack_t *ifs; 74 { 75 iplookupflush_t fop; 76 77 fop.iplf_unit = IPL_LOGALL; 78 (void)fr_flushhtable(&fop, ifs); 79 } 80 81 82 int fr_gethtablestat(op, ifs) 83 iplookupop_t *op; 84 ipf_stack_t *ifs; 85 { 86 iphtstat_t stats; 87 88 if (op->iplo_size != sizeof(stats)) 89 return EINVAL; 90 91 stats.iphs_tables = ifs->ifs_ipf_htables[op->iplo_unit]; 92 stats.iphs_numtables = ifs->ifs_ipf_nhtables[op->iplo_unit]; 93 stats.iphs_numnodes = ifs->ifs_ipf_nhtnodes[op->iplo_unit]; 94 stats.iphs_nomem = ifs->ifs_ipht_nomem[op->iplo_unit]; 95 96 return COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 97 98 } 99 100 101 /* 102 * Create a new hash table using the template passed. 103 */ 104 int fr_newhtable(op, ifs) 105 iplookupop_t *op; 106 ipf_stack_t *ifs; 107 { 108 iphtable_t *iph, *oiph; 109 char name[FR_GROUPLEN]; 110 int err, i, unit; 111 112 KMALLOC(iph, iphtable_t *); 113 if (iph == NULL) { 114 ifs->ifs_ipht_nomem[op->iplo_unit]++; 115 return ENOMEM; 116 } 117 118 err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); 119 if (err != 0) { 120 KFREE(iph); 121 return EFAULT; 122 } 123 124 unit = op->iplo_unit; 125 if (iph->iph_unit != unit) { 126 KFREE(iph); 127 return EINVAL; 128 } 129 130 if ((op->iplo_arg & IPHASH_ANON) == 0) { 131 if (fr_findhtable(op->iplo_unit, op->iplo_name, ifs) != NULL) { 132 KFREE(iph); 133 return EEXIST; 134 } 135 } else { 136 i = IPHASH_ANON; 137 do { 138 i++; 139 #if defined(SNPRINTF) && defined(_KERNEL) 140 (void)SNPRINTF(name, sizeof(name), "%u", i); 141 #else 142 (void)sprintf(name, "%u", i); 143 #endif 144 for (oiph = ifs->ifs_ipf_htables[unit]; oiph != NULL; 145 oiph = oiph->iph_next) 146 if (strncmp(oiph->iph_name, name, 147 sizeof(oiph->iph_name)) == 0) 148 break; 149 } while (oiph != NULL); 150 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); 151 err = COPYOUT(iph, op->iplo_struct, sizeof(*iph)); 152 if (err != 0) { 153 KFREE(iph); 154 return EFAULT; 155 } 156 iph->iph_type |= IPHASH_ANON; 157 } 158 159 KMALLOCS(iph->iph_table, iphtent_t **, 160 iph->iph_size * sizeof(*iph->iph_table)); 161 if (iph->iph_table == NULL) { 162 KFREE(iph); 163 ifs->ifs_ipht_nomem[unit]++; 164 return ENOMEM; 165 } 166 167 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 168 iph->iph_masks[0] = 0; 169 iph->iph_masks[1] = 0; 170 iph->iph_masks[2] = 0; 171 iph->iph_masks[3] = 0; 172 iph->iph_list = NULL; 173 174 iph->iph_ref = 1; 175 iph->iph_next = ifs->ifs_ipf_htables[unit]; 176 iph->iph_pnext = &ifs->ifs_ipf_htables[unit]; 177 if (ifs->ifs_ipf_htables[unit] != NULL) 178 ifs->ifs_ipf_htables[unit]->iph_pnext = &iph->iph_next; 179 ifs->ifs_ipf_htables[unit] = iph; 180 181 ifs->ifs_ipf_nhtables[unit]++; 182 183 return 0; 184 } 185 186 187 /* 188 */ 189 int fr_removehtable(op, ifs) 190 iplookupop_t *op; 191 ipf_stack_t *ifs; 192 { 193 iphtable_t *iph; 194 195 196 iph = fr_findhtable(op->iplo_unit, op->iplo_name, ifs); 197 if (iph == NULL) 198 return ESRCH; 199 200 if (iph->iph_unit != op->iplo_unit) { 201 return EINVAL; 202 } 203 204 if (iph->iph_ref != 1) { 205 return EBUSY; 206 } 207 208 fr_delhtable(iph, ifs); 209 210 return 0; 211 } 212 213 214 void fr_delhtable(iph, ifs) 215 iphtable_t *iph; 216 ipf_stack_t *ifs; 217 { 218 iphtent_t *ipe; 219 int i; 220 221 for (i = 0; i < iph->iph_size; i++) 222 while ((ipe = iph->iph_table[i]) != NULL) 223 if (fr_delhtent(iph, ipe, ifs) != 0) 224 return; 225 226 *iph->iph_pnext = iph->iph_next; 227 if (iph->iph_next != NULL) 228 iph->iph_next->iph_pnext = iph->iph_pnext; 229 230 ifs->ifs_ipf_nhtables[iph->iph_unit]--; 231 232 if (iph->iph_ref == 1) { 233 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 234 KFREE(iph); 235 } 236 } 237 238 239 void fr_derefhtable(iph, ifs) 240 iphtable_t *iph; 241 ipf_stack_t *ifs; 242 { 243 iph->iph_ref--; 244 if (iph->iph_ref == 0) 245 fr_delhtable(iph, ifs); 246 } 247 248 249 void fr_derefhtent(ipe) 250 iphtent_t *ipe; 251 { 252 ipe->ipe_ref--; 253 if (ipe->ipe_ref == 0) { 254 KFREE(ipe); 255 } 256 } 257 258 259 iphtable_t *fr_findhtable(unit, name, ifs) 260 int unit; 261 char *name; 262 ipf_stack_t *ifs; 263 { 264 iphtable_t *iph; 265 266 for (iph = ifs->ifs_ipf_htables[unit]; iph != NULL; iph = iph->iph_next) 267 if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0) 268 break; 269 return iph; 270 } 271 272 273 size_t fr_flushhtable(op, ifs) 274 iplookupflush_t *op; 275 ipf_stack_t *ifs; 276 { 277 iphtable_t *iph; 278 size_t freed; 279 int i; 280 281 freed = 0; 282 283 for (i = 0; i <= IPL_LOGMAX; i++) { 284 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { 285 while ((iph = ifs->ifs_ipf_htables[i]) != NULL) { 286 fr_delhtable(iph, ifs); 287 freed++; 288 } 289 } 290 } 291 292 return freed; 293 } 294 295 296 /* 297 * Add an entry to a hash table. 298 */ 299 int fr_addhtent(iph, ipeo, ifs) 300 iphtable_t *iph; 301 iphtent_t *ipeo; 302 ipf_stack_t *ifs; 303 { 304 iphtent_t *ipe; 305 u_int hv; 306 int bits; 307 308 KMALLOC(ipe, iphtent_t *); 309 if (ipe == NULL) 310 return -1; 311 312 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); 313 #ifdef USE_INET6 314 if (ipe->ipe_family == AF_INET6) { 315 bits = count6bits((u_32_t *)ipe->ipe_mask.in6_addr8); 316 hv = IPE_HASH_FN(sum4((uint32_t *)ipe->ipe_addr.in6_addr8), 317 sum4((uint32_t *)ipe->ipe_mask.in6_addr8), 318 iph->iph_size); 319 } else 320 #endif 321 if (ipe->ipe_family == AF_INET) 322 { 323 ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr; 324 ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr); 325 bits = count4bits(ipe->ipe_mask.in4_addr); 326 ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr); 327 328 hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, 329 iph->iph_size); 330 } else 331 return -1; 332 333 ipe->ipe_ref = 1; 334 ipe->ipe_next = iph->iph_table[hv]; 335 ipe->ipe_pnext = iph->iph_table + hv; 336 337 if (iph->iph_table[hv] != NULL) 338 iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next; 339 iph->iph_table[hv] = ipe; 340 341 ipe->ipe_snext = iph->iph_list; 342 ipe->ipe_psnext = &iph->iph_list; 343 if (ipe->ipe_next != NULL) 344 ipe->ipe_next->ipe_psnext = &ipe->ipe_snext; 345 iph->iph_list = ipe; 346 347 #ifdef USE_INET6 348 if (ipe->ipe_family == AF_INET6) { 349 if ((bits >= 0) && (bits != 128)) 350 if (bits >= 96) 351 iph->iph_masks[0] |= 1 << (bits - 96); 352 else if (bits >= 64) 353 iph->iph_masks[1] |= 1 << (bits - 64); 354 else if (bits >= 32) 355 iph->iph_masks[2] |= 1 << (bits - 32); 356 else 357 iph->iph_masks[3] |= 1 << bits; 358 359 } else 360 #endif 361 { 362 if ((bits >= 0) && (bits != 32)) 363 iph->iph_masks[3] |= 1 << bits; 364 } 365 366 switch (iph->iph_type & ~IPHASH_ANON) 367 { 368 case IPHASH_GROUPMAP : 369 ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL, 370 iph->iph_flags, IPL_LOGIPF, 371 ifs->ifs_fr_active, ifs); 372 break; 373 374 default : 375 ipe->ipe_ptr = NULL; 376 ipe->ipe_value = 0; 377 break; 378 } 379 380 ifs->ifs_ipf_nhtnodes[iph->iph_unit]++; 381 382 return 0; 383 } 384 385 386 /* 387 * Delete an entry from a hash table. 388 */ 389 int fr_delhtent(iph, ipe, ifs) 390 iphtable_t *iph; 391 iphtent_t *ipe; 392 ipf_stack_t *ifs; 393 { 394 if (ipe->ipe_ref != 1) 395 return EBUSY; 396 397 398 *ipe->ipe_pnext = ipe->ipe_next; 399 if (ipe->ipe_next != NULL) 400 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 401 402 switch (iph->iph_type & ~IPHASH_ANON) 403 { 404 case IPHASH_GROUPMAP : 405 if (ipe->ipe_group != NULL) 406 fr_delgroup(ipe->ipe_group, IPL_LOGIPF, 407 ifs->ifs_fr_active, ifs); 408 break; 409 410 default : 411 ipe->ipe_ptr = NULL; 412 ipe->ipe_value = 0; 413 break; 414 } 415 416 KFREE(ipe); 417 418 ifs->ifs_ipf_nhtnodes[iph->iph_unit]--; 419 420 return 0; 421 } 422 423 424 void *fr_iphmfindgroup(tptr, version, aptr, ifs) 425 void *tptr; 426 int version; 427 void *aptr; 428 ipf_stack_t *ifs; 429 { 430 i6addr_t *addr; 431 iphtable_t *iph; 432 iphtent_t *ipe; 433 void *rval; 434 435 if ((version != 4) 436 #ifdef USE_INET6 437 && (version != 6) 438 #endif 439 ) 440 return NULL; 441 442 READ_ENTER(&ifs->ifs_ip_poolrw); 443 iph = tptr; 444 addr = aptr; 445 446 #ifdef USE_INET6 447 if (version == 6) 448 ipe = fr_iphmfind6(iph, &addr->in6); 449 else 450 #endif 451 if (version == 4) 452 ipe = fr_iphmfind(iph, &addr->in4); 453 else 454 ipe = NULL; 455 if (ipe != NULL) 456 rval = ipe->ipe_ptr; 457 else 458 rval = NULL; 459 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 460 return rval; 461 } 462 463 464 /* ------------------------------------------------------------------------ */ 465 /* Function: fr_iphmfindip */ 466 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 467 /* Parameters: tptr(I) - pointer to the pool to search */ 468 /* version(I) - IP protocol version (4 or 6) */ 469 /* aptr(I) - pointer to address information */ 470 /* */ 471 /* Search the hash table for a given address and return a search result. */ 472 /* ------------------------------------------------------------------------ */ 473 int fr_iphmfindip(tptr, version, aptr, ifs) 474 void *tptr, *aptr; 475 int version; 476 ipf_stack_t *ifs; 477 { 478 i6addr_t *addr; 479 iphtable_t *iph; 480 iphtent_t *ipe; 481 int rval; 482 483 if ((version != 4) 484 #ifdef USE_INET6 485 && (version != 6) 486 #endif 487 ) 488 return -1; 489 490 if (tptr == NULL || aptr == NULL) 491 return -1; 492 493 iph = tptr; 494 addr = aptr; 495 496 READ_ENTER(&ifs->ifs_ip_poolrw); 497 #ifdef USE_INET6 498 if (version == 6) 499 ipe = fr_iphmfind6(iph, &addr->in6); 500 else 501 #endif 502 if (version == 4) 503 ipe = fr_iphmfind(iph, &addr->in4); 504 else 505 ipe = NULL; 506 if (ipe != NULL) 507 rval = 0; 508 else 509 rval = 1; 510 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 511 return rval; 512 } 513 514 515 /* Locks: ip_poolrw */ 516 static iphtent_t *fr_iphmfind(iph, addr) 517 iphtable_t *iph; 518 struct in_addr *addr; 519 { 520 u_32_t hmsk, msk, ips; 521 iphtent_t *ipe; 522 u_int hv; 523 524 hmsk = iph->iph_masks[3]; 525 msk = 0xffffffff; 526 maskloop: 527 ips = ntohl(addr->s_addr) & msk; 528 hv = IPE_HASH_FN(ips, msk, iph->iph_size); 529 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 530 if (ipe->ipe_mask.in4_addr != msk || 531 ipe->ipe_addr.in4_addr != ips) { 532 continue; 533 } 534 break; 535 } 536 537 if ((ipe == NULL) && (hmsk != 0)) { 538 while (hmsk != 0) { 539 msk <<= 1; 540 if (hmsk & 0x80000000) 541 break; 542 hmsk <<= 1; 543 } 544 if (hmsk != 0) { 545 hmsk <<= 1; 546 goto maskloop; 547 } 548 } 549 return ipe; 550 } 551 552 553 #ifdef USE_INET6 554 /* Locks: ip_poolrw */ 555 static iphtent_t *fr_iphmfind6(iph, addr) 556 iphtable_t *iph; 557 struct in6_addr *addr; 558 { 559 u_32_t hmsk[4], msk[4], ips[4], *and; 560 iphtent_t *ipe; 561 u_int hv; 562 563 hmsk[0] = iph->iph_masks[0]; 564 hmsk[1] = iph->iph_masks[1]; 565 hmsk[2] = iph->iph_masks[2]; 566 hmsk[3] = iph->iph_masks[3]; 567 568 msk[0] = 0xffffffff; 569 msk[1] = 0xffffffff; 570 msk[2] = 0xffffffff; 571 msk[3] = 0xffffffff; 572 maskloop: 573 and = (u_32_t *)addr->s6_addr; 574 ips[0] = *and & msk[0]; 575 ips[1] = *(and + 1) & msk[1]; 576 ips[2] = *(and + 2) & msk[2]; 577 ips[3] = *(and + 3) & msk[3]; 578 579 hv = IPE_HASH_FN(sum4((uint32_t *)addr), sum4((uint32_t *)msk), 580 iph->iph_size); 581 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 582 if (bcmp((void *)&ipe->ipe_mask.in6, (void *)msk, 16) || 583 bcmp((void *)&ipe->ipe_addr.in6, (void *)ips, 16)) 584 continue; 585 break; 586 } 587 588 if ((ipe == NULL) && ((hmsk[0] != 0) || 589 (hmsk[1] != 0) || 590 (hmsk[2] != 0) || 591 (hmsk[3] != 0) )) { 592 while ((hmsk[0] != 0) && (hmsk[1] != 0) && 593 (hmsk[2] != 0) && (hmsk[3] != 0)) { 594 left_shift_ipv6((char *)msk); 595 if (hmsk[0] & 0x80000000) 596 break; 597 left_shift_ipv6((char *)hmsk); 598 } 599 if ((hmsk[0] != 0) && (hmsk[1] != 0) && 600 (hmsk[2] != 0) && (hmsk[3] != 0)) { 601 left_shift_ipv6((char *)hmsk); 602 goto maskloop; 603 } 604 } 605 return ipe; 606 } 607 608 609 /* 610 * sum4: ipv6 add -> 4 bytes values 611 */ 612 static uint32_t sum4(add) 613 uint32_t *add; 614 { 615 return (*add + *(add + 1) + *(add + 2) + *(add + 3)); 616 } 617 618 /* 619 * left shift on 128 bits 620 */ 621 static void left_shift_ipv6(data) 622 char *data; 623 { 624 u_32_t *sd; 625 626 sd = (u_32_t *)data; 627 sd[0] <<= 1; 628 if (sd[1] >= 0x80000000) 629 sd[0] += 1; 630 631 sd[1] <<= 1; 632 if (sd[2] >= 0x80000000) 633 sd[1] += 1; 634 635 sd[2] <<= 1; 636 if (sd[3] >= 0x80000000) 637 sd[2] += 1; 638 639 sd[3] <<= 1; 640 } 641 #endif 642 643 int fr_htable_getnext(token, ilp, ifs) 644 ipftoken_t *token; 645 ipflookupiter_t *ilp; 646 ipf_stack_t *ifs; 647 { 648 iphtent_t *node, zn, *nextnode; 649 iphtable_t *iph, zp, *nextiph; 650 int err; 651 652 err = 0; 653 iph = NULL; 654 node = NULL; 655 nextiph = NULL; 656 nextnode = NULL; 657 658 READ_ENTER(&ifs->ifs_ip_poolrw); 659 660 /* 661 * Get "previous" entry from the token and find the next entry. 662 * 663 * If we found an entry, add a reference to it and update the token. 664 * Otherwise, zero out data to be returned and NULL out token. 665 */ 666 switch (ilp->ili_otype) 667 { 668 case IPFLOOKUPITER_LIST : 669 iph = token->ipt_data; 670 if (iph == NULL) { 671 nextiph = ifs->ifs_ipf_htables[(int)ilp->ili_unit]; 672 } else { 673 nextiph = iph->iph_next; 674 } 675 if (nextiph != NULL) { 676 ATOMIC_INC(nextiph->iph_ref); 677 token->ipt_data = nextiph; 678 } else { 679 bzero((char *)&zp, sizeof(zp)); 680 nextiph = &zp; 681 token->ipt_data = NULL; 682 } 683 break; 684 685 case IPFLOOKUPITER_NODE : 686 node = token->ipt_data; 687 if (node == NULL) { 688 iph = fr_findhtable(ilp->ili_unit, ilp->ili_name, ifs); 689 if (iph == NULL) 690 err = ESRCH; 691 else { 692 nextnode = iph->iph_list; 693 } 694 } else { 695 nextnode = node->ipe_snext; 696 } 697 if (nextnode != NULL) { 698 ATOMIC_INC(nextnode->ipe_ref); 699 token->ipt_data = nextnode; 700 } else { 701 bzero((char *)&zn, sizeof(zn)); 702 nextnode = &zn; 703 token->ipt_data = NULL; 704 } 705 break; 706 707 default : 708 err = EINVAL; 709 break; 710 } 711 712 /* 713 * Now that we have ref, it's save to give up lock. 714 */ 715 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 716 if (err != 0) 717 return err; 718 719 /* 720 * Copy out data and clean up references and token as needed. 721 */ 722 switch (ilp->ili_otype) 723 { 724 case IPFLOOKUPITER_LIST : 725 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph)); 726 if (err != 0) 727 err = EFAULT; 728 if (token->ipt_data == NULL) { 729 ipf_freetoken(token, ifs); 730 } else { 731 if (iph != NULL) { 732 WRITE_ENTER(&ifs->ifs_ip_poolrw); 733 fr_derefhtable(iph, ifs); 734 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 735 } 736 if (nextiph->iph_next == NULL) 737 ipf_freetoken(token, ifs); 738 } 739 break; 740 741 case IPFLOOKUPITER_NODE : 742 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 743 if (err != 0) 744 err = EFAULT; 745 if (token->ipt_data == NULL) { 746 ipf_freetoken(token, ifs); 747 } else { 748 if (node != NULL) { 749 WRITE_ENTER(&ifs->ifs_ip_poolrw); 750 fr_derefhtent(node); 751 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 752 } 753 if (nextnode->ipe_snext == NULL) 754 ipf_freetoken(token, ifs); 755 } 756 break; 757 } 758 759 return err; 760 } 761 762 763 void fr_htable_iterderef(otype, unit, data, ifs) 764 u_int otype; 765 int unit; 766 void *data; 767 ipf_stack_t *ifs; 768 { 769 770 if (data == NULL) 771 return; 772 773 if (unit < 0 || unit > IPL_LOGMAX) 774 return; 775 776 switch (otype) 777 { 778 case IPFLOOKUPITER_LIST : 779 WRITE_ENTER(&ifs->ifs_ip_poolrw); 780 fr_derefhtable((iphtable_t *)data, ifs); 781 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 782 break; 783 784 case IPFLOOKUPITER_NODE : 785 WRITE_ENTER(&ifs->ifs_ip_poolrw); 786 fr_derefhtent((iphtent_t *)data); 787 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 788 break; 789 default : 790 break; 791 } 792 } 793 #endif /* IPFILTER_LOOKUP */ 794