xref: /onnv-gate/usr/src/uts/common/inet/ipf/ip_frag.c (revision 3448:aaf16568054b)
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