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