1 2 /* 3 * Copyright (C) 2012 by Darren Reed. 4 * 5 * See the IPFILTER.LICENCE file for details on licencing. 6 */ 7 #if defined(KERNEL) || defined(_KERNEL) 8 # undef KERNEL 9 # undef _KERNEL 10 # define KERNEL 1 11 # define _KERNEL 1 12 #endif 13 #include <sys/param.h> 14 #include <sys/types.h> 15 #include <sys/errno.h> 16 #include <sys/time.h> 17 #include <sys/file.h> 18 #if !defined(_KERNEL) 19 # include <stdlib.h> 20 # include <string.h> 21 # define _KERNEL 22 # include <sys/uio.h> 23 # undef _KERNEL 24 #endif 25 #include <sys/socket.h> 26 #if defined(__FreeBSD__) 27 # include <sys/malloc.h> 28 #endif 29 #if defined(__FreeBSD__) 30 # include <sys/cdefs.h> 31 # include <sys/proc.h> 32 #endif 33 #if !defined(__SVR4) 34 # include <sys/mbuf.h> 35 #endif 36 #if defined(_KERNEL) 37 # include <sys/systm.h> 38 #else 39 # include "ipf.h" 40 #endif 41 #include <netinet/in.h> 42 #include <net/if.h> 43 44 #include "netinet/ip_compat.h" 45 #include "netinet/ip_fil.h" 46 #include "netinet/ip_lookup.h" 47 #include "netinet/ip_htable.h" 48 /* END OF INCLUDES */ 49 50 51 # ifdef USE_INET6 52 static iphtent_t *ipf_iphmfind6(iphtable_t *, i6addr_t *); 53 # endif 54 static iphtent_t *ipf_iphmfind(iphtable_t *, struct in_addr *); 55 static int ipf_iphmfindip(ipf_main_softc_t *, void *, int, void *, u_int); 56 static int ipf_htable_clear(ipf_main_softc_t *, void *, iphtable_t *); 57 static int ipf_htable_create(ipf_main_softc_t *, void *, iplookupop_t *); 58 static int ipf_htable_deref(ipf_main_softc_t *, void *, void *); 59 static int ipf_htable_destroy(ipf_main_softc_t *, void *, int, char *); 60 static void *ipf_htable_exists(void *, int, char *); 61 static size_t ipf_htable_flush(ipf_main_softc_t *, void *, 62 iplookupflush_t *); 63 static void ipf_htable_free(void *, iphtable_t *); 64 static int ipf_htable_iter_deref(ipf_main_softc_t *, void *, int, 65 int, void *); 66 static int ipf_htable_iter_next(ipf_main_softc_t *, void *, ipftoken_t *, 67 ipflookupiter_t *); 68 static int ipf_htable_node_add(ipf_main_softc_t *, void *, 69 iplookupop_t *, int); 70 static int ipf_htable_node_del(ipf_main_softc_t *, void *, 71 iplookupop_t *, int); 72 static int ipf_htable_remove(ipf_main_softc_t *, void *, iphtable_t *); 73 static void *ipf_htable_soft_create(ipf_main_softc_t *); 74 static void ipf_htable_soft_destroy(ipf_main_softc_t *, void *); 75 static int ipf_htable_soft_init(ipf_main_softc_t *, void *); 76 static void ipf_htable_soft_fini(ipf_main_softc_t *, void *); 77 static int ipf_htable_stats_get(ipf_main_softc_t *, void *, 78 iplookupop_t *); 79 static int ipf_htable_table_add(ipf_main_softc_t *, void *, 80 iplookupop_t *); 81 static int ipf_htable_table_del(ipf_main_softc_t *, void *, 82 iplookupop_t *); 83 static int ipf_htent_deref(void *, iphtent_t *); 84 static iphtent_t *ipf_htent_find(iphtable_t *, iphtent_t *); 85 static int ipf_htent_insert(ipf_main_softc_t *, void *, iphtable_t *, 86 iphtent_t *); 87 static int ipf_htent_remove(ipf_main_softc_t *, void *, iphtable_t *, 88 iphtent_t *); 89 static void *ipf_htable_select_add_ref(void *, int, char *); 90 static void ipf_htable_expire(ipf_main_softc_t *, void *); 91 92 93 typedef struct ipf_htable_softc_s { 94 u_long ipht_nomem[LOOKUP_POOL_SZ]; 95 u_long ipf_nhtables[LOOKUP_POOL_SZ]; 96 u_long ipf_nhtnodes[LOOKUP_POOL_SZ]; 97 iphtable_t *ipf_htables[LOOKUP_POOL_SZ]; 98 iphtent_t *ipf_node_explist; 99 } ipf_htable_softc_t; 100 101 ipf_lookup_t ipf_htable_backend = { 102 IPLT_HASH, 103 ipf_htable_soft_create, 104 ipf_htable_soft_destroy, 105 ipf_htable_soft_init, 106 ipf_htable_soft_fini, 107 ipf_iphmfindip, 108 ipf_htable_flush, 109 ipf_htable_iter_deref, 110 ipf_htable_iter_next, 111 ipf_htable_node_add, 112 ipf_htable_node_del, 113 ipf_htable_stats_get, 114 ipf_htable_table_add, 115 ipf_htable_table_del, 116 ipf_htable_deref, 117 ipf_htable_exists, 118 ipf_htable_select_add_ref, 119 NULL, 120 ipf_htable_expire, 121 NULL 122 }; 123 124 125 /* ------------------------------------------------------------------------ */ 126 /* Function: ipf_htable_soft_create */ 127 /* Returns: void * - NULL = failure, else pointer to local context */ 128 /* Parameters: softc(I) - pointer to soft context main structure */ 129 /* */ 130 /* Initialise the routing table data structures where required. */ 131 /* ------------------------------------------------------------------------ */ 132 static void * 133 ipf_htable_soft_create(ipf_main_softc_t *softc) 134 { 135 ipf_htable_softc_t *softh; 136 137 KMALLOC(softh, ipf_htable_softc_t *); 138 if (softh == NULL) { 139 IPFERROR(30026); 140 return (NULL); 141 } 142 143 bzero((char *)softh, sizeof(*softh)); 144 145 return (softh); 146 } 147 148 149 /* ------------------------------------------------------------------------ */ 150 /* Function: ipf_htable_soft_destroy */ 151 /* Returns: Nil */ 152 /* Parameters: softc(I) - pointer to soft context main structure */ 153 /* arg(I) - pointer to local context to use */ 154 /* */ 155 /* Clean up the pool by free'ing the radix tree associated with it and free */ 156 /* up the pool context too. */ 157 /* ------------------------------------------------------------------------ */ 158 static void 159 ipf_htable_soft_destroy(ipf_main_softc_t *softc, void *arg) 160 { 161 ipf_htable_softc_t *softh = arg; 162 163 KFREE(softh); 164 } 165 166 167 /* ------------------------------------------------------------------------ */ 168 /* Function: ipf_htable_soft_init */ 169 /* Returns: int - 0 = success, else error */ 170 /* Parameters: softc(I) - pointer to soft context main structure */ 171 /* arg(I) - pointer to local context to use */ 172 /* */ 173 /* Initialise the hash table ready for use. */ 174 /* ------------------------------------------------------------------------ */ 175 static int 176 ipf_htable_soft_init(ipf_main_softc_t *softc, void *arg) 177 { 178 ipf_htable_softc_t *softh = arg; 179 180 bzero((char *)softh, sizeof(*softh)); 181 182 return (0); 183 } 184 185 186 /* ------------------------------------------------------------------------ */ 187 /* Function: ipf_htable_soft_fini */ 188 /* Returns: Nil */ 189 /* Parameters: softc(I) - pointer to soft context main structure */ 190 /* arg(I) - pointer to local context to use */ 191 /* Locks: WRITE(ipf_global) */ 192 /* */ 193 /* Clean up all the pool data structures allocated and call the cleanup */ 194 /* function for the radix tree that supports the pools. ipf_pool_destroy is */ 195 /* used to delete the pools one by one to ensure they're properly freed up. */ 196 /* ------------------------------------------------------------------------ */ 197 static void 198 ipf_htable_soft_fini(ipf_main_softc_t *softc, void *arg) 199 { 200 iplookupflush_t fop; 201 202 fop.iplf_type = IPLT_HASH; 203 fop.iplf_unit = IPL_LOGALL; 204 fop.iplf_arg = 0; 205 fop.iplf_count = 0; 206 *fop.iplf_name = '\0'; 207 ipf_htable_flush(softc, arg, &fop); 208 } 209 210 211 /* ------------------------------------------------------------------------ */ 212 /* Function: ipf_htable_stats_get */ 213 /* Returns: int - 0 = success, else error */ 214 /* Parameters: softc(I) - pointer to soft context main structure */ 215 /* arg(I) - pointer to local context to use */ 216 /* op(I) - pointer to lookup operation data */ 217 /* */ 218 /* Copy the relevant statistics out of internal structures and into the */ 219 /* structure used to export statistics. */ 220 /* ------------------------------------------------------------------------ */ 221 static int 222 ipf_htable_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) 223 { 224 ipf_htable_softc_t *softh = arg; 225 iphtstat_t stats; 226 int err; 227 228 if (op->iplo_size != sizeof(stats)) { 229 IPFERROR(30001); 230 return (EINVAL); 231 } 232 233 stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1]; 234 stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1]; 235 stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1]; 236 stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1]; 237 238 err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); 239 if (err != 0) { 240 IPFERROR(30013); 241 return (EFAULT); 242 } 243 return (0); 244 245 } 246 247 248 /* ------------------------------------------------------------------------ */ 249 /* Function: ipf_htable_create */ 250 /* Returns: int - 0 = success, else error */ 251 /* Parameters: softc(I) - pointer to soft context main structure */ 252 /* arg(I) - pointer to local context to use */ 253 /* op(I) - pointer to lookup operation data */ 254 /* */ 255 /* Create a new hash table using the template passed. */ 256 /* ------------------------------------------------------------------------ */ 257 static int 258 ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) 259 { 260 ipf_htable_softc_t *softh = arg; 261 iphtable_t htab, *iph, *oiph; 262 char name[FR_GROUPLEN]; 263 int err, i, unit; 264 265 if (op->iplo_size != sizeof(htab)) { 266 IPFERROR(30024); 267 return (EINVAL); 268 } 269 err = COPYIN(op->iplo_struct, &htab, sizeof(htab)); 270 if (err != 0) { 271 IPFERROR(30003); 272 return (EFAULT); 273 } 274 275 unit = op->iplo_unit; 276 if (htab.iph_unit != unit) { 277 IPFERROR(30005); 278 return (EINVAL); 279 } 280 if (htab.iph_size < 1) { 281 IPFERROR(30025); 282 return (EINVAL); 283 } 284 285 286 if ((op->iplo_arg & IPHASH_ANON) == 0) { 287 iph = ipf_htable_exists(softh, unit, op->iplo_name); 288 if (iph != NULL) { 289 if ((iph->iph_flags & IPHASH_DELETE) == 0) { 290 IPFERROR(30004); 291 return (EEXIST); 292 } 293 iph->iph_flags &= ~IPHASH_DELETE; 294 iph->iph_ref++; 295 return (0); 296 } 297 } 298 299 KMALLOC(iph, iphtable_t *); 300 if (iph == NULL) { 301 softh->ipht_nomem[op->iplo_unit + 1]++; 302 IPFERROR(30002); 303 return (ENOMEM); 304 } 305 *iph = htab; 306 307 if ((op->iplo_arg & IPHASH_ANON) != 0) { 308 i = IPHASH_ANON; 309 do { 310 i++; 311 (void)snprintf(name, sizeof(name), "%u", i); 312 for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL; 313 oiph = oiph->iph_next) 314 if (strncmp(oiph->iph_name, name, 315 sizeof(oiph->iph_name)) == 0) 316 break; 317 } while (oiph != NULL); 318 319 (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); 320 (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); 321 iph->iph_type |= IPHASH_ANON; 322 } else { 323 (void)strncpy(iph->iph_name, op->iplo_name, 324 sizeof(iph->iph_name)); 325 iph->iph_name[sizeof(iph->iph_name) - 1] = '\0'; 326 } 327 328 KMALLOCS(iph->iph_table, iphtent_t **, 329 iph->iph_size * sizeof(*iph->iph_table)); 330 if (iph->iph_table == NULL) { 331 KFREE(iph); 332 softh->ipht_nomem[unit + 1]++; 333 IPFERROR(30006); 334 return (ENOMEM); 335 } 336 337 bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 338 iph->iph_maskset[0] = 0; 339 iph->iph_maskset[1] = 0; 340 iph->iph_maskset[2] = 0; 341 iph->iph_maskset[3] = 0; 342 343 iph->iph_ref = 1; 344 iph->iph_list = NULL; 345 iph->iph_tail = &iph->iph_list; 346 iph->iph_next = softh->ipf_htables[unit + 1]; 347 iph->iph_pnext = &softh->ipf_htables[unit + 1]; 348 if (softh->ipf_htables[unit + 1] != NULL) 349 softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next; 350 softh->ipf_htables[unit + 1] = iph; 351 352 softh->ipf_nhtables[unit + 1]++; 353 354 return (0); 355 } 356 357 358 /* ------------------------------------------------------------------------ */ 359 /* Function: ipf_htable_table_del */ 360 /* Returns: int - 0 = success, else error */ 361 /* Parameters: softc(I) - pointer to soft context main structure */ 362 /* arg(I) - pointer to local context to use */ 363 /* op(I) - pointer to lookup operation data */ 364 /* */ 365 /* ------------------------------------------------------------------------ */ 366 static int 367 ipf_htable_table_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) 368 { 369 return (ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name)); 370 } 371 372 373 /* ------------------------------------------------------------------------ */ 374 /* Function: ipf_htable_destroy */ 375 /* Returns: int - 0 = success, else error */ 376 /* Parameters: softc(I) - pointer to soft context main structure */ 377 /* arg(I) - pointer to local context to use */ 378 /* op(I) - pointer to lookup operation data */ 379 /* */ 380 /* Find the hash table that belongs to the relevant part of ipfilter with a */ 381 /* matching name and attempt to destroy it. If it is in use, empty it out */ 382 /* and mark it for deletion so that when all the references disappear, it */ 383 /* can be removed. */ 384 /* ------------------------------------------------------------------------ */ 385 static int 386 ipf_htable_destroy(ipf_main_softc_t *softc, void *arg, int unit, char *name) 387 { 388 iphtable_t *iph; 389 390 iph = ipf_htable_find(arg, unit, name); 391 if (iph == NULL) { 392 IPFERROR(30007); 393 return (ESRCH); 394 } 395 396 if (iph->iph_unit != unit) { 397 IPFERROR(30008); 398 return (EINVAL); 399 } 400 401 if (iph->iph_ref != 0) { 402 ipf_htable_clear(softc, arg, iph); 403 iph->iph_flags |= IPHASH_DELETE; 404 return (0); 405 } 406 407 ipf_htable_remove(softc, arg, iph); 408 409 return (0); 410 } 411 412 413 /* ------------------------------------------------------------------------ */ 414 /* Function: ipf_htable_clear */ 415 /* Returns: int - 0 = success, else error */ 416 /* Parameters: softc(I) - pointer to soft context main structure */ 417 /* arg(I) - pointer to local context to use */ 418 /* iph(I) - pointer to hash table to destroy */ 419 /* */ 420 /* Clean out the hash table by walking the list of entries and removing */ 421 /* each one, one by one. */ 422 /* ------------------------------------------------------------------------ */ 423 static int 424 ipf_htable_clear(ipf_main_softc_t *softc, void *arg, iphtable_t *iph) 425 { 426 iphtent_t *ipe; 427 428 while ((ipe = iph->iph_list) != NULL) 429 if (ipf_htent_remove(softc, arg, iph, ipe) != 0) 430 return (1); 431 return (0); 432 } 433 434 435 /* ------------------------------------------------------------------------ */ 436 /* Function: ipf_htable_free */ 437 /* Returns: Nil */ 438 /* Parameters: arg(I) - pointer to local context to use */ 439 /* iph(I) - pointer to hash table to destroy */ 440 /* */ 441 /* ------------------------------------------------------------------------ */ 442 static void 443 ipf_htable_free(void *arg, iphtable_t *iph) 444 { 445 ipf_htable_softc_t *softh = arg; 446 447 if (iph->iph_next != NULL) 448 iph->iph_next->iph_pnext = iph->iph_pnext; 449 if (iph->iph_pnext != NULL) 450 *iph->iph_pnext = iph->iph_next; 451 iph->iph_pnext = NULL; 452 iph->iph_next = NULL; 453 454 softh->ipf_nhtables[iph->iph_unit + 1]--; 455 456 KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); 457 KFREE(iph); 458 } 459 460 461 /* ------------------------------------------------------------------------ */ 462 /* Function: ipf_htable_remove */ 463 /* Returns: int - 0 = success, else error */ 464 /* Parameters: softc(I) - pointer to soft context main structure */ 465 /* arg(I) - pointer to local context to use */ 466 /* iph(I) - pointer to hash table to destroy */ 467 /* */ 468 /* It is necessary to unlink here as well as free (called by deref) so that */ 469 /* the while loop in ipf_htable_flush() functions properly. */ 470 /* ------------------------------------------------------------------------ */ 471 static int 472 ipf_htable_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph) 473 { 474 475 if (ipf_htable_clear(softc, arg, iph) != 0) 476 return (1); 477 478 if (iph->iph_pnext != NULL) 479 *iph->iph_pnext = iph->iph_next; 480 if (iph->iph_next != NULL) 481 iph->iph_next->iph_pnext = iph->iph_pnext; 482 iph->iph_pnext = NULL; 483 iph->iph_next = NULL; 484 485 return (ipf_htable_deref(softc, arg, iph)); 486 } 487 488 489 /* ------------------------------------------------------------------------ */ 490 /* Function: ipf_htable_node_del */ 491 /* Returns: int - 0 = success, else error */ 492 /* Parameters: softc(I) - pointer to soft context main structure */ 493 /* arg(I) - pointer to local context to use */ 494 /* op(I) - pointer to lookup operation data */ 495 /* uid(I) - real uid of process doing operation */ 496 /* */ 497 /* ------------------------------------------------------------------------ */ 498 static int 499 ipf_htable_node_del(ipf_main_softc_t *softc, void *arg, iplookupop_t *op, 500 int uid) 501 { 502 iphtable_t *iph; 503 iphtent_t hte, *ent; 504 int err; 505 506 if (op->iplo_size != sizeof(hte)) { 507 IPFERROR(30014); 508 return (EINVAL); 509 } 510 511 err = COPYIN(op->iplo_struct, &hte, sizeof(hte)); 512 if (err != 0) { 513 IPFERROR(30015); 514 return (EFAULT); 515 } 516 517 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name); 518 if (iph == NULL) { 519 IPFERROR(30016); 520 return (ESRCH); 521 } 522 523 ent = ipf_htent_find(iph, &hte); 524 if (ent == NULL) { 525 IPFERROR(30022); 526 return (ESRCH); 527 } 528 529 if ((uid != 0) && (ent->ipe_uid != uid)) { 530 IPFERROR(30023); 531 return (EACCES); 532 } 533 534 err = ipf_htent_remove(softc, arg, iph, ent); 535 536 return (err); 537 } 538 539 540 /* ------------------------------------------------------------------------ */ 541 /* Function: ipf_htable_node_del */ 542 /* Returns: int - 0 = success, else error */ 543 /* Parameters: softc(I) - pointer to soft context main structure */ 544 /* arg(I) - pointer to local context to use */ 545 /* op(I) - pointer to lookup operation data */ 546 /* */ 547 /* ------------------------------------------------------------------------ */ 548 static int 549 ipf_htable_table_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op) 550 { 551 int err; 552 553 if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) { 554 IPFERROR(30017); 555 err = EEXIST; 556 } else { 557 err = ipf_htable_create(softc, arg, op); 558 } 559 560 return (err); 561 } 562 563 564 /* ------------------------------------------------------------------------ */ 565 /* Function: ipf_htent_remove */ 566 /* Returns: int - 0 = success, else error */ 567 /* Parameters: softc(I) - pointer to soft context main structure */ 568 /* arg(I) - pointer to local context to use */ 569 /* iph(I) - pointer to hash table */ 570 /* ipe(I) - pointer to hash table entry to remove */ 571 /* */ 572 /* Delete an entry from a hash table. */ 573 /* ------------------------------------------------------------------------ */ 574 static int 575 ipf_htent_remove(ipf_main_softc_t *softc, void *arg, iphtable_t *iph, 576 iphtent_t *ipe) 577 { 578 579 if (iph->iph_tail == &ipe->ipe_next) 580 iph->iph_tail = ipe->ipe_pnext; 581 582 if (ipe->ipe_hnext != NULL) 583 ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext; 584 if (ipe->ipe_phnext != NULL) 585 *ipe->ipe_phnext = ipe->ipe_hnext; 586 ipe->ipe_phnext = NULL; 587 ipe->ipe_hnext = NULL; 588 589 if (ipe->ipe_dnext != NULL) 590 ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext; 591 if (ipe->ipe_pdnext != NULL) 592 *ipe->ipe_pdnext = ipe->ipe_dnext; 593 ipe->ipe_pdnext = NULL; 594 ipe->ipe_dnext = NULL; 595 596 if (ipe->ipe_next != NULL) 597 ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; 598 if (ipe->ipe_pnext != NULL) 599 *ipe->ipe_pnext = ipe->ipe_next; 600 ipe->ipe_pnext = NULL; 601 ipe->ipe_next = NULL; 602 603 switch (iph->iph_type & ~IPHASH_ANON) 604 { 605 case IPHASH_GROUPMAP : 606 if (ipe->ipe_group != NULL) 607 ipf_group_del(softc, ipe->ipe_ptr, NULL); 608 break; 609 610 default : 611 ipe->ipe_ptr = NULL; 612 ipe->ipe_value = 0; 613 break; 614 } 615 616 return (ipf_htent_deref(arg, ipe)); 617 } 618 619 620 /* ------------------------------------------------------------------------ */ 621 /* Function: ipf_htable_deref */ 622 /* Returns: int - 0 = success, else error */ 623 /* Parameters: softc(I) - pointer to soft context main structure */ 624 /* arg(I) - pointer to local context to use */ 625 /* object(I) - pointer to hash table */ 626 /* */ 627 /* ------------------------------------------------------------------------ */ 628 static int 629 ipf_htable_deref(ipf_main_softc_t *softc, void *arg, void *object) 630 { 631 ipf_htable_softc_t *softh = arg; 632 iphtable_t *iph = object; 633 int refs; 634 635 iph->iph_ref--; 636 refs = iph->iph_ref; 637 638 if (iph->iph_ref == 0) { 639 ipf_htable_free(softh, iph); 640 } 641 642 return (refs); 643 } 644 645 646 /* ------------------------------------------------------------------------ */ 647 /* Function: ipf_htent_deref */ 648 /* Parameters: arg(I) - pointer to local context to use */ 649 /* ipe(I) - */ 650 /* */ 651 /* ------------------------------------------------------------------------ */ 652 static int 653 ipf_htent_deref(void *arg, iphtent_t *ipe) 654 { 655 ipf_htable_softc_t *softh = arg; 656 657 ipe->ipe_ref--; 658 if (ipe->ipe_ref == 0) { 659 softh->ipf_nhtnodes[ipe->ipe_unit + 1]--; 660 KFREE(ipe); 661 662 return (0); 663 } 664 665 return (ipe->ipe_ref); 666 } 667 668 669 /* ------------------------------------------------------------------------ */ 670 /* Function: ipf_htable_exists */ 671 /* Parameters: arg(I) - pointer to local context to use */ 672 /* */ 673 /* ------------------------------------------------------------------------ */ 674 static void * 675 ipf_htable_exists(void *arg, int unit, char *name) 676 { 677 ipf_htable_softc_t *softh = arg; 678 iphtable_t *iph; 679 680 if (unit == IPL_LOGALL) { 681 int i; 682 683 for (i = 0; i <= LOOKUP_POOL_MAX; i++) { 684 for (iph = softh->ipf_htables[i]; iph != NULL; 685 iph = iph->iph_next) { 686 if (strncmp(iph->iph_name, name, 687 sizeof(iph->iph_name)) == 0) 688 break; 689 } 690 if (iph != NULL) 691 break; 692 } 693 } else { 694 for (iph = softh->ipf_htables[unit + 1]; iph != NULL; 695 iph = iph->iph_next) { 696 if (strncmp(iph->iph_name, name, 697 sizeof(iph->iph_name)) == 0) 698 break; 699 } 700 } 701 return (iph); 702 } 703 704 705 /* ------------------------------------------------------------------------ */ 706 /* Function: ipf_htable_select_add_ref */ 707 /* Returns: void * - NULL = failure, else pointer to the hash table */ 708 /* Parameters: arg(I) - pointer to local context to use */ 709 /* unit(I) - ipfilter device to which we are working on */ 710 /* name(I) - name of the hash table */ 711 /* */ 712 /* ------------------------------------------------------------------------ */ 713 static void * 714 ipf_htable_select_add_ref(void *arg, int unit, char *name) 715 { 716 iphtable_t *iph; 717 718 iph = ipf_htable_exists(arg, unit, name); 719 if (iph != NULL) { 720 ATOMIC_INC32(iph->iph_ref); 721 } 722 return (iph); 723 } 724 725 726 /* ------------------------------------------------------------------------ */ 727 /* Function: ipf_htable_find */ 728 /* Returns: void * - NULL = failure, else pointer to the hash table */ 729 /* Parameters: arg(I) - pointer to local context to use */ 730 /* unit(I) - ipfilter device to which we are working on */ 731 /* name(I) - name of the hash table */ 732 /* */ 733 /* This function is exposed becaues it is used in the group-map feature. */ 734 /* ------------------------------------------------------------------------ */ 735 iphtable_t * 736 ipf_htable_find(void *arg, int unit, char *name) 737 { 738 iphtable_t *iph; 739 740 iph = ipf_htable_exists(arg, unit, name); 741 if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0) 742 return (iph); 743 744 return (NULL); 745 } 746 747 748 /* ------------------------------------------------------------------------ */ 749 /* Function: ipf_htable_flush */ 750 /* Returns: size_t - number of entries flushed */ 751 /* Parameters: softc(I) - pointer to soft context main structure */ 752 /* arg(I) - pointer to local context to use */ 753 /* op(I) - pointer to lookup operation data */ 754 /* */ 755 /* ------------------------------------------------------------------------ */ 756 static size_t 757 ipf_htable_flush(ipf_main_softc_t *softc, void *arg, iplookupflush_t *op) 758 { 759 ipf_htable_softc_t *softh = arg; 760 iphtable_t *iph; 761 size_t freed; 762 int i; 763 764 freed = 0; 765 766 for (i = -1; i <= IPL_LOGMAX; i++) { 767 if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { 768 while ((iph = softh->ipf_htables[i + 1]) != NULL) { 769 if (ipf_htable_remove(softc, arg, iph) == 0) { 770 freed++; 771 } else { 772 iph->iph_flags |= IPHASH_DELETE; 773 } 774 } 775 } 776 } 777 778 return (freed); 779 } 780 781 782 /* ------------------------------------------------------------------------ */ 783 /* Function: ipf_htable_node_add */ 784 /* Returns: int - 0 = success, else error */ 785 /* Parameters: softc(I) - pointer to soft context main structure */ 786 /* arg(I) - pointer to local context to use */ 787 /* op(I) - pointer to lookup operation data */ 788 /* uid(I) - real uid of process doing operation */ 789 /* */ 790 /* ------------------------------------------------------------------------ */ 791 static int 792 ipf_htable_node_add(ipf_main_softc_t *softc, void *arg, iplookupop_t *op, 793 int uid) 794 { 795 iphtable_t *iph; 796 iphtent_t hte; 797 int err; 798 799 if (op->iplo_size != sizeof(hte)) { 800 IPFERROR(30018); 801 return (EINVAL); 802 } 803 804 err = COPYIN(op->iplo_struct, &hte, sizeof(hte)); 805 if (err != 0) { 806 IPFERROR(30019); 807 return (EFAULT); 808 } 809 hte.ipe_uid = uid; 810 811 iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name); 812 if (iph == NULL) { 813 IPFERROR(30020); 814 return (ESRCH); 815 } 816 817 if (ipf_htent_find(iph, &hte) != NULL) { 818 IPFERROR(30021); 819 return (EEXIST); 820 } 821 822 err = ipf_htent_insert(softc, arg, iph, &hte); 823 824 return (err); 825 } 826 827 828 /* ------------------------------------------------------------------------ */ 829 /* Function: ipf_htent_insert */ 830 /* Returns: int - 0 = success, -1 = error */ 831 /* Parameters: softc(I) - pointer to soft context main structure */ 832 /* arg(I) - pointer to local context to use */ 833 /* op(I) - pointer to lookup operation data */ 834 /* ipeo(I) - */ 835 /* */ 836 /* Add an entry to a hash table. */ 837 /* ------------------------------------------------------------------------ */ 838 static int 839 ipf_htent_insert(ipf_main_softc_t *softc, void *arg, iphtable_t *iph, 840 iphtent_t *ipeo) 841 { 842 ipf_htable_softc_t *softh = arg; 843 iphtent_t *ipe; 844 u_int hv; 845 int bits; 846 847 KMALLOC(ipe, iphtent_t *); 848 if (ipe == NULL) 849 return (-1); 850 851 bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); 852 ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0]; 853 if (ipe->ipe_family == AF_INET) { 854 bits = count4bits(ipe->ipe_mask.in4_addr); 855 ipe->ipe_addr.i6[1] = 0; 856 ipe->ipe_addr.i6[2] = 0; 857 ipe->ipe_addr.i6[3] = 0; 858 ipe->ipe_mask.i6[1] = 0; 859 ipe->ipe_mask.i6[2] = 0; 860 ipe->ipe_mask.i6[3] = 0; 861 hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr, 862 ipe->ipe_mask.in4_addr, iph->iph_size); 863 } else 864 #ifdef USE_INET6 865 if (ipe->ipe_family == AF_INET6) { 866 ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1]; 867 ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2]; 868 ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3]; 869 870 bits = count6bits(ipe->ipe_mask.i6); 871 hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6, 872 ipe->ipe_mask.i6, iph->iph_size); 873 } else 874 #endif 875 { 876 KFREE(ipe); 877 return (-1); 878 } 879 880 ipe->ipe_owner = iph; 881 ipe->ipe_ref = 1; 882 ipe->ipe_hnext = iph->iph_table[hv]; 883 ipe->ipe_phnext = iph->iph_table + hv; 884 885 if (iph->iph_table[hv] != NULL) 886 iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext; 887 iph->iph_table[hv] = ipe; 888 889 ipe->ipe_pnext = iph->iph_tail; 890 *iph->iph_tail = ipe; 891 iph->iph_tail = &ipe->ipe_next; 892 ipe->ipe_next = NULL; 893 894 if (ipe->ipe_die != 0) { 895 /* 896 * If the new node has a given expiration time, insert it 897 * into the list of expiring nodes with the ones to be 898 * removed first added to the front of the list. The 899 * insertion is O(n) but it is kept sorted for quick scans 900 * at expiration interval checks. 901 */ 902 iphtent_t *n; 903 904 ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die); 905 for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) { 906 if (ipe->ipe_die < n->ipe_die) 907 break; 908 if (n->ipe_dnext == NULL) { 909 /* 910 * We've got to the last node and everything 911 * wanted to be expired before this new node, 912 * so we have to tack it on the end... 913 */ 914 n->ipe_dnext = ipe; 915 ipe->ipe_pdnext = &n->ipe_dnext; 916 n = NULL; 917 break; 918 } 919 } 920 921 if (softh->ipf_node_explist == NULL) { 922 softh->ipf_node_explist = ipe; 923 ipe->ipe_pdnext = &softh->ipf_node_explist; 924 } else if (n != NULL) { 925 ipe->ipe_dnext = n; 926 ipe->ipe_pdnext = n->ipe_pdnext; 927 n->ipe_pdnext = &ipe->ipe_dnext; 928 } 929 } 930 931 if (ipe->ipe_family == AF_INET) { 932 ipf_inet_mask_add(bits, &iph->iph_v4_masks); 933 } 934 #ifdef USE_INET6 935 else if (ipe->ipe_family == AF_INET6) { 936 ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks); 937 } 938 #endif 939 940 switch (iph->iph_type & ~IPHASH_ANON) 941 { 942 case IPHASH_GROUPMAP : 943 ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL, 944 iph->iph_flags, IPL_LOGIPF, 945 softc->ipf_active); 946 break; 947 948 default : 949 ipe->ipe_ptr = NULL; 950 ipe->ipe_value = 0; 951 break; 952 } 953 954 ipe->ipe_unit = iph->iph_unit; 955 softh->ipf_nhtnodes[ipe->ipe_unit + 1]++; 956 957 return (0); 958 } 959 960 961 /* ------------------------------------------------------------------------ */ 962 /* Function: ipf_htent_find */ 963 /* Returns: int - 0 = success, else error */ 964 /* Parameters: iph(I) - pointer to table to search */ 965 /* ipeo(I) - pointer to entry to find */ 966 /* */ 967 /* While it isn't absolutely necessary to for the address and mask to be */ 968 /* passed in through an iphtent_t structure, one is always present when it */ 969 /* is time to call this function, so it is just more convenient. */ 970 /* ------------------------------------------------------------------------ */ 971 static iphtent_t * 972 ipf_htent_find(iphtable_t *iph, iphtent_t *ipeo) 973 { 974 iphtent_t ipe, *ent; 975 u_int hv; 976 int bits; 977 978 bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe)); 979 ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0]; 980 ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1]; 981 ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2]; 982 ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3]; 983 if (ipe.ipe_family == AF_INET) { 984 bits = count4bits(ipe.ipe_mask.in4_addr); 985 ipe.ipe_addr.i6[1] = 0; 986 ipe.ipe_addr.i6[2] = 0; 987 ipe.ipe_addr.i6[3] = 0; 988 ipe.ipe_mask.i6[1] = 0; 989 ipe.ipe_mask.i6[2] = 0; 990 ipe.ipe_mask.i6[3] = 0; 991 hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr, 992 ipe.ipe_mask.in4_addr, iph->iph_size); 993 } else 994 #ifdef USE_INET6 995 if (ipe.ipe_family == AF_INET6) { 996 bits = count6bits(ipe.ipe_mask.i6); 997 hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6, 998 ipe.ipe_mask.i6, iph->iph_size); 999 } else 1000 #endif 1001 return (NULL); 1002 1003 for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) { 1004 if (ent->ipe_family != ipe.ipe_family) 1005 continue; 1006 if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr)) 1007 continue; 1008 if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask)) 1009 continue; 1010 break; 1011 } 1012 1013 return (ent); 1014 } 1015 1016 1017 /* ------------------------------------------------------------------------ */ 1018 /* Function: ipf_iphmfindgroup */ 1019 /* Returns: int - 0 = success, else error */ 1020 /* Parameters: softc(I) - pointer to soft context main structure */ 1021 /* tptr(I) - */ 1022 /* aptr(I) - */ 1023 /* */ 1024 /* Search a hash table for a matching entry and return the pointer stored */ 1025 /* in it for use as the next group of rules to search. */ 1026 /* */ 1027 /* This function is exposed becaues it is used in the group-map feature. */ 1028 /* ------------------------------------------------------------------------ */ 1029 void * 1030 ipf_iphmfindgroup(ipf_main_softc_t *softc, void *tptr, void *aptr) 1031 { 1032 struct in_addr *addr; 1033 iphtable_t *iph; 1034 iphtent_t *ipe; 1035 void *rval; 1036 1037 READ_ENTER(&softc->ipf_poolrw); 1038 iph = tptr; 1039 addr = aptr; 1040 1041 ipe = ipf_iphmfind(iph, addr); 1042 if (ipe != NULL) 1043 rval = ipe->ipe_ptr; 1044 else 1045 rval = NULL; 1046 RWLOCK_EXIT(&softc->ipf_poolrw); 1047 return (rval); 1048 } 1049 1050 1051 /* ------------------------------------------------------------------------ */ 1052 /* Function: ipf_iphmfindip */ 1053 /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ 1054 /* Parameters: softc(I) - pointer to soft context main structure */ 1055 /* tptr(I) - pointer to the pool to search */ 1056 /* ipversion(I) - IP protocol version (4 or 6) */ 1057 /* aptr(I) - pointer to address information */ 1058 /* bytes(I) - packet length */ 1059 /* */ 1060 /* Search the hash table for a given address and return a search result. */ 1061 /* ------------------------------------------------------------------------ */ 1062 static int 1063 ipf_iphmfindip(ipf_main_softc_t *softc, void *tptr, int ipversion, void *aptr, 1064 u_int bytes) 1065 { 1066 struct in_addr *addr; 1067 iphtable_t *iph; 1068 iphtent_t *ipe; 1069 int rval; 1070 1071 if (tptr == NULL || aptr == NULL) 1072 return (-1); 1073 1074 iph = tptr; 1075 addr = aptr; 1076 1077 READ_ENTER(&softc->ipf_poolrw); 1078 if (ipversion == 4) { 1079 ipe = ipf_iphmfind(iph, addr); 1080 #ifdef USE_INET6 1081 } else if (ipversion == 6) { 1082 ipe = ipf_iphmfind6(iph, (i6addr_t *)addr); 1083 #endif 1084 } else { 1085 ipe = NULL; 1086 } 1087 1088 if (ipe != NULL) { 1089 rval = 0; 1090 ipe->ipe_hits++; 1091 ipe->ipe_bytes += bytes; 1092 } else { 1093 rval = 1; 1094 } 1095 RWLOCK_EXIT(&softc->ipf_poolrw); 1096 return (rval); 1097 } 1098 1099 1100 /* ------------------------------------------------------------------------ */ 1101 /* Function: ipf_iphmfindip */ 1102 /* Parameters: iph(I) - pointer to hash table */ 1103 /* addr(I) - pointer to IPv4 address */ 1104 /* Locks: ipf_poolrw */ 1105 /* */ 1106 /* ------------------------------------------------------------------------ */ 1107 static iphtent_t * 1108 ipf_iphmfind(iphtable_t *iph, struct in_addr *addr) 1109 { 1110 u_32_t msk, ips; 1111 iphtent_t *ipe; 1112 u_int hv; 1113 int i; 1114 1115 i = 0; 1116 maskloop: 1117 msk = iph->iph_v4_masks.imt4_active[i]; 1118 ips = addr->s_addr & msk; 1119 hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size); 1120 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) { 1121 if ((ipe->ipe_family != AF_INET) || 1122 (ipe->ipe_mask.in4_addr != msk) || 1123 (ipe->ipe_addr.in4_addr != ips)) { 1124 continue; 1125 } 1126 break; 1127 } 1128 1129 if (ipe == NULL) { 1130 i++; 1131 if (i < iph->iph_v4_masks.imt4_max) 1132 goto maskloop; 1133 } 1134 return (ipe); 1135 } 1136 1137 1138 /* ------------------------------------------------------------------------ */ 1139 /* Function: ipf_htable_iter_next */ 1140 /* Returns: int - 0 = success, else error */ 1141 /* Parameters: softc(I) - pointer to soft context main structure */ 1142 /* arg(I) - pointer to local context to use */ 1143 /* token(I) - */ 1144 /* ilp(I) - */ 1145 /* */ 1146 /* ------------------------------------------------------------------------ */ 1147 static int 1148 ipf_htable_iter_next(ipf_main_softc_t *softc, void *arg, ipftoken_t *token, 1149 ipflookupiter_t *ilp) 1150 { 1151 ipf_htable_softc_t *softh = arg; 1152 iphtent_t *node, zn, *nextnode; 1153 iphtable_t *iph, zp, *nextiph; 1154 void *hnext; 1155 int err; 1156 1157 err = 0; 1158 iph = NULL; 1159 node = NULL; 1160 nextiph = NULL; 1161 nextnode = NULL; 1162 1163 READ_ENTER(&softc->ipf_poolrw); 1164 1165 switch (ilp->ili_otype) 1166 { 1167 case IPFLOOKUPITER_LIST : 1168 iph = token->ipt_data; 1169 if (iph == NULL) { 1170 nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1]; 1171 } else { 1172 nextiph = iph->iph_next; 1173 } 1174 1175 if (nextiph != NULL) { 1176 ATOMIC_INC(nextiph->iph_ref); 1177 token->ipt_data = nextiph; 1178 } else { 1179 bzero((char *)&zp, sizeof(zp)); 1180 nextiph = &zp; 1181 token->ipt_data = NULL; 1182 } 1183 hnext = nextiph->iph_next; 1184 break; 1185 1186 case IPFLOOKUPITER_NODE : 1187 node = token->ipt_data; 1188 if (node == NULL) { 1189 iph = ipf_htable_find(arg, ilp->ili_unit, 1190 ilp->ili_name); 1191 if (iph == NULL) { 1192 IPFERROR(30009); 1193 err = ESRCH; 1194 } else { 1195 nextnode = iph->iph_list; 1196 } 1197 } else { 1198 nextnode = node->ipe_next; 1199 } 1200 1201 if (nextnode != NULL) { 1202 ATOMIC_INC(nextnode->ipe_ref); 1203 token->ipt_data = nextnode; 1204 } else { 1205 bzero((char *)&zn, sizeof(zn)); 1206 nextnode = &zn; 1207 token->ipt_data = NULL; 1208 } 1209 hnext = nextnode->ipe_next; 1210 break; 1211 1212 default : 1213 IPFERROR(30010); 1214 err = EINVAL; 1215 hnext = NULL; 1216 break; 1217 } 1218 1219 RWLOCK_EXIT(&softc->ipf_poolrw); 1220 if (err != 0) 1221 return (err); 1222 1223 switch (ilp->ili_otype) 1224 { 1225 case IPFLOOKUPITER_LIST : 1226 err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph)); 1227 if (err != 0) { 1228 IPFERROR(30011); 1229 err = EFAULT; 1230 } 1231 if (iph != NULL) { 1232 WRITE_ENTER(&softc->ipf_poolrw); 1233 ipf_htable_deref(softc, softh, iph); 1234 RWLOCK_EXIT(&softc->ipf_poolrw); 1235 } 1236 break; 1237 1238 case IPFLOOKUPITER_NODE : 1239 err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); 1240 if (err != 0) { 1241 IPFERROR(30012); 1242 err = EFAULT; 1243 } 1244 if (node != NULL) { 1245 WRITE_ENTER(&softc->ipf_poolrw); 1246 ipf_htent_deref(softc, node); 1247 RWLOCK_EXIT(&softc->ipf_poolrw); 1248 } 1249 break; 1250 } 1251 1252 if (hnext == NULL) 1253 ipf_token_mark_complete(token); 1254 1255 return (err); 1256 } 1257 1258 1259 /* ------------------------------------------------------------------------ */ 1260 /* Function: ipf_htable_iter_deref */ 1261 /* Returns: int - 0 = success, else error */ 1262 /* Parameters: softc(I) - pointer to soft context main structure */ 1263 /* arg(I) - pointer to local context to use */ 1264 /* otype(I) - which data structure type is being walked */ 1265 /* unit(I) - ipfilter device to which we are working on */ 1266 /* data(I) - pointer to old data structure */ 1267 /* */ 1268 /* ------------------------------------------------------------------------ */ 1269 static int 1270 ipf_htable_iter_deref(ipf_main_softc_t *softc, void *arg, int otype, int unit, 1271 void *data) 1272 { 1273 1274 if (data == NULL) 1275 return (EFAULT); 1276 1277 if (unit < -1 || unit > IPL_LOGMAX) 1278 return (EINVAL); 1279 1280 switch (otype) 1281 { 1282 case IPFLOOKUPITER_LIST : 1283 ipf_htable_deref(softc, arg, (iphtable_t *)data); 1284 break; 1285 1286 case IPFLOOKUPITER_NODE : 1287 ipf_htent_deref(arg, (iphtent_t *)data); 1288 break; 1289 default : 1290 break; 1291 } 1292 1293 return (0); 1294 } 1295 1296 1297 #ifdef USE_INET6 1298 /* ------------------------------------------------------------------------ */ 1299 /* Function: ipf_iphmfind6 */ 1300 /* Parameters: iph(I) - pointer to hash table */ 1301 /* addr(I) - pointer to IPv6 address */ 1302 /* Locks: ipf_poolrw */ 1303 /* */ 1304 /* ------------------------------------------------------------------------ */ 1305 static iphtent_t * 1306 ipf_iphmfind6(iphtable_t *iph, i6addr_t *addr) 1307 { 1308 i6addr_t *msk, ips; 1309 iphtent_t *ipe; 1310 u_int hv; 1311 int i; 1312 1313 i = 0; 1314 maskloop: 1315 msk = iph->iph_v6_masks.imt6_active + i; 1316 ips.i6[0] = addr->i6[0] & msk->i6[0]; 1317 ips.i6[1] = addr->i6[1] & msk->i6[1]; 1318 ips.i6[2] = addr->i6[2] & msk->i6[2]; 1319 ips.i6[3] = addr->i6[3] & msk->i6[3]; 1320 hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size); 1321 for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { 1322 if ((ipe->ipe_family != AF_INET6) || 1323 IP6_NEQ(&ipe->ipe_mask, msk) || 1324 IP6_NEQ(&ipe->ipe_addr, &ips)) { 1325 continue; 1326 } 1327 break; 1328 } 1329 1330 if (ipe == NULL) { 1331 i++; 1332 if (i < iph->iph_v6_masks.imt6_max) 1333 goto maskloop; 1334 } 1335 return (ipe); 1336 } 1337 #endif 1338 1339 1340 static void 1341 ipf_htable_expire(ipf_main_softc_t *softc, void *arg) 1342 { 1343 ipf_htable_softc_t *softh = arg; 1344 iphtent_t *n; 1345 1346 while ((n = softh->ipf_node_explist) != NULL) { 1347 if (n->ipe_die > softc->ipf_ticks) 1348 break; 1349 1350 ipf_htent_remove(softc, softh, n->ipe_owner, n); 1351 } 1352 } 1353 1354 1355 #ifndef _KERNEL 1356 1357 /* ------------------------------------------------------------------------ */ 1358 /* */ 1359 /* ------------------------------------------------------------------------ */ 1360 void 1361 ipf_htable_dump(ipf_main_softc_t *softc, void *arg) 1362 { 1363 ipf_htable_softc_t *softh = arg; 1364 iphtable_t *iph; 1365 int i; 1366 1367 printf("List of configured hash tables\n"); 1368 for (i = 0; i < IPL_LOGSIZE; i++) 1369 for (iph = softh->ipf_htables[i]; iph != NULL; 1370 iph = iph->iph_next) 1371 printhash(iph, bcopywrap, NULL, opts, NULL); 1372 1373 } 1374 #endif 1375