xref: /titanic_52/usr/src/uts/common/inet/ipf/ip_frag.c (revision f56257d84449cae424f3943cec01573a5027af36)
1ab25eeb5Syz155240 /*
2ab25eeb5Syz155240  * Copyright (C) 1993-2003 by Darren Reed.
3ab25eeb5Syz155240  *
4ab25eeb5Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
5ab25eeb5Syz155240  *
672680cf5SDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
7ab25eeb5Syz155240  * Use is subject to license terms.
8ab25eeb5Syz155240  */
9ab25eeb5Syz155240 
10ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL)
11ab25eeb5Syz155240 # undef KERNEL
12ab25eeb5Syz155240 # undef _KERNEL
13ab25eeb5Syz155240 # define        KERNEL	1
14ab25eeb5Syz155240 # define        _KERNEL	1
15ab25eeb5Syz155240 #endif
16ab25eeb5Syz155240 #include <sys/errno.h>
17ab25eeb5Syz155240 #include <sys/types.h>
18ab25eeb5Syz155240 #include <sys/param.h>
19ab25eeb5Syz155240 #include <sys/time.h>
20ab25eeb5Syz155240 #include <sys/file.h>
21ab25eeb5Syz155240 #ifdef __hpux
22ab25eeb5Syz155240 # include <sys/timeout.h>
23ab25eeb5Syz155240 #endif
24ab25eeb5Syz155240 #if !defined(_KERNEL)
25ab25eeb5Syz155240 # include <stdio.h>
26ab25eeb5Syz155240 # include <string.h>
27ab25eeb5Syz155240 # include <stdlib.h>
28ab25eeb5Syz155240 # define _KERNEL
29ab25eeb5Syz155240 # ifdef __OpenBSD__
30ab25eeb5Syz155240 struct file;
31ab25eeb5Syz155240 # endif
32ab25eeb5Syz155240 # include <sys/uio.h>
33ab25eeb5Syz155240 # undef _KERNEL
34ab25eeb5Syz155240 #endif
35ab25eeb5Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
36ab25eeb5Syz155240 # include <sys/filio.h>
37ab25eeb5Syz155240 # include <sys/fcntl.h>
38ab25eeb5Syz155240 #else
39ab25eeb5Syz155240 # include <sys/ioctl.h>
40ab25eeb5Syz155240 #endif
41ab25eeb5Syz155240 #if !defined(linux)
42ab25eeb5Syz155240 # include <sys/protosw.h>
43ab25eeb5Syz155240 #endif
44ab25eeb5Syz155240 #include <sys/socket.h>
45ab25eeb5Syz155240 #if defined(_KERNEL)
46ab25eeb5Syz155240 # include <sys/systm.h>
47ab25eeb5Syz155240 # if !defined(__SVR4) && !defined(__svr4__)
48ab25eeb5Syz155240 #  include <sys/mbuf.h>
49ab25eeb5Syz155240 # endif
50ab25eeb5Syz155240 #endif
51ab25eeb5Syz155240 #if !defined(__SVR4) && !defined(__svr4__)
52ab25eeb5Syz155240 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
53ab25eeb5Syz155240 #  include <sys/kernel.h>
54ab25eeb5Syz155240 # endif
55ab25eeb5Syz155240 #else
56ab25eeb5Syz155240 # include <sys/byteorder.h>
57ab25eeb5Syz155240 # ifdef _KERNEL
58ab25eeb5Syz155240 #  include <sys/dditypes.h>
59ab25eeb5Syz155240 # endif
60ab25eeb5Syz155240 # include <sys/stream.h>
61ab25eeb5Syz155240 # include <sys/kmem.h>
62ab25eeb5Syz155240 #endif
63ab25eeb5Syz155240 #include <net/if.h>
64ab25eeb5Syz155240 #ifdef sun
65ab25eeb5Syz155240 # include <net/af.h>
66ab25eeb5Syz155240 #endif
67ab25eeb5Syz155240 #include <net/route.h>
68ab25eeb5Syz155240 #include <netinet/in.h>
69ab25eeb5Syz155240 #include <netinet/in_systm.h>
70ab25eeb5Syz155240 #include <netinet/ip.h>
71ab25eeb5Syz155240 #if !defined(linux)
72ab25eeb5Syz155240 # include <netinet/ip_var.h>
73ab25eeb5Syz155240 #endif
74ab25eeb5Syz155240 #include <netinet/tcp.h>
75ab25eeb5Syz155240 #include <netinet/udp.h>
76ab25eeb5Syz155240 #include <netinet/ip_icmp.h>
77ab25eeb5Syz155240 #include "netinet/ip_compat.h"
78ab25eeb5Syz155240 #include <netinet/tcpip.h>
79ab25eeb5Syz155240 #include "netinet/ip_fil.h"
80ab25eeb5Syz155240 #include "netinet/ip_nat.h"
81ab25eeb5Syz155240 #include "netinet/ip_frag.h"
82ab25eeb5Syz155240 #include "netinet/ip_state.h"
83ab25eeb5Syz155240 #include "netinet/ip_auth.h"
84f4b3ec61Sdh155122 #include "netinet/ipf_stack.h"
85ab25eeb5Syz155240 #if (__FreeBSD_version >= 300000)
86ab25eeb5Syz155240 # include <sys/malloc.h>
87ab25eeb5Syz155240 # if defined(_KERNEL)
88ab25eeb5Syz155240 #  ifndef IPFILTER_LKM
89ab25eeb5Syz155240 #   include <sys/libkern.h>
90ab25eeb5Syz155240 #   include <sys/systm.h>
91ab25eeb5Syz155240 #  endif
92ab25eeb5Syz155240 extern struct callout_handle fr_slowtimer_ch;
93ab25eeb5Syz155240 # endif
94ab25eeb5Syz155240 #endif
95ab25eeb5Syz155240 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
96ab25eeb5Syz155240 # include <sys/callout.h>
97ab25eeb5Syz155240 extern struct callout fr_slowtimer_ch;
98ab25eeb5Syz155240 #endif
99ab25eeb5Syz155240 #if defined(__OpenBSD__)
100ab25eeb5Syz155240 # include <sys/timeout.h>
101ab25eeb5Syz155240 extern struct timeout fr_slowtimer_ch;
102ab25eeb5Syz155240 #endif
103ab25eeb5Syz155240 /* END OF INCLUDES */
104ab25eeb5Syz155240 
105ab25eeb5Syz155240 #if !defined(lint)
106ab25eeb5Syz155240 static const char sccsid[] = "@(#)ip_frag.c	1.11 3/24/96 (C) 1993-2000 Darren Reed";
107ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $";
108ab25eeb5Syz155240 #endif
109ab25eeb5Syz155240 
11072680cf5SDarren Reed static INLINE int ipfr_index __P((fr_info_t *, ipfr_t *));
111ab25eeb5Syz155240 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
112ab25eeb5Syz155240 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
113f4b3ec61Sdh155122 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***, ipf_stack_t *));
114ab25eeb5Syz155240 
115ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
116ab25eeb5Syz155240 /* Function:    fr_fraginit                                                 */
117ab25eeb5Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
118ab25eeb5Syz155240 /* Parameters:  Nil                                                         */
119ab25eeb5Syz155240 /*                                                                          */
120ab25eeb5Syz155240 /* Initialise the hash tables for the fragment cache lookups.               */
121ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
122f4b3ec61Sdh155122 int fr_fraginit(ifs)
123f4b3ec61Sdh155122 ipf_stack_t *ifs;
124ab25eeb5Syz155240 {
125f4b3ec61Sdh155122 	ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list;
126f4b3ec61Sdh155122 	ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist;
127f4b3ec61Sdh155122 	ifs->ifs_ipfr_ipidtail = &ifs->ifs_ipfr_ipidlist;
1288128a42dSan207044 	/* the IP frag related variables are set in ipftuneable_setdefs() to
1298128a42dSan207044 	 * their default values
1308128a42dSan207044 	 */
131ab25eeb5Syz155240 
132f4b3ec61Sdh155122 	KMALLOCS(ifs->ifs_ipfr_heads, ipfr_t **,
133f4b3ec61Sdh155122 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
134f4b3ec61Sdh155122 	if (ifs->ifs_ipfr_heads == NULL)
135ab25eeb5Syz155240 		return -1;
136f4b3ec61Sdh155122 	bzero((char *)ifs->ifs_ipfr_heads,
137f4b3ec61Sdh155122 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
138ab25eeb5Syz155240 
139f4b3ec61Sdh155122 	KMALLOCS(ifs->ifs_ipfr_nattab, ipfr_t **,
140f4b3ec61Sdh155122 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
141f4b3ec61Sdh155122 	if (ifs->ifs_ipfr_nattab == NULL)
142ab25eeb5Syz155240 		return -1;
143f4b3ec61Sdh155122 	bzero((char *)ifs->ifs_ipfr_nattab,
144f4b3ec61Sdh155122 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
145ab25eeb5Syz155240 
146f4b3ec61Sdh155122 	KMALLOCS(ifs->ifs_ipfr_ipidtab, ipfr_t **,
147f4b3ec61Sdh155122 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
148f4b3ec61Sdh155122 	if (ifs->ifs_ipfr_ipidtab == NULL)
149f4b3ec61Sdh155122 		return -1;
150f4b3ec61Sdh155122 	bzero((char *)ifs->ifs_ipfr_ipidtab,
151f4b3ec61Sdh155122 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
152f4b3ec61Sdh155122 
153f4b3ec61Sdh155122 	RWLOCK_INIT(&ifs->ifs_ipf_frag, "ipf fragment rwlock");
154ab25eeb5Syz155240 
155ab25eeb5Syz155240 	/* Initialise frblock with "block in all" */
156f4b3ec61Sdh155122 	bzero((char *)&ifs->ifs_frblock, sizeof(ifs->ifs_frblock));
157f4b3ec61Sdh155122 	ifs->ifs_frblock.fr_flags = FR_BLOCK|FR_INQUE;	/* block in */
158f4b3ec61Sdh155122 	ifs->ifs_frblock.fr_ref = 1;
159ab25eeb5Syz155240 
160f4b3ec61Sdh155122 	ifs->ifs_fr_frag_init = 1;
161ab25eeb5Syz155240 
162ab25eeb5Syz155240 	return 0;
163ab25eeb5Syz155240 }
164ab25eeb5Syz155240 
165ab25eeb5Syz155240 
166ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
167ab25eeb5Syz155240 /* Function:    fr_fragunload                                               */
168ab25eeb5Syz155240 /* Returns:     Nil                                                         */
169ab25eeb5Syz155240 /* Parameters:  Nil                                                         */
170ab25eeb5Syz155240 /*                                                                          */
171ab25eeb5Syz155240 /* Free all memory allocated whilst running and from initialisation.        */
172ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
173f4b3ec61Sdh155122 void fr_fragunload(ifs)
174f4b3ec61Sdh155122 ipf_stack_t *ifs;
175ab25eeb5Syz155240 {
176f4b3ec61Sdh155122 	if (ifs->ifs_fr_frag_init == 1) {
177f4b3ec61Sdh155122 		fr_fragclear(ifs);
178ab25eeb5Syz155240 
179f4b3ec61Sdh155122 		RW_DESTROY(&ifs->ifs_ipf_frag);
180f4b3ec61Sdh155122 		ifs->ifs_fr_frag_init = 0;
181ab25eeb5Syz155240 	}
182ab25eeb5Syz155240 
183f4b3ec61Sdh155122 	if (ifs->ifs_ipfr_heads != NULL) {
184f4b3ec61Sdh155122 		KFREES(ifs->ifs_ipfr_heads,
185f4b3ec61Sdh155122 		    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
186f4b3ec61Sdh155122 	}
187f4b3ec61Sdh155122 	ifs->ifs_ipfr_heads = NULL;
188ab25eeb5Syz155240 
189f4b3ec61Sdh155122 	if (ifs->ifs_ipfr_nattab != NULL) {
190f4b3ec61Sdh155122 		KFREES(ifs->ifs_ipfr_nattab,
191f4b3ec61Sdh155122 		    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
192f4b3ec61Sdh155122 	}
193f4b3ec61Sdh155122 	ifs->ifs_ipfr_nattab = NULL;
194ab25eeb5Syz155240 
195f4b3ec61Sdh155122 	if (ifs->ifs_ipfr_ipidtab != NULL) {
196f4b3ec61Sdh155122 		KFREES(ifs->ifs_ipfr_ipidtab,
197f4b3ec61Sdh155122 		    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
198f4b3ec61Sdh155122 	}
199f4b3ec61Sdh155122 	ifs->ifs_ipfr_ipidtab = NULL;
200ab25eeb5Syz155240 }
201ab25eeb5Syz155240 
202ab25eeb5Syz155240 
203ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
204ab25eeb5Syz155240 /* Function:    fr_fragstats                                                */
205ab25eeb5Syz155240 /* Returns:     ipfrstat_t* - pointer to struct with current frag stats     */
206ab25eeb5Syz155240 /* Parameters:  Nil                                                         */
207ab25eeb5Syz155240 /*                                                                          */
208ab25eeb5Syz155240 /* Updates ipfr_stats with current information and returns a pointer to it  */
209ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
210f4b3ec61Sdh155122 ipfrstat_t *fr_fragstats(ifs)
211f4b3ec61Sdh155122 ipf_stack_t *ifs;
212ab25eeb5Syz155240 {
213f4b3ec61Sdh155122 	ifs->ifs_ipfr_stats.ifs_table = ifs->ifs_ipfr_heads;
214f4b3ec61Sdh155122 	ifs->ifs_ipfr_stats.ifs_nattab = ifs->ifs_ipfr_nattab;
215f4b3ec61Sdh155122 	ifs->ifs_ipfr_stats.ifs_inuse = ifs->ifs_ipfr_inuse;
216f4b3ec61Sdh155122 	return &ifs->ifs_ipfr_stats;
217ab25eeb5Syz155240 }
218ab25eeb5Syz155240 
219ab25eeb5Syz155240 
220ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
22172680cf5SDarren Reed /* Function:    ipfr_index                                                  */
22272680cf5SDarren Reed /* Returns:     int     - index in fragment table for given packet          */
22372680cf5SDarren Reed /* Parameters:  fin(I)  - pointer to packet information                     */
22472680cf5SDarren Reed /*              frag(O) - pointer to ipfr_t structure to fill               */
22572680cf5SDarren Reed /*                                                                          */
22672680cf5SDarren Reed /* Compute the index in the fragment table while filling the per packet     */
22772680cf5SDarren Reed /* part of the fragment state.                                              */
22872680cf5SDarren Reed /* ------------------------------------------------------------------------ */
22972680cf5SDarren Reed static INLINE int ipfr_index(fin, frag)
23072680cf5SDarren Reed fr_info_t *fin;
23172680cf5SDarren Reed ipfr_t *frag;
23272680cf5SDarren Reed {
23372680cf5SDarren Reed 	u_int idx;
23472680cf5SDarren Reed 
23572680cf5SDarren Reed 	/*
23672680cf5SDarren Reed 	 * For fragments, we record protocol, packet id, TOS and both IP#'s
23772680cf5SDarren Reed 	 * (these should all be the same for all fragments of a packet).
23872680cf5SDarren Reed 	 *
23972680cf5SDarren Reed 	 * build up a hash value to index the table with.
24072680cf5SDarren Reed 	 */
24172680cf5SDarren Reed 
24272680cf5SDarren Reed #ifdef	USE_INET6
24372680cf5SDarren Reed 	if (fin->fin_v == 6) {
24472680cf5SDarren Reed 		ip6_t *ip6 = (ip6_t *)fin->fin_ip;
24572680cf5SDarren Reed 
24672680cf5SDarren Reed 		frag->ipfr_p = fin->fin_fi.fi_p;
24772680cf5SDarren Reed 		frag->ipfr_id = fin->fin_id;
24872680cf5SDarren Reed 		frag->ipfr_tos = ip6->ip6_flow & IPV6_FLOWINFO_MASK;
24972680cf5SDarren Reed 		frag->ipfr_src.in6 = ip6->ip6_src;
25072680cf5SDarren Reed 		frag->ipfr_dst.in6 = ip6->ip6_dst;
25172680cf5SDarren Reed 	} else
25272680cf5SDarren Reed #endif
25372680cf5SDarren Reed 	{
25472680cf5SDarren Reed 		ip_t *ip = fin->fin_ip;
25572680cf5SDarren Reed 
25672680cf5SDarren Reed 		frag->ipfr_p = ip->ip_p;
25772680cf5SDarren Reed 		frag->ipfr_id = ip->ip_id;
25872680cf5SDarren Reed 		frag->ipfr_tos = ip->ip_tos;
25972680cf5SDarren Reed 		frag->ipfr_src.in4.s_addr = ip->ip_src.s_addr;
26072680cf5SDarren Reed 		frag->ipfr_src.i6[1] = 0;
26172680cf5SDarren Reed 		frag->ipfr_src.i6[2] = 0;
26272680cf5SDarren Reed 		frag->ipfr_src.i6[3] = 0;
26372680cf5SDarren Reed 		frag->ipfr_dst.in4.s_addr = ip->ip_dst.s_addr;
26472680cf5SDarren Reed 		frag->ipfr_dst.i6[1] = 0;
26572680cf5SDarren Reed 		frag->ipfr_dst.i6[2] = 0;
26672680cf5SDarren Reed 		frag->ipfr_dst.i6[3] = 0;
26772680cf5SDarren Reed 	}
26872680cf5SDarren Reed 	frag->ipfr_ifp = fin->fin_ifp;
26972680cf5SDarren Reed 	frag->ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
27072680cf5SDarren Reed 	frag->ipfr_secmsk = fin->fin_fi.fi_secmsk;
27172680cf5SDarren Reed 	frag->ipfr_auth = fin->fin_fi.fi_auth;
27272680cf5SDarren Reed 
27372680cf5SDarren Reed 	idx = frag->ipfr_p;
27472680cf5SDarren Reed 	idx += frag->ipfr_id;
27572680cf5SDarren Reed 	idx += frag->ipfr_src.i6[0];
27672680cf5SDarren Reed 	idx += frag->ipfr_src.i6[1];
27772680cf5SDarren Reed 	idx += frag->ipfr_src.i6[2];
27872680cf5SDarren Reed 	idx += frag->ipfr_src.i6[3];
27972680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[0];
28072680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[1];
28172680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[2];
28272680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[3];
28372680cf5SDarren Reed 	idx *= 127;
28472680cf5SDarren Reed 	idx %= IPFT_SIZE;
28572680cf5SDarren Reed 
28672680cf5SDarren Reed 	return idx;
28772680cf5SDarren Reed }
28872680cf5SDarren Reed 
28972680cf5SDarren Reed 
29072680cf5SDarren Reed /* ------------------------------------------------------------------------ */
291ab25eeb5Syz155240 /* Function:    ipfr_newfrag                                                */
292ab25eeb5Syz155240 /* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
293ab25eeb5Syz155240 /* Parameters:  fin(I)   - pointer to packet information                    */
294ab25eeb5Syz155240 /*              table(I) - pointer to frag table to add to                  */
295ab25eeb5Syz155240 /*                                                                          */
296ab25eeb5Syz155240 /* Add a new entry to the fragment cache, registering it as having come     */
297ab25eeb5Syz155240 /* through this box, with the result of the filter operation.               */
298ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
299ab25eeb5Syz155240 static ipfr_t *ipfr_newfrag(fin, pass, table)
300ab25eeb5Syz155240 fr_info_t *fin;
301ab25eeb5Syz155240 u_32_t pass;
302ab25eeb5Syz155240 ipfr_t *table[];
303ab25eeb5Syz155240 {
304ab25eeb5Syz155240 	ipfr_t *fra, frag;
305ab25eeb5Syz155240 	u_int idx, off;
306f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
307ab25eeb5Syz155240 
308bd5ba10fSan207044 	if (ifs->ifs_ipfr_inuse >= ifs->ifs_ipfr_size)
309ab25eeb5Syz155240 		return NULL;
310ab25eeb5Syz155240 
311ab25eeb5Syz155240 	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
312ab25eeb5Syz155240 		return NULL;
313ab25eeb5Syz155240 
314ab25eeb5Syz155240 	if (pass & FR_FRSTRICT)
315ab25eeb5Syz155240 		if (fin->fin_off != 0)
316ab25eeb5Syz155240 			return NULL;
317ab25eeb5Syz155240 
31872680cf5SDarren Reed 	idx = ipfr_index(fin, &frag);
319ab25eeb5Syz155240 
320ab25eeb5Syz155240 	/*
321ab25eeb5Syz155240 	 * first, make sure it isn't already there...
322ab25eeb5Syz155240 	 */
323ab25eeb5Syz155240 	for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
324ab25eeb5Syz155240 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
325ab25eeb5Syz155240 			  IPFR_CMPSZ)) {
326f4b3ec61Sdh155122 			ifs->ifs_ipfr_stats.ifs_exists++;
327ab25eeb5Syz155240 			return NULL;
328ab25eeb5Syz155240 		}
329ab25eeb5Syz155240 
330ab25eeb5Syz155240 	/*
331ab25eeb5Syz155240 	 * allocate some memory, if possible, if not, just record that we
332ab25eeb5Syz155240 	 * failed to do so.
333ab25eeb5Syz155240 	 */
334ab25eeb5Syz155240 	KMALLOC(fra, ipfr_t *);
335ab25eeb5Syz155240 	if (fra == NULL) {
336f4b3ec61Sdh155122 		ifs->ifs_ipfr_stats.ifs_nomem++;
337ab25eeb5Syz155240 		return NULL;
338ab25eeb5Syz155240 	}
339ab25eeb5Syz155240 
340ab25eeb5Syz155240 	fra->ipfr_rule = fin->fin_fr;
341ab25eeb5Syz155240 	if (fra->ipfr_rule != NULL) {
342ab25eeb5Syz155240 
343ab25eeb5Syz155240 		frentry_t *fr;
344ab25eeb5Syz155240 
345ab25eeb5Syz155240 		fr = fin->fin_fr;
346ab25eeb5Syz155240 		MUTEX_ENTER(&fr->fr_lock);
347ab25eeb5Syz155240 		fr->fr_ref++;
348ab25eeb5Syz155240 		MUTEX_EXIT(&fr->fr_lock);
349ab25eeb5Syz155240 	}
350ab25eeb5Syz155240 
351ab25eeb5Syz155240 	/*
352ab25eeb5Syz155240 	 * Insert the fragment into the fragment table, copy the struct used
353ab25eeb5Syz155240 	 * in the search using bcopy rather than reassign each field.
354ab25eeb5Syz155240 	 * Set the ttl to the default.
355ab25eeb5Syz155240 	 */
356ab25eeb5Syz155240 	if ((fra->ipfr_hnext = table[idx]) != NULL)
357ab25eeb5Syz155240 		table[idx]->ipfr_hprev = &fra->ipfr_hnext;
358ab25eeb5Syz155240 	fra->ipfr_hprev = table + idx;
359ab25eeb5Syz155240 	fra->ipfr_data = NULL;
360ab25eeb5Syz155240 	table[idx] = fra;
361ab25eeb5Syz155240 	bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
362f4b3ec61Sdh155122 	fra->ipfr_ttl = ifs->ifs_fr_ticks + ifs->ifs_fr_ipfrttl;
363ab25eeb5Syz155240 
364ab25eeb5Syz155240 	/*
365ab25eeb5Syz155240 	 * Compute the offset of the expected start of the next packet.
366ab25eeb5Syz155240 	 */
36772680cf5SDarren Reed 	off = fin->fin_off >> 3;
368ab25eeb5Syz155240 	if (off == 0) {
369ab25eeb5Syz155240 		fra->ipfr_seen0 = 1;
370ab25eeb5Syz155240 	} else {
371ab25eeb5Syz155240 		fra->ipfr_seen0 = 0;
372ab25eeb5Syz155240 	}
373ab25eeb5Syz155240 	fra->ipfr_off = off + fin->fin_dlen;
374ab25eeb5Syz155240 	fra->ipfr_pass = pass;
375f4b3ec61Sdh155122 	fra->ipfr_ref = 1;
376f4b3ec61Sdh155122 	ifs->ifs_ipfr_stats.ifs_new++;
377f4b3ec61Sdh155122 	ifs->ifs_ipfr_inuse++;
378ab25eeb5Syz155240 	return fra;
379ab25eeb5Syz155240 }
380ab25eeb5Syz155240 
381ab25eeb5Syz155240 
382ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
383ab25eeb5Syz155240 /* Function:    fr_newfrag                                                  */
384ab25eeb5Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
385ab25eeb5Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
386ab25eeb5Syz155240 /*                                                                          */
387ab25eeb5Syz155240 /* Add a new entry to the fragment cache table based on the current packet  */
388ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
389ab25eeb5Syz155240 int fr_newfrag(fin, pass)
390ab25eeb5Syz155240 u_32_t pass;
391ab25eeb5Syz155240 fr_info_t *fin;
392ab25eeb5Syz155240 {
393ab25eeb5Syz155240 	ipfr_t	*fra;
394f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
395ab25eeb5Syz155240 
396f4b3ec61Sdh155122 	if (ifs->ifs_fr_frag_lock != 0)
397ab25eeb5Syz155240 		return -1;
398ab25eeb5Syz155240 
399f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_frag);
400f4b3ec61Sdh155122 	fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_heads);
401ab25eeb5Syz155240 	if (fra != NULL) {
402f4b3ec61Sdh155122 		*ifs->ifs_ipfr_tail = fra;
403f4b3ec61Sdh155122 		fra->ipfr_prev = ifs->ifs_ipfr_tail;
404f4b3ec61Sdh155122 		ifs->ifs_ipfr_tail = &fra->ipfr_next;
405f4b3ec61Sdh155122 		if (ifs->ifs_ipfr_list == NULL)
406f4b3ec61Sdh155122 			ifs->ifs_ipfr_list = fra;
407ab25eeb5Syz155240 		fra->ipfr_next = NULL;
408ab25eeb5Syz155240 	}
409f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
410ab25eeb5Syz155240 	return fra ? 0 : -1;
411ab25eeb5Syz155240 }
412ab25eeb5Syz155240 
413ab25eeb5Syz155240 
414ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
415ab25eeb5Syz155240 /* Function:    fr_nat_newfrag                                              */
416ab25eeb5Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
417ab25eeb5Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
418ab25eeb5Syz155240 /*              nat(I)  - pointer to NAT structure                          */
419ab25eeb5Syz155240 /*                                                                          */
420ab25eeb5Syz155240 /* Create a new NAT fragment cache entry based on the current packet and    */
421ab25eeb5Syz155240 /* the NAT structure for this "session".                                    */
422ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
423ab25eeb5Syz155240 int fr_nat_newfrag(fin, pass, nat)
424ab25eeb5Syz155240 fr_info_t *fin;
425ab25eeb5Syz155240 u_32_t pass;
426ab25eeb5Syz155240 nat_t *nat;
427ab25eeb5Syz155240 {
428ab25eeb5Syz155240 	ipfr_t	*fra;
429f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
430ab25eeb5Syz155240 
43172680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock != 0)
432ab25eeb5Syz155240 		return 0;
433ab25eeb5Syz155240 
434f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
435f4b3ec61Sdh155122 	fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_nattab);
436ab25eeb5Syz155240 	if (fra != NULL) {
437ab25eeb5Syz155240 		fra->ipfr_data = nat;
438ab25eeb5Syz155240 		nat->nat_data = fra;
439f4b3ec61Sdh155122 		*ifs->ifs_ipfr_nattail = fra;
440f4b3ec61Sdh155122 		fra->ipfr_prev = ifs->ifs_ipfr_nattail;
441f4b3ec61Sdh155122 		ifs->ifs_ipfr_nattail = &fra->ipfr_next;
442ab25eeb5Syz155240 		fra->ipfr_next = NULL;
443ab25eeb5Syz155240 	}
444f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
445ab25eeb5Syz155240 	return fra ? 0 : -1;
446ab25eeb5Syz155240 }
447ab25eeb5Syz155240 
448ab25eeb5Syz155240 
449ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
450ab25eeb5Syz155240 /* Function:    fr_ipid_newfrag                                             */
451ab25eeb5Syz155240 /* Returns:     int - 0 == success, -1 == error                             */
452ab25eeb5Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
453ab25eeb5Syz155240 /*              ipid(I) - new IP ID for this fragmented packet              */
454ab25eeb5Syz155240 /*                                                                          */
455ab25eeb5Syz155240 /* Create a new fragment cache entry for this packet and store, as a data   */
456ab25eeb5Syz155240 /* pointer, the new IP ID value.                                            */
457ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
458ab25eeb5Syz155240 int fr_ipid_newfrag(fin, ipid)
459ab25eeb5Syz155240 fr_info_t *fin;
460ab25eeb5Syz155240 u_32_t ipid;
461ab25eeb5Syz155240 {
462ab25eeb5Syz155240 	ipfr_t	*fra;
463f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
464ab25eeb5Syz155240 
465f4b3ec61Sdh155122 	if (ifs->ifs_fr_frag_lock)
466ab25eeb5Syz155240 		return 0;
467ab25eeb5Syz155240 
468f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_ipidfrag);
469f4b3ec61Sdh155122 	fra = ipfr_newfrag(fin, 0, ifs->ifs_ipfr_ipidtab);
470ab25eeb5Syz155240 	if (fra != NULL) {
471ab25eeb5Syz155240 		fra->ipfr_data = (void *)(uintptr_t)ipid;
472f4b3ec61Sdh155122 		*ifs->ifs_ipfr_ipidtail = fra;
473f4b3ec61Sdh155122 		fra->ipfr_prev = ifs->ifs_ipfr_ipidtail;
474f4b3ec61Sdh155122 		ifs->ifs_ipfr_ipidtail = &fra->ipfr_next;
475ab25eeb5Syz155240 		fra->ipfr_next = NULL;
476ab25eeb5Syz155240 	}
477f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
478ab25eeb5Syz155240 	return fra ? 0 : -1;
479ab25eeb5Syz155240 }
480ab25eeb5Syz155240 
481ab25eeb5Syz155240 
482ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
483ab25eeb5Syz155240 /* Function:    fr_fraglookup                                               */
484ab25eeb5Syz155240 /* Returns:     ipfr_t * - pointer to ipfr_t structure if there's a         */
485ab25eeb5Syz155240 /*                         matching entry in the frag table, else NULL      */
486ab25eeb5Syz155240 /* Parameters:  fin(I)   - pointer to packet information                    */
487ab25eeb5Syz155240 /*              table(I) - pointer to fragment cache table to search        */
488ab25eeb5Syz155240 /*                                                                          */
489ab25eeb5Syz155240 /* Check the fragment cache to see if there is already a record of this     */
490ab25eeb5Syz155240 /* packet with its filter result known.                                     */
491ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
492ab25eeb5Syz155240 static ipfr_t *fr_fraglookup(fin, table)
493ab25eeb5Syz155240 fr_info_t *fin;
494ab25eeb5Syz155240 ipfr_t *table[];
495ab25eeb5Syz155240 {
496ab25eeb5Syz155240 	ipfr_t *f, frag;
497ab25eeb5Syz155240 	u_int idx;
498f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
499ab25eeb5Syz155240 
500ab25eeb5Syz155240 	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
501ab25eeb5Syz155240 		return NULL;
502ab25eeb5Syz155240 
503ab25eeb5Syz155240 	/*
504ab25eeb5Syz155240 	 * For fragments, we record protocol, packet id, TOS and both IP#'s
505ab25eeb5Syz155240 	 * (these should all be the same for all fragments of a packet).
506ab25eeb5Syz155240 	 *
507ab25eeb5Syz155240 	 * build up a hash value to index the table with.
508ab25eeb5Syz155240 	 */
50972680cf5SDarren Reed 	idx = ipfr_index(fin, &frag);
510ab25eeb5Syz155240 
511ab25eeb5Syz155240 	/*
512ab25eeb5Syz155240 	 * check the table, careful to only compare the right amount of data
513ab25eeb5Syz155240 	 */
514ab25eeb5Syz155240 	for (f = table[idx]; f; f = f->ipfr_hnext)
515ab25eeb5Syz155240 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
516ab25eeb5Syz155240 			  IPFR_CMPSZ)) {
517ab25eeb5Syz155240 			u_short	off;
518ab25eeb5Syz155240 
519ab25eeb5Syz155240 			/*
520ab25eeb5Syz155240 			 * We don't want to let short packets match because
521ab25eeb5Syz155240 			 * they could be compromising the security of other
522ab25eeb5Syz155240 			 * rules that want to match on layer 4 fields (and
523ab25eeb5Syz155240 			 * can't because they have been fragmented off.)
524ab25eeb5Syz155240 			 * Why do this check here?  The counter acts as an
525ab25eeb5Syz155240 			 * indicator of this kind of attack, whereas if it was
526ab25eeb5Syz155240 			 * elsewhere, it wouldn't know if other matching
527ab25eeb5Syz155240 			 * packets had been seen.
528ab25eeb5Syz155240 			 */
529ab25eeb5Syz155240 			if (fin->fin_flx & FI_SHORT) {
530f4b3ec61Sdh155122 				ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_short);
531ab25eeb5Syz155240 				continue;
532ab25eeb5Syz155240 			}
533ab25eeb5Syz155240 
534ab25eeb5Syz155240 			/*
535ab25eeb5Syz155240 			 * XXX - We really need to be guarding against the
536ab25eeb5Syz155240 			 * retransmission of (src,dst,id,offset-range) here
537ab25eeb5Syz155240 			 * because a fragmented packet is never resent with
538ab25eeb5Syz155240 			 * the same IP ID# (or shouldn't).
539ab25eeb5Syz155240 			 */
54072680cf5SDarren Reed 			off = fin->fin_off >> 3;
541ab25eeb5Syz155240 			if (f->ipfr_seen0) {
542ab25eeb5Syz155240 				if (off == 0) {
543f4b3ec61Sdh155122 					ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_retrans0);
544ab25eeb5Syz155240 					continue;
545ab25eeb5Syz155240 				}
546ab25eeb5Syz155240 			} else if (off == 0) {
547ab25eeb5Syz155240 				f->ipfr_seen0 = 1;
548ab25eeb5Syz155240 			}
549ab25eeb5Syz155240 
550ab25eeb5Syz155240 			if (f != table[idx]) {
551ab25eeb5Syz155240 				ipfr_t **fp;
552ab25eeb5Syz155240 
553ab25eeb5Syz155240 				/*
554ab25eeb5Syz155240 				 * Move fragment info. to the top of the list
555ab25eeb5Syz155240 				 * to speed up searches.  First, delink...
556ab25eeb5Syz155240 				 */
557ab25eeb5Syz155240 				fp = f->ipfr_hprev;
558ab25eeb5Syz155240 				(*fp) = f->ipfr_hnext;
559ab25eeb5Syz155240 				if (f->ipfr_hnext != NULL)
560ab25eeb5Syz155240 					f->ipfr_hnext->ipfr_hprev = fp;
561ab25eeb5Syz155240 				/*
562ab25eeb5Syz155240 				 * Then put back at the top of the chain.
563ab25eeb5Syz155240 				 */
564ab25eeb5Syz155240 				f->ipfr_hnext = table[idx];
565ab25eeb5Syz155240 				table[idx]->ipfr_hprev = &f->ipfr_hnext;
566ab25eeb5Syz155240 				f->ipfr_hprev = table + idx;
567ab25eeb5Syz155240 				table[idx] = f;
568ab25eeb5Syz155240 			}
569ab25eeb5Syz155240 
570ab25eeb5Syz155240 			/*
571ab25eeb5Syz155240 			 * If we've follwed the fragments, and this is the
572ab25eeb5Syz155240 			 * last (in order), shrink expiration time.
573ab25eeb5Syz155240 			 */
574ab25eeb5Syz155240 			if (off == f->ipfr_off) {
57572680cf5SDarren Reed 				if (!(fin->fin_flx & FI_MOREFRAG))
576f4b3ec61Sdh155122 					f->ipfr_ttl = ifs->ifs_fr_ticks + 1;
577ab25eeb5Syz155240 				f->ipfr_off = fin->fin_dlen + off;
578ab25eeb5Syz155240 			} else if (f->ipfr_pass & FR_FRSTRICT)
579ab25eeb5Syz155240 				continue;
580f4b3ec61Sdh155122 			ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_hits);
581ab25eeb5Syz155240 			return f;
582ab25eeb5Syz155240 		}
583ab25eeb5Syz155240 	return NULL;
584ab25eeb5Syz155240 }
585ab25eeb5Syz155240 
586ab25eeb5Syz155240 
587ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
588ab25eeb5Syz155240 /* Function:    fr_nat_knownfrag                                            */
589ab25eeb5Syz155240 /* Returns:     nat_t* - pointer to 'parent' NAT structure if frag table    */
590ab25eeb5Syz155240 /*                       match found, else NULL                             */
591ab25eeb5Syz155240 /* Parameters:  fin(I)  - pointer to packet information                     */
592ab25eeb5Syz155240 /*                                                                          */
593ab25eeb5Syz155240 /* Functional interface for NAT lookups of the NAT fragment cache           */
594ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
595ab25eeb5Syz155240 nat_t *fr_nat_knownfrag(fin)
596ab25eeb5Syz155240 fr_info_t *fin;
597ab25eeb5Syz155240 {
598ab25eeb5Syz155240 	nat_t	*nat;
599ab25eeb5Syz155240 	ipfr_t	*ipf;
600f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
601ab25eeb5Syz155240 
60272680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_natlist)
603ab25eeb5Syz155240 		return NULL;
604f4b3ec61Sdh155122 	READ_ENTER(&ifs->ifs_ipf_natfrag);
605f4b3ec61Sdh155122 	ipf = fr_fraglookup(fin, ifs->ifs_ipfr_nattab);
606ab25eeb5Syz155240 	if (ipf != NULL) {
607ab25eeb5Syz155240 		nat = ipf->ipfr_data;
608ab25eeb5Syz155240 		/*
609ab25eeb5Syz155240 		 * This is the last fragment for this packet.
610ab25eeb5Syz155240 		 */
611f4b3ec61Sdh155122 		if ((ipf->ipfr_ttl == ifs->ifs_fr_ticks + 1) && (nat != NULL)) {
612ab25eeb5Syz155240 			nat->nat_data = NULL;
613ab25eeb5Syz155240 			ipf->ipfr_data = NULL;
614ab25eeb5Syz155240 		}
615ab25eeb5Syz155240 	} else
616ab25eeb5Syz155240 		nat = NULL;
617f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
618ab25eeb5Syz155240 	return nat;
619ab25eeb5Syz155240 }
620ab25eeb5Syz155240 
621ab25eeb5Syz155240 
622ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
623ab25eeb5Syz155240 /* Function:    fr_ipid_knownfrag                                           */
624ab25eeb5Syz155240 /* Returns:     u_32_t - IPv4 ID for this packet if match found, else       */
625ab25eeb5Syz155240 /*                       return 0xfffffff to indicate no match.             */
626ab25eeb5Syz155240 /* Parameters:  fin(I) - pointer to packet information                      */
627ab25eeb5Syz155240 /*                                                                          */
628ab25eeb5Syz155240 /* Functional interface for IP ID lookups of the IP ID fragment cache       */
629ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
630ab25eeb5Syz155240 u_32_t fr_ipid_knownfrag(fin)
631ab25eeb5Syz155240 fr_info_t *fin;
632ab25eeb5Syz155240 {
633ab25eeb5Syz155240 	ipfr_t	*ipf;
634ab25eeb5Syz155240 	u_32_t	id;
635f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
636ab25eeb5Syz155240 
63772680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_ipidlist)
638ab25eeb5Syz155240 		return 0xffffffff;
639ab25eeb5Syz155240 
640f4b3ec61Sdh155122 	READ_ENTER(&ifs->ifs_ipf_ipidfrag);
641f4b3ec61Sdh155122 	ipf = fr_fraglookup(fin, ifs->ifs_ipfr_ipidtab);
642ab25eeb5Syz155240 	if (ipf != NULL)
643ab25eeb5Syz155240 		id = (u_32_t)(uintptr_t)ipf->ipfr_data;
644ab25eeb5Syz155240 	else
645ab25eeb5Syz155240 		id = 0xffffffff;
646f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
647ab25eeb5Syz155240 	return id;
648ab25eeb5Syz155240 }
649ab25eeb5Syz155240 
650ab25eeb5Syz155240 
651ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
652ab25eeb5Syz155240 /* Function:    fr_knownfrag                                                */
653ab25eeb5Syz155240 /* Returns:     frentry_t* - pointer to filter rule if a match is found in  */
654ab25eeb5Syz155240 /*                           the frag cache table, else NULL.               */
655ab25eeb5Syz155240 /* Parameters:  fin(I)   - pointer to packet information                    */
656ab25eeb5Syz155240 /*              passp(O) - pointer to where to store rule flags resturned   */
657ab25eeb5Syz155240 /*                                                                          */
658ab25eeb5Syz155240 /* Functional interface for normal lookups of the fragment cache.  If a     */
659ab25eeb5Syz155240 /* match is found, return the rule pointer and flags from the rule, except  */
660ab25eeb5Syz155240 /* that if FR_LOGFIRST is set, reset FR_LOG.                                */
661ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
662ab25eeb5Syz155240 frentry_t *fr_knownfrag(fin, passp)
663ab25eeb5Syz155240 fr_info_t *fin;
664ab25eeb5Syz155240 u_32_t *passp;
665ab25eeb5Syz155240 {
666ab25eeb5Syz155240 	frentry_t *fr = NULL;
667ab25eeb5Syz155240 	ipfr_t	*fra;
668ab25eeb5Syz155240 	u_32_t pass, oflx;
669f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
670ab25eeb5Syz155240 
67172680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock || (ifs->ifs_ipfr_list == NULL))
672ab25eeb5Syz155240 		return NULL;
673ab25eeb5Syz155240 
674f4b3ec61Sdh155122 	READ_ENTER(&ifs->ifs_ipf_frag);
675ab25eeb5Syz155240 	oflx = fin->fin_flx;
676f4b3ec61Sdh155122 	fra = fr_fraglookup(fin, ifs->ifs_ipfr_heads);
677ab25eeb5Syz155240 	if (fra != NULL) {
678ab25eeb5Syz155240 		fr = fra->ipfr_rule;
679ab25eeb5Syz155240 		fin->fin_fr = fr;
680ab25eeb5Syz155240 		if (fr != NULL) {
681ab25eeb5Syz155240 			pass = fr->fr_flags;
682ab25eeb5Syz155240 			if ((pass & FR_LOGFIRST) != 0)
683ab25eeb5Syz155240 				pass &= ~(FR_LOGFIRST|FR_LOG);
684ab25eeb5Syz155240 			*passp = pass;
685ab25eeb5Syz155240 		}
686ab25eeb5Syz155240 	}
687ab25eeb5Syz155240 	if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) {
688ab25eeb5Syz155240 		*passp &= ~FR_CMDMASK;
689ab25eeb5Syz155240 		*passp |= FR_BLOCK;
690f4b3ec61Sdh155122 		fr = &ifs->ifs_frblock;
691ab25eeb5Syz155240 	}
692f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
693ab25eeb5Syz155240 	return fr;
694ab25eeb5Syz155240 }
695ab25eeb5Syz155240 
696ab25eeb5Syz155240 
697ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
698ab25eeb5Syz155240 /* Function:    fr_forget                                                   */
699ab25eeb5Syz155240 /* Returns:     Nil                                                         */
700ab25eeb5Syz155240 /* Parameters:  ptr(I) - pointer to data structure                          */
701ab25eeb5Syz155240 /*                                                                          */
702ab25eeb5Syz155240 /* Search through all of the fragment cache entries and wherever a pointer  */
703ab25eeb5Syz155240 /* is found to match ptr, reset it to NULL.                                 */
704ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
705f4b3ec61Sdh155122 void fr_forget(ptr, ifs)
706ab25eeb5Syz155240 void *ptr;
707f4b3ec61Sdh155122 ipf_stack_t *ifs;
708ab25eeb5Syz155240 {
709ab25eeb5Syz155240 	ipfr_t	*fr;
710ab25eeb5Syz155240 
711f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_frag);
712f4b3ec61Sdh155122 	for (fr = ifs->ifs_ipfr_list; fr; fr = fr->ipfr_next)
713ab25eeb5Syz155240 		if (fr->ipfr_data == ptr)
714ab25eeb5Syz155240 			fr->ipfr_data = NULL;
715f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
716ab25eeb5Syz155240 }
717ab25eeb5Syz155240 
718ab25eeb5Syz155240 
719ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
720ab25eeb5Syz155240 /* Function:    fr_forgetnat                                                */
721ab25eeb5Syz155240 /* Returns:     Nil                                                         */
722ab25eeb5Syz155240 /* Parameters:  ptr(I) - pointer to data structure                          */
723ab25eeb5Syz155240 /*                                                                          */
724ab25eeb5Syz155240 /* Search through all of the fragment cache entries for NAT and wherever a  */
725ab25eeb5Syz155240 /* pointer  is found to match ptr, reset it to NULL.                        */
726ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
727f4b3ec61Sdh155122 void fr_forgetnat(ptr, ifs)
728ab25eeb5Syz155240 void *ptr;
729f4b3ec61Sdh155122 ipf_stack_t *ifs;
730ab25eeb5Syz155240 {
731ab25eeb5Syz155240 	ipfr_t	*fr;
732ab25eeb5Syz155240 
733f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
734f4b3ec61Sdh155122 	for (fr = ifs->ifs_ipfr_natlist; fr; fr = fr->ipfr_next)
735ab25eeb5Syz155240 		if (fr->ipfr_data == ptr)
736ab25eeb5Syz155240 			fr->ipfr_data = NULL;
737f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
738ab25eeb5Syz155240 }
739ab25eeb5Syz155240 
740ab25eeb5Syz155240 
741ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
742ab25eeb5Syz155240 /* Function:    fr_fragdelete                                               */
743ab25eeb5Syz155240 /* Returns:     Nil                                                         */
744ab25eeb5Syz155240 /* Parameters:  fra(I)   - pointer to fragment structure to delete          */
745ab25eeb5Syz155240 /*              tail(IO) - pointer to the pointer to the tail of the frag   */
746ab25eeb5Syz155240 /*                         list                                             */
747ab25eeb5Syz155240 /*                                                                          */
748ab25eeb5Syz155240 /* Remove a fragment cache table entry from the table & list.  Also free    */
749ab25eeb5Syz155240 /* the filter rule it is associated with it if it is no longer used as a    */
750ab25eeb5Syz155240 /* result of decreasing the reference count.                                */
751ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
752f4b3ec61Sdh155122 static void fr_fragdelete(fra, tail, ifs)
753ab25eeb5Syz155240 ipfr_t *fra, ***tail;
754f4b3ec61Sdh155122 ipf_stack_t *ifs;
755ab25eeb5Syz155240 {
756ab25eeb5Syz155240 	frentry_t *fr;
757ab25eeb5Syz155240 
758ab25eeb5Syz155240 	fr = fra->ipfr_rule;
759ab25eeb5Syz155240 	if (fr != NULL)
760f4b3ec61Sdh155122 	    (void)fr_derefrule(&fr, ifs);
761ab25eeb5Syz155240 
762ab25eeb5Syz155240 	if (fra->ipfr_next)
763ab25eeb5Syz155240 		fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
764ab25eeb5Syz155240 	*fra->ipfr_prev = fra->ipfr_next;
765ab25eeb5Syz155240 	if (*tail == &fra->ipfr_next)
766ab25eeb5Syz155240 		*tail = fra->ipfr_prev;
767ab25eeb5Syz155240 
768ab25eeb5Syz155240 	if (fra->ipfr_hnext)
769ab25eeb5Syz155240 		fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
770ab25eeb5Syz155240 	*fra->ipfr_hprev = fra->ipfr_hnext;
771f4b3ec61Sdh155122 
772f4b3ec61Sdh155122 	if (fra->ipfr_ref <= 0)
773ab25eeb5Syz155240 		KFREE(fra);
774ab25eeb5Syz155240 }
775ab25eeb5Syz155240 
776ab25eeb5Syz155240 
777ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
778ab25eeb5Syz155240 /* Function:    fr_fragclear                                                */
779ab25eeb5Syz155240 /* Returns:     Nil                                                         */
780ab25eeb5Syz155240 /* Parameters:  Nil                                                         */
781ab25eeb5Syz155240 /*                                                                          */
782ab25eeb5Syz155240 /* Free memory in use by fragment state information kept.  Do the normal    */
783ab25eeb5Syz155240 /* fragment state stuff first and then the NAT-fragment table.              */
784ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
785f4b3ec61Sdh155122 void fr_fragclear(ifs)
786f4b3ec61Sdh155122 ipf_stack_t *ifs;
787ab25eeb5Syz155240 {
788ab25eeb5Syz155240 	ipfr_t	*fra;
789ab25eeb5Syz155240 	nat_t	*nat;
790ab25eeb5Syz155240 
791f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_frag);
792f4b3ec61Sdh155122 	while ((fra = ifs->ifs_ipfr_list) != NULL) {
793f4b3ec61Sdh155122 		fra->ipfr_ref--;
794f4b3ec61Sdh155122 		fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs);
795f4b3ec61Sdh155122 	}
796f4b3ec61Sdh155122 	ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list;
797f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
798ab25eeb5Syz155240 
799f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_nat);
800f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
801f4b3ec61Sdh155122 	while ((fra = ifs->ifs_ipfr_natlist) != NULL) {
802ab25eeb5Syz155240 		nat = fra->ipfr_data;
803ab25eeb5Syz155240 		if (nat != NULL) {
804ab25eeb5Syz155240 			if (nat->nat_data == fra)
805ab25eeb5Syz155240 				nat->nat_data = NULL;
806ab25eeb5Syz155240 		}
807f4b3ec61Sdh155122 		fra->ipfr_ref--;
808f4b3ec61Sdh155122 		fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs);
809ab25eeb5Syz155240 	}
810f4b3ec61Sdh155122 	ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist;
811f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
812f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
813ab25eeb5Syz155240 }
814ab25eeb5Syz155240 
815ab25eeb5Syz155240 
816ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
817ab25eeb5Syz155240 /* Function:    fr_fragexpire                                               */
818ab25eeb5Syz155240 /* Returns:     Nil                                                         */
819ab25eeb5Syz155240 /* Parameters:  Nil                                                         */
820ab25eeb5Syz155240 /*                                                                          */
821ab25eeb5Syz155240 /* Expire entries in the fragment cache table that have been there too long */
822ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
823f4b3ec61Sdh155122 void fr_fragexpire(ifs)
824f4b3ec61Sdh155122 ipf_stack_t *ifs;
825ab25eeb5Syz155240 {
826ab25eeb5Syz155240 	ipfr_t	**fp, *fra;
827ab25eeb5Syz155240 	nat_t	*nat;
828ab25eeb5Syz155240 	SPL_INT(s);
829ab25eeb5Syz155240 
830f4b3ec61Sdh155122 	if (ifs->ifs_fr_frag_lock)
831ab25eeb5Syz155240 		return;
832ab25eeb5Syz155240 
833ab25eeb5Syz155240 	SPL_NET(s);
834f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_frag);
835ab25eeb5Syz155240 	/*
836ab25eeb5Syz155240 	 * Go through the entire table, looking for entries to expire,
837f4b3ec61Sdh155122 	 * which is indicated by the ttl being less than or equal to
838f4b3ec61Sdh155122 	 * ifs_fr_ticks.
839ab25eeb5Syz155240 	 */
840f4b3ec61Sdh155122 	for (fp = &ifs->ifs_ipfr_list; ((fra = *fp) != NULL); ) {
841f4b3ec61Sdh155122 		if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
842ab25eeb5Syz155240 			break;
843f4b3ec61Sdh155122 		fra->ipfr_ref--;
844f4b3ec61Sdh155122 		fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs);
845f4b3ec61Sdh155122 		ifs->ifs_ipfr_stats.ifs_expire++;
846f4b3ec61Sdh155122 		ifs->ifs_ipfr_inuse--;
847ab25eeb5Syz155240 	}
848f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
849ab25eeb5Syz155240 
850f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_ipidfrag);
851f4b3ec61Sdh155122 	for (fp = &ifs->ifs_ipfr_ipidlist; ((fra = *fp) != NULL); ) {
852f4b3ec61Sdh155122 		if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
853ab25eeb5Syz155240 			break;
854f4b3ec61Sdh155122 		fra->ipfr_ref--;
855f4b3ec61Sdh155122 		fr_fragdelete(fra, &ifs->ifs_ipfr_ipidtail, ifs);
856f4b3ec61Sdh155122 		ifs->ifs_ipfr_stats.ifs_expire++;
857f4b3ec61Sdh155122 		ifs->ifs_ipfr_inuse--;
858ab25eeb5Syz155240 	}
859f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
860ab25eeb5Syz155240 
861ab25eeb5Syz155240 	/*
862ab25eeb5Syz155240 	 * Same again for the NAT table, except that if the structure also
863ab25eeb5Syz155240 	 * still points to a NAT structure, and the NAT structure points back
864ab25eeb5Syz155240 	 * at the one to be free'd, NULL the reference from the NAT struct.
865ab25eeb5Syz155240 	 * NOTE: We need to grab both mutex's early, and in this order so as
866ab25eeb5Syz155240 	 * to prevent a deadlock if both try to expire at the same time.
867ab25eeb5Syz155240 	 */
868f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_nat);
869f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
870f4b3ec61Sdh155122 	for (fp = &ifs->ifs_ipfr_natlist; ((fra = *fp) != NULL); ) {
871f4b3ec61Sdh155122 		if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
872ab25eeb5Syz155240 			break;
873ab25eeb5Syz155240 		nat = fra->ipfr_data;
874ab25eeb5Syz155240 		if (nat != NULL) {
875ab25eeb5Syz155240 			if (nat->nat_data == fra)
876ab25eeb5Syz155240 				nat->nat_data = NULL;
877ab25eeb5Syz155240 		}
878f4b3ec61Sdh155122 		fra->ipfr_ref--;
879f4b3ec61Sdh155122 		fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs);
880f4b3ec61Sdh155122 		ifs->ifs_ipfr_stats.ifs_expire++;
881f4b3ec61Sdh155122 		ifs->ifs_ipfr_inuse--;
882ab25eeb5Syz155240 	}
883f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
884f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
885ab25eeb5Syz155240 	SPL_X(s);
886ab25eeb5Syz155240 }
887ab25eeb5Syz155240 
888ab25eeb5Syz155240 
889ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
890ab25eeb5Syz155240 /* Function:    fr_slowtimer                                                */
891ab25eeb5Syz155240 /* Returns:     Nil                                                         */
892ab25eeb5Syz155240 /* Parameters:  Nil                                                         */
893ab25eeb5Syz155240 /*                                                                          */
894ab25eeb5Syz155240 /* Slowly expire held state for fragments.  Timeouts are set * in           */
895ab25eeb5Syz155240 /* expectation of this being called twice per second.                       */
896ab25eeb5Syz155240 /* ------------------------------------------------------------------------ */
897*f56257d8SToomas Soome #if !defined(_KERNEL) || (!defined(SOLARIS) && !defined(__hpux) && \
898*f56257d8SToomas Soome 	!defined(__sgi) && !defined(__osf__) && !defined(linux))
899ab25eeb5Syz155240 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
900f4b3ec61Sdh155122 void fr_slowtimer __P((void *arg))
901ab25eeb5Syz155240 # else
902f4b3ec61Sdh155122 int fr_slowtimer(void *arg)
903ab25eeb5Syz155240 # endif
904ab25eeb5Syz155240 {
905f4b3ec61Sdh155122 	ipf_stack_t *ifs = arg;
906ab25eeb5Syz155240 
907f4b3ec61Sdh155122 	READ_ENTER(&ifs->ifs_ipf_global);
908f4b3ec61Sdh155122 
909f4b3ec61Sdh155122 	fr_fragexpire(ifs);
910f4b3ec61Sdh155122 	fr_timeoutstate(ifs);
911f4b3ec61Sdh155122 	fr_natexpire(ifs);
912f4b3ec61Sdh155122 	fr_authexpire(ifs);
913f4b3ec61Sdh155122 	ifs->ifs_fr_ticks++;
914f4b3ec61Sdh155122 	if (ifs->ifs_fr_running <= 0)
915ab25eeb5Syz155240 		goto done;
916ab25eeb5Syz155240 # ifdef _KERNEL
917ab25eeb5Syz155240 #  if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
918ab25eeb5Syz155240 	callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
919ab25eeb5Syz155240 #  else
920ab25eeb5Syz155240 #   if defined(__OpenBSD__)
921ab25eeb5Syz155240 	timeout_add(&fr_slowtimer_ch, hz/2);
922ab25eeb5Syz155240 #   else
923ab25eeb5Syz155240 #    if (__FreeBSD_version >= 300000)
924ab25eeb5Syz155240 	fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
925ab25eeb5Syz155240 #    else
926ab25eeb5Syz155240 #     ifdef linux
927ab25eeb5Syz155240 	;
928ab25eeb5Syz155240 #     else
929ab25eeb5Syz155240 	timeout(fr_slowtimer, NULL, hz/2);
930ab25eeb5Syz155240 #     endif
931ab25eeb5Syz155240 #    endif /* FreeBSD */
932ab25eeb5Syz155240 #   endif /* OpenBSD */
933ab25eeb5Syz155240 #  endif /* NetBSD */
934ab25eeb5Syz155240 # endif
935ab25eeb5Syz155240 done:
936f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
937ab25eeb5Syz155240 # if (BSD < 199103) || !defined(_KERNEL)
938ab25eeb5Syz155240 	return 0;
939ab25eeb5Syz155240 # endif
940ab25eeb5Syz155240 }
941ab25eeb5Syz155240 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
942f4b3ec61Sdh155122 
943f4b3ec61Sdh155122 /*ARGSUSED*/
944f4b3ec61Sdh155122 int fr_nextfrag(token, itp, top, tail, lock, ifs)
945f4b3ec61Sdh155122 ipftoken_t *token;
946f4b3ec61Sdh155122 ipfgeniter_t *itp;
947f4b3ec61Sdh155122 ipfr_t **top, ***tail;
948f4b3ec61Sdh155122 ipfrwlock_t *lock;
949f4b3ec61Sdh155122 ipf_stack_t *ifs;
950f4b3ec61Sdh155122 {
951f4b3ec61Sdh155122 	ipfr_t *frag, *next, zero;
952f4b3ec61Sdh155122 	int error = 0;
953f4b3ec61Sdh155122 
954f4b3ec61Sdh155122 	READ_ENTER(lock);
955786c7074Sjojemann 
956786c7074Sjojemann 	/*
957786c7074Sjojemann 	 * Retrieve "previous" entry from token and find the next entry.
958786c7074Sjojemann 	 */
959786c7074Sjojemann 	frag = token->ipt_data;
960f4b3ec61Sdh155122 	if (frag == NULL)
961f4b3ec61Sdh155122 		next = *top;
962f4b3ec61Sdh155122 	else
963f4b3ec61Sdh155122 		next = frag->ipfr_next;
964f4b3ec61Sdh155122 
965786c7074Sjojemann 	/*
966786c7074Sjojemann 	 * If we found an entry, add reference to it and update token.
967786c7074Sjojemann 	 * Otherwise, zero out data to be returned and NULL out token.
968786c7074Sjojemann 	 */
969f4b3ec61Sdh155122 	if (next != NULL) {
970f4b3ec61Sdh155122 		ATOMIC_INC(next->ipfr_ref);
971f4b3ec61Sdh155122 		token->ipt_data = next;
972f4b3ec61Sdh155122 	} else {
973f4b3ec61Sdh155122 		bzero(&zero, sizeof(zero));
974f4b3ec61Sdh155122 		next = &zero;
975786c7074Sjojemann 		token->ipt_data = NULL;
976f4b3ec61Sdh155122 	}
977786c7074Sjojemann 
978786c7074Sjojemann 	/*
979786c7074Sjojemann 	 * Now that we have ref, it's save to give up lock.
980786c7074Sjojemann 	 */
981f4b3ec61Sdh155122 	RWLOCK_EXIT(lock);
982f4b3ec61Sdh155122 
983786c7074Sjojemann 	/*
984786c7074Sjojemann 	 * Copy out data and clean up references and token as needed.
985786c7074Sjojemann 	 */
986f4b3ec61Sdh155122 	error = COPYOUT(next, itp->igi_data, sizeof(*next));
987f4b3ec61Sdh155122 	if (error != 0)
988f4b3ec61Sdh155122 		error = EFAULT;
989786c7074Sjojemann 	if (token->ipt_data == NULL) {
990786c7074Sjojemann 		ipf_freetoken(token, ifs);
991786c7074Sjojemann 	} else {
992786c7074Sjojemann 		if (frag != NULL)
993786c7074Sjojemann 			fr_fragderef(&frag, lock, ifs);
994786c7074Sjojemann 		if (next->ipfr_next == NULL)
995786c7074Sjojemann 			ipf_freetoken(token, ifs);
996786c7074Sjojemann 	}
997f4b3ec61Sdh155122 	return error;
998f4b3ec61Sdh155122 }
999f4b3ec61Sdh155122 
1000f4b3ec61Sdh155122 
1001f4b3ec61Sdh155122 void fr_fragderef(frp, lock, ifs)
1002f4b3ec61Sdh155122 ipfr_t **frp;
1003f4b3ec61Sdh155122 ipfrwlock_t *lock;
1004f4b3ec61Sdh155122 ipf_stack_t *ifs;
1005f4b3ec61Sdh155122 {
1006f4b3ec61Sdh155122 	ipfr_t *fra;
1007f4b3ec61Sdh155122 
1008f4b3ec61Sdh155122 	fra = *frp;
1009f4b3ec61Sdh155122 	*frp = NULL;
1010f4b3ec61Sdh155122 
1011f4b3ec61Sdh155122 	WRITE_ENTER(lock);
1012f4b3ec61Sdh155122 	fra->ipfr_ref--;
1013f4b3ec61Sdh155122 	if (fra->ipfr_ref <= 0) {
1014f4b3ec61Sdh155122 		KFREE(fra);
1015f4b3ec61Sdh155122 		ifs->ifs_ipfr_stats.ifs_expire++;
1016f4b3ec61Sdh155122 		ifs->ifs_ipfr_inuse--;
1017f4b3ec61Sdh155122 	}
1018f4b3ec61Sdh155122 	RWLOCK_EXIT(lock);
1019f4b3ec61Sdh155122 }
1020