17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright (C) 1993-2003 by Darren Reed. 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz * 6*72680cf5SDarren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 77c478bd9Sstevel@tonic-gate * Use is subject to license terms. 87c478bd9Sstevel@tonic-gate */ 97c478bd9Sstevel@tonic-gate 107c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL) 117c478bd9Sstevel@tonic-gate # undef KERNEL 127c478bd9Sstevel@tonic-gate # undef _KERNEL 137c478bd9Sstevel@tonic-gate # define KERNEL 1 147c478bd9Sstevel@tonic-gate # define _KERNEL 1 157c478bd9Sstevel@tonic-gate #endif 167c478bd9Sstevel@tonic-gate #include <sys/errno.h> 177c478bd9Sstevel@tonic-gate #include <sys/types.h> 187c478bd9Sstevel@tonic-gate #include <sys/param.h> 197c478bd9Sstevel@tonic-gate #include <sys/time.h> 207c478bd9Sstevel@tonic-gate #include <sys/file.h> 217c478bd9Sstevel@tonic-gate #ifdef __hpux 227c478bd9Sstevel@tonic-gate # include <sys/timeout.h> 237c478bd9Sstevel@tonic-gate #endif 247c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) 257c478bd9Sstevel@tonic-gate # include <stdio.h> 267c478bd9Sstevel@tonic-gate # include <string.h> 277c478bd9Sstevel@tonic-gate # include <stdlib.h> 287c478bd9Sstevel@tonic-gate # define _KERNEL 297c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__ 307c478bd9Sstevel@tonic-gate struct file; 317c478bd9Sstevel@tonic-gate # endif 327c478bd9Sstevel@tonic-gate # include <sys/uio.h> 337c478bd9Sstevel@tonic-gate # undef _KERNEL 347c478bd9Sstevel@tonic-gate #endif 357c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 367c478bd9Sstevel@tonic-gate # include <sys/filio.h> 377c478bd9Sstevel@tonic-gate # include <sys/fcntl.h> 387c478bd9Sstevel@tonic-gate #else 397c478bd9Sstevel@tonic-gate # include <sys/ioctl.h> 407c478bd9Sstevel@tonic-gate #endif 41ab25eeb5Syz #if !defined(linux) 42ab25eeb5Syz # include <sys/protosw.h> 43ab25eeb5Syz #endif 447c478bd9Sstevel@tonic-gate #include <sys/socket.h> 457c478bd9Sstevel@tonic-gate #if defined(_KERNEL) 467c478bd9Sstevel@tonic-gate # include <sys/systm.h> 477c478bd9Sstevel@tonic-gate # if !defined(__SVR4) && !defined(__svr4__) 487c478bd9Sstevel@tonic-gate # include <sys/mbuf.h> 497c478bd9Sstevel@tonic-gate # endif 507c478bd9Sstevel@tonic-gate #endif 517c478bd9Sstevel@tonic-gate #if !defined(__SVR4) && !defined(__svr4__) 52ab25eeb5Syz # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX) 537c478bd9Sstevel@tonic-gate # include <sys/kernel.h> 547c478bd9Sstevel@tonic-gate # endif 557c478bd9Sstevel@tonic-gate #else 567c478bd9Sstevel@tonic-gate # include <sys/byteorder.h> 577c478bd9Sstevel@tonic-gate # ifdef _KERNEL 587c478bd9Sstevel@tonic-gate # include <sys/dditypes.h> 597c478bd9Sstevel@tonic-gate # endif 607c478bd9Sstevel@tonic-gate # include <sys/stream.h> 617c478bd9Sstevel@tonic-gate # include <sys/kmem.h> 627c478bd9Sstevel@tonic-gate #endif 637c478bd9Sstevel@tonic-gate #include <net/if.h> 647c478bd9Sstevel@tonic-gate #ifdef sun 657c478bd9Sstevel@tonic-gate # include <net/af.h> 667c478bd9Sstevel@tonic-gate #endif 677c478bd9Sstevel@tonic-gate #include <net/route.h> 687c478bd9Sstevel@tonic-gate #include <netinet/in.h> 697c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 707c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 71ab25eeb5Syz #if !defined(linux) 72ab25eeb5Syz # include <netinet/ip_var.h> 73ab25eeb5Syz #endif 747c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 757c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 767c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 777c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h" 78ab25eeb5Syz #include <netinet/tcpip.h> 797c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h" 807c478bd9Sstevel@tonic-gate #include "netinet/ip_nat.h" 817c478bd9Sstevel@tonic-gate #include "netinet/ip_frag.h" 827c478bd9Sstevel@tonic-gate #include "netinet/ip_state.h" 837c478bd9Sstevel@tonic-gate #include "netinet/ip_auth.h" 84f4b3ec61Sdh #include "netinet/ipf_stack.h" 857c478bd9Sstevel@tonic-gate #if (__FreeBSD_version >= 300000) 867c478bd9Sstevel@tonic-gate # include <sys/malloc.h> 877c478bd9Sstevel@tonic-gate # if defined(_KERNEL) 887c478bd9Sstevel@tonic-gate # ifndef IPFILTER_LKM 897c478bd9Sstevel@tonic-gate # include <sys/libkern.h> 907c478bd9Sstevel@tonic-gate # include <sys/systm.h> 917c478bd9Sstevel@tonic-gate # endif 927c478bd9Sstevel@tonic-gate extern struct callout_handle fr_slowtimer_ch; 937c478bd9Sstevel@tonic-gate # endif 947c478bd9Sstevel@tonic-gate #endif 957c478bd9Sstevel@tonic-gate #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 967c478bd9Sstevel@tonic-gate # include <sys/callout.h> 977c478bd9Sstevel@tonic-gate extern struct callout fr_slowtimer_ch; 987c478bd9Sstevel@tonic-gate #endif 997c478bd9Sstevel@tonic-gate #if defined(__OpenBSD__) 1007c478bd9Sstevel@tonic-gate # include <sys/timeout.h> 1017c478bd9Sstevel@tonic-gate extern struct timeout fr_slowtimer_ch; 1027c478bd9Sstevel@tonic-gate #endif 103ab25eeb5Syz /* END OF INCLUDES */ 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate #if !defined(lint) 1067c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; 107ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $"; 1087c478bd9Sstevel@tonic-gate #endif 1097c478bd9Sstevel@tonic-gate 110*72680cf5SDarren Reed static INLINE int ipfr_index __P((fr_info_t *, ipfr_t *)); 1117c478bd9Sstevel@tonic-gate static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); 1127c478bd9Sstevel@tonic-gate static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); 113f4b3ec61Sdh static void fr_fragdelete __P((ipfr_t *, ipfr_t ***, ipf_stack_t *)); 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1167c478bd9Sstevel@tonic-gate /* Function: fr_fraginit */ 1177c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 1187c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1197c478bd9Sstevel@tonic-gate /* */ 1207c478bd9Sstevel@tonic-gate /* Initialise the hash tables for the fragment cache lookups. */ 1217c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 122f4b3ec61Sdh int fr_fraginit(ifs) 123f4b3ec61Sdh ipf_stack_t *ifs; 1247c478bd9Sstevel@tonic-gate { 125f4b3ec61Sdh ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 126f4b3ec61Sdh ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 127f4b3ec61Sdh ifs->ifs_ipfr_ipidtail = &ifs->ifs_ipfr_ipidlist; 1288128a42dSan /* the IP frag related variables are set in ipftuneable_setdefs() to 1298128a42dSan * their default values 1308128a42dSan */ 131f4b3ec61Sdh 132f4b3ec61Sdh KMALLOCS(ifs->ifs_ipfr_heads, ipfr_t **, 133f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 134f4b3ec61Sdh if (ifs->ifs_ipfr_heads == NULL) 1357c478bd9Sstevel@tonic-gate return -1; 136f4b3ec61Sdh bzero((char *)ifs->ifs_ipfr_heads, 137f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1387c478bd9Sstevel@tonic-gate 139f4b3ec61Sdh KMALLOCS(ifs->ifs_ipfr_nattab, ipfr_t **, 140f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 141f4b3ec61Sdh if (ifs->ifs_ipfr_nattab == NULL) 1427c478bd9Sstevel@tonic-gate return -1; 143f4b3ec61Sdh bzero((char *)ifs->ifs_ipfr_nattab, 144f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1457c478bd9Sstevel@tonic-gate 146f4b3ec61Sdh KMALLOCS(ifs->ifs_ipfr_ipidtab, ipfr_t **, 147f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 148f4b3ec61Sdh if (ifs->ifs_ipfr_ipidtab == NULL) 1497c478bd9Sstevel@tonic-gate return -1; 150f4b3ec61Sdh bzero((char *)ifs->ifs_ipfr_ipidtab, 151f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1527c478bd9Sstevel@tonic-gate 153f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_frag, "ipf fragment rwlock"); 1547663b816Sml 1557663b816Sml /* Initialise frblock with "block in all" */ 156f4b3ec61Sdh bzero((char *)&ifs->ifs_frblock, sizeof(ifs->ifs_frblock)); 157f4b3ec61Sdh ifs->ifs_frblock.fr_flags = FR_BLOCK|FR_INQUE; /* block in */ 158f4b3ec61Sdh ifs->ifs_frblock.fr_ref = 1; 1597663b816Sml 160f4b3ec61Sdh ifs->ifs_fr_frag_init = 1; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate return 0; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 1677c478bd9Sstevel@tonic-gate /* Function: fr_fragunload */ 1687c478bd9Sstevel@tonic-gate /* Returns: Nil */ 1697c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 1707c478bd9Sstevel@tonic-gate /* */ 1717c478bd9Sstevel@tonic-gate /* Free all memory allocated whilst running and from initialisation. */ 1727c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 173f4b3ec61Sdh void fr_fragunload(ifs) 174f4b3ec61Sdh ipf_stack_t *ifs; 1757c478bd9Sstevel@tonic-gate { 176f4b3ec61Sdh if (ifs->ifs_fr_frag_init == 1) { 177f4b3ec61Sdh fr_fragclear(ifs); 1787c478bd9Sstevel@tonic-gate 179f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_frag); 180f4b3ec61Sdh ifs->ifs_fr_frag_init = 0; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 183f4b3ec61Sdh if (ifs->ifs_ipfr_heads != NULL) { 184f4b3ec61Sdh KFREES(ifs->ifs_ipfr_heads, 185f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 186f4b3ec61Sdh } 187f4b3ec61Sdh ifs->ifs_ipfr_heads = NULL; 1887c478bd9Sstevel@tonic-gate 189f4b3ec61Sdh if (ifs->ifs_ipfr_nattab != NULL) { 190f4b3ec61Sdh KFREES(ifs->ifs_ipfr_nattab, 191f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 192f4b3ec61Sdh } 193f4b3ec61Sdh ifs->ifs_ipfr_nattab = NULL; 1947c478bd9Sstevel@tonic-gate 195f4b3ec61Sdh if (ifs->ifs_ipfr_ipidtab != NULL) { 196f4b3ec61Sdh KFREES(ifs->ifs_ipfr_ipidtab, 197f4b3ec61Sdh ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 198f4b3ec61Sdh } 199f4b3ec61Sdh ifs->ifs_ipfr_ipidtab = NULL; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 2047c478bd9Sstevel@tonic-gate /* Function: fr_fragstats */ 205ab25eeb5Syz /* Returns: ipfrstat_t* - pointer to struct with current frag stats */ 2067c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 2077c478bd9Sstevel@tonic-gate /* */ 2087c478bd9Sstevel@tonic-gate /* Updates ipfr_stats with current information and returns a pointer to it */ 2097c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 210f4b3ec61Sdh ipfrstat_t *fr_fragstats(ifs) 211f4b3ec61Sdh ipf_stack_t *ifs; 2127c478bd9Sstevel@tonic-gate { 213f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_table = ifs->ifs_ipfr_heads; 214f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_nattab = ifs->ifs_ipfr_nattab; 215f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_inuse = ifs->ifs_ipfr_inuse; 216f4b3ec61Sdh return &ifs->ifs_ipfr_stats; 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate 220*72680cf5SDarren Reed /* ------------------------------------------------------------------------ */ 221*72680cf5SDarren Reed /* Function: ipfr_index */ 222*72680cf5SDarren Reed /* Returns: int - index in fragment table for given packet */ 223*72680cf5SDarren Reed /* Parameters: fin(I) - pointer to packet information */ 224*72680cf5SDarren Reed /* frag(O) - pointer to ipfr_t structure to fill */ 225*72680cf5SDarren Reed /* */ 226*72680cf5SDarren Reed /* Compute the index in the fragment table while filling the per packet */ 227*72680cf5SDarren Reed /* part of the fragment state. */ 228*72680cf5SDarren Reed /* ------------------------------------------------------------------------ */ 229*72680cf5SDarren Reed static INLINE int ipfr_index(fin, frag) 230*72680cf5SDarren Reed fr_info_t *fin; 231*72680cf5SDarren Reed ipfr_t *frag; 232*72680cf5SDarren Reed { 233*72680cf5SDarren Reed u_int idx; 234*72680cf5SDarren Reed 235*72680cf5SDarren Reed /* 236*72680cf5SDarren Reed * For fragments, we record protocol, packet id, TOS and both IP#'s 237*72680cf5SDarren Reed * (these should all be the same for all fragments of a packet). 238*72680cf5SDarren Reed * 239*72680cf5SDarren Reed * build up a hash value to index the table with. 240*72680cf5SDarren Reed */ 241*72680cf5SDarren Reed 242*72680cf5SDarren Reed #ifdef USE_INET6 243*72680cf5SDarren Reed if (fin->fin_v == 6) { 244*72680cf5SDarren Reed ip6_t *ip6 = (ip6_t *)fin->fin_ip; 245*72680cf5SDarren Reed 246*72680cf5SDarren Reed frag->ipfr_p = fin->fin_fi.fi_p; 247*72680cf5SDarren Reed frag->ipfr_id = fin->fin_id; 248*72680cf5SDarren Reed frag->ipfr_tos = ip6->ip6_flow & IPV6_FLOWINFO_MASK; 249*72680cf5SDarren Reed frag->ipfr_src.in6 = ip6->ip6_src; 250*72680cf5SDarren Reed frag->ipfr_dst.in6 = ip6->ip6_dst; 251*72680cf5SDarren Reed } else 252*72680cf5SDarren Reed #endif 253*72680cf5SDarren Reed { 254*72680cf5SDarren Reed ip_t *ip = fin->fin_ip; 255*72680cf5SDarren Reed 256*72680cf5SDarren Reed frag->ipfr_p = ip->ip_p; 257*72680cf5SDarren Reed frag->ipfr_id = ip->ip_id; 258*72680cf5SDarren Reed frag->ipfr_tos = ip->ip_tos; 259*72680cf5SDarren Reed frag->ipfr_src.in4.s_addr = ip->ip_src.s_addr; 260*72680cf5SDarren Reed frag->ipfr_src.i6[1] = 0; 261*72680cf5SDarren Reed frag->ipfr_src.i6[2] = 0; 262*72680cf5SDarren Reed frag->ipfr_src.i6[3] = 0; 263*72680cf5SDarren Reed frag->ipfr_dst.in4.s_addr = ip->ip_dst.s_addr; 264*72680cf5SDarren Reed frag->ipfr_dst.i6[1] = 0; 265*72680cf5SDarren Reed frag->ipfr_dst.i6[2] = 0; 266*72680cf5SDarren Reed frag->ipfr_dst.i6[3] = 0; 267*72680cf5SDarren Reed } 268*72680cf5SDarren Reed frag->ipfr_ifp = fin->fin_ifp; 269*72680cf5SDarren Reed frag->ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 270*72680cf5SDarren Reed frag->ipfr_secmsk = fin->fin_fi.fi_secmsk; 271*72680cf5SDarren Reed frag->ipfr_auth = fin->fin_fi.fi_auth; 272*72680cf5SDarren Reed 273*72680cf5SDarren Reed idx = frag->ipfr_p; 274*72680cf5SDarren Reed idx += frag->ipfr_id; 275*72680cf5SDarren Reed idx += frag->ipfr_src.i6[0]; 276*72680cf5SDarren Reed idx += frag->ipfr_src.i6[1]; 277*72680cf5SDarren Reed idx += frag->ipfr_src.i6[2]; 278*72680cf5SDarren Reed idx += frag->ipfr_src.i6[3]; 279*72680cf5SDarren Reed idx += frag->ipfr_dst.i6[0]; 280*72680cf5SDarren Reed idx += frag->ipfr_dst.i6[1]; 281*72680cf5SDarren Reed idx += frag->ipfr_dst.i6[2]; 282*72680cf5SDarren Reed idx += frag->ipfr_dst.i6[3]; 283*72680cf5SDarren Reed idx *= 127; 284*72680cf5SDarren Reed idx %= IPFT_SIZE; 285*72680cf5SDarren Reed 286*72680cf5SDarren Reed return idx; 287*72680cf5SDarren Reed } 288*72680cf5SDarren Reed 289*72680cf5SDarren Reed 2907c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 2917c478bd9Sstevel@tonic-gate /* Function: ipfr_newfrag */ 2927c478bd9Sstevel@tonic-gate /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ 2937c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 2947c478bd9Sstevel@tonic-gate /* table(I) - pointer to frag table to add to */ 2957c478bd9Sstevel@tonic-gate /* */ 2967c478bd9Sstevel@tonic-gate /* Add a new entry to the fragment cache, registering it as having come */ 2977c478bd9Sstevel@tonic-gate /* through this box, with the result of the filter operation. */ 2987c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 2997c478bd9Sstevel@tonic-gate static ipfr_t *ipfr_newfrag(fin, pass, table) 3007c478bd9Sstevel@tonic-gate fr_info_t *fin; 3017c478bd9Sstevel@tonic-gate u_32_t pass; 3027c478bd9Sstevel@tonic-gate ipfr_t *table[]; 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate ipfr_t *fra, frag; 3057c478bd9Sstevel@tonic-gate u_int idx, off; 306f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 3077c478bd9Sstevel@tonic-gate 308bd5ba10fSan if (ifs->ifs_ipfr_inuse >= ifs->ifs_ipfr_size) 3097c478bd9Sstevel@tonic-gate return NULL; 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 3127c478bd9Sstevel@tonic-gate return NULL; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate if (pass & FR_FRSTRICT) 3157663b816Sml if (fin->fin_off != 0) 3167c478bd9Sstevel@tonic-gate return NULL; 3177c478bd9Sstevel@tonic-gate 318*72680cf5SDarren Reed idx = ipfr_index(fin, &frag); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * first, make sure it isn't already there... 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 3247c478bd9Sstevel@tonic-gate if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, 3257c478bd9Sstevel@tonic-gate IPFR_CMPSZ)) { 326f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_exists++; 3277c478bd9Sstevel@tonic-gate return NULL; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * allocate some memory, if possible, if not, just record that we 3327c478bd9Sstevel@tonic-gate * failed to do so. 3337c478bd9Sstevel@tonic-gate */ 3347c478bd9Sstevel@tonic-gate KMALLOC(fra, ipfr_t *); 3357c478bd9Sstevel@tonic-gate if (fra == NULL) { 336f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_nomem++; 3377c478bd9Sstevel@tonic-gate return NULL; 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 340ab25eeb5Syz fra->ipfr_rule = fin->fin_fr; 341ab25eeb5Syz if (fra->ipfr_rule != NULL) { 342ab25eeb5Syz 343ab25eeb5Syz frentry_t *fr; 344ab25eeb5Syz 345ab25eeb5Syz fr = fin->fin_fr; 346ab25eeb5Syz MUTEX_ENTER(&fr->fr_lock); 347ab25eeb5Syz fr->fr_ref++; 348ab25eeb5Syz MUTEX_EXIT(&fr->fr_lock); 3497663b816Sml } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * Insert the fragment into the fragment table, copy the struct used 3537c478bd9Sstevel@tonic-gate * in the search using bcopy rather than reassign each field. 3547c478bd9Sstevel@tonic-gate * Set the ttl to the default. 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate if ((fra->ipfr_hnext = table[idx]) != NULL) 3577c478bd9Sstevel@tonic-gate table[idx]->ipfr_hprev = &fra->ipfr_hnext; 3587c478bd9Sstevel@tonic-gate fra->ipfr_hprev = table + idx; 3597c478bd9Sstevel@tonic-gate fra->ipfr_data = NULL; 3607c478bd9Sstevel@tonic-gate table[idx] = fra; 3617c478bd9Sstevel@tonic-gate bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 362f4b3ec61Sdh fra->ipfr_ttl = ifs->ifs_fr_ticks + ifs->ifs_fr_ipfrttl; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * Compute the offset of the expected start of the next packet. 3667c478bd9Sstevel@tonic-gate */ 367*72680cf5SDarren Reed off = fin->fin_off >> 3; 3687663b816Sml if (off == 0) { 3697c478bd9Sstevel@tonic-gate fra->ipfr_seen0 = 1; 3707663b816Sml } else { 3717663b816Sml fra->ipfr_seen0 = 0; 3727663b816Sml } 373ab25eeb5Syz fra->ipfr_off = off + fin->fin_dlen; 3747c478bd9Sstevel@tonic-gate fra->ipfr_pass = pass; 375f4b3ec61Sdh fra->ipfr_ref = 1; 376f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_new++; 377f4b3ec61Sdh ifs->ifs_ipfr_inuse++; 3787c478bd9Sstevel@tonic-gate return fra; 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3837c478bd9Sstevel@tonic-gate /* Function: fr_newfrag */ 3847c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 3857c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 3867c478bd9Sstevel@tonic-gate /* */ 3877c478bd9Sstevel@tonic-gate /* Add a new entry to the fragment cache table based on the current packet */ 3887c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3897c478bd9Sstevel@tonic-gate int fr_newfrag(fin, pass) 3907c478bd9Sstevel@tonic-gate u_32_t pass; 3917c478bd9Sstevel@tonic-gate fr_info_t *fin; 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate ipfr_t *fra; 394f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 3957c478bd9Sstevel@tonic-gate 396f4b3ec61Sdh if (ifs->ifs_fr_frag_lock != 0) 397ab25eeb5Syz return -1; 3987c478bd9Sstevel@tonic-gate 399f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 400f4b3ec61Sdh fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_heads); 4017c478bd9Sstevel@tonic-gate if (fra != NULL) { 402f4b3ec61Sdh *ifs->ifs_ipfr_tail = fra; 403f4b3ec61Sdh fra->ipfr_prev = ifs->ifs_ipfr_tail; 404f4b3ec61Sdh ifs->ifs_ipfr_tail = &fra->ipfr_next; 405f4b3ec61Sdh if (ifs->ifs_ipfr_list == NULL) 406f4b3ec61Sdh ifs->ifs_ipfr_list = fra; 4077c478bd9Sstevel@tonic-gate fra->ipfr_next = NULL; 4087c478bd9Sstevel@tonic-gate } 409f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 4107c478bd9Sstevel@tonic-gate return fra ? 0 : -1; 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4157c478bd9Sstevel@tonic-gate /* Function: fr_nat_newfrag */ 4167c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 4177c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 4187c478bd9Sstevel@tonic-gate /* nat(I) - pointer to NAT structure */ 4197c478bd9Sstevel@tonic-gate /* */ 4207c478bd9Sstevel@tonic-gate /* Create a new NAT fragment cache entry based on the current packet and */ 4217c478bd9Sstevel@tonic-gate /* the NAT structure for this "session". */ 4227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4237c478bd9Sstevel@tonic-gate int fr_nat_newfrag(fin, pass, nat) 4247c478bd9Sstevel@tonic-gate fr_info_t *fin; 4257c478bd9Sstevel@tonic-gate u_32_t pass; 4267c478bd9Sstevel@tonic-gate nat_t *nat; 4277c478bd9Sstevel@tonic-gate { 4287c478bd9Sstevel@tonic-gate ipfr_t *fra; 429f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 4307c478bd9Sstevel@tonic-gate 431*72680cf5SDarren Reed if (ifs->ifs_fr_frag_lock != 0) 4327c478bd9Sstevel@tonic-gate return 0; 4337c478bd9Sstevel@tonic-gate 434f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 435f4b3ec61Sdh fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_nattab); 4367c478bd9Sstevel@tonic-gate if (fra != NULL) { 4377c478bd9Sstevel@tonic-gate fra->ipfr_data = nat; 4387c478bd9Sstevel@tonic-gate nat->nat_data = fra; 439f4b3ec61Sdh *ifs->ifs_ipfr_nattail = fra; 440f4b3ec61Sdh fra->ipfr_prev = ifs->ifs_ipfr_nattail; 441f4b3ec61Sdh ifs->ifs_ipfr_nattail = &fra->ipfr_next; 4427c478bd9Sstevel@tonic-gate fra->ipfr_next = NULL; 4437c478bd9Sstevel@tonic-gate } 444f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 4457c478bd9Sstevel@tonic-gate return fra ? 0 : -1; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4507c478bd9Sstevel@tonic-gate /* Function: fr_ipid_newfrag */ 4517c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error */ 4527c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 4537c478bd9Sstevel@tonic-gate /* ipid(I) - new IP ID for this fragmented packet */ 4547c478bd9Sstevel@tonic-gate /* */ 4557c478bd9Sstevel@tonic-gate /* Create a new fragment cache entry for this packet and store, as a data */ 4567c478bd9Sstevel@tonic-gate /* pointer, the new IP ID value. */ 4577c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4587c478bd9Sstevel@tonic-gate int fr_ipid_newfrag(fin, ipid) 4597c478bd9Sstevel@tonic-gate fr_info_t *fin; 4607c478bd9Sstevel@tonic-gate u_32_t ipid; 4617c478bd9Sstevel@tonic-gate { 4627c478bd9Sstevel@tonic-gate ipfr_t *fra; 463f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 4647c478bd9Sstevel@tonic-gate 465f4b3ec61Sdh if (ifs->ifs_fr_frag_lock) 4667c478bd9Sstevel@tonic-gate return 0; 4677c478bd9Sstevel@tonic-gate 468f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 469f4b3ec61Sdh fra = ipfr_newfrag(fin, 0, ifs->ifs_ipfr_ipidtab); 4707c478bd9Sstevel@tonic-gate if (fra != NULL) { 4717c478bd9Sstevel@tonic-gate fra->ipfr_data = (void *)(uintptr_t)ipid; 472f4b3ec61Sdh *ifs->ifs_ipfr_ipidtail = fra; 473f4b3ec61Sdh fra->ipfr_prev = ifs->ifs_ipfr_ipidtail; 474f4b3ec61Sdh ifs->ifs_ipfr_ipidtail = &fra->ipfr_next; 4757c478bd9Sstevel@tonic-gate fra->ipfr_next = NULL; 4767c478bd9Sstevel@tonic-gate } 477f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 4787c478bd9Sstevel@tonic-gate return fra ? 0 : -1; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4837c478bd9Sstevel@tonic-gate /* Function: fr_fraglookup */ 4847c478bd9Sstevel@tonic-gate /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 4857c478bd9Sstevel@tonic-gate /* matching entry in the frag table, else NULL */ 4867c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 4877c478bd9Sstevel@tonic-gate /* table(I) - pointer to fragment cache table to search */ 4887c478bd9Sstevel@tonic-gate /* */ 4897c478bd9Sstevel@tonic-gate /* Check the fragment cache to see if there is already a record of this */ 4907c478bd9Sstevel@tonic-gate /* packet with its filter result known. */ 4917c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4927c478bd9Sstevel@tonic-gate static ipfr_t *fr_fraglookup(fin, table) 4937c478bd9Sstevel@tonic-gate fr_info_t *fin; 4947c478bd9Sstevel@tonic-gate ipfr_t *table[]; 4957c478bd9Sstevel@tonic-gate { 4967c478bd9Sstevel@tonic-gate ipfr_t *f, frag; 4977c478bd9Sstevel@tonic-gate u_int idx; 498f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 5017c478bd9Sstevel@tonic-gate return NULL; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate * For fragments, we record protocol, packet id, TOS and both IP#'s 5057c478bd9Sstevel@tonic-gate * (these should all be the same for all fragments of a packet). 5067c478bd9Sstevel@tonic-gate * 5077c478bd9Sstevel@tonic-gate * build up a hash value to index the table with. 5087c478bd9Sstevel@tonic-gate */ 509*72680cf5SDarren Reed idx = ipfr_index(fin, &frag); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate /* 5127c478bd9Sstevel@tonic-gate * check the table, careful to only compare the right amount of data 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate for (f = table[idx]; f; f = f->ipfr_hnext) 5157c478bd9Sstevel@tonic-gate if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, 5167c478bd9Sstevel@tonic-gate IPFR_CMPSZ)) { 5177c478bd9Sstevel@tonic-gate u_short off; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /* 5207c478bd9Sstevel@tonic-gate * We don't want to let short packets match because 5217c478bd9Sstevel@tonic-gate * they could be compromising the security of other 5227c478bd9Sstevel@tonic-gate * rules that want to match on layer 4 fields (and 5237c478bd9Sstevel@tonic-gate * can't because they have been fragmented off.) 5247c478bd9Sstevel@tonic-gate * Why do this check here? The counter acts as an 5257c478bd9Sstevel@tonic-gate * indicator of this kind of attack, whereas if it was 5267c478bd9Sstevel@tonic-gate * elsewhere, it wouldn't know if other matching 5277c478bd9Sstevel@tonic-gate * packets had been seen. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate if (fin->fin_flx & FI_SHORT) { 530f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_short); 5317c478bd9Sstevel@tonic-gate continue; 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* 5357c478bd9Sstevel@tonic-gate * XXX - We really need to be guarding against the 5367c478bd9Sstevel@tonic-gate * retransmission of (src,dst,id,offset-range) here 5377c478bd9Sstevel@tonic-gate * because a fragmented packet is never resent with 5387c478bd9Sstevel@tonic-gate * the same IP ID# (or shouldn't). 5397c478bd9Sstevel@tonic-gate */ 540*72680cf5SDarren Reed off = fin->fin_off >> 3; 5417c478bd9Sstevel@tonic-gate if (f->ipfr_seen0) { 5427c478bd9Sstevel@tonic-gate if (off == 0) { 543f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_retrans0); 5447c478bd9Sstevel@tonic-gate continue; 5457c478bd9Sstevel@tonic-gate } 5467663b816Sml } else if (off == 0) { 5477c478bd9Sstevel@tonic-gate f->ipfr_seen0 = 1; 5487663b816Sml } 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate if (f != table[idx]) { 5517c478bd9Sstevel@tonic-gate ipfr_t **fp; 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* 5547c478bd9Sstevel@tonic-gate * Move fragment info. to the top of the list 5557c478bd9Sstevel@tonic-gate * to speed up searches. First, delink... 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate fp = f->ipfr_hprev; 5587c478bd9Sstevel@tonic-gate (*fp) = f->ipfr_hnext; 5597c478bd9Sstevel@tonic-gate if (f->ipfr_hnext != NULL) 5607c478bd9Sstevel@tonic-gate f->ipfr_hnext->ipfr_hprev = fp; 5617c478bd9Sstevel@tonic-gate /* 5627c478bd9Sstevel@tonic-gate * Then put back at the top of the chain. 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate f->ipfr_hnext = table[idx]; 5657c478bd9Sstevel@tonic-gate table[idx]->ipfr_hprev = &f->ipfr_hnext; 5667c478bd9Sstevel@tonic-gate f->ipfr_hprev = table + idx; 5677c478bd9Sstevel@tonic-gate table[idx] = f; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * If we've follwed the fragments, and this is the 5727c478bd9Sstevel@tonic-gate * last (in order), shrink expiration time. 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate if (off == f->ipfr_off) { 575*72680cf5SDarren Reed if (!(fin->fin_flx & FI_MOREFRAG)) 576f4b3ec61Sdh f->ipfr_ttl = ifs->ifs_fr_ticks + 1; 577ab25eeb5Syz f->ipfr_off = fin->fin_dlen + off; 5787c478bd9Sstevel@tonic-gate } else if (f->ipfr_pass & FR_FRSTRICT) 5797c478bd9Sstevel@tonic-gate continue; 580f4b3ec61Sdh ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_hits); 5817c478bd9Sstevel@tonic-gate return f; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate return NULL; 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5887c478bd9Sstevel@tonic-gate /* Function: fr_nat_knownfrag */ 5897c478bd9Sstevel@tonic-gate /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 5907c478bd9Sstevel@tonic-gate /* match found, else NULL */ 5917c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 5927c478bd9Sstevel@tonic-gate /* */ 5937c478bd9Sstevel@tonic-gate /* Functional interface for NAT lookups of the NAT fragment cache */ 5947c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5957c478bd9Sstevel@tonic-gate nat_t *fr_nat_knownfrag(fin) 5967c478bd9Sstevel@tonic-gate fr_info_t *fin; 5977c478bd9Sstevel@tonic-gate { 5987c478bd9Sstevel@tonic-gate nat_t *nat; 5997c478bd9Sstevel@tonic-gate ipfr_t *ipf; 600f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 6017c478bd9Sstevel@tonic-gate 602*72680cf5SDarren Reed if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_natlist) 6037c478bd9Sstevel@tonic-gate return NULL; 604f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_natfrag); 605f4b3ec61Sdh ipf = fr_fraglookup(fin, ifs->ifs_ipfr_nattab); 6067c478bd9Sstevel@tonic-gate if (ipf != NULL) { 6077c478bd9Sstevel@tonic-gate nat = ipf->ipfr_data; 6087c478bd9Sstevel@tonic-gate /* 6097c478bd9Sstevel@tonic-gate * This is the last fragment for this packet. 6107c478bd9Sstevel@tonic-gate */ 611f4b3ec61Sdh if ((ipf->ipfr_ttl == ifs->ifs_fr_ticks + 1) && (nat != NULL)) { 6127c478bd9Sstevel@tonic-gate nat->nat_data = NULL; 6137c478bd9Sstevel@tonic-gate ipf->ipfr_data = NULL; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate } else 6167c478bd9Sstevel@tonic-gate nat = NULL; 617f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 6187c478bd9Sstevel@tonic-gate return nat; 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6237c478bd9Sstevel@tonic-gate /* Function: fr_ipid_knownfrag */ 6247c478bd9Sstevel@tonic-gate /* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 6257c478bd9Sstevel@tonic-gate /* return 0xfffffff to indicate no match. */ 6267c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 6277c478bd9Sstevel@tonic-gate /* */ 6287c478bd9Sstevel@tonic-gate /* Functional interface for IP ID lookups of the IP ID fragment cache */ 6297c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6307c478bd9Sstevel@tonic-gate u_32_t fr_ipid_knownfrag(fin) 6317c478bd9Sstevel@tonic-gate fr_info_t *fin; 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate ipfr_t *ipf; 6347c478bd9Sstevel@tonic-gate u_32_t id; 635f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 6367c478bd9Sstevel@tonic-gate 637*72680cf5SDarren Reed if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_ipidlist) 6387c478bd9Sstevel@tonic-gate return 0xffffffff; 6397c478bd9Sstevel@tonic-gate 640f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_ipidfrag); 641f4b3ec61Sdh ipf = fr_fraglookup(fin, ifs->ifs_ipfr_ipidtab); 6427c478bd9Sstevel@tonic-gate if (ipf != NULL) 6437c478bd9Sstevel@tonic-gate id = (u_32_t)(uintptr_t)ipf->ipfr_data; 6447c478bd9Sstevel@tonic-gate else 6457c478bd9Sstevel@tonic-gate id = 0xffffffff; 646f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 6477c478bd9Sstevel@tonic-gate return id; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6527c478bd9Sstevel@tonic-gate /* Function: fr_knownfrag */ 6537c478bd9Sstevel@tonic-gate /* Returns: frentry_t* - pointer to filter rule if a match is found in */ 6547c478bd9Sstevel@tonic-gate /* the frag cache table, else NULL. */ 6557c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 6567c478bd9Sstevel@tonic-gate /* passp(O) - pointer to where to store rule flags resturned */ 6577c478bd9Sstevel@tonic-gate /* */ 6587c478bd9Sstevel@tonic-gate /* Functional interface for normal lookups of the fragment cache. If a */ 6597c478bd9Sstevel@tonic-gate /* match is found, return the rule pointer and flags from the rule, except */ 6607c478bd9Sstevel@tonic-gate /* that if FR_LOGFIRST is set, reset FR_LOG. */ 6617c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6627c478bd9Sstevel@tonic-gate frentry_t *fr_knownfrag(fin, passp) 6637c478bd9Sstevel@tonic-gate fr_info_t *fin; 6647c478bd9Sstevel@tonic-gate u_32_t *passp; 6657c478bd9Sstevel@tonic-gate { 6667c478bd9Sstevel@tonic-gate frentry_t *fr = NULL; 6677c478bd9Sstevel@tonic-gate ipfr_t *fra; 6687663b816Sml u_32_t pass, oflx; 669f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 6707c478bd9Sstevel@tonic-gate 671*72680cf5SDarren Reed if (ifs->ifs_fr_frag_lock || (ifs->ifs_ipfr_list == NULL)) 6727c478bd9Sstevel@tonic-gate return NULL; 6737c478bd9Sstevel@tonic-gate 674f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_frag); 6757663b816Sml oflx = fin->fin_flx; 676f4b3ec61Sdh fra = fr_fraglookup(fin, ifs->ifs_ipfr_heads); 6777c478bd9Sstevel@tonic-gate if (fra != NULL) { 6787c478bd9Sstevel@tonic-gate fr = fra->ipfr_rule; 6797c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 6807c478bd9Sstevel@tonic-gate if (fr != NULL) { 6817c478bd9Sstevel@tonic-gate pass = fr->fr_flags; 6827c478bd9Sstevel@tonic-gate if ((pass & FR_LOGFIRST) != 0) 6837c478bd9Sstevel@tonic-gate pass &= ~(FR_LOGFIRST|FR_LOG); 6847c478bd9Sstevel@tonic-gate *passp = pass; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate } 6877663b816Sml if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) { 6887663b816Sml *passp &= ~FR_CMDMASK; 6897663b816Sml *passp |= FR_BLOCK; 690f4b3ec61Sdh fr = &ifs->ifs_frblock; 6917663b816Sml } 692f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 6937c478bd9Sstevel@tonic-gate return fr; 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6987c478bd9Sstevel@tonic-gate /* Function: fr_forget */ 6997c478bd9Sstevel@tonic-gate /* Returns: Nil */ 7007c478bd9Sstevel@tonic-gate /* Parameters: ptr(I) - pointer to data structure */ 7017c478bd9Sstevel@tonic-gate /* */ 7027c478bd9Sstevel@tonic-gate /* Search through all of the fragment cache entries and wherever a pointer */ 7037c478bd9Sstevel@tonic-gate /* is found to match ptr, reset it to NULL. */ 7047c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 705f4b3ec61Sdh void fr_forget(ptr, ifs) 7067c478bd9Sstevel@tonic-gate void *ptr; 707f4b3ec61Sdh ipf_stack_t *ifs; 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate ipfr_t *fr; 7107c478bd9Sstevel@tonic-gate 711f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 712f4b3ec61Sdh for (fr = ifs->ifs_ipfr_list; fr; fr = fr->ipfr_next) 7137c478bd9Sstevel@tonic-gate if (fr->ipfr_data == ptr) 7147c478bd9Sstevel@tonic-gate fr->ipfr_data = NULL; 715f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7207c478bd9Sstevel@tonic-gate /* Function: fr_forgetnat */ 7217c478bd9Sstevel@tonic-gate /* Returns: Nil */ 7227c478bd9Sstevel@tonic-gate /* Parameters: ptr(I) - pointer to data structure */ 7237c478bd9Sstevel@tonic-gate /* */ 7247c478bd9Sstevel@tonic-gate /* Search through all of the fragment cache entries for NAT and wherever a */ 7257c478bd9Sstevel@tonic-gate /* pointer is found to match ptr, reset it to NULL. */ 7267c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 727f4b3ec61Sdh void fr_forgetnat(ptr, ifs) 7287c478bd9Sstevel@tonic-gate void *ptr; 729f4b3ec61Sdh ipf_stack_t *ifs; 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate ipfr_t *fr; 7327c478bd9Sstevel@tonic-gate 733f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 734f4b3ec61Sdh for (fr = ifs->ifs_ipfr_natlist; fr; fr = fr->ipfr_next) 7357c478bd9Sstevel@tonic-gate if (fr->ipfr_data == ptr) 7367c478bd9Sstevel@tonic-gate fr->ipfr_data = NULL; 737f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7427c478bd9Sstevel@tonic-gate /* Function: fr_fragdelete */ 7437c478bd9Sstevel@tonic-gate /* Returns: Nil */ 7447c478bd9Sstevel@tonic-gate /* Parameters: fra(I) - pointer to fragment structure to delete */ 7457c478bd9Sstevel@tonic-gate /* tail(IO) - pointer to the pointer to the tail of the frag */ 7467c478bd9Sstevel@tonic-gate /* list */ 7477c478bd9Sstevel@tonic-gate /* */ 7487c478bd9Sstevel@tonic-gate /* Remove a fragment cache table entry from the table & list. Also free */ 7497c478bd9Sstevel@tonic-gate /* the filter rule it is associated with it if it is no longer used as a */ 7507c478bd9Sstevel@tonic-gate /* result of decreasing the reference count. */ 7517c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 752f4b3ec61Sdh static void fr_fragdelete(fra, tail, ifs) 7537c478bd9Sstevel@tonic-gate ipfr_t *fra, ***tail; 754f4b3ec61Sdh ipf_stack_t *ifs; 7557c478bd9Sstevel@tonic-gate { 7567c478bd9Sstevel@tonic-gate frentry_t *fr; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate fr = fra->ipfr_rule; 7597c478bd9Sstevel@tonic-gate if (fr != NULL) 760f4b3ec61Sdh (void)fr_derefrule(&fr, ifs); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate if (fra->ipfr_next) 7637c478bd9Sstevel@tonic-gate fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 7647c478bd9Sstevel@tonic-gate *fra->ipfr_prev = fra->ipfr_next; 7657c478bd9Sstevel@tonic-gate if (*tail == &fra->ipfr_next) 7667c478bd9Sstevel@tonic-gate *tail = fra->ipfr_prev; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate if (fra->ipfr_hnext) 7697c478bd9Sstevel@tonic-gate fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 7707c478bd9Sstevel@tonic-gate *fra->ipfr_hprev = fra->ipfr_hnext; 771f4b3ec61Sdh 772f4b3ec61Sdh if (fra->ipfr_ref <= 0) 773f4b3ec61Sdh KFREE(fra); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7787c478bd9Sstevel@tonic-gate /* Function: fr_fragclear */ 7797c478bd9Sstevel@tonic-gate /* Returns: Nil */ 7807c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 7817c478bd9Sstevel@tonic-gate /* */ 7827c478bd9Sstevel@tonic-gate /* Free memory in use by fragment state information kept. Do the normal */ 7837c478bd9Sstevel@tonic-gate /* fragment state stuff first and then the NAT-fragment table. */ 7847c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 785f4b3ec61Sdh void fr_fragclear(ifs) 786f4b3ec61Sdh ipf_stack_t *ifs; 7877c478bd9Sstevel@tonic-gate { 7887c478bd9Sstevel@tonic-gate ipfr_t *fra; 7897c478bd9Sstevel@tonic-gate nat_t *nat; 7907c478bd9Sstevel@tonic-gate 791f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 792f4b3ec61Sdh while ((fra = ifs->ifs_ipfr_list) != NULL) { 793f4b3ec61Sdh fra->ipfr_ref--; 794f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 795f4b3ec61Sdh } 796f4b3ec61Sdh ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 797f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 7987c478bd9Sstevel@tonic-gate 799f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_nat); 800f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 801f4b3ec61Sdh while ((fra = ifs->ifs_ipfr_natlist) != NULL) { 8027c478bd9Sstevel@tonic-gate nat = fra->ipfr_data; 8037c478bd9Sstevel@tonic-gate if (nat != NULL) { 8047c478bd9Sstevel@tonic-gate if (nat->nat_data == fra) 8057c478bd9Sstevel@tonic-gate nat->nat_data = NULL; 8067c478bd9Sstevel@tonic-gate } 807f4b3ec61Sdh fra->ipfr_ref--; 808f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 8097c478bd9Sstevel@tonic-gate } 810f4b3ec61Sdh ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 811f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 812f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_nat); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 8177c478bd9Sstevel@tonic-gate /* Function: fr_fragexpire */ 8187c478bd9Sstevel@tonic-gate /* Returns: Nil */ 8197c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 8207c478bd9Sstevel@tonic-gate /* */ 8217c478bd9Sstevel@tonic-gate /* Expire entries in the fragment cache table that have been there too long */ 8227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 823f4b3ec61Sdh void fr_fragexpire(ifs) 824f4b3ec61Sdh ipf_stack_t *ifs; 8257c478bd9Sstevel@tonic-gate { 8267c478bd9Sstevel@tonic-gate ipfr_t **fp, *fra; 8277c478bd9Sstevel@tonic-gate nat_t *nat; 828ab25eeb5Syz SPL_INT(s); 8297c478bd9Sstevel@tonic-gate 830f4b3ec61Sdh if (ifs->ifs_fr_frag_lock) 8317c478bd9Sstevel@tonic-gate return; 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate SPL_NET(s); 834f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_frag); 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * Go through the entire table, looking for entries to expire, 837f4b3ec61Sdh * which is indicated by the ttl being less than or equal to 838f4b3ec61Sdh * ifs_fr_ticks. 8397c478bd9Sstevel@tonic-gate */ 840f4b3ec61Sdh for (fp = &ifs->ifs_ipfr_list; ((fra = *fp) != NULL); ) { 841f4b3ec61Sdh if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8427c478bd9Sstevel@tonic-gate break; 843f4b3ec61Sdh fra->ipfr_ref--; 844f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 845f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 846f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 8477c478bd9Sstevel@tonic-gate } 848f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_frag); 8497c478bd9Sstevel@tonic-gate 850f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 851f4b3ec61Sdh for (fp = &ifs->ifs_ipfr_ipidlist; ((fra = *fp) != NULL); ) { 852f4b3ec61Sdh if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8537c478bd9Sstevel@tonic-gate break; 854f4b3ec61Sdh fra->ipfr_ref--; 855f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_ipidtail, ifs); 856f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 857f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 8587c478bd9Sstevel@tonic-gate } 859f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * Same again for the NAT table, except that if the structure also 8637c478bd9Sstevel@tonic-gate * still points to a NAT structure, and the NAT structure points back 8647c478bd9Sstevel@tonic-gate * at the one to be free'd, NULL the reference from the NAT struct. 8657c478bd9Sstevel@tonic-gate * NOTE: We need to grab both mutex's early, and in this order so as 8667c478bd9Sstevel@tonic-gate * to prevent a deadlock if both try to expire at the same time. 8677c478bd9Sstevel@tonic-gate */ 868f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_nat); 869f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_natfrag); 870f4b3ec61Sdh for (fp = &ifs->ifs_ipfr_natlist; ((fra = *fp) != NULL); ) { 871f4b3ec61Sdh if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8727c478bd9Sstevel@tonic-gate break; 8737c478bd9Sstevel@tonic-gate nat = fra->ipfr_data; 8747c478bd9Sstevel@tonic-gate if (nat != NULL) { 8757c478bd9Sstevel@tonic-gate if (nat->nat_data == fra) 8767c478bd9Sstevel@tonic-gate nat->nat_data = NULL; 8777c478bd9Sstevel@tonic-gate } 878f4b3ec61Sdh fra->ipfr_ref--; 879f4b3ec61Sdh fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 880f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 881f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 8827c478bd9Sstevel@tonic-gate } 883f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 884f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_nat); 8857c478bd9Sstevel@tonic-gate SPL_X(s); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 8907c478bd9Sstevel@tonic-gate /* Function: fr_slowtimer */ 8917c478bd9Sstevel@tonic-gate /* Returns: Nil */ 8927c478bd9Sstevel@tonic-gate /* Parameters: Nil */ 8937c478bd9Sstevel@tonic-gate /* */ 8947c478bd9Sstevel@tonic-gate /* Slowly expire held state for fragments. Timeouts are set * in */ 8957c478bd9Sstevel@tonic-gate /* expectation of this being called twice per second. */ 8967c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 8977c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ 898ab25eeb5Syz !defined(__osf__) && !defined(linux)) 8997c478bd9Sstevel@tonic-gate # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) 900f4b3ec61Sdh void fr_slowtimer __P((void *arg)) 9017c478bd9Sstevel@tonic-gate # else 902f4b3ec61Sdh int fr_slowtimer(void *arg) 9037c478bd9Sstevel@tonic-gate # endif 9047c478bd9Sstevel@tonic-gate { 905f4b3ec61Sdh ipf_stack_t *ifs = arg; 906f4b3ec61Sdh 907f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 908f4b3ec61Sdh 909f4b3ec61Sdh fr_fragexpire(ifs); 910f4b3ec61Sdh fr_timeoutstate(ifs); 911f4b3ec61Sdh fr_natexpire(ifs); 912f4b3ec61Sdh fr_authexpire(ifs); 913f4b3ec61Sdh ifs->ifs_fr_ticks++; 914f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) 9157c478bd9Sstevel@tonic-gate goto done; 9167c478bd9Sstevel@tonic-gate # ifdef _KERNEL 9177c478bd9Sstevel@tonic-gate # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) 9187c478bd9Sstevel@tonic-gate callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); 9197c478bd9Sstevel@tonic-gate # else 9207c478bd9Sstevel@tonic-gate # if defined(__OpenBSD__) 9217c478bd9Sstevel@tonic-gate timeout_add(&fr_slowtimer_ch, hz/2); 9227c478bd9Sstevel@tonic-gate # else 9237c478bd9Sstevel@tonic-gate # if (__FreeBSD_version >= 300000) 9247c478bd9Sstevel@tonic-gate fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); 9257c478bd9Sstevel@tonic-gate # else 926ab25eeb5Syz # ifdef linux 927ab25eeb5Syz ; 928ab25eeb5Syz # else 9297c478bd9Sstevel@tonic-gate timeout(fr_slowtimer, NULL, hz/2); 930ab25eeb5Syz # endif 9317c478bd9Sstevel@tonic-gate # endif /* FreeBSD */ 9327c478bd9Sstevel@tonic-gate # endif /* OpenBSD */ 9337c478bd9Sstevel@tonic-gate # endif /* NetBSD */ 9347c478bd9Sstevel@tonic-gate # endif 9357c478bd9Sstevel@tonic-gate done: 936f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 9377c478bd9Sstevel@tonic-gate # if (BSD < 199103) || !defined(_KERNEL) 9387c478bd9Sstevel@tonic-gate return 0; 9397c478bd9Sstevel@tonic-gate # endif 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ 942f4b3ec61Sdh 943f4b3ec61Sdh /*ARGSUSED*/ 944f4b3ec61Sdh int fr_nextfrag(token, itp, top, tail, lock, ifs) 945f4b3ec61Sdh ipftoken_t *token; 946f4b3ec61Sdh ipfgeniter_t *itp; 947f4b3ec61Sdh ipfr_t **top, ***tail; 948f4b3ec61Sdh ipfrwlock_t *lock; 949f4b3ec61Sdh ipf_stack_t *ifs; 950f4b3ec61Sdh { 951f4b3ec61Sdh ipfr_t *frag, *next, zero; 952f4b3ec61Sdh int error = 0; 953f4b3ec61Sdh 954f4b3ec61Sdh READ_ENTER(lock); 955786c7074Sjojemann 956786c7074Sjojemann /* 957786c7074Sjojemann * Retrieve "previous" entry from token and find the next entry. 958786c7074Sjojemann */ 959786c7074Sjojemann frag = token->ipt_data; 960f4b3ec61Sdh if (frag == NULL) 961f4b3ec61Sdh next = *top; 962f4b3ec61Sdh else 963f4b3ec61Sdh next = frag->ipfr_next; 964f4b3ec61Sdh 965786c7074Sjojemann /* 966786c7074Sjojemann * If we found an entry, add reference to it and update token. 967786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 968786c7074Sjojemann */ 969f4b3ec61Sdh if (next != NULL) { 970f4b3ec61Sdh ATOMIC_INC(next->ipfr_ref); 971f4b3ec61Sdh token->ipt_data = next; 972f4b3ec61Sdh } else { 973f4b3ec61Sdh bzero(&zero, sizeof(zero)); 974f4b3ec61Sdh next = &zero; 975786c7074Sjojemann token->ipt_data = NULL; 976f4b3ec61Sdh } 977f4b3ec61Sdh 978786c7074Sjojemann /* 979786c7074Sjojemann * Now that we have ref, it's save to give up lock. 980786c7074Sjojemann */ 981786c7074Sjojemann RWLOCK_EXIT(lock); 982f4b3ec61Sdh 983786c7074Sjojemann /* 984786c7074Sjojemann * Copy out data and clean up references and token as needed. 985786c7074Sjojemann */ 986f4b3ec61Sdh error = COPYOUT(next, itp->igi_data, sizeof(*next)); 987f4b3ec61Sdh if (error != 0) 988f4b3ec61Sdh error = EFAULT; 989786c7074Sjojemann if (token->ipt_data == NULL) { 990786c7074Sjojemann ipf_freetoken(token, ifs); 991786c7074Sjojemann } else { 992786c7074Sjojemann if (frag != NULL) 993786c7074Sjojemann fr_fragderef(&frag, lock, ifs); 994786c7074Sjojemann if (next->ipfr_next == NULL) 995786c7074Sjojemann ipf_freetoken(token, ifs); 996786c7074Sjojemann } 997f4b3ec61Sdh return error; 998f4b3ec61Sdh } 999f4b3ec61Sdh 1000f4b3ec61Sdh 1001f4b3ec61Sdh void fr_fragderef(frp, lock, ifs) 1002f4b3ec61Sdh ipfr_t **frp; 1003f4b3ec61Sdh ipfrwlock_t *lock; 1004f4b3ec61Sdh ipf_stack_t *ifs; 1005f4b3ec61Sdh { 1006f4b3ec61Sdh ipfr_t *fra; 1007f4b3ec61Sdh 1008f4b3ec61Sdh fra = *frp; 1009f4b3ec61Sdh *frp = NULL; 1010f4b3ec61Sdh 1011f4b3ec61Sdh WRITE_ENTER(lock); 1012f4b3ec61Sdh fra->ipfr_ref--; 1013f4b3ec61Sdh if (fra->ipfr_ref <= 0) { 1014f4b3ec61Sdh KFREE(fra); 1015f4b3ec61Sdh ifs->ifs_ipfr_stats.ifs_expire++; 1016f4b3ec61Sdh ifs->ifs_ipfr_inuse--; 1017f4b3ec61Sdh } 1018f4b3ec61Sdh RWLOCK_EXIT(lock); 1019f4b3ec61Sdh } 1020