ip_frag.c revision 369277
1/* $FreeBSD: stable/11/sys/contrib/ipfilter/netinet/ip_frag.c 369277 2021-02-16 00:48:38Z cy $ */ 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/errno.h> 15#include <sys/types.h> 16#include <sys/param.h> 17#include <sys/time.h> 18#include <sys/file.h> 19#if !defined(_KERNEL) 20# include <stdio.h> 21# include <string.h> 22# include <stdlib.h> 23# define _KERNEL 24# include <sys/uio.h> 25# undef _KERNEL 26#endif 27#if defined(_KERNEL) && defined(__FreeBSD__) 28# include <sys/filio.h> 29# include <sys/fcntl.h> 30#else 31# include <sys/ioctl.h> 32#endif 33# include <sys/protosw.h> 34#include <sys/socket.h> 35#if defined(_KERNEL) 36# include <sys/systm.h> 37# if !defined(__SVR4) 38# include <sys/mbuf.h> 39# endif 40#endif 41#if !defined(__SVR4) 42# if defined(_KERNEL) 43# include <sys/kernel.h> 44# endif 45#else 46# include <sys/byteorder.h> 47# ifdef _KERNEL 48# include <sys/dditypes.h> 49# endif 50# include <sys/stream.h> 51# include <sys/kmem.h> 52#endif 53#include <net/if.h> 54#ifdef sun 55# include <net/af.h> 56#endif 57#include <netinet/in.h> 58#include <netinet/in_systm.h> 59#include <netinet/ip.h> 60# include <netinet/ip_var.h> 61#include <netinet/tcp.h> 62#include <netinet/udp.h> 63#include <netinet/ip_icmp.h> 64#include "netinet/ip_compat.h" 65#include <netinet/tcpip.h> 66#include "netinet/ip_fil.h" 67#include "netinet/ip_nat.h" 68#include "netinet/ip_frag.h" 69#include "netinet/ip_state.h" 70#include "netinet/ip_auth.h" 71#include "netinet/ip_lookup.h" 72#include "netinet/ip_proxy.h" 73#include "netinet/ip_sync.h" 74/* END OF INCLUDES */ 75 76#if !defined(lint) 77static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; 78static const char rcsid[] = "@(#)$FreeBSD: stable/11/sys/contrib/ipfilter/netinet/ip_frag.c 369277 2021-02-16 00:48:38Z cy $"; 79/* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; */ 80#endif 81 82 83#ifdef USE_MUTEXES 84static ipfr_t *ipfr_frag_new(ipf_main_softc_t *, ipf_frag_softc_t *, 85 fr_info_t *, u_32_t, ipfr_t **, 86 ipfrwlock_t *); 87static ipfr_t *ipf_frag_lookup(ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *); 88static void ipf_frag_deref(void *, ipfr_t **, ipfrwlock_t *); 89static int ipf_frag_next(ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *, 90 ipfr_t **, ipfrwlock_t *); 91#else 92static ipfr_t *ipfr_frag_new(ipf_main_softc_t *, ipf_frag_softc_t *, 93 fr_info_t *, u_32_t, ipfr_t **); 94static ipfr_t *ipf_frag_lookup(ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **); 95static void ipf_frag_deref(void *, ipfr_t **); 96static int ipf_frag_next(ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *, 97 ipfr_t **); 98#endif 99static void ipf_frag_delete(ipf_main_softc_t *, ipfr_t *, ipfr_t ***); 100static void ipf_frag_free(ipf_frag_softc_t *, ipfr_t *); 101 102static frentry_t ipfr_block; 103 104static ipftuneable_t ipf_frag_tuneables[] = { 105 { { (void *)offsetof(ipf_frag_softc_t, ipfr_size) }, 106 "frag_size", 1, 0x7fffffff, 107 stsizeof(ipf_frag_softc_t, ipfr_size), 108 IPFT_WRDISABLED, NULL, NULL }, 109 { { (void *)offsetof(ipf_frag_softc_t, ipfr_ttl) }, 110 "frag_ttl", 1, 0x7fffffff, 111 stsizeof(ipf_frag_softc_t, ipfr_ttl), 112 0, NULL, NULL }, 113 { { NULL }, 114 NULL, 0, 0, 115 0, 116 0, NULL, NULL } 117}; 118 119#define FBUMP(x) softf->ipfr_stats.x++ 120#define FBUMPD(x) do { softf->ipfr_stats.x++; DT(x); } while (0) 121 122 123/* ------------------------------------------------------------------------ */ 124/* Function: ipf_frag_main_load */ 125/* Returns: int - 0 == success, -1 == error */ 126/* Parameters: Nil */ 127/* */ 128/* Initialise the filter rule associted with blocked packets - everyone can */ 129/* use it. */ 130/* ------------------------------------------------------------------------ */ 131int 132ipf_frag_main_load() 133{ 134 bzero((char *)&ipfr_block, sizeof(ipfr_block)); 135 ipfr_block.fr_flags = FR_BLOCK|FR_QUICK; 136 ipfr_block.fr_ref = 1; 137 138 return 0; 139} 140 141 142/* ------------------------------------------------------------------------ */ 143/* Function: ipf_frag_main_unload */ 144/* Returns: int - 0 == success, -1 == error */ 145/* Parameters: Nil */ 146/* */ 147/* A null-op function that exists as a placeholder so that the flow in */ 148/* other functions is obvious. */ 149/* ------------------------------------------------------------------------ */ 150int 151ipf_frag_main_unload() 152{ 153 return 0; 154} 155 156 157/* ------------------------------------------------------------------------ */ 158/* Function: ipf_frag_soft_create */ 159/* Returns: void * - NULL = failure, else pointer to local context */ 160/* Parameters: softc(I) - pointer to soft context main structure */ 161/* */ 162/* Allocate a new soft context structure to track fragment related info. */ 163/* ------------------------------------------------------------------------ */ 164/*ARGSUSED*/ 165void * 166ipf_frag_soft_create(softc) 167 ipf_main_softc_t *softc; 168{ 169 ipf_frag_softc_t *softf; 170 171 KMALLOC(softf, ipf_frag_softc_t *); 172 if (softf == NULL) 173 return NULL; 174 175 bzero((char *)softf, sizeof(*softf)); 176 177 RWLOCK_INIT(&softf->ipfr_ipidfrag, "frag ipid lock"); 178 RWLOCK_INIT(&softf->ipfr_frag, "ipf fragment rwlock"); 179 RWLOCK_INIT(&softf->ipfr_natfrag, "ipf NAT fragment rwlock"); 180 181 softf->ipf_frag_tune = ipf_tune_array_copy(softf, 182 sizeof(ipf_frag_tuneables), 183 ipf_frag_tuneables); 184 if (softf->ipf_frag_tune == NULL) { 185 ipf_frag_soft_destroy(softc, softf); 186 return NULL; 187 } 188 if (ipf_tune_array_link(softc, softf->ipf_frag_tune) == -1) { 189 ipf_frag_soft_destroy(softc, softf); 190 return NULL; 191 } 192 193 softf->ipfr_size = IPFT_SIZE; 194 softf->ipfr_ttl = IPF_TTLVAL(60); 195 softf->ipfr_lock = 1; 196 softf->ipfr_tail = &softf->ipfr_list; 197 softf->ipfr_nattail = &softf->ipfr_natlist; 198 softf->ipfr_ipidtail = &softf->ipfr_ipidlist; 199 200 return softf; 201} 202 203 204/* ------------------------------------------------------------------------ */ 205/* Function: ipf_frag_soft_destroy */ 206/* Returns: Nil */ 207/* Parameters: softc(I) - pointer to soft context main structure */ 208/* arg(I) - pointer to local context to use */ 209/* */ 210/* Initialise the hash tables for the fragment cache lookups. */ 211/* ------------------------------------------------------------------------ */ 212void 213ipf_frag_soft_destroy(softc, arg) 214 ipf_main_softc_t *softc; 215 void *arg; 216{ 217 ipf_frag_softc_t *softf = arg; 218 219 RW_DESTROY(&softf->ipfr_ipidfrag); 220 RW_DESTROY(&softf->ipfr_frag); 221 RW_DESTROY(&softf->ipfr_natfrag); 222 223 if (softf->ipf_frag_tune != NULL) { 224 ipf_tune_array_unlink(softc, softf->ipf_frag_tune); 225 KFREES(softf->ipf_frag_tune, sizeof(ipf_frag_tuneables)); 226 softf->ipf_frag_tune = NULL; 227 } 228 229 KFREE(softf); 230} 231 232 233/* ------------------------------------------------------------------------ */ 234/* Function: ipf_frag_soft_init */ 235/* Returns: int - 0 == success, -1 == error */ 236/* Parameters: softc(I) - pointer to soft context main structure */ 237/* arg(I) - pointer to local context to use */ 238/* */ 239/* Initialise the hash tables for the fragment cache lookups. */ 240/* ------------------------------------------------------------------------ */ 241/*ARGSUSED*/ 242int 243ipf_frag_soft_init(softc, arg) 244 ipf_main_softc_t *softc; 245 void *arg; 246{ 247 ipf_frag_softc_t *softf = arg; 248 249 KMALLOCS(softf->ipfr_heads, ipfr_t **, 250 softf->ipfr_size * sizeof(ipfr_t *)); 251 if (softf->ipfr_heads == NULL) 252 return -1; 253 254 bzero((char *)softf->ipfr_heads, softf->ipfr_size * sizeof(ipfr_t *)); 255 256 KMALLOCS(softf->ipfr_nattab, ipfr_t **, 257 softf->ipfr_size * sizeof(ipfr_t *)); 258 if (softf->ipfr_nattab == NULL) 259 return -2; 260 261 bzero((char *)softf->ipfr_nattab, softf->ipfr_size * sizeof(ipfr_t *)); 262 263 KMALLOCS(softf->ipfr_ipidtab, ipfr_t **, 264 softf->ipfr_size * sizeof(ipfr_t *)); 265 if (softf->ipfr_ipidtab == NULL) 266 return -3; 267 268 bzero((char *)softf->ipfr_ipidtab, 269 softf->ipfr_size * sizeof(ipfr_t *)); 270 271 softf->ipfr_lock = 0; 272 softf->ipfr_inited = 1; 273 274 return 0; 275} 276 277 278/* ------------------------------------------------------------------------ */ 279/* Function: ipf_frag_soft_fini */ 280/* Returns: int - 0 == success, -1 == error */ 281/* Parameters: softc(I) - pointer to soft context main structure */ 282/* arg(I) - pointer to local context to use */ 283/* */ 284/* Free all memory allocated whilst running and from initialisation. */ 285/* ------------------------------------------------------------------------ */ 286int 287ipf_frag_soft_fini(softc, arg) 288 ipf_main_softc_t *softc; 289 void *arg; 290{ 291 ipf_frag_softc_t *softf = arg; 292 293 softf->ipfr_lock = 1; 294 295 if (softf->ipfr_inited == 1) { 296 ipf_frag_clear(softc); 297 298 softf->ipfr_inited = 0; 299 } 300 301 if (softf->ipfr_heads != NULL) 302 KFREES(softf->ipfr_heads, 303 softf->ipfr_size * sizeof(ipfr_t *)); 304 softf->ipfr_heads = NULL; 305 306 if (softf->ipfr_nattab != NULL) 307 KFREES(softf->ipfr_nattab, 308 softf->ipfr_size * sizeof(ipfr_t *)); 309 softf->ipfr_nattab = NULL; 310 311 if (softf->ipfr_ipidtab != NULL) 312 KFREES(softf->ipfr_ipidtab, 313 softf->ipfr_size * sizeof(ipfr_t *)); 314 softf->ipfr_ipidtab = NULL; 315 316 return 0; 317} 318 319 320/* ------------------------------------------------------------------------ */ 321/* Function: ipf_frag_set_lock */ 322/* Returns: Nil */ 323/* Parameters: arg(I) - pointer to local context to use */ 324/* tmp(I) - new value for lock */ 325/* */ 326/* Stub function that allows for external manipulation of ipfr_lock */ 327/* ------------------------------------------------------------------------ */ 328void 329ipf_frag_setlock(arg, tmp) 330 void *arg; 331 int tmp; 332{ 333 ipf_frag_softc_t *softf = arg; 334 335 softf->ipfr_lock = tmp; 336} 337 338 339/* ------------------------------------------------------------------------ */ 340/* Function: ipf_frag_stats */ 341/* Returns: ipfrstat_t* - pointer to struct with current frag stats */ 342/* Parameters: arg(I) - pointer to local context to use */ 343/* */ 344/* Updates ipfr_stats with current information and returns a pointer to it */ 345/* ------------------------------------------------------------------------ */ 346ipfrstat_t * 347ipf_frag_stats(arg) 348 void *arg; 349{ 350 ipf_frag_softc_t *softf = arg; 351 352 softf->ipfr_stats.ifs_table = softf->ipfr_heads; 353 softf->ipfr_stats.ifs_nattab = softf->ipfr_nattab; 354 return &softf->ipfr_stats; 355} 356 357 358/* ------------------------------------------------------------------------ */ 359/* Function: ipfr_frag_new */ 360/* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ 361/* Parameters: fin(I) - pointer to packet information */ 362/* table(I) - pointer to frag table to add to */ 363/* lock(I) - pointer to lock to get a write hold of */ 364/* */ 365/* Add a new entry to the fragment cache, registering it as having come */ 366/* through this box, with the result of the filter operation. */ 367/* */ 368/* If this function succeeds, it returns with a write lock held on "lock". */ 369/* If it fails, no lock is held on return. */ 370/* ------------------------------------------------------------------------ */ 371static ipfr_t * 372ipfr_frag_new(softc, softf, fin, pass, table 373#ifdef USE_MUTEXES 374, lock 375#endif 376) 377 ipf_main_softc_t *softc; 378 ipf_frag_softc_t *softf; 379 fr_info_t *fin; 380 u_32_t pass; 381 ipfr_t *table[]; 382#ifdef USE_MUTEXES 383 ipfrwlock_t *lock; 384#endif 385{ 386 ipfr_t *fra, frag, *fran; 387 u_int idx, off; 388 frentry_t *fr; 389 390 if (softf->ipfr_stats.ifs_inuse >= softf->ipfr_size) { 391 FBUMPD(ifs_maximum); 392 return NULL; 393 } 394 395 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) { 396 FBUMPD(ifs_newbad); 397 return NULL; 398 } 399 400 if (pass & FR_FRSTRICT) { 401 if (fin->fin_off != 0) { 402 FBUMPD(ifs_newrestrictnot0); 403 return NULL; 404 } 405 } 406 407 memset(&frag, 0, sizeof(frag)); 408 frag.ipfr_v = fin->fin_v; 409 idx = fin->fin_v; 410 frag.ipfr_p = fin->fin_p; 411 idx += fin->fin_p; 412 frag.ipfr_id = fin->fin_id; 413 idx += fin->fin_id; 414 frag.ipfr_source = fin->fin_fi.fi_src; 415 idx += frag.ipfr_src.s_addr; 416 frag.ipfr_dest = fin->fin_fi.fi_dst; 417 idx += frag.ipfr_dst.s_addr; 418 frag.ipfr_ifp = fin->fin_ifp; 419 idx *= 127; 420 idx %= softf->ipfr_size; 421 422 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 423 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 424 frag.ipfr_auth = fin->fin_fi.fi_auth; 425 426 off = fin->fin_off >> 3; 427 if (off == 0) { 428 char *ptr; 429 int end; 430 431#ifdef USE_INET6 432 if (fin->fin_v == 6) { 433 434 ptr = (char *)fin->fin_fraghdr + 435 sizeof(struct ip6_frag); 436 } else 437#endif 438 { 439 ptr = fin->fin_dp; 440 } 441 end = fin->fin_plen - (ptr - (char *)fin->fin_ip); 442 frag.ipfr_firstend = end >> 3; 443 } else { 444 frag.ipfr_firstend = 0; 445 } 446 447 /* 448 * allocate some memory, if possible, if not, just record that we 449 * failed to do so. 450 */ 451 KMALLOC(fran, ipfr_t *); 452 if (fran == NULL) { 453 FBUMPD(ifs_nomem); 454 return NULL; 455 } 456 memset(fran, 0, sizeof(*fran)); 457 458 WRITE_ENTER(lock); 459 460 /* 461 * first, make sure it isn't already there... 462 */ 463 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 464 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, 465 IPFR_CMPSZ)) { 466 RWLOCK_EXIT(lock); 467 FBUMPD(ifs_exists); 468 KFREE(fran); 469 return NULL; 470 } 471 472 fra = fran; 473 fran = NULL; 474 fr = fin->fin_fr; 475 fra->ipfr_rule = fr; 476 if (fr != NULL) { 477 MUTEX_ENTER(&fr->fr_lock); 478 fr->fr_ref++; 479 MUTEX_EXIT(&fr->fr_lock); 480 } 481 482 /* 483 * Insert the fragment into the fragment table, copy the struct used 484 * in the search using bcopy rather than reassign each field. 485 * Set the ttl to the default. 486 */ 487 if ((fra->ipfr_hnext = table[idx]) != NULL) 488 table[idx]->ipfr_hprev = &fra->ipfr_hnext; 489 fra->ipfr_hprev = table + idx; 490 fra->ipfr_data = NULL; 491 table[idx] = fra; 492 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 493 fra->ipfr_v = fin->fin_v; 494 fra->ipfr_p = fin->fin_p; 495 fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl; 496 fra->ipfr_firstend = frag.ipfr_firstend; 497 498 /* 499 * Compute the offset of the expected start of the next packet. 500 */ 501 if (off == 0) 502 fra->ipfr_seen0 = 1; 503 fra->ipfr_off = off + (fin->fin_dlen >> 3); 504 fra->ipfr_pass = pass; 505 fra->ipfr_ref = 1; 506 fra->ipfr_pkts = 1; 507 fra->ipfr_bytes = fin->fin_plen; 508 FBUMP(ifs_inuse); 509 FBUMP(ifs_new); 510 return fra; 511} 512 513 514/* ------------------------------------------------------------------------ */ 515/* Function: ipf_frag_new */ 516/* Returns: int - 0 == success, -1 == error */ 517/* Parameters: fin(I) - pointer to packet information */ 518/* */ 519/* Add a new entry to the fragment cache table based on the current packet */ 520/* ------------------------------------------------------------------------ */ 521int 522ipf_frag_new(softc, fin, pass) 523 ipf_main_softc_t *softc; 524 u_32_t pass; 525 fr_info_t *fin; 526{ 527 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 528 ipfr_t *fra; 529 530 if (softf->ipfr_lock != 0) 531 return -1; 532 533#ifdef USE_MUTEXES 534 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag); 535#else 536 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads); 537#endif 538 if (fra != NULL) { 539 *softf->ipfr_tail = fra; 540 fra->ipfr_prev = softf->ipfr_tail; 541 softf->ipfr_tail = &fra->ipfr_next; 542 fra->ipfr_next = NULL; 543 RWLOCK_EXIT(&softc->ipf_frag); 544 } 545 return fra ? 0 : -1; 546} 547 548 549/* ------------------------------------------------------------------------ */ 550/* Function: ipf_frag_natnew */ 551/* Returns: int - 0 == success, -1 == error */ 552/* Parameters: fin(I) - pointer to packet information */ 553/* nat(I) - pointer to NAT structure */ 554/* */ 555/* Create a new NAT fragment cache entry based on the current packet and */ 556/* the NAT structure for this "session". */ 557/* ------------------------------------------------------------------------ */ 558int 559ipf_frag_natnew(softc, fin, pass, nat) 560 ipf_main_softc_t *softc; 561 fr_info_t *fin; 562 u_32_t pass; 563 nat_t *nat; 564{ 565 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 566 ipfr_t *fra; 567 568 if (softf->ipfr_lock != 0) 569 return 0; 570 571#ifdef USE_MUTEXES 572 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab, 573 &softf->ipfr_natfrag); 574#else 575 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab); 576#endif 577 if (fra != NULL) { 578 fra->ipfr_data = nat; 579 nat->nat_data = fra; 580 *softf->ipfr_nattail = fra; 581 fra->ipfr_prev = softf->ipfr_nattail; 582 softf->ipfr_nattail = &fra->ipfr_next; 583 fra->ipfr_next = NULL; 584 RWLOCK_EXIT(&softf->ipfr_natfrag); 585 return 0; 586 } 587 return -1; 588} 589 590 591/* ------------------------------------------------------------------------ */ 592/* Function: ipf_frag_ipidnew */ 593/* Returns: int - 0 == success, -1 == error */ 594/* Parameters: fin(I) - pointer to packet information */ 595/* ipid(I) - new IP ID for this fragmented packet */ 596/* */ 597/* Create a new fragment cache entry for this packet and store, as a data */ 598/* pointer, the new IP ID value. */ 599/* ------------------------------------------------------------------------ */ 600int 601ipf_frag_ipidnew(fin, ipid) 602 fr_info_t *fin; 603 u_32_t ipid; 604{ 605 ipf_main_softc_t *softc = fin->fin_main_soft; 606 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 607 ipfr_t *fra; 608 609 if (softf->ipfr_lock) 610 return 0; 611 612#ifdef USE_MUTEXES 613 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag); 614#else 615 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab); 616#endif 617 if (fra != NULL) { 618 fra->ipfr_data = (void *)(intptr_t)ipid; 619 *softf->ipfr_ipidtail = fra; 620 fra->ipfr_prev = softf->ipfr_ipidtail; 621 softf->ipfr_ipidtail = &fra->ipfr_next; 622 fra->ipfr_next = NULL; 623 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 624 } 625 return fra ? 0 : -1; 626} 627 628 629/* ------------------------------------------------------------------------ */ 630/* Function: ipf_frag_lookup */ 631/* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 632/* matching entry in the frag table, else NULL */ 633/* Parameters: fin(I) - pointer to packet information */ 634/* table(I) - pointer to fragment cache table to search */ 635/* */ 636/* Check the fragment cache to see if there is already a record of this */ 637/* packet with its filter result known. */ 638/* */ 639/* If this function succeeds, it returns with a write lock held on "lock". */ 640/* If it fails, no lock is held on return. */ 641/* ------------------------------------------------------------------------ */ 642static ipfr_t * 643ipf_frag_lookup(softc, softf, fin, table 644#ifdef USE_MUTEXES 645, lock 646#endif 647) 648 ipf_main_softc_t *softc; 649 ipf_frag_softc_t *softf; 650 fr_info_t *fin; 651 ipfr_t *table[]; 652#ifdef USE_MUTEXES 653 ipfrwlock_t *lock; 654#endif 655{ 656 ipfr_t *f, frag; 657 u_int idx; 658 659 /* 660 * We don't want to let short packets match because they could be 661 * compromising the security of other rules that want to match on 662 * layer 4 fields (and can't because they have been fragmented off.) 663 * Why do this check here? The counter acts as an indicator of this 664 * kind of attack, whereas if it was elsewhere, it wouldn't know if 665 * other matching packets had been seen. 666 */ 667 if (fin->fin_flx & FI_SHORT) { 668 FBUMPD(ifs_short); 669 return NULL; 670 } 671 672 if ((fin->fin_flx & FI_BAD) != 0) { 673 FBUMPD(ifs_bad); 674 return NULL; 675 } 676 677 /* 678 * For fragments, we record protocol, packet id, TOS and both IP#'s 679 * (these should all be the same for all fragments of a packet). 680 * 681 * build up a hash value to index the table with. 682 */ 683 memset(&frag, 0, sizeof(frag)); 684 frag.ipfr_v = fin->fin_v; 685 idx = fin->fin_v; 686 frag.ipfr_p = fin->fin_p; 687 idx += fin->fin_p; 688 frag.ipfr_id = fin->fin_id; 689 idx += fin->fin_id; 690 frag.ipfr_source = fin->fin_fi.fi_src; 691 idx += frag.ipfr_src.s_addr; 692 frag.ipfr_dest = fin->fin_fi.fi_dst; 693 idx += frag.ipfr_dst.s_addr; 694 frag.ipfr_ifp = fin->fin_ifp; 695 idx *= 127; 696 idx %= softf->ipfr_size; 697 698 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 699 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 700 frag.ipfr_auth = fin->fin_fi.fi_auth; 701 702 READ_ENTER(lock); 703 704 /* 705 * check the table, careful to only compare the right amount of data 706 */ 707 for (f = table[idx]; f; f = f->ipfr_hnext) { 708 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, 709 IPFR_CMPSZ)) { 710 u_short off; 711 712 /* 713 * XXX - We really need to be guarding against the 714 * retransmission of (src,dst,id,offset-range) here 715 * because a fragmented packet is never resent with 716 * the same IP ID# (or shouldn't). 717 */ 718 off = fin->fin_off >> 3; 719 if (f->ipfr_seen0) { 720 if (off == 0) { 721 FBUMPD(ifs_retrans0); 722 continue; 723 } 724 725 /* 726 * Case 3. See comment for frpr_fragment6. 727 */ 728 if ((f->ipfr_firstend != 0) && 729 (off < f->ipfr_firstend)) { 730 FBUMP(ifs_overlap); 731 DT2(ifs_overlap, u_short, off, 732 ipfr_t *, f); 733 DT3(ipf_fi_bad_ifs_overlap, fr_info_t *, fin, u_short, off, 734 ipfr_t *, f); 735 fin->fin_flx |= FI_BAD; 736 break; 737 } 738 } else if (off == 0) 739 f->ipfr_seen0 = 1; 740 741 if (f != table[idx] && MUTEX_TRY_UPGRADE(lock)) { 742 ipfr_t **fp; 743 744 /* 745 * Move fragment info. to the top of the list 746 * to speed up searches. First, delink... 747 */ 748 fp = f->ipfr_hprev; 749 (*fp) = f->ipfr_hnext; 750 if (f->ipfr_hnext != NULL) 751 f->ipfr_hnext->ipfr_hprev = fp; 752 /* 753 * Then put back at the top of the chain. 754 */ 755 f->ipfr_hnext = table[idx]; 756 table[idx]->ipfr_hprev = &f->ipfr_hnext; 757 f->ipfr_hprev = table + idx; 758 table[idx] = f; 759 MUTEX_DOWNGRADE(lock); 760 } 761 762 /* 763 * If we've follwed the fragments, and this is the 764 * last (in order), shrink expiration time. 765 */ 766 if (off == f->ipfr_off) { 767 f->ipfr_off = (fin->fin_dlen >> 3) + off; 768 769 /* 770 * Well, we could shrink the expiration time 771 * but only if every fragment has been seen 772 * in order upto this, the last. ipfr_badorder 773 * is used here to count those out of order 774 * and if it equals 0 when we get to the last 775 * fragment then we can assume all of the 776 * fragments have been seen and in order. 777 */ 778#if 0 779 /* 780 * Doing this properly requires moving it to 781 * the head of the list which is infesible. 782 */ 783 if ((more == 0) && (f->ipfr_badorder == 0)) 784 f->ipfr_ttl = softc->ipf_ticks + 1; 785#endif 786 } else { 787 f->ipfr_badorder++; 788 FBUMPD(ifs_unordered); 789 if (f->ipfr_pass & FR_FRSTRICT) { 790 FBUMPD(ifs_strict); 791 continue; 792 } 793 } 794 f->ipfr_pkts++; 795 f->ipfr_bytes += fin->fin_plen; 796 FBUMP(ifs_hits); 797 return f; 798 } 799 } 800 801 RWLOCK_EXIT(lock); 802 FBUMP(ifs_miss); 803 return NULL; 804} 805 806 807/* ------------------------------------------------------------------------ */ 808/* Function: ipf_frag_natknown */ 809/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 810/* match found, else NULL */ 811/* Parameters: fin(I) - pointer to packet information */ 812/* */ 813/* Functional interface for NAT lookups of the NAT fragment cache */ 814/* ------------------------------------------------------------------------ */ 815nat_t * 816ipf_frag_natknown(fin) 817 fr_info_t *fin; 818{ 819 ipf_main_softc_t *softc = fin->fin_main_soft; 820 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 821 nat_t *nat; 822 ipfr_t *ipf; 823 824 if ((softf->ipfr_lock) || !softf->ipfr_natlist) 825 return NULL; 826#ifdef USE_MUTEXES 827 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab, 828 &softf->ipfr_natfrag); 829#else 830 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab); 831#endif 832 if (ipf != NULL) { 833 nat = ipf->ipfr_data; 834 /* 835 * This is the last fragment for this packet. 836 */ 837 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) { 838 nat->nat_data = NULL; 839 ipf->ipfr_data = NULL; 840 } 841 RWLOCK_EXIT(&softf->ipfr_natfrag); 842 } else 843 nat = NULL; 844 return nat; 845} 846 847 848/* ------------------------------------------------------------------------ */ 849/* Function: ipf_frag_ipidknown */ 850/* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 851/* return 0xfffffff to indicate no match. */ 852/* Parameters: fin(I) - pointer to packet information */ 853/* */ 854/* Functional interface for IP ID lookups of the IP ID fragment cache */ 855/* ------------------------------------------------------------------------ */ 856u_32_t 857ipf_frag_ipidknown(fin) 858 fr_info_t *fin; 859{ 860 ipf_main_softc_t *softc = fin->fin_main_soft; 861 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 862 ipfr_t *ipf; 863 u_32_t id; 864 865 if (softf->ipfr_lock || !softf->ipfr_ipidlist) 866 return 0xffffffff; 867 868#ifdef USE_MUTEXES 869 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab, 870 &softf->ipfr_ipidfrag); 871#else 872 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab); 873#endif 874 if (ipf != NULL) { 875 id = (u_32_t)(intptr_t)ipf->ipfr_data; 876 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 877 } else 878 id = 0xffffffff; 879 return id; 880} 881 882 883/* ------------------------------------------------------------------------ */ 884/* Function: ipf_frag_known */ 885/* Returns: frentry_t* - pointer to filter rule if a match is found in */ 886/* the frag cache table, else NULL. */ 887/* Parameters: fin(I) - pointer to packet information */ 888/* passp(O) - pointer to where to store rule flags resturned */ 889/* */ 890/* Functional interface for normal lookups of the fragment cache. If a */ 891/* match is found, return the rule pointer and flags from the rule, except */ 892/* that if FR_LOGFIRST is set, reset FR_LOG. */ 893/* ------------------------------------------------------------------------ */ 894frentry_t * 895ipf_frag_known(fin, passp) 896 fr_info_t *fin; 897 u_32_t *passp; 898{ 899 ipf_main_softc_t *softc = fin->fin_main_soft; 900 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 901 frentry_t *fr = NULL; 902 ipfr_t *fra; 903 u_32_t pass; 904 905 if ((softf->ipfr_lock) || (softf->ipfr_list == NULL)) 906 return NULL; 907 908#ifdef USE_MUTEXES 909 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads, 910 &softc->ipf_frag); 911#else 912 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads); 913#endif 914 if (fra != NULL) { 915 if (fin->fin_flx & FI_BAD) { 916 fr = &ipfr_block; 917 fin->fin_reason = FRB_BADFRAG; 918 DT2(ipf_frb_badfrag, fr_info_t *, fin, uint, fra); 919 } else { 920 fr = fra->ipfr_rule; 921 } 922 fin->fin_fr = fr; 923 if (fr != NULL) { 924 pass = fr->fr_flags; 925 if ((pass & FR_KEEPSTATE) != 0) { 926 fin->fin_flx |= FI_STATE; 927 /* 928 * Reset the keep state flag here so that we 929 * don't try and add a new state entry because 930 * of a match here. That leads to blocking of 931 * the packet later because the add fails. 932 */ 933 pass &= ~FR_KEEPSTATE; 934 } 935 if ((pass & FR_LOGFIRST) != 0) 936 pass &= ~(FR_LOGFIRST|FR_LOG); 937 *passp = pass; 938 } 939 RWLOCK_EXIT(&softc->ipf_frag); 940 } 941 return fr; 942} 943 944 945/* ------------------------------------------------------------------------ */ 946/* Function: ipf_frag_natforget */ 947/* Returns: Nil */ 948/* Parameters: softc(I) - pointer to soft context main structure */ 949/* ptr(I) - pointer to data structure */ 950/* */ 951/* Search through all of the fragment cache entries for NAT and wherever a */ 952/* pointer is found to match ptr, reset it to NULL. */ 953/* ------------------------------------------------------------------------ */ 954void 955ipf_frag_natforget(softc, ptr) 956 ipf_main_softc_t *softc; 957 void *ptr; 958{ 959 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 960 ipfr_t *fr; 961 962 WRITE_ENTER(&softf->ipfr_natfrag); 963 for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next) 964 if (fr->ipfr_data == ptr) 965 fr->ipfr_data = NULL; 966 RWLOCK_EXIT(&softf->ipfr_natfrag); 967} 968 969 970/* ------------------------------------------------------------------------ */ 971/* Function: ipf_frag_delete */ 972/* Returns: Nil */ 973/* Parameters: softc(I) - pointer to soft context main structure */ 974/* fra(I) - pointer to fragment structure to delete */ 975/* tail(IO) - pointer to the pointer to the tail of the frag */ 976/* list */ 977/* */ 978/* Remove a fragment cache table entry from the table & list. Also free */ 979/* the filter rule it is associated with it if it is no longer used as a */ 980/* result of decreasing the reference count. */ 981/* ------------------------------------------------------------------------ */ 982static void 983ipf_frag_delete(softc, fra, tail) 984 ipf_main_softc_t *softc; 985 ipfr_t *fra, ***tail; 986{ 987 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 988 989 if (fra->ipfr_next) 990 fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 991 *fra->ipfr_prev = fra->ipfr_next; 992 if (*tail == &fra->ipfr_next) 993 *tail = fra->ipfr_prev; 994 995 if (fra->ipfr_hnext) 996 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 997 *fra->ipfr_hprev = fra->ipfr_hnext; 998 999 if (fra->ipfr_rule != NULL) { 1000 (void) ipf_derefrule(softc, &fra->ipfr_rule); 1001 } 1002 1003 if (fra->ipfr_ref <= 0) 1004 ipf_frag_free(softf, fra); 1005} 1006 1007 1008/* ------------------------------------------------------------------------ */ 1009/* Function: ipf_frag_free */ 1010/* Returns: Nil */ 1011/* Parameters: softf(I) - pointer to fragment context information */ 1012/* fra(I) - pointer to fragment structure to free */ 1013/* */ 1014/* Free up a fragment cache entry and bump relevent statistics. */ 1015/* ------------------------------------------------------------------------ */ 1016static void 1017ipf_frag_free(softf, fra) 1018 ipf_frag_softc_t *softf; 1019 ipfr_t *fra; 1020{ 1021 KFREE(fra); 1022 FBUMP(ifs_expire); 1023 softf->ipfr_stats.ifs_inuse--; 1024} 1025 1026 1027/* ------------------------------------------------------------------------ */ 1028/* Function: ipf_frag_clear */ 1029/* Returns: Nil */ 1030/* Parameters: softc(I) - pointer to soft context main structure */ 1031/* */ 1032/* Free memory in use by fragment state information kept. Do the normal */ 1033/* fragment state stuff first and then the NAT-fragment table. */ 1034/* ------------------------------------------------------------------------ */ 1035void 1036ipf_frag_clear(softc) 1037 ipf_main_softc_t *softc; 1038{ 1039 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1040 ipfr_t *fra; 1041 nat_t *nat; 1042 1043 WRITE_ENTER(&softc->ipf_frag); 1044 while ((fra = softf->ipfr_list) != NULL) { 1045 fra->ipfr_ref--; 1046 ipf_frag_delete(softc, fra, &softf->ipfr_tail); 1047 } 1048 softf->ipfr_tail = &softf->ipfr_list; 1049 RWLOCK_EXIT(&softc->ipf_frag); 1050 1051 WRITE_ENTER(&softc->ipf_nat); 1052 WRITE_ENTER(&softf->ipfr_natfrag); 1053 while ((fra = softf->ipfr_natlist) != NULL) { 1054 nat = fra->ipfr_data; 1055 if (nat != NULL) { 1056 if (nat->nat_data == fra) 1057 nat->nat_data = NULL; 1058 } 1059 fra->ipfr_ref--; 1060 ipf_frag_delete(softc, fra, &softf->ipfr_nattail); 1061 } 1062 softf->ipfr_nattail = &softf->ipfr_natlist; 1063 RWLOCK_EXIT(&softf->ipfr_natfrag); 1064 RWLOCK_EXIT(&softc->ipf_nat); 1065} 1066 1067 1068/* ------------------------------------------------------------------------ */ 1069/* Function: ipf_frag_expire */ 1070/* Returns: Nil */ 1071/* Parameters: softc(I) - pointer to soft context main structure */ 1072/* */ 1073/* Expire entries in the fragment cache table that have been there too long */ 1074/* ------------------------------------------------------------------------ */ 1075void 1076ipf_frag_expire(softc) 1077 ipf_main_softc_t *softc; 1078{ 1079 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1080 ipfr_t **fp, *fra; 1081 nat_t *nat; 1082 SPL_INT(s); 1083 1084 if (softf->ipfr_lock) 1085 return; 1086 1087 SPL_NET(s); 1088 WRITE_ENTER(&softc->ipf_frag); 1089 /* 1090 * Go through the entire table, looking for entries to expire, 1091 * which is indicated by the ttl being less than or equal to ipf_ticks. 1092 */ 1093 for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) { 1094 if (fra->ipfr_ttl > softc->ipf_ticks) 1095 break; 1096 fra->ipfr_ref--; 1097 ipf_frag_delete(softc, fra, &softf->ipfr_tail); 1098 } 1099 RWLOCK_EXIT(&softc->ipf_frag); 1100 1101 WRITE_ENTER(&softf->ipfr_ipidfrag); 1102 for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) { 1103 if (fra->ipfr_ttl > softc->ipf_ticks) 1104 break; 1105 fra->ipfr_ref--; 1106 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail); 1107 } 1108 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 1109 1110 /* 1111 * Same again for the NAT table, except that if the structure also 1112 * still points to a NAT structure, and the NAT structure points back 1113 * at the one to be free'd, NULL the reference from the NAT struct. 1114 * NOTE: We need to grab both mutex's early, and in this order so as 1115 * to prevent a deadlock if both try to expire at the same time. 1116 * The extra if() statement here is because it locks out all NAT 1117 * operations - no need to do that if there are no entries in this 1118 * list, right? 1119 */ 1120 if (softf->ipfr_natlist != NULL) { 1121 WRITE_ENTER(&softc->ipf_nat); 1122 WRITE_ENTER(&softf->ipfr_natfrag); 1123 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) { 1124 if (fra->ipfr_ttl > softc->ipf_ticks) 1125 break; 1126 nat = fra->ipfr_data; 1127 if (nat != NULL) { 1128 if (nat->nat_data == fra) 1129 nat->nat_data = NULL; 1130 } 1131 fra->ipfr_ref--; 1132 ipf_frag_delete(softc, fra, &softf->ipfr_nattail); 1133 } 1134 RWLOCK_EXIT(&softf->ipfr_natfrag); 1135 RWLOCK_EXIT(&softc->ipf_nat); 1136 } 1137 SPL_X(s); 1138} 1139 1140 1141/* ------------------------------------------------------------------------ */ 1142/* Function: ipf_frag_pkt_next */ 1143/* Returns: int - 0 == success, else error */ 1144/* Parameters: softc(I) - pointer to soft context main structure */ 1145/* token(I) - pointer to token information for this caller */ 1146/* itp(I) - pointer to generic iterator from caller */ 1147/* */ 1148/* This function is used to step through the fragment cache list used for */ 1149/* filter rules. The hard work is done by the more generic ipf_frag_next. */ 1150/* ------------------------------------------------------------------------ */ 1151int 1152ipf_frag_pkt_next(softc, token, itp) 1153 ipf_main_softc_t *softc; 1154 ipftoken_t *token; 1155 ipfgeniter_t *itp; 1156{ 1157 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1158 1159#ifdef USE_MUTEXES 1160 return ipf_frag_next(softc, token, itp, &softf->ipfr_list, 1161 &softf->ipfr_frag); 1162#else 1163 return ipf_frag_next(softc, token, itp, &softf->ipfr_list); 1164#endif 1165} 1166 1167 1168/* ------------------------------------------------------------------------ */ 1169/* Function: ipf_frag_nat_next */ 1170/* Returns: int - 0 == success, else error */ 1171/* Parameters: softc(I) - pointer to soft context main structure */ 1172/* token(I) - pointer to token information for this caller */ 1173/* itp(I) - pointer to generic iterator from caller */ 1174/* */ 1175/* This function is used to step through the fragment cache list used for */ 1176/* NAT. The hard work is done by the more generic ipf_frag_next. */ 1177/* ------------------------------------------------------------------------ */ 1178int 1179ipf_frag_nat_next(softc, token, itp) 1180 ipf_main_softc_t *softc; 1181 ipftoken_t *token; 1182 ipfgeniter_t *itp; 1183{ 1184 ipf_frag_softc_t *softf = softc->ipf_frag_soft;; 1185 1186#ifdef USE_MUTEXES 1187 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist, 1188 &softf->ipfr_natfrag); 1189#else 1190 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist); 1191#endif 1192} 1193 1194/* ------------------------------------------------------------------------ */ 1195/* Function: ipf_frag_next */ 1196/* Returns: int - 0 == success, else error */ 1197/* Parameters: softc(I) - pointer to soft context main structure */ 1198/* token(I) - pointer to token information for this caller */ 1199/* itp(I) - pointer to generic iterator from caller */ 1200/* top(I) - top of the fragment list */ 1201/* lock(I) - fragment cache lock */ 1202/* */ 1203/* This function is used to interate through the list of entries in the */ 1204/* fragment cache. It increases the reference count on the one currently */ 1205/* being returned so that the caller can come back and resume from it later.*/ 1206/* */ 1207/* This function is used for both the NAT fragment cache as well as the ipf */ 1208/* fragment cache - hence the reason for passing in top and lock. */ 1209/* ------------------------------------------------------------------------ */ 1210static int 1211ipf_frag_next(softc, token, itp, top 1212#ifdef USE_MUTEXES 1213, lock 1214#endif 1215) 1216 ipf_main_softc_t *softc; 1217 ipftoken_t *token; 1218 ipfgeniter_t *itp; 1219 ipfr_t **top; 1220#ifdef USE_MUTEXES 1221 ipfrwlock_t *lock; 1222#endif 1223{ 1224 ipfr_t *frag, *next, zero; 1225 int error = 0; 1226 1227 if (itp->igi_data == NULL) { 1228 IPFERROR(20001); 1229 return EFAULT; 1230 } 1231 1232 if (itp->igi_nitems != 1) { 1233 IPFERROR(20003); 1234 return EFAULT; 1235 } 1236 1237 frag = token->ipt_data; 1238 1239 READ_ENTER(lock); 1240 1241 if (frag == NULL) 1242 next = *top; 1243 else 1244 next = frag->ipfr_next; 1245 1246 if (next != NULL) { 1247 ATOMIC_INC(next->ipfr_ref); 1248 token->ipt_data = next; 1249 } else { 1250 bzero(&zero, sizeof(zero)); 1251 next = &zero; 1252 token->ipt_data = NULL; 1253 } 1254 if (next->ipfr_next == NULL) 1255 ipf_token_mark_complete(token); 1256 1257 RWLOCK_EXIT(lock); 1258 1259 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 1260 if (error != 0) 1261 IPFERROR(20002); 1262 1263 if (frag != NULL) { 1264#ifdef USE_MUTEXES 1265 ipf_frag_deref(softc, &frag, lock); 1266#else 1267 ipf_frag_deref(softc, &frag); 1268#endif 1269 } 1270 return error; 1271} 1272 1273 1274/* ------------------------------------------------------------------------ */ 1275/* Function: ipf_frag_pkt_deref */ 1276/* Returns: Nil */ 1277/* Parameters: softc(I) - pointer to soft context main structure */ 1278/* data(I) - pointer to frag cache pointer */ 1279/* */ 1280/* This function is the external interface for dropping a reference to a */ 1281/* fragment cache entry used by filter rules. */ 1282/* ------------------------------------------------------------------------ */ 1283void 1284ipf_frag_pkt_deref(softc, data) 1285 ipf_main_softc_t *softc; 1286 void *data; 1287{ 1288 ipfr_t **frp = data; 1289 1290#ifdef USE_MUTEXES 1291 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1292 1293 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag); 1294#else 1295 ipf_frag_deref(softc->ipf_frag_soft, frp); 1296#endif 1297} 1298 1299 1300/* ------------------------------------------------------------------------ */ 1301/* Function: ipf_frag_nat_deref */ 1302/* Returns: Nil */ 1303/* Parameters: softc(I) - pointer to soft context main structure */ 1304/* data(I) - pointer to frag cache pointer */ 1305/* */ 1306/* This function is the external interface for dropping a reference to a */ 1307/* fragment cache entry used by NAT table entries. */ 1308/* ------------------------------------------------------------------------ */ 1309void 1310ipf_frag_nat_deref(softc, data) 1311 ipf_main_softc_t *softc; 1312 void *data; 1313{ 1314 ipfr_t **frp = data; 1315 1316#ifdef USE_MUTEXES 1317 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1318 1319 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag); 1320#else 1321 ipf_frag_deref(softc->ipf_frag_soft, frp); 1322#endif 1323} 1324 1325 1326/* ------------------------------------------------------------------------ */ 1327/* Function: ipf_frag_deref */ 1328/* Returns: Nil */ 1329/* Parameters: frp(IO) - pointer to fragment structure to deference */ 1330/* lock(I) - lock associated with the fragment */ 1331/* */ 1332/* This function dereferences a fragment structure (ipfr_t). The pointer */ 1333/* passed in will always be reset back to NULL, even if the structure is */ 1334/* not freed, to enforce the notion that the caller is no longer entitled */ 1335/* to use the pointer it is dropping the reference to. */ 1336/* ------------------------------------------------------------------------ */ 1337static void 1338ipf_frag_deref(arg, frp 1339#ifdef USE_MUTEXES 1340, lock 1341#endif 1342) 1343 void *arg; 1344 ipfr_t **frp; 1345#ifdef USE_MUTEXES 1346 ipfrwlock_t *lock; 1347#endif 1348{ 1349 ipf_frag_softc_t *softf = arg; 1350 ipfr_t *fra; 1351 1352 fra = *frp; 1353 *frp = NULL; 1354 1355 WRITE_ENTER(lock); 1356 fra->ipfr_ref--; 1357 if (fra->ipfr_ref <= 0) 1358 ipf_frag_free(softf, fra); 1359 RWLOCK_EXIT(lock); 1360} 1361