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 /* ------------------------------------------------------------------------ */
fr_fraginit(ifs)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 /* ------------------------------------------------------------------------ */
fr_fragunload(ifs)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 /* ------------------------------------------------------------------------ */
fr_fragstats(ifs)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 /* ------------------------------------------------------------------------ */
ipfr_index(fin,frag)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 /* ------------------------------------------------------------------------ */
ipfr_newfrag(fin,pass,table)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 /* ------------------------------------------------------------------------ */
fr_newfrag(fin,pass)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 /* ------------------------------------------------------------------------ */
fr_nat_newfrag(fin,pass,nat)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 /* ------------------------------------------------------------------------ */
fr_ipid_newfrag(fin,ipid)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 /* ------------------------------------------------------------------------ */
fr_fraglookup(fin,table)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 /* ------------------------------------------------------------------------ */
fr_nat_knownfrag(fin)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 /* ------------------------------------------------------------------------ */
fr_ipid_knownfrag(fin)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 /* ------------------------------------------------------------------------ */
fr_knownfrag(fin,passp)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 /* ------------------------------------------------------------------------ */
fr_forget(ptr,ifs)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 /* ------------------------------------------------------------------------ */
fr_forgetnat(ptr,ifs)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 /* ------------------------------------------------------------------------ */
fr_fragdelete(fra,tail,ifs)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 /* ------------------------------------------------------------------------ */
fr_fragclear(ifs)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 /* ------------------------------------------------------------------------ */
fr_fragexpire(ifs)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))
fr_slowtimer(void * arg)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*/
fr_nextfrag(token,itp,top,tail,lock,ifs)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
fr_fragderef(frp,lock,ifs)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