12393Syz155240 /* 22393Syz155240 * Copyright (C) 1993-2003 by Darren Reed. 32393Syz155240 * 42393Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 52393Syz155240 * 6*3448Sdh155122 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 72393Syz155240 * Use is subject to license terms. 82393Syz155240 */ 92393Syz155240 102393Syz155240 #pragma ident "%Z%%M% %I% %E% SMI" 112393Syz155240 122393Syz155240 #if defined(KERNEL) || defined(_KERNEL) 132393Syz155240 # undef KERNEL 142393Syz155240 # undef _KERNEL 152393Syz155240 # define KERNEL 1 162393Syz155240 # define _KERNEL 1 172393Syz155240 #endif 182393Syz155240 #include <sys/errno.h> 192393Syz155240 #include <sys/types.h> 202393Syz155240 #include <sys/param.h> 212393Syz155240 #include <sys/time.h> 222393Syz155240 #include <sys/file.h> 232393Syz155240 #ifdef __hpux 242393Syz155240 # include <sys/timeout.h> 252393Syz155240 #endif 262393Syz155240 #if !defined(_KERNEL) 272393Syz155240 # include <stdio.h> 282393Syz155240 # include <string.h> 292393Syz155240 # include <stdlib.h> 302393Syz155240 # define _KERNEL 312393Syz155240 # ifdef __OpenBSD__ 322393Syz155240 struct file; 332393Syz155240 # endif 342393Syz155240 # include <sys/uio.h> 352393Syz155240 # undef _KERNEL 362393Syz155240 #endif 372393Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 382393Syz155240 # include <sys/filio.h> 392393Syz155240 # include <sys/fcntl.h> 402393Syz155240 #else 412393Syz155240 # include <sys/ioctl.h> 422393Syz155240 #endif 432393Syz155240 #if !defined(linux) 442393Syz155240 # include <sys/protosw.h> 452393Syz155240 #endif 462393Syz155240 #include <sys/socket.h> 472393Syz155240 #if defined(_KERNEL) 482393Syz155240 # include <sys/systm.h> 492393Syz155240 # if !defined(__SVR4) && !defined(__svr4__) 502393Syz155240 # include <sys/mbuf.h> 512393Syz155240 # endif 522393Syz155240 #endif 532393Syz155240 #if !defined(__SVR4) && !defined(__svr4__) 542393Syz155240 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX) 552393Syz155240 # include <sys/kernel.h> 562393Syz155240 # endif 572393Syz155240 #else 582393Syz155240 # include <sys/byteorder.h> 592393Syz155240 # ifdef _KERNEL 602393Syz155240 # include <sys/dditypes.h> 612393Syz155240 # endif 622393Syz155240 # include <sys/stream.h> 632393Syz155240 # include <sys/kmem.h> 642393Syz155240 #endif 652393Syz155240 #include <net/if.h> 662393Syz155240 #ifdef sun 672393Syz155240 # include <net/af.h> 682393Syz155240 #endif 692393Syz155240 #include <net/route.h> 702393Syz155240 #include <netinet/in.h> 712393Syz155240 #include <netinet/in_systm.h> 722393Syz155240 #include <netinet/ip.h> 732393Syz155240 #if !defined(linux) 742393Syz155240 # include <netinet/ip_var.h> 752393Syz155240 #endif 762393Syz155240 #include <netinet/tcp.h> 772393Syz155240 #include <netinet/udp.h> 782393Syz155240 #include <netinet/ip_icmp.h> 792393Syz155240 #include "netinet/ip_compat.h" 802393Syz155240 #include <netinet/tcpip.h> 812393Syz155240 #include "netinet/ip_fil.h" 822393Syz155240 #include "netinet/ip_nat.h" 832393Syz155240 #include "netinet/ip_frag.h" 842393Syz155240 #include "netinet/ip_state.h" 852393Syz155240 #include "netinet/ip_auth.h" 86*3448Sdh155122 #include "netinet/ipf_stack.h" 872393Syz155240 #if (__FreeBSD_version >= 300000) 882393Syz155240 # include <sys/malloc.h> 892393Syz155240 # if defined(_KERNEL) 902393Syz155240 # ifndef IPFILTER_LKM 912393Syz155240 # include <sys/libkern.h> 922393Syz155240 # include <sys/systm.h> 932393Syz155240 # endif 942393Syz155240 extern struct callout_handle fr_slowtimer_ch; 952393Syz155240 # endif 962393Syz155240 #endif 972393Syz155240 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 982393Syz155240 # include <sys/callout.h> 992393Syz155240 extern struct callout fr_slowtimer_ch; 1002393Syz155240 #endif 1012393Syz155240 #if defined(__OpenBSD__) 1022393Syz155240 # include <sys/timeout.h> 1032393Syz155240 extern struct timeout fr_slowtimer_ch; 1042393Syz155240 #endif 1052393Syz155240 /* END OF INCLUDES */ 1062393Syz155240 1072393Syz155240 #if !defined(lint) 1082393Syz155240 static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; 1092393Syz155240 static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $"; 1102393Syz155240 #endif 1112393Syz155240 1122393Syz155240 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); 1132393Syz155240 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); 114*3448Sdh155122 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***, ipf_stack_t *)); 1152393Syz155240 1162393Syz155240 /* ------------------------------------------------------------------------ */ 1172393Syz155240 /* Function: fr_fraginit */ 1182393Syz155240 /* Returns: int - 0 == success, -1 == error */ 1192393Syz155240 /* Parameters: Nil */ 1202393Syz155240 /* */ 1212393Syz155240 /* Initialise the hash tables for the fragment cache lookups. */ 1222393Syz155240 /* ------------------------------------------------------------------------ */ 123*3448Sdh155122 int fr_fraginit(ifs) 124*3448Sdh155122 ipf_stack_t *ifs; 1252393Syz155240 { 126*3448Sdh155122 ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 127*3448Sdh155122 ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 128*3448Sdh155122 ifs->ifs_ipfr_ipidtail = &ifs->ifs_ipfr_ipidlist; 129*3448Sdh155122 ifs->ifs_ipfr_size = IPFT_SIZE; 130*3448Sdh155122 ifs->ifs_fr_ipfrttl = 120; /* 60 seconds */ 131*3448Sdh155122 132*3448Sdh155122 KMALLOCS(ifs->ifs_ipfr_heads, ipfr_t **, 133*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 134*3448Sdh155122 if (ifs->ifs_ipfr_heads == NULL) 1352393Syz155240 return -1; 136*3448Sdh155122 bzero((char *)ifs->ifs_ipfr_heads, 137*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1382393Syz155240 139*3448Sdh155122 KMALLOCS(ifs->ifs_ipfr_nattab, ipfr_t **, 140*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 141*3448Sdh155122 if (ifs->ifs_ipfr_nattab == NULL) 1422393Syz155240 return -1; 143*3448Sdh155122 bzero((char *)ifs->ifs_ipfr_nattab, 144*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1452393Syz155240 146*3448Sdh155122 KMALLOCS(ifs->ifs_ipfr_ipidtab, ipfr_t **, 147*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 148*3448Sdh155122 if (ifs->ifs_ipfr_ipidtab == NULL) 1492393Syz155240 return -1; 150*3448Sdh155122 bzero((char *)ifs->ifs_ipfr_ipidtab, 151*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 1522393Syz155240 153*3448Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_frag, "ipf fragment rwlock"); 1542393Syz155240 1552393Syz155240 /* Initialise frblock with "block in all" */ 156*3448Sdh155122 bzero((char *)&ifs->ifs_frblock, sizeof(ifs->ifs_frblock)); 157*3448Sdh155122 ifs->ifs_frblock.fr_flags = FR_BLOCK|FR_INQUE; /* block in */ 158*3448Sdh155122 ifs->ifs_frblock.fr_ref = 1; 1592393Syz155240 160*3448Sdh155122 ifs->ifs_fr_frag_init = 1; 1612393Syz155240 1622393Syz155240 return 0; 1632393Syz155240 } 1642393Syz155240 1652393Syz155240 1662393Syz155240 /* ------------------------------------------------------------------------ */ 1672393Syz155240 /* Function: fr_fragunload */ 1682393Syz155240 /* Returns: Nil */ 1692393Syz155240 /* Parameters: Nil */ 1702393Syz155240 /* */ 1712393Syz155240 /* Free all memory allocated whilst running and from initialisation. */ 1722393Syz155240 /* ------------------------------------------------------------------------ */ 173*3448Sdh155122 void fr_fragunload(ifs) 174*3448Sdh155122 ipf_stack_t *ifs; 1752393Syz155240 { 176*3448Sdh155122 if (ifs->ifs_fr_frag_init == 1) { 177*3448Sdh155122 fr_fragclear(ifs); 1782393Syz155240 179*3448Sdh155122 RW_DESTROY(&ifs->ifs_ipf_frag); 180*3448Sdh155122 ifs->ifs_fr_frag_init = 0; 1812393Syz155240 } 1822393Syz155240 183*3448Sdh155122 if (ifs->ifs_ipfr_heads != NULL) { 184*3448Sdh155122 KFREES(ifs->ifs_ipfr_heads, 185*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 186*3448Sdh155122 } 187*3448Sdh155122 ifs->ifs_ipfr_heads = NULL; 1882393Syz155240 189*3448Sdh155122 if (ifs->ifs_ipfr_nattab != NULL) { 190*3448Sdh155122 KFREES(ifs->ifs_ipfr_nattab, 191*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 192*3448Sdh155122 } 193*3448Sdh155122 ifs->ifs_ipfr_nattab = NULL; 1942393Syz155240 195*3448Sdh155122 if (ifs->ifs_ipfr_ipidtab != NULL) { 196*3448Sdh155122 KFREES(ifs->ifs_ipfr_ipidtab, 197*3448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *)); 198*3448Sdh155122 } 199*3448Sdh155122 ifs->ifs_ipfr_ipidtab = NULL; 2002393Syz155240 } 2012393Syz155240 2022393Syz155240 2032393Syz155240 /* ------------------------------------------------------------------------ */ 2042393Syz155240 /* Function: fr_fragstats */ 2052393Syz155240 /* Returns: ipfrstat_t* - pointer to struct with current frag stats */ 2062393Syz155240 /* Parameters: Nil */ 2072393Syz155240 /* */ 2082393Syz155240 /* Updates ipfr_stats with current information and returns a pointer to it */ 2092393Syz155240 /* ------------------------------------------------------------------------ */ 210*3448Sdh155122 ipfrstat_t *fr_fragstats(ifs) 211*3448Sdh155122 ipf_stack_t *ifs; 2122393Syz155240 { 213*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_table = ifs->ifs_ipfr_heads; 214*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_nattab = ifs->ifs_ipfr_nattab; 215*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_inuse = ifs->ifs_ipfr_inuse; 216*3448Sdh155122 return &ifs->ifs_ipfr_stats; 2172393Syz155240 } 2182393Syz155240 2192393Syz155240 2202393Syz155240 /* ------------------------------------------------------------------------ */ 2212393Syz155240 /* Function: ipfr_newfrag */ 2222393Syz155240 /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ 2232393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 2242393Syz155240 /* table(I) - pointer to frag table to add to */ 2252393Syz155240 /* */ 2262393Syz155240 /* Add a new entry to the fragment cache, registering it as having come */ 2272393Syz155240 /* through this box, with the result of the filter operation. */ 2282393Syz155240 /* ------------------------------------------------------------------------ */ 2292393Syz155240 static ipfr_t *ipfr_newfrag(fin, pass, table) 2302393Syz155240 fr_info_t *fin; 2312393Syz155240 u_32_t pass; 2322393Syz155240 ipfr_t *table[]; 2332393Syz155240 { 2342393Syz155240 ipfr_t *fra, frag; 2352393Syz155240 u_int idx, off; 236*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2372393Syz155240 238*3448Sdh155122 if (ifs->ifs_ipfr_inuse >= IPFT_SIZE) 2392393Syz155240 return NULL; 2402393Syz155240 2412393Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 2422393Syz155240 return NULL; 2432393Syz155240 2442393Syz155240 if (pass & FR_FRSTRICT) 2452393Syz155240 if (fin->fin_off != 0) 2462393Syz155240 return NULL; 2472393Syz155240 2482393Syz155240 frag.ipfr_p = fin->fin_p; 2492393Syz155240 idx = fin->fin_p; 2502393Syz155240 frag.ipfr_id = fin->fin_id; 2512393Syz155240 idx += fin->fin_id; 2522393Syz155240 frag.ipfr_source = fin->fin_fi.fi_src; 2532393Syz155240 idx += frag.ipfr_src.s_addr; 2542393Syz155240 frag.ipfr_dest = fin->fin_fi.fi_dst; 2552393Syz155240 idx += frag.ipfr_dst.s_addr; 2562393Syz155240 frag.ipfr_ifp = fin->fin_ifp; 2572393Syz155240 idx *= 127; 2582393Syz155240 idx %= IPFT_SIZE; 2592393Syz155240 2602393Syz155240 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 2612393Syz155240 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 2622393Syz155240 frag.ipfr_auth = fin->fin_fi.fi_auth; 2632393Syz155240 2642393Syz155240 /* 2652393Syz155240 * first, make sure it isn't already there... 2662393Syz155240 */ 2672393Syz155240 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 2682393Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, 2692393Syz155240 IPFR_CMPSZ)) { 270*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_exists++; 2712393Syz155240 return NULL; 2722393Syz155240 } 2732393Syz155240 2742393Syz155240 /* 2752393Syz155240 * allocate some memory, if possible, if not, just record that we 2762393Syz155240 * failed to do so. 2772393Syz155240 */ 2782393Syz155240 KMALLOC(fra, ipfr_t *); 2792393Syz155240 if (fra == NULL) { 280*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_nomem++; 2812393Syz155240 return NULL; 2822393Syz155240 } 2832393Syz155240 2842393Syz155240 fra->ipfr_rule = fin->fin_fr; 2852393Syz155240 if (fra->ipfr_rule != NULL) { 2862393Syz155240 2872393Syz155240 frentry_t *fr; 2882393Syz155240 2892393Syz155240 fr = fin->fin_fr; 2902393Syz155240 MUTEX_ENTER(&fr->fr_lock); 2912393Syz155240 fr->fr_ref++; 2922393Syz155240 MUTEX_EXIT(&fr->fr_lock); 2932393Syz155240 } 2942393Syz155240 2952393Syz155240 /* 2962393Syz155240 * Insert the fragment into the fragment table, copy the struct used 2972393Syz155240 * in the search using bcopy rather than reassign each field. 2982393Syz155240 * Set the ttl to the default. 2992393Syz155240 */ 3002393Syz155240 if ((fra->ipfr_hnext = table[idx]) != NULL) 3012393Syz155240 table[idx]->ipfr_hprev = &fra->ipfr_hnext; 3022393Syz155240 fra->ipfr_hprev = table + idx; 3032393Syz155240 fra->ipfr_data = NULL; 3042393Syz155240 table[idx] = fra; 3052393Syz155240 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 306*3448Sdh155122 fra->ipfr_ttl = ifs->ifs_fr_ticks + ifs->ifs_fr_ipfrttl; 3072393Syz155240 3082393Syz155240 /* 3092393Syz155240 * Compute the offset of the expected start of the next packet. 3102393Syz155240 */ 3112393Syz155240 off = fin->fin_off; 3122393Syz155240 if (off == 0) { 3132393Syz155240 fra->ipfr_seen0 = 1; 3142393Syz155240 fra->ipfr_firstend = fin->fin_flen; 3152393Syz155240 } else { 3162393Syz155240 fra->ipfr_seen0 = 0; 3172393Syz155240 fra->ipfr_firstend = 0; 3182393Syz155240 } 3192393Syz155240 fra->ipfr_off = off + fin->fin_dlen; 3202393Syz155240 fra->ipfr_pass = pass; 321*3448Sdh155122 fra->ipfr_ref = 1; 322*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_new++; 323*3448Sdh155122 ifs->ifs_ipfr_inuse++; 3242393Syz155240 return fra; 3252393Syz155240 } 3262393Syz155240 3272393Syz155240 3282393Syz155240 /* ------------------------------------------------------------------------ */ 3292393Syz155240 /* Function: fr_newfrag */ 3302393Syz155240 /* Returns: int - 0 == success, -1 == error */ 3312393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3322393Syz155240 /* */ 3332393Syz155240 /* Add a new entry to the fragment cache table based on the current packet */ 3342393Syz155240 /* ------------------------------------------------------------------------ */ 3352393Syz155240 int fr_newfrag(fin, pass) 3362393Syz155240 u_32_t pass; 3372393Syz155240 fr_info_t *fin; 3382393Syz155240 { 3392393Syz155240 ipfr_t *fra; 340*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3412393Syz155240 342*3448Sdh155122 if (ifs->ifs_fr_frag_lock != 0) 3432393Syz155240 return -1; 3442393Syz155240 345*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 346*3448Sdh155122 fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_heads); 3472393Syz155240 if (fra != NULL) { 348*3448Sdh155122 *ifs->ifs_ipfr_tail = fra; 349*3448Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_tail; 350*3448Sdh155122 ifs->ifs_ipfr_tail = &fra->ipfr_next; 351*3448Sdh155122 if (ifs->ifs_ipfr_list == NULL) 352*3448Sdh155122 ifs->ifs_ipfr_list = fra; 3532393Syz155240 fra->ipfr_next = NULL; 3542393Syz155240 } 355*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 3562393Syz155240 return fra ? 0 : -1; 3572393Syz155240 } 3582393Syz155240 3592393Syz155240 3602393Syz155240 /* ------------------------------------------------------------------------ */ 3612393Syz155240 /* Function: fr_nat_newfrag */ 3622393Syz155240 /* Returns: int - 0 == success, -1 == error */ 3632393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3642393Syz155240 /* nat(I) - pointer to NAT structure */ 3652393Syz155240 /* */ 3662393Syz155240 /* Create a new NAT fragment cache entry based on the current packet and */ 3672393Syz155240 /* the NAT structure for this "session". */ 3682393Syz155240 /* ------------------------------------------------------------------------ */ 3692393Syz155240 int fr_nat_newfrag(fin, pass, nat) 3702393Syz155240 fr_info_t *fin; 3712393Syz155240 u_32_t pass; 3722393Syz155240 nat_t *nat; 3732393Syz155240 { 3742393Syz155240 ipfr_t *fra; 375*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 3762393Syz155240 377*3448Sdh155122 if ((fin->fin_v != 4) || (ifs->ifs_fr_frag_lock != 0)) 3782393Syz155240 return 0; 3792393Syz155240 380*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 381*3448Sdh155122 fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_nattab); 3822393Syz155240 if (fra != NULL) { 3832393Syz155240 fra->ipfr_data = nat; 3842393Syz155240 nat->nat_data = fra; 385*3448Sdh155122 *ifs->ifs_ipfr_nattail = fra; 386*3448Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_nattail; 387*3448Sdh155122 ifs->ifs_ipfr_nattail = &fra->ipfr_next; 3882393Syz155240 fra->ipfr_next = NULL; 3892393Syz155240 } 390*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 3912393Syz155240 return fra ? 0 : -1; 3922393Syz155240 } 3932393Syz155240 3942393Syz155240 3952393Syz155240 /* ------------------------------------------------------------------------ */ 3962393Syz155240 /* Function: fr_ipid_newfrag */ 3972393Syz155240 /* Returns: int - 0 == success, -1 == error */ 3982393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 3992393Syz155240 /* ipid(I) - new IP ID for this fragmented packet */ 4002393Syz155240 /* */ 4012393Syz155240 /* Create a new fragment cache entry for this packet and store, as a data */ 4022393Syz155240 /* pointer, the new IP ID value. */ 4032393Syz155240 /* ------------------------------------------------------------------------ */ 4042393Syz155240 int fr_ipid_newfrag(fin, ipid) 4052393Syz155240 fr_info_t *fin; 4062393Syz155240 u_32_t ipid; 4072393Syz155240 { 4082393Syz155240 ipfr_t *fra; 409*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4102393Syz155240 411*3448Sdh155122 if (ifs->ifs_fr_frag_lock) 4122393Syz155240 return 0; 4132393Syz155240 414*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 415*3448Sdh155122 fra = ipfr_newfrag(fin, 0, ifs->ifs_ipfr_ipidtab); 4162393Syz155240 if (fra != NULL) { 4172393Syz155240 fra->ipfr_data = (void *)(uintptr_t)ipid; 418*3448Sdh155122 *ifs->ifs_ipfr_ipidtail = fra; 419*3448Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_ipidtail; 420*3448Sdh155122 ifs->ifs_ipfr_ipidtail = &fra->ipfr_next; 4212393Syz155240 fra->ipfr_next = NULL; 4222393Syz155240 } 423*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 4242393Syz155240 return fra ? 0 : -1; 4252393Syz155240 } 4262393Syz155240 4272393Syz155240 4282393Syz155240 /* ------------------------------------------------------------------------ */ 4292393Syz155240 /* Function: fr_fraglookup */ 4302393Syz155240 /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 4312393Syz155240 /* matching entry in the frag table, else NULL */ 4322393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 4332393Syz155240 /* table(I) - pointer to fragment cache table to search */ 4342393Syz155240 /* */ 4352393Syz155240 /* Check the fragment cache to see if there is already a record of this */ 4362393Syz155240 /* packet with its filter result known. */ 4372393Syz155240 /* ------------------------------------------------------------------------ */ 4382393Syz155240 static ipfr_t *fr_fraglookup(fin, table) 4392393Syz155240 fr_info_t *fin; 4402393Syz155240 ipfr_t *table[]; 4412393Syz155240 { 4422393Syz155240 ipfr_t *f, frag; 4432393Syz155240 u_int idx; 444*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 4452393Syz155240 4462393Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 4472393Syz155240 return NULL; 4482393Syz155240 4492393Syz155240 /* 4502393Syz155240 * For fragments, we record protocol, packet id, TOS and both IP#'s 4512393Syz155240 * (these should all be the same for all fragments of a packet). 4522393Syz155240 * 4532393Syz155240 * build up a hash value to index the table with. 4542393Syz155240 */ 4552393Syz155240 frag.ipfr_p = fin->fin_p; 4562393Syz155240 idx = fin->fin_p; 4572393Syz155240 frag.ipfr_id = fin->fin_id; 4582393Syz155240 idx += fin->fin_id; 4592393Syz155240 frag.ipfr_source = fin->fin_fi.fi_src; 4602393Syz155240 idx += frag.ipfr_src.s_addr; 4612393Syz155240 frag.ipfr_dest = fin->fin_fi.fi_dst; 4622393Syz155240 idx += frag.ipfr_dst.s_addr; 4632393Syz155240 frag.ipfr_ifp = fin->fin_ifp; 4642393Syz155240 idx *= 127; 4652393Syz155240 idx %= IPFT_SIZE; 4662393Syz155240 4672393Syz155240 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 4682393Syz155240 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 4692393Syz155240 frag.ipfr_auth = fin->fin_fi.fi_auth; 4702393Syz155240 4712393Syz155240 /* 4722393Syz155240 * check the table, careful to only compare the right amount of data 4732393Syz155240 */ 4742393Syz155240 for (f = table[idx]; f; f = f->ipfr_hnext) 4752393Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, 4762393Syz155240 IPFR_CMPSZ)) { 4772393Syz155240 u_short off; 4782393Syz155240 4792393Syz155240 /* 4802393Syz155240 * We don't want to let short packets match because 4812393Syz155240 * they could be compromising the security of other 4822393Syz155240 * rules that want to match on layer 4 fields (and 4832393Syz155240 * can't because they have been fragmented off.) 4842393Syz155240 * Why do this check here? The counter acts as an 4852393Syz155240 * indicator of this kind of attack, whereas if it was 4862393Syz155240 * elsewhere, it wouldn't know if other matching 4872393Syz155240 * packets had been seen. 4882393Syz155240 */ 4892393Syz155240 if (fin->fin_flx & FI_SHORT) { 490*3448Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_short); 4912393Syz155240 continue; 4922393Syz155240 } 4932393Syz155240 4942393Syz155240 /* 4952393Syz155240 * XXX - We really need to be guarding against the 4962393Syz155240 * retransmission of (src,dst,id,offset-range) here 4972393Syz155240 * because a fragmented packet is never resent with 4982393Syz155240 * the same IP ID# (or shouldn't). 4992393Syz155240 */ 5002393Syz155240 off = fin->fin_off; /* same as in ipfr_newfrag() */ 5012393Syz155240 if (f->ipfr_seen0) { 5022393Syz155240 if (off == 0) { 503*3448Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_retrans0); 5042393Syz155240 continue; 5052393Syz155240 } 5062393Syz155240 } else if (off == 0) { 5072393Syz155240 f->ipfr_seen0 = 1; 5082393Syz155240 f->ipfr_firstend = fin->fin_flen; 5092393Syz155240 } 5102393Syz155240 5112393Syz155240 if (f != table[idx]) { 5122393Syz155240 ipfr_t **fp; 5132393Syz155240 5142393Syz155240 /* 5152393Syz155240 * Move fragment info. to the top of the list 5162393Syz155240 * to speed up searches. First, delink... 5172393Syz155240 */ 5182393Syz155240 fp = f->ipfr_hprev; 5192393Syz155240 (*fp) = f->ipfr_hnext; 5202393Syz155240 if (f->ipfr_hnext != NULL) 5212393Syz155240 f->ipfr_hnext->ipfr_hprev = fp; 5222393Syz155240 /* 5232393Syz155240 * Then put back at the top of the chain. 5242393Syz155240 */ 5252393Syz155240 f->ipfr_hnext = table[idx]; 5262393Syz155240 table[idx]->ipfr_hprev = &f->ipfr_hnext; 5272393Syz155240 f->ipfr_hprev = table + idx; 5282393Syz155240 table[idx] = f; 5292393Syz155240 } 5302393Syz155240 5312393Syz155240 if (fin->fin_v == 6) { 5322393Syz155240 if (f->ipfr_seen0 && (off < f->ipfr_firstend)) 5332393Syz155240 fin->fin_flx |= FI_BAD; 5342393Syz155240 } 5352393Syz155240 /* 5362393Syz155240 * If we've follwed the fragments, and this is the 5372393Syz155240 * last (in order), shrink expiration time. 5382393Syz155240 */ 5392393Syz155240 if (off == f->ipfr_off) { 5402393Syz155240 if (!(fin->fin_ip->ip_off & IP_MF)) 541*3448Sdh155122 f->ipfr_ttl = ifs->ifs_fr_ticks + 1; 5422393Syz155240 f->ipfr_off = fin->fin_dlen + off; 5432393Syz155240 } else if (f->ipfr_pass & FR_FRSTRICT) 5442393Syz155240 continue; 545*3448Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_hits); 5462393Syz155240 return f; 5472393Syz155240 } 5482393Syz155240 return NULL; 5492393Syz155240 } 5502393Syz155240 5512393Syz155240 5522393Syz155240 /* ------------------------------------------------------------------------ */ 5532393Syz155240 /* Function: fr_nat_knownfrag */ 5542393Syz155240 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 5552393Syz155240 /* match found, else NULL */ 5562393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 5572393Syz155240 /* */ 5582393Syz155240 /* Functional interface for NAT lookups of the NAT fragment cache */ 5592393Syz155240 /* ------------------------------------------------------------------------ */ 5602393Syz155240 nat_t *fr_nat_knownfrag(fin) 5612393Syz155240 fr_info_t *fin; 5622393Syz155240 { 5632393Syz155240 nat_t *nat; 5642393Syz155240 ipfr_t *ipf; 565*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 5662393Syz155240 567*3448Sdh155122 if ((fin->fin_v != 4) || (ifs->ifs_fr_frag_lock) || !ifs->ifs_ipfr_natlist) 5682393Syz155240 return NULL; 569*3448Sdh155122 READ_ENTER(&ifs->ifs_ipf_natfrag); 570*3448Sdh155122 ipf = fr_fraglookup(fin, ifs->ifs_ipfr_nattab); 5712393Syz155240 if (ipf != NULL) { 5722393Syz155240 nat = ipf->ipfr_data; 5732393Syz155240 /* 5742393Syz155240 * This is the last fragment for this packet. 5752393Syz155240 */ 576*3448Sdh155122 if ((ipf->ipfr_ttl == ifs->ifs_fr_ticks + 1) && (nat != NULL)) { 5772393Syz155240 nat->nat_data = NULL; 5782393Syz155240 ipf->ipfr_data = NULL; 5792393Syz155240 } 5802393Syz155240 } else 5812393Syz155240 nat = NULL; 582*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 5832393Syz155240 return nat; 5842393Syz155240 } 5852393Syz155240 5862393Syz155240 5872393Syz155240 /* ------------------------------------------------------------------------ */ 5882393Syz155240 /* Function: fr_ipid_knownfrag */ 5892393Syz155240 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 5902393Syz155240 /* return 0xfffffff to indicate no match. */ 5912393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 5922393Syz155240 /* */ 5932393Syz155240 /* Functional interface for IP ID lookups of the IP ID fragment cache */ 5942393Syz155240 /* ------------------------------------------------------------------------ */ 5952393Syz155240 u_32_t fr_ipid_knownfrag(fin) 5962393Syz155240 fr_info_t *fin; 5972393Syz155240 { 5982393Syz155240 ipfr_t *ipf; 5992393Syz155240 u_32_t id; 600*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 6012393Syz155240 602*3448Sdh155122 if ((fin->fin_v != 4) || (ifs->ifs_fr_frag_lock) || !ifs->ifs_ipfr_ipidlist) 6032393Syz155240 return 0xffffffff; 6042393Syz155240 605*3448Sdh155122 READ_ENTER(&ifs->ifs_ipf_ipidfrag); 606*3448Sdh155122 ipf = fr_fraglookup(fin, ifs->ifs_ipfr_ipidtab); 6072393Syz155240 if (ipf != NULL) 6082393Syz155240 id = (u_32_t)(uintptr_t)ipf->ipfr_data; 6092393Syz155240 else 6102393Syz155240 id = 0xffffffff; 611*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 6122393Syz155240 return id; 6132393Syz155240 } 6142393Syz155240 6152393Syz155240 6162393Syz155240 /* ------------------------------------------------------------------------ */ 6172393Syz155240 /* Function: fr_knownfrag */ 6182393Syz155240 /* Returns: frentry_t* - pointer to filter rule if a match is found in */ 6192393Syz155240 /* the frag cache table, else NULL. */ 6202393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 6212393Syz155240 /* passp(O) - pointer to where to store rule flags resturned */ 6222393Syz155240 /* */ 6232393Syz155240 /* Functional interface for normal lookups of the fragment cache. If a */ 6242393Syz155240 /* match is found, return the rule pointer and flags from the rule, except */ 6252393Syz155240 /* that if FR_LOGFIRST is set, reset FR_LOG. */ 6262393Syz155240 /* ------------------------------------------------------------------------ */ 6272393Syz155240 frentry_t *fr_knownfrag(fin, passp) 6282393Syz155240 fr_info_t *fin; 6292393Syz155240 u_32_t *passp; 6302393Syz155240 { 6312393Syz155240 frentry_t *fr = NULL; 6322393Syz155240 ipfr_t *fra; 6332393Syz155240 u_32_t pass, oflx; 634*3448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 6352393Syz155240 636*3448Sdh155122 if ((ifs->ifs_fr_frag_lock) || (ifs->ifs_ipfr_list == NULL)) 6372393Syz155240 return NULL; 6382393Syz155240 639*3448Sdh155122 READ_ENTER(&ifs->ifs_ipf_frag); 6402393Syz155240 oflx = fin->fin_flx; 641*3448Sdh155122 fra = fr_fraglookup(fin, ifs->ifs_ipfr_heads); 6422393Syz155240 if (fra != NULL) { 6432393Syz155240 fr = fra->ipfr_rule; 6442393Syz155240 fin->fin_fr = fr; 6452393Syz155240 if (fr != NULL) { 6462393Syz155240 pass = fr->fr_flags; 6472393Syz155240 if ((pass & FR_LOGFIRST) != 0) 6482393Syz155240 pass &= ~(FR_LOGFIRST|FR_LOG); 6492393Syz155240 *passp = pass; 6502393Syz155240 } 6512393Syz155240 } 6522393Syz155240 if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) { 6532393Syz155240 *passp &= ~FR_CMDMASK; 6542393Syz155240 *passp |= FR_BLOCK; 655*3448Sdh155122 fr = &ifs->ifs_frblock; 6562393Syz155240 } 657*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 6582393Syz155240 return fr; 6592393Syz155240 } 6602393Syz155240 6612393Syz155240 6622393Syz155240 /* ------------------------------------------------------------------------ */ 6632393Syz155240 /* Function: fr_forget */ 6642393Syz155240 /* Returns: Nil */ 6652393Syz155240 /* Parameters: ptr(I) - pointer to data structure */ 6662393Syz155240 /* */ 6672393Syz155240 /* Search through all of the fragment cache entries and wherever a pointer */ 6682393Syz155240 /* is found to match ptr, reset it to NULL. */ 6692393Syz155240 /* ------------------------------------------------------------------------ */ 670*3448Sdh155122 void fr_forget(ptr, ifs) 6712393Syz155240 void *ptr; 672*3448Sdh155122 ipf_stack_t *ifs; 6732393Syz155240 { 6742393Syz155240 ipfr_t *fr; 6752393Syz155240 676*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 677*3448Sdh155122 for (fr = ifs->ifs_ipfr_list; fr; fr = fr->ipfr_next) 6782393Syz155240 if (fr->ipfr_data == ptr) 6792393Syz155240 fr->ipfr_data = NULL; 680*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 6812393Syz155240 } 6822393Syz155240 6832393Syz155240 6842393Syz155240 /* ------------------------------------------------------------------------ */ 6852393Syz155240 /* Function: fr_forgetnat */ 6862393Syz155240 /* Returns: Nil */ 6872393Syz155240 /* Parameters: ptr(I) - pointer to data structure */ 6882393Syz155240 /* */ 6892393Syz155240 /* Search through all of the fragment cache entries for NAT and wherever a */ 6902393Syz155240 /* pointer is found to match ptr, reset it to NULL. */ 6912393Syz155240 /* ------------------------------------------------------------------------ */ 692*3448Sdh155122 void fr_forgetnat(ptr, ifs) 6932393Syz155240 void *ptr; 694*3448Sdh155122 ipf_stack_t *ifs; 6952393Syz155240 { 6962393Syz155240 ipfr_t *fr; 6972393Syz155240 698*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 699*3448Sdh155122 for (fr = ifs->ifs_ipfr_natlist; fr; fr = fr->ipfr_next) 7002393Syz155240 if (fr->ipfr_data == ptr) 7012393Syz155240 fr->ipfr_data = NULL; 702*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 7032393Syz155240 } 7042393Syz155240 7052393Syz155240 7062393Syz155240 /* ------------------------------------------------------------------------ */ 7072393Syz155240 /* Function: fr_fragdelete */ 7082393Syz155240 /* Returns: Nil */ 7092393Syz155240 /* Parameters: fra(I) - pointer to fragment structure to delete */ 7102393Syz155240 /* tail(IO) - pointer to the pointer to the tail of the frag */ 7112393Syz155240 /* list */ 7122393Syz155240 /* */ 7132393Syz155240 /* Remove a fragment cache table entry from the table & list. Also free */ 7142393Syz155240 /* the filter rule it is associated with it if it is no longer used as a */ 7152393Syz155240 /* result of decreasing the reference count. */ 7162393Syz155240 /* ------------------------------------------------------------------------ */ 717*3448Sdh155122 static void fr_fragdelete(fra, tail, ifs) 7182393Syz155240 ipfr_t *fra, ***tail; 719*3448Sdh155122 ipf_stack_t *ifs; 7202393Syz155240 { 7212393Syz155240 frentry_t *fr; 7222393Syz155240 7232393Syz155240 fr = fra->ipfr_rule; 7242393Syz155240 if (fr != NULL) 725*3448Sdh155122 (void)fr_derefrule(&fr, ifs); 7262393Syz155240 7272393Syz155240 if (fra->ipfr_next) 7282393Syz155240 fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 7292393Syz155240 *fra->ipfr_prev = fra->ipfr_next; 7302393Syz155240 if (*tail == &fra->ipfr_next) 7312393Syz155240 *tail = fra->ipfr_prev; 7322393Syz155240 7332393Syz155240 if (fra->ipfr_hnext) 7342393Syz155240 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 7352393Syz155240 *fra->ipfr_hprev = fra->ipfr_hnext; 736*3448Sdh155122 737*3448Sdh155122 if (fra->ipfr_ref <= 0) 738*3448Sdh155122 KFREE(fra); 7392393Syz155240 } 7402393Syz155240 7412393Syz155240 7422393Syz155240 /* ------------------------------------------------------------------------ */ 7432393Syz155240 /* Function: fr_fragclear */ 7442393Syz155240 /* Returns: Nil */ 7452393Syz155240 /* Parameters: Nil */ 7462393Syz155240 /* */ 7472393Syz155240 /* Free memory in use by fragment state information kept. Do the normal */ 7482393Syz155240 /* fragment state stuff first and then the NAT-fragment table. */ 7492393Syz155240 /* ------------------------------------------------------------------------ */ 750*3448Sdh155122 void fr_fragclear(ifs) 751*3448Sdh155122 ipf_stack_t *ifs; 7522393Syz155240 { 7532393Syz155240 ipfr_t *fra; 7542393Syz155240 nat_t *nat; 7552393Syz155240 756*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 757*3448Sdh155122 while ((fra = ifs->ifs_ipfr_list) != NULL) { 758*3448Sdh155122 fra->ipfr_ref--; 759*3448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 760*3448Sdh155122 } 761*3448Sdh155122 ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list; 762*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 7632393Syz155240 764*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 765*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 766*3448Sdh155122 while ((fra = ifs->ifs_ipfr_natlist) != NULL) { 7672393Syz155240 nat = fra->ipfr_data; 7682393Syz155240 if (nat != NULL) { 7692393Syz155240 if (nat->nat_data == fra) 7702393Syz155240 nat->nat_data = NULL; 7712393Syz155240 } 772*3448Sdh155122 fra->ipfr_ref--; 773*3448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 7742393Syz155240 } 775*3448Sdh155122 ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist; 776*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 777*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 7782393Syz155240 } 7792393Syz155240 7802393Syz155240 7812393Syz155240 /* ------------------------------------------------------------------------ */ 7822393Syz155240 /* Function: fr_fragexpire */ 7832393Syz155240 /* Returns: Nil */ 7842393Syz155240 /* Parameters: Nil */ 7852393Syz155240 /* */ 7862393Syz155240 /* Expire entries in the fragment cache table that have been there too long */ 7872393Syz155240 /* ------------------------------------------------------------------------ */ 788*3448Sdh155122 void fr_fragexpire(ifs) 789*3448Sdh155122 ipf_stack_t *ifs; 7902393Syz155240 { 7912393Syz155240 ipfr_t **fp, *fra; 7922393Syz155240 nat_t *nat; 7932393Syz155240 SPL_INT(s); 7942393Syz155240 795*3448Sdh155122 if (ifs->ifs_fr_frag_lock) 7962393Syz155240 return; 7972393Syz155240 7982393Syz155240 SPL_NET(s); 799*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag); 8002393Syz155240 /* 8012393Syz155240 * Go through the entire table, looking for entries to expire, 802*3448Sdh155122 * which is indicated by the ttl being less than or equal to 803*3448Sdh155122 * ifs_fr_ticks. 8042393Syz155240 */ 805*3448Sdh155122 for (fp = &ifs->ifs_ipfr_list; ((fra = *fp) != NULL); ) { 806*3448Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8072393Syz155240 break; 808*3448Sdh155122 fra->ipfr_ref--; 809*3448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs); 810*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 811*3448Sdh155122 ifs->ifs_ipfr_inuse--; 8122393Syz155240 } 813*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag); 8142393Syz155240 815*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_ipidfrag); 816*3448Sdh155122 for (fp = &ifs->ifs_ipfr_ipidlist; ((fra = *fp) != NULL); ) { 817*3448Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8182393Syz155240 break; 819*3448Sdh155122 fra->ipfr_ref--; 820*3448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_ipidtail, ifs); 821*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 822*3448Sdh155122 ifs->ifs_ipfr_inuse--; 8232393Syz155240 } 824*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag); 8252393Syz155240 8262393Syz155240 /* 8272393Syz155240 * Same again for the NAT table, except that if the structure also 8282393Syz155240 * still points to a NAT structure, and the NAT structure points back 8292393Syz155240 * at the one to be free'd, NULL the reference from the NAT struct. 8302393Syz155240 * NOTE: We need to grab both mutex's early, and in this order so as 8312393Syz155240 * to prevent a deadlock if both try to expire at the same time. 8322393Syz155240 */ 833*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat); 834*3448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag); 835*3448Sdh155122 for (fp = &ifs->ifs_ipfr_natlist; ((fra = *fp) != NULL); ) { 836*3448Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks) 8372393Syz155240 break; 8382393Syz155240 nat = fra->ipfr_data; 8392393Syz155240 if (nat != NULL) { 8402393Syz155240 if (nat->nat_data == fra) 8412393Syz155240 nat->nat_data = NULL; 8422393Syz155240 } 843*3448Sdh155122 fra->ipfr_ref--; 844*3448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs); 845*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 846*3448Sdh155122 ifs->ifs_ipfr_inuse--; 8472393Syz155240 } 848*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag); 849*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 8502393Syz155240 SPL_X(s); 8512393Syz155240 } 8522393Syz155240 8532393Syz155240 8542393Syz155240 /* ------------------------------------------------------------------------ */ 8552393Syz155240 /* Function: fr_slowtimer */ 8562393Syz155240 /* Returns: Nil */ 8572393Syz155240 /* Parameters: Nil */ 8582393Syz155240 /* */ 8592393Syz155240 /* Slowly expire held state for fragments. Timeouts are set * in */ 8602393Syz155240 /* expectation of this being called twice per second. */ 8612393Syz155240 /* ------------------------------------------------------------------------ */ 8622393Syz155240 #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ 8632393Syz155240 !defined(__osf__) && !defined(linux)) 8642393Syz155240 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) 865*3448Sdh155122 void fr_slowtimer __P((void *arg)) 8662393Syz155240 # else 867*3448Sdh155122 int fr_slowtimer(void *arg) 8682393Syz155240 # endif 8692393Syz155240 { 870*3448Sdh155122 ipf_stack_t *ifs = arg; 871*3448Sdh155122 872*3448Sdh155122 READ_ENTER(&ifs->ifs_ipf_global); 8732393Syz155240 874*3448Sdh155122 fr_fragexpire(ifs); 875*3448Sdh155122 fr_timeoutstate(ifs); 876*3448Sdh155122 fr_natexpire(ifs); 877*3448Sdh155122 fr_authexpire(ifs); 878*3448Sdh155122 ifs->ifs_fr_ticks++; 879*3448Sdh155122 if (ifs->ifs_fr_running <= 0) 8802393Syz155240 goto done; 8812393Syz155240 # ifdef _KERNEL 8822393Syz155240 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) 8832393Syz155240 callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); 8842393Syz155240 # else 8852393Syz155240 # if defined(__OpenBSD__) 8862393Syz155240 timeout_add(&fr_slowtimer_ch, hz/2); 8872393Syz155240 # else 8882393Syz155240 # if (__FreeBSD_version >= 300000) 8892393Syz155240 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); 8902393Syz155240 # else 8912393Syz155240 # ifdef linux 8922393Syz155240 ; 8932393Syz155240 # else 8942393Syz155240 timeout(fr_slowtimer, NULL, hz/2); 8952393Syz155240 # endif 8962393Syz155240 # endif /* FreeBSD */ 8972393Syz155240 # endif /* OpenBSD */ 8982393Syz155240 # endif /* NetBSD */ 8992393Syz155240 # endif 9002393Syz155240 done: 901*3448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 9022393Syz155240 # if (BSD < 199103) || !defined(_KERNEL) 9032393Syz155240 return 0; 9042393Syz155240 # endif 9052393Syz155240 } 9062393Syz155240 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ 907*3448Sdh155122 908*3448Sdh155122 /*ARGSUSED*/ 909*3448Sdh155122 int fr_nextfrag(token, itp, top, tail, lock, ifs) 910*3448Sdh155122 ipftoken_t *token; 911*3448Sdh155122 ipfgeniter_t *itp; 912*3448Sdh155122 ipfr_t **top, ***tail; 913*3448Sdh155122 ipfrwlock_t *lock; 914*3448Sdh155122 ipf_stack_t *ifs; 915*3448Sdh155122 { 916*3448Sdh155122 ipfr_t *frag, *next, zero; 917*3448Sdh155122 int error = 0; 918*3448Sdh155122 919*3448Sdh155122 frag = token->ipt_data; 920*3448Sdh155122 if (frag == (ipfr_t *)-1) { 921*3448Sdh155122 ipf_freetoken(token, ifs); 922*3448Sdh155122 return ESRCH; 923*3448Sdh155122 } 924*3448Sdh155122 925*3448Sdh155122 READ_ENTER(lock); 926*3448Sdh155122 if (frag == NULL) 927*3448Sdh155122 next = *top; 928*3448Sdh155122 else 929*3448Sdh155122 next = frag->ipfr_next; 930*3448Sdh155122 931*3448Sdh155122 if (next != NULL) { 932*3448Sdh155122 ATOMIC_INC(next->ipfr_ref); 933*3448Sdh155122 token->ipt_data = next; 934*3448Sdh155122 } else { 935*3448Sdh155122 bzero(&zero, sizeof(zero)); 936*3448Sdh155122 next = &zero; 937*3448Sdh155122 token->ipt_data = (void *)-1; 938*3448Sdh155122 } 939*3448Sdh155122 RWLOCK_EXIT(lock); 940*3448Sdh155122 941*3448Sdh155122 if (frag != NULL) { 942*3448Sdh155122 fr_fragderef(&frag, lock, ifs); 943*3448Sdh155122 } 944*3448Sdh155122 945*3448Sdh155122 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 946*3448Sdh155122 if (error != 0) 947*3448Sdh155122 error = EFAULT; 948*3448Sdh155122 949*3448Sdh155122 return error; 950*3448Sdh155122 } 951*3448Sdh155122 952*3448Sdh155122 953*3448Sdh155122 void fr_fragderef(frp, lock, ifs) 954*3448Sdh155122 ipfr_t **frp; 955*3448Sdh155122 ipfrwlock_t *lock; 956*3448Sdh155122 ipf_stack_t *ifs; 957*3448Sdh155122 { 958*3448Sdh155122 ipfr_t *fra; 959*3448Sdh155122 960*3448Sdh155122 fra = *frp; 961*3448Sdh155122 *frp = NULL; 962*3448Sdh155122 963*3448Sdh155122 WRITE_ENTER(lock); 964*3448Sdh155122 fra->ipfr_ref--; 965*3448Sdh155122 if (fra->ipfr_ref <= 0) { 966*3448Sdh155122 KFREE(fra); 967*3448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++; 968*3448Sdh155122 ifs->ifs_ipfr_inuse--; 969*3448Sdh155122 } 970*3448Sdh155122 RWLOCK_EXIT(lock); 971*3448Sdh155122 } 972