ip_frag.c revision 314251
1/* $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_frag.c 314251 2017-02-25 08:07:28Z 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 314251 2017-02-25 08:07:28Z 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] && MUTEX_TRY_UPGRADE(lock)) { 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 MUTEX_DOWNGRADE(lock); 765 } 766 767 /* 768 * If we've follwed the fragments, and this is the 769 * last (in order), shrink expiration time. 770 */ 771 if (off == f->ipfr_off) { 772 f->ipfr_off = (fin->fin_dlen >> 3) + off; 773 774 /* 775 * Well, we could shrink the expiration time 776 * but only if every fragment has been seen 777 * in order upto this, the last. ipfr_badorder 778 * is used here to count those out of order 779 * and if it equals 0 when we get to the last 780 * fragment then we can assume all of the 781 * fragments have been seen and in order. 782 */ 783#if 0 784 /* 785 * Doing this properly requires moving it to 786 * the head of the list which is infesible. 787 */ 788 if ((more == 0) && (f->ipfr_badorder == 0)) 789 f->ipfr_ttl = softc->ipf_ticks + 1; 790#endif 791 } else { 792 f->ipfr_badorder++; 793 FBUMPD(ifs_unordered); 794 if (f->ipfr_pass & FR_FRSTRICT) { 795 FBUMPD(ifs_strict); 796 continue; 797 } 798 } 799 f->ipfr_pkts++; 800 f->ipfr_bytes += fin->fin_plen; 801 FBUMP(ifs_hits); 802 return f; 803 } 804 } 805 806 RWLOCK_EXIT(lock); 807 FBUMP(ifs_miss); 808 return NULL; 809} 810 811 812/* ------------------------------------------------------------------------ */ 813/* Function: ipf_frag_natknown */ 814/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 815/* match found, else NULL */ 816/* Parameters: fin(I) - pointer to packet information */ 817/* */ 818/* Functional interface for NAT lookups of the NAT fragment cache */ 819/* ------------------------------------------------------------------------ */ 820nat_t * 821ipf_frag_natknown(fin) 822 fr_info_t *fin; 823{ 824 ipf_main_softc_t *softc = fin->fin_main_soft; 825 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 826 nat_t *nat; 827 ipfr_t *ipf; 828 829 if ((softf->ipfr_lock) || !softf->ipfr_natlist) 830 return NULL; 831#ifdef USE_MUTEXES 832 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab, 833 &softf->ipfr_natfrag); 834#else 835 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab); 836#endif 837 if (ipf != NULL) { 838 nat = ipf->ipfr_data; 839 /* 840 * This is the last fragment for this packet. 841 */ 842 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) { 843 nat->nat_data = NULL; 844 ipf->ipfr_data = NULL; 845 } 846 RWLOCK_EXIT(&softf->ipfr_natfrag); 847 } else 848 nat = NULL; 849 return nat; 850} 851 852 853/* ------------------------------------------------------------------------ */ 854/* Function: ipf_frag_ipidknown */ 855/* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 856/* return 0xfffffff to indicate no match. */ 857/* Parameters: fin(I) - pointer to packet information */ 858/* */ 859/* Functional interface for IP ID lookups of the IP ID fragment cache */ 860/* ------------------------------------------------------------------------ */ 861u_32_t 862ipf_frag_ipidknown(fin) 863 fr_info_t *fin; 864{ 865 ipf_main_softc_t *softc = fin->fin_main_soft; 866 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 867 ipfr_t *ipf; 868 u_32_t id; 869 870 if (softf->ipfr_lock || !softf->ipfr_ipidlist) 871 return 0xffffffff; 872 873#ifdef USE_MUTEXES 874 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab, 875 &softf->ipfr_ipidfrag); 876#else 877 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab); 878#endif 879 if (ipf != NULL) { 880 id = (u_32_t)(intptr_t)ipf->ipfr_data; 881 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 882 } else 883 id = 0xffffffff; 884 return id; 885} 886 887 888/* ------------------------------------------------------------------------ */ 889/* Function: ipf_frag_known */ 890/* Returns: frentry_t* - pointer to filter rule if a match is found in */ 891/* the frag cache table, else NULL. */ 892/* Parameters: fin(I) - pointer to packet information */ 893/* passp(O) - pointer to where to store rule flags resturned */ 894/* */ 895/* Functional interface for normal lookups of the fragment cache. If a */ 896/* match is found, return the rule pointer and flags from the rule, except */ 897/* that if FR_LOGFIRST is set, reset FR_LOG. */ 898/* ------------------------------------------------------------------------ */ 899frentry_t * 900ipf_frag_known(fin, passp) 901 fr_info_t *fin; 902 u_32_t *passp; 903{ 904 ipf_main_softc_t *softc = fin->fin_main_soft; 905 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 906 frentry_t *fr = NULL; 907 ipfr_t *fra; 908 u_32_t pass; 909 910 if ((softf->ipfr_lock) || (softf->ipfr_list == NULL)) 911 return NULL; 912 913#ifdef USE_MUTEXES 914 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads, 915 &softc->ipf_frag); 916#else 917 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads); 918#endif 919 if (fra != NULL) { 920 if (fin->fin_flx & FI_BAD) { 921 fr = &ipfr_block; 922 fin->fin_reason = FRB_BADFRAG; 923 } else { 924 fr = fra->ipfr_rule; 925 } 926 fin->fin_fr = fr; 927 if (fr != NULL) { 928 pass = fr->fr_flags; 929 if ((pass & FR_KEEPSTATE) != 0) { 930 fin->fin_flx |= FI_STATE; 931 /* 932 * Reset the keep state flag here so that we 933 * don't try and add a new state entry because 934 * of a match here. That leads to blocking of 935 * the packet later because the add fails. 936 */ 937 pass &= ~FR_KEEPSTATE; 938 } 939 if ((pass & FR_LOGFIRST) != 0) 940 pass &= ~(FR_LOGFIRST|FR_LOG); 941 *passp = pass; 942 } 943 RWLOCK_EXIT(&softc->ipf_frag); 944 } 945 return fr; 946} 947 948 949/* ------------------------------------------------------------------------ */ 950/* Function: ipf_frag_natforget */ 951/* Returns: Nil */ 952/* Parameters: softc(I) - pointer to soft context main structure */ 953/* ptr(I) - pointer to data structure */ 954/* */ 955/* Search through all of the fragment cache entries for NAT and wherever a */ 956/* pointer is found to match ptr, reset it to NULL. */ 957/* ------------------------------------------------------------------------ */ 958void 959ipf_frag_natforget(softc, ptr) 960 ipf_main_softc_t *softc; 961 void *ptr; 962{ 963 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 964 ipfr_t *fr; 965 966 WRITE_ENTER(&softf->ipfr_natfrag); 967 for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next) 968 if (fr->ipfr_data == ptr) 969 fr->ipfr_data = NULL; 970 RWLOCK_EXIT(&softf->ipfr_natfrag); 971} 972 973 974/* ------------------------------------------------------------------------ */ 975/* Function: ipf_frag_delete */ 976/* Returns: Nil */ 977/* Parameters: softc(I) - pointer to soft context main structure */ 978/* fra(I) - pointer to fragment structure to delete */ 979/* tail(IO) - pointer to the pointer to the tail of the frag */ 980/* list */ 981/* */ 982/* Remove a fragment cache table entry from the table & list. Also free */ 983/* the filter rule it is associated with it if it is no longer used as a */ 984/* result of decreasing the reference count. */ 985/* ------------------------------------------------------------------------ */ 986static void 987ipf_frag_delete(softc, fra, tail) 988 ipf_main_softc_t *softc; 989 ipfr_t *fra, ***tail; 990{ 991 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 992 993 if (fra->ipfr_next) 994 fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 995 *fra->ipfr_prev = fra->ipfr_next; 996 if (*tail == &fra->ipfr_next) 997 *tail = fra->ipfr_prev; 998 999 if (fra->ipfr_hnext) 1000 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 1001 *fra->ipfr_hprev = fra->ipfr_hnext; 1002 1003 if (fra->ipfr_rule != NULL) { 1004 (void) ipf_derefrule(softc, &fra->ipfr_rule); 1005 } 1006 1007 if (fra->ipfr_ref <= 0) 1008 ipf_frag_free(softf, fra); 1009} 1010 1011 1012/* ------------------------------------------------------------------------ */ 1013/* Function: ipf_frag_free */ 1014/* Returns: Nil */ 1015/* Parameters: softf(I) - pointer to fragment context information */ 1016/* fra(I) - pointer to fragment structure to free */ 1017/* */ 1018/* Free up a fragment cache entry and bump relevent statistics. */ 1019/* ------------------------------------------------------------------------ */ 1020static void 1021ipf_frag_free(softf, fra) 1022 ipf_frag_softc_t *softf; 1023 ipfr_t *fra; 1024{ 1025 KFREE(fra); 1026 FBUMP(ifs_expire); 1027 softf->ipfr_stats.ifs_inuse--; 1028} 1029 1030 1031/* ------------------------------------------------------------------------ */ 1032/* Function: ipf_frag_clear */ 1033/* Returns: Nil */ 1034/* Parameters: softc(I) - pointer to soft context main structure */ 1035/* */ 1036/* Free memory in use by fragment state information kept. Do the normal */ 1037/* fragment state stuff first and then the NAT-fragment table. */ 1038/* ------------------------------------------------------------------------ */ 1039void 1040ipf_frag_clear(softc) 1041 ipf_main_softc_t *softc; 1042{ 1043 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1044 ipfr_t *fra; 1045 nat_t *nat; 1046 1047 WRITE_ENTER(&softc->ipf_frag); 1048 while ((fra = softf->ipfr_list) != NULL) { 1049 fra->ipfr_ref--; 1050 ipf_frag_delete(softc, fra, &softf->ipfr_tail); 1051 } 1052 softf->ipfr_tail = &softf->ipfr_list; 1053 RWLOCK_EXIT(&softc->ipf_frag); 1054 1055 WRITE_ENTER(&softc->ipf_nat); 1056 WRITE_ENTER(&softf->ipfr_natfrag); 1057 while ((fra = softf->ipfr_natlist) != NULL) { 1058 nat = fra->ipfr_data; 1059 if (nat != NULL) { 1060 if (nat->nat_data == fra) 1061 nat->nat_data = NULL; 1062 } 1063 fra->ipfr_ref--; 1064 ipf_frag_delete(softc, fra, &softf->ipfr_nattail); 1065 } 1066 softf->ipfr_nattail = &softf->ipfr_natlist; 1067 RWLOCK_EXIT(&softf->ipfr_natfrag); 1068 RWLOCK_EXIT(&softc->ipf_nat); 1069} 1070 1071 1072/* ------------------------------------------------------------------------ */ 1073/* Function: ipf_frag_expire */ 1074/* Returns: Nil */ 1075/* Parameters: softc(I) - pointer to soft context main structure */ 1076/* */ 1077/* Expire entries in the fragment cache table that have been there too long */ 1078/* ------------------------------------------------------------------------ */ 1079void 1080ipf_frag_expire(softc) 1081 ipf_main_softc_t *softc; 1082{ 1083 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1084 ipfr_t **fp, *fra; 1085 nat_t *nat; 1086 SPL_INT(s); 1087 1088 if (softf->ipfr_lock) 1089 return; 1090 1091 SPL_NET(s); 1092 WRITE_ENTER(&softc->ipf_frag); 1093 /* 1094 * Go through the entire table, looking for entries to expire, 1095 * which is indicated by the ttl being less than or equal to ipf_ticks. 1096 */ 1097 for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) { 1098 if (fra->ipfr_ttl > softc->ipf_ticks) 1099 break; 1100 fra->ipfr_ref--; 1101 ipf_frag_delete(softc, fra, &softf->ipfr_tail); 1102 } 1103 RWLOCK_EXIT(&softc->ipf_frag); 1104 1105 WRITE_ENTER(&softf->ipfr_ipidfrag); 1106 for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) { 1107 if (fra->ipfr_ttl > softc->ipf_ticks) 1108 break; 1109 fra->ipfr_ref--; 1110 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail); 1111 } 1112 RWLOCK_EXIT(&softf->ipfr_ipidfrag); 1113 1114 /* 1115 * Same again for the NAT table, except that if the structure also 1116 * still points to a NAT structure, and the NAT structure points back 1117 * at the one to be free'd, NULL the reference from the NAT struct. 1118 * NOTE: We need to grab both mutex's early, and in this order so as 1119 * to prevent a deadlock if both try to expire at the same time. 1120 * The extra if() statement here is because it locks out all NAT 1121 * operations - no need to do that if there are no entries in this 1122 * list, right? 1123 */ 1124 if (softf->ipfr_natlist != NULL) { 1125 WRITE_ENTER(&softc->ipf_nat); 1126 WRITE_ENTER(&softf->ipfr_natfrag); 1127 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) { 1128 if (fra->ipfr_ttl > softc->ipf_ticks) 1129 break; 1130 nat = fra->ipfr_data; 1131 if (nat != NULL) { 1132 if (nat->nat_data == fra) 1133 nat->nat_data = NULL; 1134 } 1135 fra->ipfr_ref--; 1136 ipf_frag_delete(softc, fra, &softf->ipfr_nattail); 1137 } 1138 RWLOCK_EXIT(&softf->ipfr_natfrag); 1139 RWLOCK_EXIT(&softc->ipf_nat); 1140 } 1141 SPL_X(s); 1142} 1143 1144 1145/* ------------------------------------------------------------------------ */ 1146/* Function: ipf_frag_pkt_next */ 1147/* Returns: int - 0 == success, else error */ 1148/* Parameters: softc(I) - pointer to soft context main structure */ 1149/* token(I) - pointer to token information for this caller */ 1150/* itp(I) - pointer to generic iterator from caller */ 1151/* */ 1152/* This function is used to step through the fragment cache list used for */ 1153/* filter rules. The hard work is done by the more generic ipf_frag_next. */ 1154/* ------------------------------------------------------------------------ */ 1155int 1156ipf_frag_pkt_next(softc, token, itp) 1157 ipf_main_softc_t *softc; 1158 ipftoken_t *token; 1159 ipfgeniter_t *itp; 1160{ 1161 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1162 1163#ifdef USE_MUTEXES 1164 return ipf_frag_next(softc, token, itp, &softf->ipfr_list, 1165 &softf->ipfr_frag); 1166#else 1167 return ipf_frag_next(softc, token, itp, &softf->ipfr_list); 1168#endif 1169} 1170 1171 1172/* ------------------------------------------------------------------------ */ 1173/* Function: ipf_frag_nat_next */ 1174/* Returns: int - 0 == success, else error */ 1175/* Parameters: softc(I) - pointer to soft context main structure */ 1176/* token(I) - pointer to token information for this caller */ 1177/* itp(I) - pointer to generic iterator from caller */ 1178/* */ 1179/* This function is used to step through the fragment cache list used for */ 1180/* NAT. The hard work is done by the more generic ipf_frag_next. */ 1181/* ------------------------------------------------------------------------ */ 1182int 1183ipf_frag_nat_next(softc, token, itp) 1184 ipf_main_softc_t *softc; 1185 ipftoken_t *token; 1186 ipfgeniter_t *itp; 1187{ 1188 ipf_frag_softc_t *softf = softc->ipf_frag_soft;; 1189 1190#ifdef USE_MUTEXES 1191 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist, 1192 &softf->ipfr_natfrag); 1193#else 1194 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist); 1195#endif 1196} 1197 1198/* ------------------------------------------------------------------------ */ 1199/* Function: ipf_frag_next */ 1200/* Returns: int - 0 == success, else error */ 1201/* Parameters: softc(I) - pointer to soft context main structure */ 1202/* token(I) - pointer to token information for this caller */ 1203/* itp(I) - pointer to generic iterator from caller */ 1204/* top(I) - top of the fragment list */ 1205/* lock(I) - fragment cache lock */ 1206/* */ 1207/* This function is used to interate through the list of entries in the */ 1208/* fragment cache. It increases the reference count on the one currently */ 1209/* being returned so that the caller can come back and resume from it later.*/ 1210/* */ 1211/* This function is used for both the NAT fragment cache as well as the ipf */ 1212/* fragment cache - hence the reason for passing in top and lock. */ 1213/* ------------------------------------------------------------------------ */ 1214static int 1215ipf_frag_next(softc, token, itp, top 1216#ifdef USE_MUTEXES 1217, lock 1218#endif 1219) 1220 ipf_main_softc_t *softc; 1221 ipftoken_t *token; 1222 ipfgeniter_t *itp; 1223 ipfr_t **top; 1224#ifdef USE_MUTEXES 1225 ipfrwlock_t *lock; 1226#endif 1227{ 1228 ipfr_t *frag, *next, zero; 1229 int error = 0; 1230 1231 if (itp->igi_data == NULL) { 1232 IPFERROR(20001); 1233 return EFAULT; 1234 } 1235 1236 if (itp->igi_nitems != 1) { 1237 IPFERROR(20003); 1238 return EFAULT; 1239 } 1240 1241 frag = token->ipt_data; 1242 1243 READ_ENTER(lock); 1244 1245 if (frag == NULL) 1246 next = *top; 1247 else 1248 next = frag->ipfr_next; 1249 1250 if (next != NULL) { 1251 ATOMIC_INC(next->ipfr_ref); 1252 token->ipt_data = next; 1253 } else { 1254 bzero(&zero, sizeof(zero)); 1255 next = &zero; 1256 token->ipt_data = NULL; 1257 } 1258 if (next->ipfr_next == NULL) 1259 ipf_token_mark_complete(token); 1260 1261 RWLOCK_EXIT(lock); 1262 1263 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 1264 if (error != 0) 1265 IPFERROR(20002); 1266 1267 if (frag != NULL) { 1268#ifdef USE_MUTEXES 1269 ipf_frag_deref(softc, &frag, lock); 1270#else 1271 ipf_frag_deref(softc, &frag); 1272#endif 1273 } 1274 return error; 1275} 1276 1277 1278/* ------------------------------------------------------------------------ */ 1279/* Function: ipf_frag_pkt_deref */ 1280/* Returns: Nil */ 1281/* Parameters: softc(I) - pointer to soft context main structure */ 1282/* data(I) - pointer to frag cache pointer */ 1283/* */ 1284/* This function is the external interface for dropping a reference to a */ 1285/* fragment cache entry used by filter rules. */ 1286/* ------------------------------------------------------------------------ */ 1287void 1288ipf_frag_pkt_deref(softc, data) 1289 ipf_main_softc_t *softc; 1290 void *data; 1291{ 1292 ipfr_t **frp = data; 1293 1294#ifdef USE_MUTEXES 1295 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1296 1297 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag); 1298#else 1299 ipf_frag_deref(softc->ipf_frag_soft, frp); 1300#endif 1301} 1302 1303 1304/* ------------------------------------------------------------------------ */ 1305/* Function: ipf_frag_nat_deref */ 1306/* Returns: Nil */ 1307/* Parameters: softc(I) - pointer to soft context main structure */ 1308/* data(I) - pointer to frag cache pointer */ 1309/* */ 1310/* This function is the external interface for dropping a reference to a */ 1311/* fragment cache entry used by NAT table entries. */ 1312/* ------------------------------------------------------------------------ */ 1313void 1314ipf_frag_nat_deref(softc, data) 1315 ipf_main_softc_t *softc; 1316 void *data; 1317{ 1318 ipfr_t **frp = data; 1319 1320#ifdef USE_MUTEXES 1321 ipf_frag_softc_t *softf = softc->ipf_frag_soft; 1322 1323 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag); 1324#else 1325 ipf_frag_deref(softc->ipf_frag_soft, frp); 1326#endif 1327} 1328 1329 1330/* ------------------------------------------------------------------------ */ 1331/* Function: ipf_frag_deref */ 1332/* Returns: Nil */ 1333/* Parameters: frp(IO) - pointer to fragment structure to deference */ 1334/* lock(I) - lock associated with the fragment */ 1335/* */ 1336/* This function dereferences a fragment structure (ipfr_t). The pointer */ 1337/* passed in will always be reset back to NULL, even if the structure is */ 1338/* not freed, to enforce the notion that the caller is no longer entitled */ 1339/* to use the pointer it is dropping the reference to. */ 1340/* ------------------------------------------------------------------------ */ 1341static void 1342ipf_frag_deref(arg, frp 1343#ifdef USE_MUTEXES 1344, lock 1345#endif 1346) 1347 void *arg; 1348 ipfr_t **frp; 1349#ifdef USE_MUTEXES 1350 ipfrwlock_t *lock; 1351#endif 1352{ 1353 ipf_frag_softc_t *softf = arg; 1354 ipfr_t *fra; 1355 1356 fra = *frp; 1357 *frp = NULL; 1358 1359 WRITE_ENTER(lock); 1360 fra->ipfr_ref--; 1361 if (fra->ipfr_ref <= 0) 1362 ipf_frag_free(softf, fra); 1363 RWLOCK_EXIT(lock); 1364} 1365