xref: /onnv-gate/usr/src/uts/common/inet/ipf/ip_frag.c (revision 2393:76e0289ce525)
1*2393Syz155240 /*
2*2393Syz155240  * Copyright (C) 1993-2003 by Darren Reed.
3*2393Syz155240  *
4*2393Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
5*2393Syz155240  *
6*2393Syz155240  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
7*2393Syz155240  * Use is subject to license terms.
8*2393Syz155240  */
9*2393Syz155240 
10*2393Syz155240 #pragma ident	"%Z%%M%	%I%	%E% SMI"
11*2393Syz155240 
12*2393Syz155240 #if defined(KERNEL) || defined(_KERNEL)
13*2393Syz155240 # undef KERNEL
14*2393Syz155240 # undef _KERNEL
15*2393Syz155240 # define        KERNEL	1
16*2393Syz155240 # define        _KERNEL	1
17*2393Syz155240 #endif
18*2393Syz155240 #include <sys/errno.h>
19*2393Syz155240 #include <sys/types.h>
20*2393Syz155240 #include <sys/param.h>
21*2393Syz155240 #include <sys/time.h>
22*2393Syz155240 #include <sys/file.h>
23*2393Syz155240 #ifdef __hpux
24*2393Syz155240 # include <sys/timeout.h>
25*2393Syz155240 #endif
26*2393Syz155240 #if !defined(_KERNEL)
27*2393Syz155240 # include <stdio.h>
28*2393Syz155240 # include <string.h>
29*2393Syz155240 # include <stdlib.h>
30*2393Syz155240 # define _KERNEL
31*2393Syz155240 # ifdef __OpenBSD__
32*2393Syz155240 struct file;
33*2393Syz155240 # endif
34*2393Syz155240 # include <sys/uio.h>
35*2393Syz155240 # undef _KERNEL
36*2393Syz155240 #endif
37*2393Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
38*2393Syz155240 # include <sys/filio.h>
39*2393Syz155240 # include <sys/fcntl.h>
40*2393Syz155240 #else
41*2393Syz155240 # include <sys/ioctl.h>
42*2393Syz155240 #endif
43*2393Syz155240 #if !defined(linux)
44*2393Syz155240 # include <sys/protosw.h>
45*2393Syz155240 #endif
46*2393Syz155240 #include <sys/socket.h>
47*2393Syz155240 #if defined(_KERNEL)
48*2393Syz155240 # include <sys/systm.h>
49*2393Syz155240 # if !defined(__SVR4) && !defined(__svr4__)
50*2393Syz155240 #  include <sys/mbuf.h>
51*2393Syz155240 # endif
52*2393Syz155240 #endif
53*2393Syz155240 #if !defined(__SVR4) && !defined(__svr4__)
54*2393Syz155240 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
55*2393Syz155240 #  include <sys/kernel.h>
56*2393Syz155240 # endif
57*2393Syz155240 #else
58*2393Syz155240 # include <sys/byteorder.h>
59*2393Syz155240 # ifdef _KERNEL
60*2393Syz155240 #  include <sys/dditypes.h>
61*2393Syz155240 # endif
62*2393Syz155240 # include <sys/stream.h>
63*2393Syz155240 # include <sys/kmem.h>
64*2393Syz155240 #endif
65*2393Syz155240 #include <net/if.h>
66*2393Syz155240 #ifdef sun
67*2393Syz155240 # include <net/af.h>
68*2393Syz155240 #endif
69*2393Syz155240 #include <net/route.h>
70*2393Syz155240 #include <netinet/in.h>
71*2393Syz155240 #include <netinet/in_systm.h>
72*2393Syz155240 #include <netinet/ip.h>
73*2393Syz155240 #if !defined(linux)
74*2393Syz155240 # include <netinet/ip_var.h>
75*2393Syz155240 #endif
76*2393Syz155240 #include <netinet/tcp.h>
77*2393Syz155240 #include <netinet/udp.h>
78*2393Syz155240 #include <netinet/ip_icmp.h>
79*2393Syz155240 #include "netinet/ip_compat.h"
80*2393Syz155240 #include <netinet/tcpip.h>
81*2393Syz155240 #include "netinet/ip_fil.h"
82*2393Syz155240 #include "netinet/ip_nat.h"
83*2393Syz155240 #include "netinet/ip_frag.h"
84*2393Syz155240 #include "netinet/ip_state.h"
85*2393Syz155240 #include "netinet/ip_auth.h"
86*2393Syz155240 #include "netinet/ip_proxy.h"
87*2393Syz155240 #if (__FreeBSD_version >= 300000)
88*2393Syz155240 # include <sys/malloc.h>
89*2393Syz155240 # if defined(_KERNEL)
90*2393Syz155240 #  ifndef IPFILTER_LKM
91*2393Syz155240 #   include <sys/libkern.h>
92*2393Syz155240 #   include <sys/systm.h>
93*2393Syz155240 #  endif
94*2393Syz155240 extern struct callout_handle fr_slowtimer_ch;
95*2393Syz155240 # endif
96*2393Syz155240 #endif
97*2393Syz155240 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
98*2393Syz155240 # include <sys/callout.h>
99*2393Syz155240 extern struct callout fr_slowtimer_ch;
100*2393Syz155240 #endif
101*2393Syz155240 #if defined(__OpenBSD__)
102*2393Syz155240 # include <sys/timeout.h>
103*2393Syz155240 extern struct timeout fr_slowtimer_ch;
104*2393Syz155240 #endif
105*2393Syz155240 /* END OF INCLUDES */
106*2393Syz155240 
107*2393Syz155240 #if !defined(lint)
108*2393Syz155240 static const char sccsid[] = "@(#)ip_frag.c	1.11 3/24/96 (C) 1993-2000 Darren Reed";
109*2393Syz155240 static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $";
110*2393Syz155240 #endif
111*2393Syz155240 
112*2393Syz155240 
113*2393Syz155240 static ipfr_t   *ipfr_list = NULL;
114*2393Syz155240 static ipfr_t   **ipfr_tail = &ipfr_list;
115*2393Syz155240 static ipfr_t	**ipfr_heads;
116*2393Syz155240 
117*2393Syz155240 static ipfr_t   *ipfr_natlist = NULL;
118*2393Syz155240 static ipfr_t   **ipfr_nattail = &ipfr_natlist;
119*2393Syz155240 static ipfr_t	**ipfr_nattab;
120*2393Syz155240 
121*2393Syz155240 static ipfr_t   *ipfr_ipidlist = NULL;
122*2393Syz155240 static ipfr_t   **ipfr_ipidtail = &ipfr_ipidlist;
123*2393Syz155240 static ipfr_t	**ipfr_ipidtab;
124*2393Syz155240 
125*2393Syz155240 static ipfrstat_t ipfr_stats;
126*2393Syz155240 static int	ipfr_inuse = 0;
127*2393Syz155240 int		ipfr_size = IPFT_SIZE;
128*2393Syz155240 
129*2393Syz155240 int	fr_ipfrttl = 120;	/* 60 seconds */
130*2393Syz155240 int	fr_frag_lock = 0;
131*2393Syz155240 int	fr_frag_init = 0;
132*2393Syz155240 u_long	fr_ticks = 0;
133*2393Syz155240 
134*2393Syz155240 
135*2393Syz155240 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
136*2393Syz155240 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
137*2393Syz155240 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***));
138*2393Syz155240 
139*2393Syz155240 static frentry_t frblock;
140*2393Syz155240 
141*2393Syz155240 /* ------------------------------------------------------------------------ */
142*2393Syz155240 /* Function:    fr_fraginit                                                 */
143*2393Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
144*2393Syz155240 /* Parameters:  Nil                                                         */
145*2393Syz155240 /*                                                                          */
146*2393Syz155240 /* Initialise the hash tables for the fragment cache lookups.               */
147*2393Syz155240 /* ------------------------------------------------------------------------ */
148*2393Syz155240 int fr_fraginit()
149*2393Syz155240 {
150*2393Syz155240 	KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
151*2393Syz155240 	if (ipfr_heads == NULL)
152*2393Syz155240 		return -1;
153*2393Syz155240 	bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *));
154*2393Syz155240 
155*2393Syz155240 	KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
156*2393Syz155240 	if (ipfr_nattab == NULL)
157*2393Syz155240 		return -1;
158*2393Syz155240 	bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
159*2393Syz155240 
160*2393Syz155240 	KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
161*2393Syz155240 	if (ipfr_ipidtab == NULL)
162*2393Syz155240 		return -1;
163*2393Syz155240 	bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
164*2393Syz155240 
165*2393Syz155240 	RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock");
166*2393Syz155240 
167*2393Syz155240 	/* Initialise frblock with "block in all" */
168*2393Syz155240 	bzero((char *)&frblock, sizeof(frblock));
169*2393Syz155240 	frblock.fr_flags = FR_BLOCK|FR_INQUE;	/* block in */
170*2393Syz155240 	frblock.fr_ref = 1;
171*2393Syz155240 
172*2393Syz155240 	fr_frag_init = 1;
173*2393Syz155240 
174*2393Syz155240 	return 0;
175*2393Syz155240 }
176*2393Syz155240 
177*2393Syz155240 
178*2393Syz155240 /* ------------------------------------------------------------------------ */
179*2393Syz155240 /* Function:    fr_fragunload                                               */
180*2393Syz155240 /* Returns:     Nil                                                         */
181*2393Syz155240 /* Parameters:  Nil                                                         */
182*2393Syz155240 /*                                                                          */
183*2393Syz155240 /* Free all memory allocated whilst running and from initialisation.        */
184*2393Syz155240 /* ------------------------------------------------------------------------ */
185*2393Syz155240 void fr_fragunload()
186*2393Syz155240 {
187*2393Syz155240 	if (fr_frag_init == 1) {
188*2393Syz155240 		fr_fragclear();
189*2393Syz155240 
190*2393Syz155240 		RW_DESTROY(&ipf_frag);
191*2393Syz155240 		fr_frag_init = 0;
192*2393Syz155240 	}
193*2393Syz155240 
194*2393Syz155240 	if (ipfr_heads != NULL)
195*2393Syz155240 		KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *));
196*2393Syz155240 	ipfr_heads = NULL;
197*2393Syz155240 
198*2393Syz155240 	if (ipfr_nattab != NULL)
199*2393Syz155240 		KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
200*2393Syz155240 	ipfr_nattab = NULL;
201*2393Syz155240 
202*2393Syz155240 	if (ipfr_ipidtab != NULL)
203*2393Syz155240 		KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
204*2393Syz155240 	ipfr_ipidtab = NULL;
205*2393Syz155240 }
206*2393Syz155240 
207*2393Syz155240 
208*2393Syz155240 /* ------------------------------------------------------------------------ */
209*2393Syz155240 /* Function:    fr_fragstats                                                */
210*2393Syz155240 /* Returns:     ipfrstat_t* - pointer to struct with current frag stats     */
211*2393Syz155240 /* Parameters:  Nil                                                         */
212*2393Syz155240 /*                                                                          */
213*2393Syz155240 /* Updates ipfr_stats with current information and returns a pointer to it  */
214*2393Syz155240 /* ------------------------------------------------------------------------ */
215*2393Syz155240 ipfrstat_t *fr_fragstats()
216*2393Syz155240 {
217*2393Syz155240 	ipfr_stats.ifs_table = ipfr_heads;
218*2393Syz155240 	ipfr_stats.ifs_nattab = ipfr_nattab;
219*2393Syz155240 	ipfr_stats.ifs_inuse = ipfr_inuse;
220*2393Syz155240 	return &ipfr_stats;
221*2393Syz155240 }
222*2393Syz155240 
223*2393Syz155240 
224*2393Syz155240 /* ------------------------------------------------------------------------ */
225*2393Syz155240 /* Function:    ipfr_newfrag                                                */
226*2393Syz155240 /* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
227*2393Syz155240 /* Parameters:  fin(I)   - pointer to packet information                    */
228*2393Syz155240 /*              table(I) - pointer to frag table to add to                  */
229*2393Syz155240 /*                                                                          */
230*2393Syz155240 /* Add a new entry to the fragment cache, registering it as having come     */
231*2393Syz155240 /* through this box, with the result of the filter operation.               */
232*2393Syz155240 /* ------------------------------------------------------------------------ */
233*2393Syz155240 static ipfr_t *ipfr_newfrag(fin, pass, table)
234*2393Syz155240 fr_info_t *fin;
235*2393Syz155240 u_32_t pass;
236*2393Syz155240 ipfr_t *table[];
237*2393Syz155240 {
238*2393Syz155240 	ipfr_t *fra, frag;
239*2393Syz155240 	u_int idx, off;
240*2393Syz155240 
241*2393Syz155240 	if (ipfr_inuse >= IPFT_SIZE)
242*2393Syz155240 		return NULL;
243*2393Syz155240 
244*2393Syz155240 	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
245*2393Syz155240 		return NULL;
246*2393Syz155240 
247*2393Syz155240 	if (pass & FR_FRSTRICT)
248*2393Syz155240 		if (fin->fin_off != 0)
249*2393Syz155240 			return NULL;
250*2393Syz155240 
251*2393Syz155240 	frag.ipfr_p = fin->fin_p;
252*2393Syz155240 	idx = fin->fin_p;
253*2393Syz155240 	frag.ipfr_id = fin->fin_id;
254*2393Syz155240 	idx += fin->fin_id;
255*2393Syz155240 	frag.ipfr_source = fin->fin_fi.fi_src;
256*2393Syz155240 	idx += frag.ipfr_src.s_addr;
257*2393Syz155240 	frag.ipfr_dest = fin->fin_fi.fi_dst;
258*2393Syz155240 	idx += frag.ipfr_dst.s_addr;
259*2393Syz155240 	frag.ipfr_ifp = fin->fin_ifp;
260*2393Syz155240 	idx *= 127;
261*2393Syz155240 	idx %= IPFT_SIZE;
262*2393Syz155240 
263*2393Syz155240 	frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
264*2393Syz155240 	frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
265*2393Syz155240 	frag.ipfr_auth = fin->fin_fi.fi_auth;
266*2393Syz155240 
267*2393Syz155240 	/*
268*2393Syz155240 	 * first, make sure it isn't already there...
269*2393Syz155240 	 */
270*2393Syz155240 	for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
271*2393Syz155240 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
272*2393Syz155240 			  IPFR_CMPSZ)) {
273*2393Syz155240 			ipfr_stats.ifs_exists++;
274*2393Syz155240 			return NULL;
275*2393Syz155240 		}
276*2393Syz155240 
277*2393Syz155240 	/*
278*2393Syz155240 	 * allocate some memory, if possible, if not, just record that we
279*2393Syz155240 	 * failed to do so.
280*2393Syz155240 	 */
281*2393Syz155240 	KMALLOC(fra, ipfr_t *);
282*2393Syz155240 	if (fra == NULL) {
283*2393Syz155240 		ipfr_stats.ifs_nomem++;
284*2393Syz155240 		return NULL;
285*2393Syz155240 	}
286*2393Syz155240 
287*2393Syz155240 	fra->ipfr_rule = fin->fin_fr;
288*2393Syz155240 	if (fra->ipfr_rule != NULL) {
289*2393Syz155240 
290*2393Syz155240 		frentry_t *fr;
291*2393Syz155240 
292*2393Syz155240 		fr = fin->fin_fr;
293*2393Syz155240 		MUTEX_ENTER(&fr->fr_lock);
294*2393Syz155240 		fr->fr_ref++;
295*2393Syz155240 		MUTEX_EXIT(&fr->fr_lock);
296*2393Syz155240 	}
297*2393Syz155240 
298*2393Syz155240 	/*
299*2393Syz155240 	 * Insert the fragment into the fragment table, copy the struct used
300*2393Syz155240 	 * in the search using bcopy rather than reassign each field.
301*2393Syz155240 	 * Set the ttl to the default.
302*2393Syz155240 	 */
303*2393Syz155240 	if ((fra->ipfr_hnext = table[idx]) != NULL)
304*2393Syz155240 		table[idx]->ipfr_hprev = &fra->ipfr_hnext;
305*2393Syz155240 	fra->ipfr_hprev = table + idx;
306*2393Syz155240 	fra->ipfr_data = NULL;
307*2393Syz155240 	table[idx] = fra;
308*2393Syz155240 	bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
309*2393Syz155240 	fra->ipfr_ttl = fr_ticks + fr_ipfrttl;
310*2393Syz155240 
311*2393Syz155240 	/*
312*2393Syz155240 	 * Compute the offset of the expected start of the next packet.
313*2393Syz155240 	 */
314*2393Syz155240 	off = fin->fin_off;
315*2393Syz155240 	if (off == 0) {
316*2393Syz155240 		fra->ipfr_seen0 = 1;
317*2393Syz155240 		fra->ipfr_firstend = fin->fin_flen;
318*2393Syz155240 	} else {
319*2393Syz155240 		fra->ipfr_seen0 = 0;
320*2393Syz155240 		fra->ipfr_firstend = 0;
321*2393Syz155240 	}
322*2393Syz155240 	fra->ipfr_off = off + fin->fin_dlen;
323*2393Syz155240 	fra->ipfr_pass = pass;
324*2393Syz155240 	ipfr_stats.ifs_new++;
325*2393Syz155240 	ipfr_inuse++;
326*2393Syz155240 	return fra;
327*2393Syz155240 }
328*2393Syz155240 
329*2393Syz155240 
330*2393Syz155240 /* ------------------------------------------------------------------------ */
331*2393Syz155240 /* Function:    fr_newfrag                                                  */
332*2393Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
333*2393Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
334*2393Syz155240 /*                                                                          */
335*2393Syz155240 /* Add a new entry to the fragment cache table based on the current packet  */
336*2393Syz155240 /* ------------------------------------------------------------------------ */
337*2393Syz155240 int fr_newfrag(fin, pass)
338*2393Syz155240 u_32_t pass;
339*2393Syz155240 fr_info_t *fin;
340*2393Syz155240 {
341*2393Syz155240 	ipfr_t	*fra;
342*2393Syz155240 
343*2393Syz155240 	if (fr_frag_lock != 0)
344*2393Syz155240 		return -1;
345*2393Syz155240 
346*2393Syz155240 	WRITE_ENTER(&ipf_frag);
347*2393Syz155240 	fra = ipfr_newfrag(fin, pass, ipfr_heads);
348*2393Syz155240 	if (fra != NULL) {
349*2393Syz155240 		*ipfr_tail = fra;
350*2393Syz155240 		fra->ipfr_prev = ipfr_tail;
351*2393Syz155240 		ipfr_tail = &fra->ipfr_next;
352*2393Syz155240 		if (ipfr_list == NULL)
353*2393Syz155240 			ipfr_list = fra;
354*2393Syz155240 		fra->ipfr_next = NULL;
355*2393Syz155240 	}
356*2393Syz155240 	RWLOCK_EXIT(&ipf_frag);
357*2393Syz155240 	return fra ? 0 : -1;
358*2393Syz155240 }
359*2393Syz155240 
360*2393Syz155240 
361*2393Syz155240 /* ------------------------------------------------------------------------ */
362*2393Syz155240 /* Function:    fr_nat_newfrag                                              */
363*2393Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
364*2393Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
365*2393Syz155240 /*              nat(I)  - pointer to NAT structure                          */
366*2393Syz155240 /*                                                                          */
367*2393Syz155240 /* Create a new NAT fragment cache entry based on the current packet and    */
368*2393Syz155240 /* the NAT structure for this "session".                                    */
369*2393Syz155240 /* ------------------------------------------------------------------------ */
370*2393Syz155240 int fr_nat_newfrag(fin, pass, nat)
371*2393Syz155240 fr_info_t *fin;
372*2393Syz155240 u_32_t pass;
373*2393Syz155240 nat_t *nat;
374*2393Syz155240 {
375*2393Syz155240 	ipfr_t	*fra;
376*2393Syz155240 
377*2393Syz155240 	if ((fin->fin_v != 4) || (fr_frag_lock != 0))
378*2393Syz155240 		return 0;
379*2393Syz155240 
380*2393Syz155240 	WRITE_ENTER(&ipf_natfrag);
381*2393Syz155240 	fra = ipfr_newfrag(fin, pass, ipfr_nattab);
382*2393Syz155240 	if (fra != NULL) {
383*2393Syz155240 		fra->ipfr_data = nat;
384*2393Syz155240 		nat->nat_data = fra;
385*2393Syz155240 		*ipfr_nattail = fra;
386*2393Syz155240 		fra->ipfr_prev = ipfr_nattail;
387*2393Syz155240 		ipfr_nattail = &fra->ipfr_next;
388*2393Syz155240 		fra->ipfr_next = NULL;
389*2393Syz155240 	}
390*2393Syz155240 	RWLOCK_EXIT(&ipf_natfrag);
391*2393Syz155240 	return fra ? 0 : -1;
392*2393Syz155240 }
393*2393Syz155240 
394*2393Syz155240 
395*2393Syz155240 /* ------------------------------------------------------------------------ */
396*2393Syz155240 /* Function:    fr_ipid_newfrag                                             */
397*2393Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
398*2393Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
399*2393Syz155240 /*              ipid(I) - new IP ID for this fragmented packet              */
400*2393Syz155240 /*                                                                          */
401*2393Syz155240 /* Create a new fragment cache entry for this packet and store, as a data   */
402*2393Syz155240 /* pointer, the new IP ID value.                                            */
403*2393Syz155240 /* ------------------------------------------------------------------------ */
404*2393Syz155240 int fr_ipid_newfrag(fin, ipid)
405*2393Syz155240 fr_info_t *fin;
406*2393Syz155240 u_32_t ipid;
407*2393Syz155240 {
408*2393Syz155240 	ipfr_t	*fra;
409*2393Syz155240 
410*2393Syz155240 	if (fr_frag_lock)
411*2393Syz155240 		return 0;
412*2393Syz155240 
413*2393Syz155240 	WRITE_ENTER(&ipf_ipidfrag);
414*2393Syz155240 	fra = ipfr_newfrag(fin, 0, ipfr_ipidtab);
415*2393Syz155240 	if (fra != NULL) {
416*2393Syz155240 		fra->ipfr_data = (void *)(uintptr_t)ipid;
417*2393Syz155240 		*ipfr_ipidtail = fra;
418*2393Syz155240 		fra->ipfr_prev = ipfr_ipidtail;
419*2393Syz155240 		ipfr_ipidtail = &fra->ipfr_next;
420*2393Syz155240 		fra->ipfr_next = NULL;
421*2393Syz155240 	}
422*2393Syz155240 	RWLOCK_EXIT(&ipf_ipidfrag);
423*2393Syz155240 	return fra ? 0 : -1;
424*2393Syz155240 }
425*2393Syz155240 
426*2393Syz155240 
427*2393Syz155240 /* ------------------------------------------------------------------------ */
428*2393Syz155240 /* Function:    fr_fraglookup                                               */
429*2393Syz155240 /* Returns:     ipfr_t * - pointer to ipfr_t structure if there's a         */
430*2393Syz155240 /*                         matching entry in the frag table, else NULL      */
431*2393Syz155240 /* Parameters:  fin(I)   - pointer to packet information                    */
432*2393Syz155240 /*              table(I) - pointer to fragment cache table to search        */
433*2393Syz155240 /*                                                                          */
434*2393Syz155240 /* Check the fragment cache to see if there is already a record of this     */
435*2393Syz155240 /* packet with its filter result known.                                     */
436*2393Syz155240 /* ------------------------------------------------------------------------ */
437*2393Syz155240 static ipfr_t *fr_fraglookup(fin, table)
438*2393Syz155240 fr_info_t *fin;
439*2393Syz155240 ipfr_t *table[];
440*2393Syz155240 {
441*2393Syz155240 	ipfr_t *f, frag;
442*2393Syz155240 	u_int idx;
443*2393Syz155240 
444*2393Syz155240 	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
445*2393Syz155240 		return NULL;
446*2393Syz155240 
447*2393Syz155240 	/*
448*2393Syz155240 	 * For fragments, we record protocol, packet id, TOS and both IP#'s
449*2393Syz155240 	 * (these should all be the same for all fragments of a packet).
450*2393Syz155240 	 *
451*2393Syz155240 	 * build up a hash value to index the table with.
452*2393Syz155240 	 */
453*2393Syz155240 	frag.ipfr_p = fin->fin_p;
454*2393Syz155240 	idx = fin->fin_p;
455*2393Syz155240 	frag.ipfr_id = fin->fin_id;
456*2393Syz155240 	idx += fin->fin_id;
457*2393Syz155240 	frag.ipfr_source = fin->fin_fi.fi_src;
458*2393Syz155240 	idx += frag.ipfr_src.s_addr;
459*2393Syz155240 	frag.ipfr_dest = fin->fin_fi.fi_dst;
460*2393Syz155240 	idx += frag.ipfr_dst.s_addr;
461*2393Syz155240 	frag.ipfr_ifp = fin->fin_ifp;
462*2393Syz155240 	idx *= 127;
463*2393Syz155240 	idx %= IPFT_SIZE;
464*2393Syz155240 
465*2393Syz155240 	frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
466*2393Syz155240 	frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
467*2393Syz155240 	frag.ipfr_auth = fin->fin_fi.fi_auth;
468*2393Syz155240 
469*2393Syz155240 	/*
470*2393Syz155240 	 * check the table, careful to only compare the right amount of data
471*2393Syz155240 	 */
472*2393Syz155240 	for (f = table[idx]; f; f = f->ipfr_hnext)
473*2393Syz155240 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
474*2393Syz155240 			  IPFR_CMPSZ)) {
475*2393Syz155240 			u_short	off;
476*2393Syz155240 
477*2393Syz155240 			/*
478*2393Syz155240 			 * We don't want to let short packets match because
479*2393Syz155240 			 * they could be compromising the security of other
480*2393Syz155240 			 * rules that want to match on layer 4 fields (and
481*2393Syz155240 			 * can't because they have been fragmented off.)
482*2393Syz155240 			 * Why do this check here?  The counter acts as an
483*2393Syz155240 			 * indicator of this kind of attack, whereas if it was
484*2393Syz155240 			 * elsewhere, it wouldn't know if other matching
485*2393Syz155240 			 * packets had been seen.
486*2393Syz155240 			 */
487*2393Syz155240 			if (fin->fin_flx & FI_SHORT) {
488*2393Syz155240 				ATOMIC_INCL(ipfr_stats.ifs_short);
489*2393Syz155240 				continue;
490*2393Syz155240 			}
491*2393Syz155240 
492*2393Syz155240 			/*
493*2393Syz155240 			 * XXX - We really need to be guarding against the
494*2393Syz155240 			 * retransmission of (src,dst,id,offset-range) here
495*2393Syz155240 			 * because a fragmented packet is never resent with
496*2393Syz155240 			 * the same IP ID# (or shouldn't).
497*2393Syz155240 			 */
498*2393Syz155240 			off = fin->fin_off; /* same as in ipfr_newfrag() */
499*2393Syz155240 			if (f->ipfr_seen0) {
500*2393Syz155240 				if (off == 0) {
501*2393Syz155240 					ATOMIC_INCL(ipfr_stats.ifs_retrans0);
502*2393Syz155240 					continue;
503*2393Syz155240 				}
504*2393Syz155240 			} else if (off == 0) {
505*2393Syz155240 				f->ipfr_seen0 = 1;
506*2393Syz155240 				f->ipfr_firstend = fin->fin_flen;
507*2393Syz155240 			}
508*2393Syz155240 
509*2393Syz155240 			if (f != table[idx]) {
510*2393Syz155240 				ipfr_t **fp;
511*2393Syz155240 
512*2393Syz155240 				/*
513*2393Syz155240 				 * Move fragment info. to the top of the list
514*2393Syz155240 				 * to speed up searches.  First, delink...
515*2393Syz155240 				 */
516*2393Syz155240 				fp = f->ipfr_hprev;
517*2393Syz155240 				(*fp) = f->ipfr_hnext;
518*2393Syz155240 				if (f->ipfr_hnext != NULL)
519*2393Syz155240 					f->ipfr_hnext->ipfr_hprev = fp;
520*2393Syz155240 				/*
521*2393Syz155240 				 * Then put back at the top of the chain.
522*2393Syz155240 				 */
523*2393Syz155240 				f->ipfr_hnext = table[idx];
524*2393Syz155240 				table[idx]->ipfr_hprev = &f->ipfr_hnext;
525*2393Syz155240 				f->ipfr_hprev = table + idx;
526*2393Syz155240 				table[idx] = f;
527*2393Syz155240 			}
528*2393Syz155240 
529*2393Syz155240 			if (fin->fin_v == 6) {
530*2393Syz155240 				if (f->ipfr_seen0 && (off < f->ipfr_firstend))
531*2393Syz155240 					fin->fin_flx |= FI_BAD;
532*2393Syz155240 			}
533*2393Syz155240 			/*
534*2393Syz155240 			 * If we've follwed the fragments, and this is the
535*2393Syz155240 			 * last (in order), shrink expiration time.
536*2393Syz155240 			 */
537*2393Syz155240 			if (off == f->ipfr_off) {
538*2393Syz155240 				if (!(fin->fin_ip->ip_off & IP_MF))
539*2393Syz155240 					f->ipfr_ttl = fr_ticks + 1;
540*2393Syz155240 				f->ipfr_off = fin->fin_dlen + off;
541*2393Syz155240 			} else if (f->ipfr_pass & FR_FRSTRICT)
542*2393Syz155240 				continue;
543*2393Syz155240 			ATOMIC_INCL(ipfr_stats.ifs_hits);
544*2393Syz155240 			return f;
545*2393Syz155240 		}
546*2393Syz155240 	return NULL;
547*2393Syz155240 }
548*2393Syz155240 
549*2393Syz155240 
550*2393Syz155240 /* ------------------------------------------------------------------------ */
551*2393Syz155240 /* Function:    fr_nat_knownfrag                                            */
552*2393Syz155240 /* Returns:     nat_t* - pointer to 'parent' NAT structure if frag table    */
553*2393Syz155240 /*                       match found, else NULL                             */
554*2393Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
555*2393Syz155240 /*                                                                          */
556*2393Syz155240 /* Functional interface for NAT lookups of the NAT fragment cache           */
557*2393Syz155240 /* ------------------------------------------------------------------------ */
558*2393Syz155240 nat_t *fr_nat_knownfrag(fin)
559*2393Syz155240 fr_info_t *fin;
560*2393Syz155240 {
561*2393Syz155240 	nat_t	*nat;
562*2393Syz155240 	ipfr_t	*ipf;
563*2393Syz155240 
564*2393Syz155240 	if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist)
565*2393Syz155240 		return NULL;
566*2393Syz155240 	READ_ENTER(&ipf_natfrag);
567*2393Syz155240 	ipf = fr_fraglookup(fin, ipfr_nattab);
568*2393Syz155240 	if (ipf != NULL) {
569*2393Syz155240 		nat = ipf->ipfr_data;
570*2393Syz155240 		/*
571*2393Syz155240 		 * This is the last fragment for this packet.
572*2393Syz155240 		 */
573*2393Syz155240 		if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) {
574*2393Syz155240 			nat->nat_data = NULL;
575*2393Syz155240 			ipf->ipfr_data = NULL;
576*2393Syz155240 		}
577*2393Syz155240 	} else
578*2393Syz155240 		nat = NULL;
579*2393Syz155240 	RWLOCK_EXIT(&ipf_natfrag);
580*2393Syz155240 	return nat;
581*2393Syz155240 }
582*2393Syz155240 
583*2393Syz155240 
584*2393Syz155240 /* ------------------------------------------------------------------------ */
585*2393Syz155240 /* Function:    fr_ipid_knownfrag                                           */
586*2393Syz155240 /* Returns:     u_32_t - IPv4 ID for this packet if match found, else       */
587*2393Syz155240 /*                       return 0xfffffff to indicate no match.             */
588*2393Syz155240 /* Parameters:  fin(I) - pointer to packet information                      */
589*2393Syz155240 /*                                                                          */
590*2393Syz155240 /* Functional interface for IP ID lookups of the IP ID fragment cache       */
591*2393Syz155240 /* ------------------------------------------------------------------------ */
592*2393Syz155240 u_32_t fr_ipid_knownfrag(fin)
593*2393Syz155240 fr_info_t *fin;
594*2393Syz155240 {
595*2393Syz155240 	ipfr_t	*ipf;
596*2393Syz155240 	u_32_t	id;
597*2393Syz155240 
598*2393Syz155240 	if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist)
599*2393Syz155240 		return 0xffffffff;
600*2393Syz155240 
601*2393Syz155240 	READ_ENTER(&ipf_ipidfrag);
602*2393Syz155240 	ipf = fr_fraglookup(fin, ipfr_ipidtab);
603*2393Syz155240 	if (ipf != NULL)
604*2393Syz155240 		id = (u_32_t)(uintptr_t)ipf->ipfr_data;
605*2393Syz155240 	else
606*2393Syz155240 		id = 0xffffffff;
607*2393Syz155240 	RWLOCK_EXIT(&ipf_ipidfrag);
608*2393Syz155240 	return id;
609*2393Syz155240 }
610*2393Syz155240 
611*2393Syz155240 
612*2393Syz155240 /* ------------------------------------------------------------------------ */
613*2393Syz155240 /* Function:    fr_knownfrag                                                */
614*2393Syz155240 /* Returns:     frentry_t* - pointer to filter rule if a match is found in  */
615*2393Syz155240 /*                           the frag cache table, else NULL.               */
616*2393Syz155240 /* Parameters:  fin(I)   - pointer to packet information                    */
617*2393Syz155240 /*              passp(O) - pointer to where to store rule flags resturned   */
618*2393Syz155240 /*                                                                          */
619*2393Syz155240 /* Functional interface for normal lookups of the fragment cache.  If a     */
620*2393Syz155240 /* match is found, return the rule pointer and flags from the rule, except  */
621*2393Syz155240 /* that if FR_LOGFIRST is set, reset FR_LOG.                                */
622*2393Syz155240 /* ------------------------------------------------------------------------ */
623*2393Syz155240 frentry_t *fr_knownfrag(fin, passp)
624*2393Syz155240 fr_info_t *fin;
625*2393Syz155240 u_32_t *passp;
626*2393Syz155240 {
627*2393Syz155240 	frentry_t *fr = NULL;
628*2393Syz155240 	ipfr_t	*fra;
629*2393Syz155240 	u_32_t pass, oflx;
630*2393Syz155240 
631*2393Syz155240 	if ((fr_frag_lock) || (ipfr_list == NULL))
632*2393Syz155240 		return NULL;
633*2393Syz155240 
634*2393Syz155240 	READ_ENTER(&ipf_frag);
635*2393Syz155240 	oflx = fin->fin_flx;
636*2393Syz155240 	fra = fr_fraglookup(fin, ipfr_heads);
637*2393Syz155240 	if (fra != NULL) {
638*2393Syz155240 		fr = fra->ipfr_rule;
639*2393Syz155240 		fin->fin_fr = fr;
640*2393Syz155240 		if (fr != NULL) {
641*2393Syz155240 			pass = fr->fr_flags;
642*2393Syz155240 			if ((pass & FR_LOGFIRST) != 0)
643*2393Syz155240 				pass &= ~(FR_LOGFIRST|FR_LOG);
644*2393Syz155240 			*passp = pass;
645*2393Syz155240 		}
646*2393Syz155240 	}
647*2393Syz155240 	if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) {
648*2393Syz155240 		*passp &= ~FR_CMDMASK;
649*2393Syz155240 		*passp |= FR_BLOCK;
650*2393Syz155240 		fr = &frblock;
651*2393Syz155240 	}
652*2393Syz155240 	RWLOCK_EXIT(&ipf_frag);
653*2393Syz155240 	return fr;
654*2393Syz155240 }
655*2393Syz155240 
656*2393Syz155240 
657*2393Syz155240 /* ------------------------------------------------------------------------ */
658*2393Syz155240 /* Function:    fr_forget                                                   */
659*2393Syz155240 /* Returns:     Nil                                                         */
660*2393Syz155240 /* Parameters:  ptr(I) - pointer to data structure                          */
661*2393Syz155240 /*                                                                          */
662*2393Syz155240 /* Search through all of the fragment cache entries and wherever a pointer  */
663*2393Syz155240 /* is found to match ptr, reset it to NULL.                                 */
664*2393Syz155240 /* ------------------------------------------------------------------------ */
665*2393Syz155240 void fr_forget(ptr)
666*2393Syz155240 void *ptr;
667*2393Syz155240 {
668*2393Syz155240 	ipfr_t	*fr;
669*2393Syz155240 
670*2393Syz155240 	WRITE_ENTER(&ipf_frag);
671*2393Syz155240 	for (fr = ipfr_list; fr; fr = fr->ipfr_next)
672*2393Syz155240 		if (fr->ipfr_data == ptr)
673*2393Syz155240 			fr->ipfr_data = NULL;
674*2393Syz155240 	RWLOCK_EXIT(&ipf_frag);
675*2393Syz155240 }
676*2393Syz155240 
677*2393Syz155240 
678*2393Syz155240 /* ------------------------------------------------------------------------ */
679*2393Syz155240 /* Function:    fr_forgetnat                                                */
680*2393Syz155240 /* Returns:     Nil                                                         */
681*2393Syz155240 /* Parameters:  ptr(I) - pointer to data structure                          */
682*2393Syz155240 /*                                                                          */
683*2393Syz155240 /* Search through all of the fragment cache entries for NAT and wherever a  */
684*2393Syz155240 /* pointer  is found to match ptr, reset it to NULL.                        */
685*2393Syz155240 /* ------------------------------------------------------------------------ */
686*2393Syz155240 void fr_forgetnat(ptr)
687*2393Syz155240 void *ptr;
688*2393Syz155240 {
689*2393Syz155240 	ipfr_t	*fr;
690*2393Syz155240 
691*2393Syz155240 	WRITE_ENTER(&ipf_natfrag);
692*2393Syz155240 	for (fr = ipfr_natlist; fr; fr = fr->ipfr_next)
693*2393Syz155240 		if (fr->ipfr_data == ptr)
694*2393Syz155240 			fr->ipfr_data = NULL;
695*2393Syz155240 	RWLOCK_EXIT(&ipf_natfrag);
696*2393Syz155240 }
697*2393Syz155240 
698*2393Syz155240 
699*2393Syz155240 /* ------------------------------------------------------------------------ */
700*2393Syz155240 /* Function:    fr_fragdelete                                               */
701*2393Syz155240 /* Returns:     Nil                                                         */
702*2393Syz155240 /* Parameters:  fra(I)   - pointer to fragment structure to delete          */
703*2393Syz155240 /*              tail(IO) - pointer to the pointer to the tail of the frag   */
704*2393Syz155240 /*                         list                                             */
705*2393Syz155240 /*                                                                          */
706*2393Syz155240 /* Remove a fragment cache table entry from the table & list.  Also free    */
707*2393Syz155240 /* the filter rule it is associated with it if it is no longer used as a    */
708*2393Syz155240 /* result of decreasing the reference count.                                */
709*2393Syz155240 /* ------------------------------------------------------------------------ */
710*2393Syz155240 static void fr_fragdelete(fra, tail)
711*2393Syz155240 ipfr_t *fra, ***tail;
712*2393Syz155240 {
713*2393Syz155240 	frentry_t *fr;
714*2393Syz155240 
715*2393Syz155240 	fr = fra->ipfr_rule;
716*2393Syz155240 	if (fr != NULL)
717*2393Syz155240 		(void)fr_derefrule(&fr);
718*2393Syz155240 
719*2393Syz155240 	if (fra->ipfr_next)
720*2393Syz155240 		fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
721*2393Syz155240 	*fra->ipfr_prev = fra->ipfr_next;
722*2393Syz155240 	if (*tail == &fra->ipfr_next)
723*2393Syz155240 		*tail = fra->ipfr_prev;
724*2393Syz155240 
725*2393Syz155240 	if (fra->ipfr_hnext)
726*2393Syz155240 		fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
727*2393Syz155240 	*fra->ipfr_hprev = fra->ipfr_hnext;
728*2393Syz155240 	KFREE(fra);
729*2393Syz155240 }
730*2393Syz155240 
731*2393Syz155240 
732*2393Syz155240 /* ------------------------------------------------------------------------ */
733*2393Syz155240 /* Function:    fr_fragclear                                                */
734*2393Syz155240 /* Returns:     Nil                                                         */
735*2393Syz155240 /* Parameters:  Nil                                                         */
736*2393Syz155240 /*                                                                          */
737*2393Syz155240 /* Free memory in use by fragment state information kept.  Do the normal    */
738*2393Syz155240 /* fragment state stuff first and then the NAT-fragment table.              */
739*2393Syz155240 /* ------------------------------------------------------------------------ */
740*2393Syz155240 void fr_fragclear()
741*2393Syz155240 {
742*2393Syz155240 	ipfr_t	*fra;
743*2393Syz155240 	nat_t	*nat;
744*2393Syz155240 
745*2393Syz155240 	WRITE_ENTER(&ipf_frag);
746*2393Syz155240 	while ((fra = ipfr_list) != NULL)
747*2393Syz155240 		fr_fragdelete(fra, &ipfr_tail);
748*2393Syz155240 	ipfr_tail = &ipfr_list;
749*2393Syz155240 	RWLOCK_EXIT(&ipf_frag);
750*2393Syz155240 
751*2393Syz155240 	WRITE_ENTER(&ipf_nat);
752*2393Syz155240 	WRITE_ENTER(&ipf_natfrag);
753*2393Syz155240 	while ((fra = ipfr_natlist) != NULL) {
754*2393Syz155240 		nat = fra->ipfr_data;
755*2393Syz155240 		if (nat != NULL) {
756*2393Syz155240 			if (nat->nat_data == fra)
757*2393Syz155240 				nat->nat_data = NULL;
758*2393Syz155240 		}
759*2393Syz155240 		fr_fragdelete(fra, &ipfr_nattail);
760*2393Syz155240 	}
761*2393Syz155240 	ipfr_nattail = &ipfr_natlist;
762*2393Syz155240 	RWLOCK_EXIT(&ipf_natfrag);
763*2393Syz155240 	RWLOCK_EXIT(&ipf_nat);
764*2393Syz155240 }
765*2393Syz155240 
766*2393Syz155240 
767*2393Syz155240 /* ------------------------------------------------------------------------ */
768*2393Syz155240 /* Function:    fr_fragexpire                                               */
769*2393Syz155240 /* Returns:     Nil                                                         */
770*2393Syz155240 /* Parameters:  Nil                                                         */
771*2393Syz155240 /*                                                                          */
772*2393Syz155240 /* Expire entries in the fragment cache table that have been there too long */
773*2393Syz155240 /* ------------------------------------------------------------------------ */
774*2393Syz155240 void fr_fragexpire()
775*2393Syz155240 {
776*2393Syz155240 	ipfr_t	**fp, *fra;
777*2393Syz155240 	nat_t	*nat;
778*2393Syz155240 	SPL_INT(s);
779*2393Syz155240 
780*2393Syz155240 	if (fr_frag_lock)
781*2393Syz155240 		return;
782*2393Syz155240 
783*2393Syz155240 	SPL_NET(s);
784*2393Syz155240 	WRITE_ENTER(&ipf_frag);
785*2393Syz155240 	/*
786*2393Syz155240 	 * Go through the entire table, looking for entries to expire,
787*2393Syz155240 	 * which is indicated by the ttl being less than or equal to fr_ticks.
788*2393Syz155240 	 */
789*2393Syz155240 	for (fp = &ipfr_list; ((fra = *fp) != NULL); ) {
790*2393Syz155240 		if (fra->ipfr_ttl > fr_ticks)
791*2393Syz155240 			break;
792*2393Syz155240 		fr_fragdelete(fra, &ipfr_tail);
793*2393Syz155240 		ipfr_stats.ifs_expire++;
794*2393Syz155240 		ipfr_inuse--;
795*2393Syz155240 	}
796*2393Syz155240 	RWLOCK_EXIT(&ipf_frag);
797*2393Syz155240 
798*2393Syz155240 	WRITE_ENTER(&ipf_ipidfrag);
799*2393Syz155240 	for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) {
800*2393Syz155240 		if (fra->ipfr_ttl > fr_ticks)
801*2393Syz155240 			break;
802*2393Syz155240 		fr_fragdelete(fra, &ipfr_ipidtail);
803*2393Syz155240 		ipfr_stats.ifs_expire++;
804*2393Syz155240 		ipfr_inuse--;
805*2393Syz155240 	}
806*2393Syz155240 	RWLOCK_EXIT(&ipf_ipidfrag);
807*2393Syz155240 
808*2393Syz155240 	/*
809*2393Syz155240 	 * Same again for the NAT table, except that if the structure also
810*2393Syz155240 	 * still points to a NAT structure, and the NAT structure points back
811*2393Syz155240 	 * at the one to be free'd, NULL the reference from the NAT struct.
812*2393Syz155240 	 * NOTE: We need to grab both mutex's early, and in this order so as
813*2393Syz155240 	 * to prevent a deadlock if both try to expire at the same time.
814*2393Syz155240 	 */
815*2393Syz155240 	WRITE_ENTER(&ipf_nat);
816*2393Syz155240 	WRITE_ENTER(&ipf_natfrag);
817*2393Syz155240 	for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) {
818*2393Syz155240 		if (fra->ipfr_ttl > fr_ticks)
819*2393Syz155240 			break;
820*2393Syz155240 		nat = fra->ipfr_data;
821*2393Syz155240 		if (nat != NULL) {
822*2393Syz155240 			if (nat->nat_data == fra)
823*2393Syz155240 				nat->nat_data = NULL;
824*2393Syz155240 		}
825*2393Syz155240 		fr_fragdelete(fra, &ipfr_nattail);
826*2393Syz155240 		ipfr_stats.ifs_expire++;
827*2393Syz155240 		ipfr_inuse--;
828*2393Syz155240 	}
829*2393Syz155240 	RWLOCK_EXIT(&ipf_natfrag);
830*2393Syz155240 	RWLOCK_EXIT(&ipf_nat);
831*2393Syz155240 	SPL_X(s);
832*2393Syz155240 }
833*2393Syz155240 
834*2393Syz155240 
835*2393Syz155240 /* ------------------------------------------------------------------------ */
836*2393Syz155240 /* Function:    fr_slowtimer                                                */
837*2393Syz155240 /* Returns:     Nil                                                         */
838*2393Syz155240 /* Parameters:  Nil                                                         */
839*2393Syz155240 /*                                                                          */
840*2393Syz155240 /* Slowly expire held state for fragments.  Timeouts are set * in           */
841*2393Syz155240 /* expectation of this being called twice per second.                       */
842*2393Syz155240 /* ------------------------------------------------------------------------ */
843*2393Syz155240 #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
844*2393Syz155240 			  !defined(__osf__) && !defined(linux))
845*2393Syz155240 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
846*2393Syz155240 void fr_slowtimer __P((void *ptr))
847*2393Syz155240 # else
848*2393Syz155240 int fr_slowtimer()
849*2393Syz155240 # endif
850*2393Syz155240 {
851*2393Syz155240 	READ_ENTER(&ipf_global);
852*2393Syz155240 
853*2393Syz155240 	fr_fragexpire();
854*2393Syz155240 	fr_timeoutstate();
855*2393Syz155240 	fr_natexpire();
856*2393Syz155240 	fr_authexpire();
857*2393Syz155240 	fr_ticks++;
858*2393Syz155240 	if (fr_running <= 0)
859*2393Syz155240 		goto done;
860*2393Syz155240 # ifdef _KERNEL
861*2393Syz155240 #  if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
862*2393Syz155240 	callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
863*2393Syz155240 #  else
864*2393Syz155240 #   if defined(__OpenBSD__)
865*2393Syz155240 	timeout_add(&fr_slowtimer_ch, hz/2);
866*2393Syz155240 #   else
867*2393Syz155240 #    if (__FreeBSD_version >= 300000)
868*2393Syz155240 	fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
869*2393Syz155240 #    else
870*2393Syz155240 #     ifdef linux
871*2393Syz155240 	;
872*2393Syz155240 #     else
873*2393Syz155240 	timeout(fr_slowtimer, NULL, hz/2);
874*2393Syz155240 #     endif
875*2393Syz155240 #    endif /* FreeBSD */
876*2393Syz155240 #   endif /* OpenBSD */
877*2393Syz155240 #  endif /* NetBSD */
878*2393Syz155240 # endif
879*2393Syz155240 done:
880*2393Syz155240 	RWLOCK_EXIT(&ipf_global);
881*2393Syz155240 # if (BSD < 199103) || !defined(_KERNEL)
882*2393Syz155240 	return 0;
883*2393Syz155240 # endif
884*2393Syz155240 }
885*2393Syz155240 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
886