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