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