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