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