ip_frag.c revision 344833
1/* $FreeBSD: stable/11/sys/contrib/ipfilter/netinet/ip_frag.c 344833 2019-03-06 02:37:25Z 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_version) 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) && !defined(__svr4__) 38# include <sys/mbuf.h> 39# endif 40#endif 41#if !defined(__SVR4) && !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 344833 2019-03-06 02:37:25Z 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 __P((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 __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *)); 88static void ipf_frag_deref __P((void *, ipfr_t **, ipfrwlock_t *)); 89static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *, 90 ipfr_t **, ipfrwlock_t *)); 91#else 92static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *, 93 fr_info_t *, u_32_t, ipfr_t **)); 94static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **)); 95static void ipf_frag_deref __P((void *, ipfr_t **)); 96static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *, 97 ipfr_t **)); 98#endif 99static void ipf_frag_delete __P((ipf_main_softc_t *, ipfr_t *, ipfr_t ***)); 100static void ipf_frag_free __P((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 frag.ipfr_v = fin->fin_v; 408 idx = fin->fin_v; 409 frag.ipfr_p = fin->fin_p; 410 idx += fin->fin_p; 411 frag.ipfr_id = fin->fin_id; 412 idx += fin->fin_id; 413 frag.ipfr_source = fin->fin_fi.fi_src; 414 idx += frag.ipfr_src.s_addr; 415 frag.ipfr_dest = fin->fin_fi.fi_dst; 416 idx += frag.ipfr_dst.s_addr; 417 frag.ipfr_ifp = fin->fin_ifp; 418 idx *= 127; 419 idx %= softf->ipfr_size; 420 421 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 422 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 423 frag.ipfr_auth = fin->fin_fi.fi_auth; 424 425 off = fin->fin_off >> 3; 426 if (off == 0) { 427 char *ptr; 428 int end; 429 430#ifdef USE_INET6 431 if (fin->fin_v == 6) { 432 433 ptr = (char *)fin->fin_fraghdr + 434 sizeof(struct ip6_frag); 435 } else 436#endif 437 { 438 ptr = fin->fin_dp; 439 } 440 end = fin->fin_plen - (ptr - (char *)fin->fin_ip); 441 frag.ipfr_firstend = end >> 3; 442 } else { 443 frag.ipfr_firstend = 0; 444 } 445 446 /* 447 * allocate some memory, if possible, if not, just record that we 448 * failed to do so. 449 */ 450 KMALLOC(fran, ipfr_t *); 451 if (fran == NULL) { 452 FBUMPD(ifs_nomem); 453 return NULL; 454 } 455 456 WRITE_ENTER(lock); 457 458 /* 459 * first, make sure it isn't already there... 460 */ 461 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 462 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, 463 IPFR_CMPSZ)) { 464 RWLOCK_EXIT(lock); 465 FBUMPD(ifs_exists); 466 KFREE(fran); 467 return NULL; 468 } 469 470 fra = fran; 471 fran = NULL; 472 fr = fin->fin_fr; 473 fra->ipfr_rule = fr; 474 if (fr != NULL) { 475 MUTEX_ENTER(&fr->fr_lock); 476 fr->fr_ref++; 477 MUTEX_EXIT(&fr->fr_lock); 478 } 479 480 /* 481 * Insert the fragment into the fragment table, copy the struct used 482 * in the search using bcopy rather than reassign each field. 483 * Set the ttl to the default. 484 */ 485 if ((fra->ipfr_hnext = table[idx]) != NULL) 486 table[idx]->ipfr_hprev = &fra->ipfr_hnext; 487 fra->ipfr_hprev = table + idx; 488 fra->ipfr_data = NULL; 489 table[idx] = fra; 490 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 491 fra->ipfr_v = fin->fin_v; 492 fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl; 493 fra->ipfr_firstend = frag.ipfr_firstend; 494 495 /* 496 * Compute the offset of the expected start of the next packet. 497 */ 498 if (off == 0) 499 fra->ipfr_seen0 = 1; 500 fra->ipfr_off = off + (fin->fin_dlen >> 3); 501 fra->ipfr_pass = pass; 502 fra->ipfr_ref = 1; 503 fra->ipfr_pkts = 1; 504 fra->ipfr_bytes = fin->fin_plen; 505 FBUMP(ifs_inuse); 506 FBUMP(ifs_new); 507 return fra; 508} 509 510 511/* ------------------------------------------------------------------------ */ 512/* Function: ipf_frag_new */ 513/* Returns: int - 0 == success, -1 == error */ 514/* Parameters: fin(I) - pointer to packet information */ 515/* */ 516/* Add a new entry to the fragment cache table based on the current packet */ 517/* ------------------------------------------------------------------------ */ 518int 519ipf_frag_new(softc, fin, pass) 520 ipf_main_softc_t *softc; 521 u_32_t pass; 522 fr_info_t *fin; 523{ 524 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 525 ipfr_t *fra; 526 527 if (softf->ipfr_lock != 0) 528 return -1; 529 530#ifdef USE_MUTEXES 531 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag); 532#else 533 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads); 534#endif 535 if (fra != NULL) { 536 *softf->ipfr_tail = fra; 537 fra->ipfr_prev = softf->ipfr_tail; 538 softf->ipfr_tail = &fra->ipfr_next; 539 fra->ipfr_next = NULL; 540 RWLOCK_EXIT(&softc->ipf_frag); 541 } 542 return fra ? 0 : -1; 543} 544 545 546/* ------------------------------------------------------------------------ */ 547/* Function: ipf_frag_natnew */ 548/* Returns: int - 0 == success, -1 == error */ 549/* Parameters: fin(I) - pointer to packet information */ 550/* nat(I) - pointer to NAT structure */ 551/* */ 552/* Create a new NAT fragment cache entry based on the current packet and */ 553/* the NAT structure for this "session". */ 554/* ------------------------------------------------------------------------ */ 555int 556ipf_frag_natnew(softc, fin, pass, nat) 557 ipf_main_softc_t *softc; 558 fr_info_t *fin; 559 u_32_t pass; 560 nat_t *nat; 561{ 562 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 563 ipfr_t *fra; 564 565 if (softf->ipfr_lock != 0) 566 return 0; 567 568#ifdef USE_MUTEXES 569 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab, 570 &softf->ipfr_natfrag); 571#else 572 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab); 573#endif 574 if (fra != NULL) { 575 fra->ipfr_data = nat; 576 nat->nat_data = fra; 577 *softf->ipfr_nattail = fra; 578 fra->ipfr_prev = softf->ipfr_nattail; 579 softf->ipfr_nattail = &fra->ipfr_next; 580 fra->ipfr_next = NULL; 581 RWLOCK_EXIT(&softf->ipfr_natfrag); 582 return 0; 583 } 584 return -1; 585} 586 587 588/* ------------------------------------------------------------------------ */ 589/* Function: ipf_frag_ipidnew */ 590/* Returns: int - 0 == success, -1 == error */ 591/* Parameters: fin(I) - pointer to packet information */ 592/* ipid(I) - new IP ID for this fragmented packet */ 593/* */ 594/* Create a new fragment cache entry for this packet and store, as a data */ 595/* pointer, the new IP ID value. */ 596/* ------------------------------------------------------------------------ */ 597int 598ipf_frag_ipidnew(fin, ipid) 599 fr_info_t *fin; 600 u_32_t ipid; 601{ 602 ipf_main_softc_t *softc = fin->fin_main_soft; 603 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 604 ipfr_t *fra; 605 606 if (softf->ipfr_lock) 607 return 0; 608 609#ifdef USE_MUTEXES 610 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag); 611#else 612 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab); 613#endif 614 if (fra != NULL) { 615 fra->ipfr_data = (void *)(intptr_t)ipid; 616 *softf->ipfr_ipidtail = fra; 617 fra->ipfr_prev = softf->ipfr_ipidtail; 618 softf->ipfr_ipidtail = &fra->ipfr_next; 619 fra->ipfr_next = NULL; 620 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 621 } 622 return fra ? 0 : -1; 623} 624 625 626/* ------------------------------------------------------------------------ */ 627/* Function: ipf_frag_lookup */ 628/* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 629/* matching entry in the frag table, else NULL */ 630/* Parameters: fin(I) - pointer to packet information */ 631/* table(I) - pointer to fragment cache table to search */ 632/* */ 633/* Check the fragment cache to see if there is already a record of this */ 634/* packet with its filter result known. */ 635/* */ 636/* If this function succeeds, it returns with a write lock held on "lock". */ 637/* If it fails, no lock is held on return. */ 638/* ------------------------------------------------------------------------ */ 639static ipfr_t * 640ipf_frag_lookup(softc, softf, fin, table 641#ifdef USE_MUTEXES 642, lock 643#endif 644) 645 ipf_main_softc_t *softc; 646 ipf_frag_softc_t *softf; 647 fr_info_t *fin; 648 ipfr_t *table[]; 649#ifdef USE_MUTEXES 650 ipfrwlock_t *lock; 651#endif 652{ 653 ipfr_t *f, frag; 654 u_int idx; 655 656 /* 657 * We don't want to let short packets match because they could be 658 * compromising the security of other rules that want to match on 659 * layer 4 fields (and can't because they have been fragmented off.) 660 * Why do this check here? The counter acts as an indicator of this 661 * kind of attack, whereas if it was elsewhere, it wouldn't know if 662 * other matching packets had been seen. 663 */ 664 if (fin->fin_flx & FI_SHORT) { 665 FBUMPD(ifs_short); 666 return NULL; 667 } 668 669 if ((fin->fin_flx & FI_BAD) != 0) { 670 FBUMPD(ifs_bad); 671 return NULL; 672 } 673 674 /* 675 * For fragments, we record protocol, packet id, TOS and both IP#'s 676 * (these should all be the same for all fragments of a packet). 677 * 678 * build up a hash value to index the table with. 679 */ 680 frag.ipfr_v = fin->fin_v; 681 idx = fin->fin_v; 682 frag.ipfr_p = fin->fin_p; 683 idx += fin->fin_p; 684 frag.ipfr_id = fin->fin_id; 685 idx += fin->fin_id; 686 frag.ipfr_source = fin->fin_fi.fi_src; 687 idx += frag.ipfr_src.s_addr; 688 frag.ipfr_dest = fin->fin_fi.fi_dst; 689 idx += frag.ipfr_dst.s_addr; 690 frag.ipfr_ifp = fin->fin_ifp; 691 idx *= 127; 692 idx %= softf->ipfr_size; 693 694 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 695 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 696 frag.ipfr_auth = fin->fin_fi.fi_auth; 697 698 READ_ENTER(lock); 699 700 /* 701 * check the table, careful to only compare the right amount of data 702 */ 703 for (f = table[idx]; f; f = f->ipfr_hnext) { 704 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, 705 IPFR_CMPSZ)) { 706 u_short off; 707 708 /* 709 * XXX - We really need to be guarding against the 710 * retransmission of (src,dst,id,offset-range) here 711 * because a fragmented packet is never resent with 712 * the same IP ID# (or shouldn't). 713 */ 714 off = fin->fin_off >> 3; 715 if (f->ipfr_seen0) { 716 if (off == 0) { 717 FBUMPD(ifs_retrans0); 718 continue; 719 } 720 721 /* 722 * Case 3. See comment for frpr_fragment6. 723 */ 724 if ((f->ipfr_firstend != 0) && 725 (off < f->ipfr_firstend)) { 726 FBUMP(ifs_overlap); 727 DT2(ifs_overlap, u_short, off, 728 ipfr_t *, f); 729 DT3(ipf_fi_bad_ifs_overlap, fr_info_t *, fin, u_short, off, 730 ipfr_t *, f); 731 fin->fin_flx |= FI_BAD; 732 break; 733 } 734 } else if (off == 0) 735 f->ipfr_seen0 = 1; 736 737 if (f != table[idx] && MUTEX_TRY_UPGRADE(lock)) { 738 ipfr_t **fp; 739 740 /* 741 * Move fragment info. to the top of the list 742 * to speed up searches. First, delink... 743 */ 744 fp = f->ipfr_hprev; 745 (*fp) = f->ipfr_hnext; 746 if (f->ipfr_hnext != NULL) 747 f->ipfr_hnext->ipfr_hprev = fp; 748 /* 749 * Then put back at the top of the chain. 750 */ 751 f->ipfr_hnext = table[idx]; 752 table[idx]->ipfr_hprev = &f->ipfr_hnext; 753 f->ipfr_hprev = table + idx; 754 table[idx] = f; 755 MUTEX_DOWNGRADE(lock); 756 } 757 758 /* 759 * If we've follwed the fragments, and this is the 760 * last (in order), shrink expiration time. 761 */ 762 if (off == f->ipfr_off) { 763 f->ipfr_off = (fin->fin_dlen >> 3) + off; 764 765 /* 766 * Well, we could shrink the expiration time 767 * but only if every fragment has been seen 768 * in order upto this, the last. ipfr_badorder 769 * is used here to count those out of order 770 * and if it equals 0 when we get to the last 771 * fragment then we can assume all of the 772 * fragments have been seen and in order. 773 */ 774#if 0 775 /* 776 * Doing this properly requires moving it to 777 * the head of the list which is infesible. 778 */ 779 if ((more == 0) && (f->ipfr_badorder == 0)) 780 f->ipfr_ttl = softc->ipf_ticks + 1; 781#endif 782 } else { 783 f->ipfr_badorder++; 784 FBUMPD(ifs_unordered); 785 if (f->ipfr_pass & FR_FRSTRICT) { 786 FBUMPD(ifs_strict); 787 continue; 788 } 789 } 790 f->ipfr_pkts++; 791 f->ipfr_bytes += fin->fin_plen; 792 FBUMP(ifs_hits); 793 return f; 794 } 795 } 796 797 RWLOCK_EXIT(lock); 798 FBUMP(ifs_miss); 799 return NULL; 800} 801 802 803/* ------------------------------------------------------------------------ */ 804/* Function: ipf_frag_natknown */ 805/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 806/* match found, else NULL */ 807/* Parameters: fin(I) - pointer to packet information */ 808/* */ 809/* Functional interface for NAT lookups of the NAT fragment cache */ 810/* ------------------------------------------------------------------------ */ 811nat_t * 812ipf_frag_natknown(fin) 813 fr_info_t *fin; 814{ 815 ipf_main_softc_t *softc = fin->fin_main_soft; 816 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 817 nat_t *nat; 818 ipfr_t *ipf; 819 820 if ((softf->ipfr_lock) || !softf->ipfr_natlist) 821 return NULL; 822#ifdef USE_MUTEXES 823 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab, 824 &softf->ipfr_natfrag); 825#else 826 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab); 827#endif 828 if (ipf != NULL) { 829 nat = ipf->ipfr_data; 830 /* 831 * This is the last fragment for this packet. 832 */ 833 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) { 834 nat->nat_data = NULL; 835 ipf->ipfr_data = NULL; 836 } 837 RWLOCK_EXIT(&softf->ipfr_natfrag); 838 } else 839 nat = NULL; 840 return nat; 841} 842 843 844/* ------------------------------------------------------------------------ */ 845/* Function: ipf_frag_ipidknown */ 846/* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 847/* return 0xfffffff to indicate no match. */ 848/* Parameters: fin(I) - pointer to packet information */ 849/* */ 850/* Functional interface for IP ID lookups of the IP ID fragment cache */ 851/* ------------------------------------------------------------------------ */ 852u_32_t 853ipf_frag_ipidknown(fin) 854 fr_info_t *fin; 855{ 856 ipf_main_softc_t *softc = fin->fin_main_soft; 857 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 858 ipfr_t *ipf; 859 u_32_t id; 860 861 if (softf->ipfr_lock || !softf->ipfr_ipidlist) 862 return 0xffffffff; 863 864#ifdef USE_MUTEXES 865 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab, 866 &softf->ipfr_ipidfrag); 867#else 868 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab); 869#endif 870 if (ipf != NULL) { 871 id = (u_32_t)(intptr_t)ipf->ipfr_data; 872 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 873 } else 874 id = 0xffffffff; 875 return id; 876} 877 878 879/* ------------------------------------------------------------------------ */ 880/* Function: ipf_frag_known */ 881/* Returns: frentry_t* - pointer to filter rule if a match is found in */ 882/* the frag cache table, else NULL. */ 883/* Parameters: fin(I) - pointer to packet information */ 884/* passp(O) - pointer to where to store rule flags resturned */ 885/* */ 886/* Functional interface for normal lookups of the fragment cache. If a */ 887/* match is found, return the rule pointer and flags from the rule, except */ 888/* that if FR_LOGFIRST is set, reset FR_LOG. */ 889/* ------------------------------------------------------------------------ */ 890frentry_t * 891ipf_frag_known(fin, passp) 892 fr_info_t *fin; 893 u_32_t *passp; 894{ 895 ipf_main_softc_t *softc = fin->fin_main_soft; 896 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 897 frentry_t *fr = NULL; 898 ipfr_t *fra; 899 u_32_t pass; 900 901 if ((softf->ipfr_lock) || (softf->ipfr_list == NULL)) 902 return NULL; 903 904#ifdef USE_MUTEXES 905 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads, 906 &softc->ipf_frag); 907#else 908 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads); 909#endif 910 if (fra != NULL) { 911 if (fin->fin_flx & FI_BAD) { 912 fr = &ipfr_block; 913 fin->fin_reason = FRB_BADFRAG; 914 DT2(ipf_frb_badfrag, fr_info_t *, fin, uint, fra); 915 } else { 916 fr = fra->ipfr_rule; 917 } 918 fin->fin_fr = fr; 919 if (fr != NULL) { 920 pass = fr->fr_flags; 921 if ((pass & FR_KEEPSTATE) != 0) { 922 fin->fin_flx |= FI_STATE; 923 /* 924 * Reset the keep state flag here so that we 925 * don't try and add a new state entry because 926 * of a match here. That leads to blocking of 927 * the packet later because the add fails. 928 */ 929 pass &= ~FR_KEEPSTATE; 930 } 931 if ((pass & FR_LOGFIRST) != 0) 932 pass &= ~(FR_LOGFIRST|FR_LOG); 933 *passp = pass; 934 } 935 RWLOCK_EXIT(&softc->ipf_frag); 936 } 937 return fr; 938} 939 940 941/* ------------------------------------------------------------------------ */ 942/* Function: ipf_frag_natforget */ 943/* Returns: Nil */ 944/* Parameters: softc(I) - pointer to soft context main structure */ 945/* ptr(I) - pointer to data structure */ 946/* */ 947/* Search through all of the fragment cache entries for NAT and wherever a */ 948/* pointer is found to match ptr, reset it to NULL. */ 949/* ------------------------------------------------------------------------ */ 950void 951ipf_frag_natforget(softc, ptr) 952 ipf_main_softc_t *softc; 953 void *ptr; 954{ 955 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 956 ipfr_t *fr; 957 958 WRITE_ENTER(&softf->ipfr_natfrag); 959 for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next) 960 if (fr->ipfr_data == ptr) 961 fr->ipfr_data = NULL; 962 RWLOCK_EXIT(&softf->ipfr_natfrag); 963} 964 965 966/* ------------------------------------------------------------------------ */ 967/* Function: ipf_frag_delete */ 968/* Returns: Nil */ 969/* Parameters: softc(I) - pointer to soft context main structure */ 970/* fra(I) - pointer to fragment structure to delete */ 971/* tail(IO) - pointer to the pointer to the tail of the frag */ 972/* list */ 973/* */ 974/* Remove a fragment cache table entry from the table & list. Also free */ 975/* the filter rule it is associated with it if it is no longer used as a */ 976/* result of decreasing the reference count. */ 977/* ------------------------------------------------------------------------ */ 978static void 979ipf_frag_delete(softc, fra, tail) 980 ipf_main_softc_t *softc; 981 ipfr_t *fra, ***tail; 982{ 983 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 984 985 if (fra->ipfr_next) 986 fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 987 *fra->ipfr_prev = fra->ipfr_next; 988 if (*tail == &fra->ipfr_next) 989 *tail = fra->ipfr_prev; 990 991 if (fra->ipfr_hnext) 992 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 993 *fra->ipfr_hprev = fra->ipfr_hnext; 994 995 if (fra->ipfr_rule != NULL) { 996 (void) ipf_derefrule(softc, &fra->ipfr_rule); 997 } 998 999 if (fra->ipfr_ref <= 0) 1000 ipf_frag_free(softf, fra); 1001} 1002 1003 1004/* ------------------------------------------------------------------------ */ 1005/* Function: ipf_frag_free */ 1006/* Returns: Nil */ 1007/* Parameters: softf(I) - pointer to fragment context information */ 1008/* fra(I) - pointer to fragment structure to free */ 1009/* */ 1010/* Free up a fragment cache entry and bump relevent statistics. */ 1011/* ------------------------------------------------------------------------ */ 1012static void 1013ipf_frag_free(softf, fra) 1014 ipf_frag_softc_t *softf; 1015 ipfr_t *fra; 1016{ 1017 KFREE(fra); 1018 FBUMP(ifs_expire); 1019 softf->ipfr_stats.ifs_inuse--; 1020} 1021 1022 1023/* ------------------------------------------------------------------------ */ 1024/* Function: ipf_frag_clear */ 1025/* Returns: Nil */ 1026/* Parameters: softc(I) - pointer to soft context main structure */ 1027/* */ 1028/* Free memory in use by fragment state information kept. Do the normal */ 1029/* fragment state stuff first and then the NAT-fragment table. */ 1030/* ------------------------------------------------------------------------ */ 1031void 1032ipf_frag_clear(softc) 1033 ipf_main_softc_t *softc; 1034{ 1035 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1036 ipfr_t *fra; 1037 nat_t *nat; 1038 1039 WRITE_ENTER(&softc->ipf_frag); 1040 while ((fra = softf->ipfr_list) != NULL) { 1041 fra->ipfr_ref--; 1042 ipf_frag_delete(softc, fra, &softf->ipfr_tail); 1043 } 1044 softf->ipfr_tail = &softf->ipfr_list; 1045 RWLOCK_EXIT(&softc->ipf_frag); 1046 1047 WRITE_ENTER(&softc->ipf_nat); 1048 WRITE_ENTER(&softf->ipfr_natfrag); 1049 while ((fra = softf->ipfr_natlist) != NULL) { 1050 nat = fra->ipfr_data; 1051 if (nat != NULL) { 1052 if (nat->nat_data == fra) 1053 nat->nat_data = NULL; 1054 } 1055 fra->ipfr_ref--; 1056 ipf_frag_delete(softc, fra, &softf->ipfr_nattail); 1057 } 1058 softf->ipfr_nattail = &softf->ipfr_natlist; 1059 RWLOCK_EXIT(&softf->ipfr_natfrag); 1060 RWLOCK_EXIT(&softc->ipf_nat); 1061} 1062 1063 1064/* ------------------------------------------------------------------------ */ 1065/* Function: ipf_frag_expire */ 1066/* Returns: Nil */ 1067/* Parameters: softc(I) - pointer to soft context main structure */ 1068/* */ 1069/* Expire entries in the fragment cache table that have been there too long */ 1070/* ------------------------------------------------------------------------ */ 1071void 1072ipf_frag_expire(softc) 1073 ipf_main_softc_t *softc; 1074{ 1075 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1076 ipfr_t **fp, *fra; 1077 nat_t *nat; 1078 SPL_INT(s); 1079 1080 if (softf->ipfr_lock) 1081 return; 1082 1083 SPL_NET(s); 1084 WRITE_ENTER(&softc->ipf_frag); 1085 /* 1086 * Go through the entire table, looking for entries to expire, 1087 * which is indicated by the ttl being less than or equal to ipf_ticks. 1088 */ 1089 for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) { 1090 if (fra->ipfr_ttl > softc->ipf_ticks) 1091 break; 1092 fra->ipfr_ref--; 1093 ipf_frag_delete(softc, fra, &softf->ipfr_tail); 1094 } 1095 RWLOCK_EXIT(&softc->ipf_frag); 1096 1097 WRITE_ENTER(&softf->ipfr_ipidfrag); 1098 for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) { 1099 if (fra->ipfr_ttl > softc->ipf_ticks) 1100 break; 1101 fra->ipfr_ref--; 1102 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail); 1103 } 1104 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 1105 1106 /* 1107 * Same again for the NAT table, except that if the structure also 1108 * still points to a NAT structure, and the NAT structure points back 1109 * at the one to be free'd, NULL the reference from the NAT struct. 1110 * NOTE: We need to grab both mutex's early, and in this order so as 1111 * to prevent a deadlock if both try to expire at the same time. 1112 * The extra if() statement here is because it locks out all NAT 1113 * operations - no need to do that if there are no entries in this 1114 * list, right? 1115 */ 1116 if (softf->ipfr_natlist != NULL) { 1117 WRITE_ENTER(&softc->ipf_nat); 1118 WRITE_ENTER(&softf->ipfr_natfrag); 1119 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) { 1120 if (fra->ipfr_ttl > softc->ipf_ticks) 1121 break; 1122 nat = fra->ipfr_data; 1123 if (nat != NULL) { 1124 if (nat->nat_data == fra) 1125 nat->nat_data = NULL; 1126 } 1127 fra->ipfr_ref--; 1128 ipf_frag_delete(softc, fra, &softf->ipfr_nattail); 1129 } 1130 RWLOCK_EXIT(&softf->ipfr_natfrag); 1131 RWLOCK_EXIT(&softc->ipf_nat); 1132 } 1133 SPL_X(s); 1134} 1135 1136 1137/* ------------------------------------------------------------------------ */ 1138/* Function: ipf_frag_pkt_next */ 1139/* Returns: int - 0 == success, else error */ 1140/* Parameters: softc(I) - pointer to soft context main structure */ 1141/* token(I) - pointer to token information for this caller */ 1142/* itp(I) - pointer to generic iterator from caller */ 1143/* */ 1144/* This function is used to step through the fragment cache list used for */ 1145/* filter rules. The hard work is done by the more generic ipf_frag_next. */ 1146/* ------------------------------------------------------------------------ */ 1147int 1148ipf_frag_pkt_next(softc, token, itp) 1149 ipf_main_softc_t *softc; 1150 ipftoken_t *token; 1151 ipfgeniter_t *itp; 1152{ 1153 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1154 1155#ifdef USE_MUTEXES 1156 return ipf_frag_next(softc, token, itp, &softf->ipfr_list, 1157 &softf->ipfr_frag); 1158#else 1159 return ipf_frag_next(softc, token, itp, &softf->ipfr_list); 1160#endif 1161} 1162 1163 1164/* ------------------------------------------------------------------------ */ 1165/* Function: ipf_frag_nat_next */ 1166/* Returns: int - 0 == success, else error */ 1167/* Parameters: softc(I) - pointer to soft context main structure */ 1168/* token(I) - pointer to token information for this caller */ 1169/* itp(I) - pointer to generic iterator from caller */ 1170/* */ 1171/* This function is used to step through the fragment cache list used for */ 1172/* NAT. The hard work is done by the more generic ipf_frag_next. */ 1173/* ------------------------------------------------------------------------ */ 1174int 1175ipf_frag_nat_next(softc, token, itp) 1176 ipf_main_softc_t *softc; 1177 ipftoken_t *token; 1178 ipfgeniter_t *itp; 1179{ 1180 ipf_frag_softc_t *softf = softc->ipf_frag_soft;; 1181 1182#ifdef USE_MUTEXES 1183 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist, 1184 &softf->ipfr_natfrag); 1185#else 1186 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist); 1187#endif 1188} 1189 1190/* ------------------------------------------------------------------------ */ 1191/* Function: ipf_frag_next */ 1192/* Returns: int - 0 == success, else error */ 1193/* Parameters: softc(I) - pointer to soft context main structure */ 1194/* token(I) - pointer to token information for this caller */ 1195/* itp(I) - pointer to generic iterator from caller */ 1196/* top(I) - top of the fragment list */ 1197/* lock(I) - fragment cache lock */ 1198/* */ 1199/* This function is used to interate through the list of entries in the */ 1200/* fragment cache. It increases the reference count on the one currently */ 1201/* being returned so that the caller can come back and resume from it later.*/ 1202/* */ 1203/* This function is used for both the NAT fragment cache as well as the ipf */ 1204/* fragment cache - hence the reason for passing in top and lock. */ 1205/* ------------------------------------------------------------------------ */ 1206static int 1207ipf_frag_next(softc, token, itp, top 1208#ifdef USE_MUTEXES 1209, lock 1210#endif 1211) 1212 ipf_main_softc_t *softc; 1213 ipftoken_t *token; 1214 ipfgeniter_t *itp; 1215 ipfr_t **top; 1216#ifdef USE_MUTEXES 1217 ipfrwlock_t *lock; 1218#endif 1219{ 1220 ipfr_t *frag, *next, zero; 1221 int error = 0; 1222 1223 if (itp->igi_data == NULL) { 1224 IPFERROR(20001); 1225 return EFAULT; 1226 } 1227 1228 if (itp->igi_nitems != 1) { 1229 IPFERROR(20003); 1230 return EFAULT; 1231 } 1232 1233 frag = token->ipt_data; 1234 1235 READ_ENTER(lock); 1236 1237 if (frag == NULL) 1238 next = *top; 1239 else 1240 next = frag->ipfr_next; 1241 1242 if (next != NULL) { 1243 ATOMIC_INC(next->ipfr_ref); 1244 token->ipt_data = next; 1245 } else { 1246 bzero(&zero, sizeof(zero)); 1247 next = &zero; 1248 token->ipt_data = NULL; 1249 } 1250 if (next->ipfr_next == NULL) 1251 ipf_token_mark_complete(token); 1252 1253 RWLOCK_EXIT(lock); 1254 1255 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 1256 if (error != 0) 1257 IPFERROR(20002); 1258 1259 if (frag != NULL) { 1260#ifdef USE_MUTEXES 1261 ipf_frag_deref(softc, &frag, lock); 1262#else 1263 ipf_frag_deref(softc, &frag); 1264#endif 1265 } 1266 return error; 1267} 1268 1269 1270/* ------------------------------------------------------------------------ */ 1271/* Function: ipf_frag_pkt_deref */ 1272/* Returns: Nil */ 1273/* Parameters: softc(I) - pointer to soft context main structure */ 1274/* data(I) - pointer to frag cache pointer */ 1275/* */ 1276/* This function is the external interface for dropping a reference to a */ 1277/* fragment cache entry used by filter rules. */ 1278/* ------------------------------------------------------------------------ */ 1279void 1280ipf_frag_pkt_deref(softc, data) 1281 ipf_main_softc_t *softc; 1282 void *data; 1283{ 1284 ipfr_t **frp = data; 1285 1286#ifdef USE_MUTEXES 1287 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1288 1289 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag); 1290#else 1291 ipf_frag_deref(softc->ipf_frag_soft, frp); 1292#endif 1293} 1294 1295 1296/* ------------------------------------------------------------------------ */ 1297/* Function: ipf_frag_nat_deref */ 1298/* Returns: Nil */ 1299/* Parameters: softc(I) - pointer to soft context main structure */ 1300/* data(I) - pointer to frag cache pointer */ 1301/* */ 1302/* This function is the external interface for dropping a reference to a */ 1303/* fragment cache entry used by NAT table entries. */ 1304/* ------------------------------------------------------------------------ */ 1305void 1306ipf_frag_nat_deref(softc, data) 1307 ipf_main_softc_t *softc; 1308 void *data; 1309{ 1310 ipfr_t **frp = data; 1311 1312#ifdef USE_MUTEXES 1313 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1314 1315 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag); 1316#else 1317 ipf_frag_deref(softc->ipf_frag_soft, frp); 1318#endif 1319} 1320 1321 1322/* ------------------------------------------------------------------------ */ 1323/* Function: ipf_frag_deref */ 1324/* Returns: Nil */ 1325/* Parameters: frp(IO) - pointer to fragment structure to deference */ 1326/* lock(I) - lock associated with the fragment */ 1327/* */ 1328/* This function dereferences a fragment structure (ipfr_t). The pointer */ 1329/* passed in will always be reset back to NULL, even if the structure is */ 1330/* not freed, to enforce the notion that the caller is no longer entitled */ 1331/* to use the pointer it is dropping the reference to. */ 1332/* ------------------------------------------------------------------------ */ 1333static void 1334ipf_frag_deref(arg, frp 1335#ifdef USE_MUTEXES 1336, lock 1337#endif 1338) 1339 void *arg; 1340 ipfr_t **frp; 1341#ifdef USE_MUTEXES 1342 ipfrwlock_t *lock; 1343#endif 1344{ 1345 ipf_frag_softc_t *softf = arg; 1346 ipfr_t *fra; 1347 1348 fra = *frp; 1349 *frp = NULL; 1350 1351 WRITE_ENTER(lock); 1352 fra->ipfr_ref--; 1353 if (fra->ipfr_ref <= 0) 1354 ipf_frag_free(softf, fra); 1355 RWLOCK_EXIT(lock); 1356} 1357