Deleted Added
full compact
ip_frag.c (139255) ip_frag.c (145522)
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_frag.c 145522 2005-04-25 18:43:14Z darrenr $ */
2
1/*
3/*
2 * Copyright (C) 1993-2001 by Darren Reed.
4 * Copyright (C) 1993-2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
6#if defined(KERNEL) && !defined(_KERNEL)
7# define _KERNEL
8#if defined(KERNEL) || defined(_KERNEL)
9# undef KERNEL
10# undef _KERNEL
11# define KERNEL 1
12# define _KERNEL 1
8#endif
13#endif
9
10#if defined(__sgi) && (IRIX > 602)
11# include <sys/ptimers.h>
12#endif
13#include <sys/errno.h>
14#include <sys/types.h>
15#include <sys/param.h>
16#include <sys/time.h>
17#include <sys/file.h>
14#include <sys/errno.h>
15#include <sys/types.h>
16#include <sys/param.h>
17#include <sys/time.h>
18#include <sys/file.h>
18#if !defined(_KERNEL) && !defined(KERNEL)
19#ifdef __hpux
20# include <sys/timeout.h>
21#endif
22#if !defined(_KERNEL)
19# include <stdio.h>
20# include <string.h>
21# include <stdlib.h>
23# include <stdio.h>
24# include <string.h>
25# include <stdlib.h>
26# define _KERNEL
27# ifdef __OpenBSD__
28struct file;
29# endif
30# include <sys/uio.h>
31# undef _KERNEL
22#endif
32#endif
23#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000)
33#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
24# include <sys/filio.h>
25# include <sys/fcntl.h>
26#else
27# include <sys/ioctl.h>
28#endif
34# include <sys/filio.h>
35# include <sys/fcntl.h>
36#else
37# include <sys/ioctl.h>
38#endif
29#ifndef linux
39#if !defined(linux)
30# include <sys/protosw.h>
31#endif
32#include <sys/socket.h>
40# include <sys/protosw.h>
41#endif
42#include <sys/socket.h>
33#if defined(_KERNEL) && !defined(linux)
43#if defined(_KERNEL)
34# include <sys/systm.h>
44# include <sys/systm.h>
45# if !defined(__SVR4) && !defined(__svr4__)
46# include <sys/mbuf.h>
47# endif
35#endif
36#if !defined(__SVR4) && !defined(__svr4__)
37# if defined(_KERNEL) && !defined(__sgi)
38# include <sys/kernel.h>
39# endif
48#endif
49#if !defined(__SVR4) && !defined(__svr4__)
50# if defined(_KERNEL) && !defined(__sgi)
51# include <sys/kernel.h>
52# endif
40# ifndef linux
41# include <sys/mbuf.h>
42# endif
43#else
44# include <sys/byteorder.h>
45# ifdef _KERNEL
46# include <sys/dditypes.h>
47# endif
48# include <sys/stream.h>
49# include <sys/kmem.h>
50#endif
51#include <net/if.h>
52#ifdef sun
53# include <net/af.h>
54#endif
55#include <net/route.h>
56#include <netinet/in.h>
57#include <netinet/in_systm.h>
58#include <netinet/ip.h>
53#else
54# include <sys/byteorder.h>
55# ifdef _KERNEL
56# include <sys/dditypes.h>
57# endif
58# include <sys/stream.h>
59# include <sys/kmem.h>
60#endif
61#include <net/if.h>
62#ifdef sun
63# include <net/af.h>
64#endif
65#include <net/route.h>
66#include <netinet/in.h>
67#include <netinet/in_systm.h>
68#include <netinet/ip.h>
59#ifndef linux
69#if !defined(linux)
60# include <netinet/ip_var.h>
61#endif
62#include <netinet/tcp.h>
63#include <netinet/udp.h>
64#include <netinet/ip_icmp.h>
65#include "netinet/ip_compat.h"
66#include <netinet/tcpip.h>
67#include "netinet/ip_fil.h"
68#include "netinet/ip_nat.h"
69#include "netinet/ip_frag.h"
70#include "netinet/ip_state.h"
71#include "netinet/ip_auth.h"
70# include <netinet/ip_var.h>
71#endif
72#include <netinet/tcp.h>
73#include <netinet/udp.h>
74#include <netinet/ip_icmp.h>
75#include "netinet/ip_compat.h"
76#include <netinet/tcpip.h>
77#include "netinet/ip_fil.h"
78#include "netinet/ip_nat.h"
79#include "netinet/ip_frag.h"
80#include "netinet/ip_state.h"
81#include "netinet/ip_auth.h"
82#include "netinet/ip_proxy.h"
72#if (__FreeBSD_version >= 300000)
73# include <sys/malloc.h>
83#if (__FreeBSD_version >= 300000)
84# include <sys/malloc.h>
74# if (defined(KERNEL) || defined(_KERNEL))
85# if defined(_KERNEL)
75# ifndef IPFILTER_LKM
76# include <sys/libkern.h>
77# include <sys/systm.h>
78# endif
86# ifndef IPFILTER_LKM
87# include <sys/libkern.h>
88# include <sys/systm.h>
89# endif
79extern struct callout_handle ipfr_slowtimer_ch;
90extern struct callout_handle fr_slowtimer_ch;
80# endif
81#endif
82#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
83# include <sys/callout.h>
91# endif
92#endif
93#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
94# include <sys/callout.h>
84extern struct callout ipfr_slowtimer_ch;
95extern struct callout fr_slowtimer_ch;
85#endif
86#if defined(__OpenBSD__)
87# include <sys/timeout.h>
96#endif
97#if defined(__OpenBSD__)
98# include <sys/timeout.h>
88extern struct timeout ipfr_slowtimer_ch;
99extern struct timeout fr_slowtimer_ch;
89#endif
100#endif
101/* END OF INCLUDES */
90
91#if !defined(lint)
92static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
102
103#if !defined(lint)
104static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
93static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_frag.c 139255 2004-12-24 09:14:26Z darrenr $";
105static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_frag.c 145522 2005-04-25 18:43:14Z darrenr $";
106static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77 2004/01/27 00:24:54 darrenr Exp";
94#endif
95
96
107#endif
108
109
97static ipfr_t *ipfr_heads[IPFT_SIZE];
98static ipfr_t *ipfr_nattab[IPFT_SIZE];
110static ipfr_t *ipfr_list = NULL;
111static ipfr_t **ipfr_tail = &ipfr_list;
112static ipfr_t **ipfr_heads;
113
114static ipfr_t *ipfr_natlist = NULL;
115static ipfr_t **ipfr_nattail = &ipfr_natlist;
116static ipfr_t **ipfr_nattab;
117
118static ipfr_t *ipfr_ipidlist = NULL;
119static ipfr_t **ipfr_ipidtail = &ipfr_ipidlist;
120static ipfr_t **ipfr_ipidtab;
121
99static ipfrstat_t ipfr_stats;
100static int ipfr_inuse = 0;
122static ipfrstat_t ipfr_stats;
123static int ipfr_inuse = 0;
124int ipfr_size = IPFT_SIZE;
101
102int fr_ipfrttl = 120; /* 60 seconds */
103int fr_frag_lock = 0;
125
126int fr_ipfrttl = 120; /* 60 seconds */
127int fr_frag_lock = 0;
128int fr_frag_init = 0;
129u_long fr_ticks = 0;
104
130
105#ifdef _KERNEL
106# if SOLARIS2 >= 7
107extern timeout_id_t ipfr_timer_id;
108# else
109extern int ipfr_timer_id;
110# endif
111#endif
112#ifdef USE_MUTEX
113extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat, ipf_mutex;
114# if SOLARIS
115extern KRWLOCK_T ipf_solaris;
116# else
117KRWLOCK_T ipf_solaris;
118# endif
119extern kmutex_t ipf_rw;
120#endif
121
131
132static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
133static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
134static void fr_fragdelete __P((ipfr_t *, ipfr_t ***));
122
135
123static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, ipfr_t **));
124static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **));
125static void ipfr_delete __P((ipfr_t *));
126
136
137/* ------------------------------------------------------------------------ */
138/* Function: fr_fraginit */
139/* Returns: int - 0 == success, -1 == error */
140/* Parameters: Nil */
141/* */
142/* Initialise the hash tables for the fragment cache lookups. */
143/* ------------------------------------------------------------------------ */
144int fr_fraginit()
145{
146 KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
147 if (ipfr_heads == NULL)
148 return -1;
149 bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *));
127
150
128ipfrstat_t *ipfr_fragstats()
151 KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
152 if (ipfr_nattab == NULL)
153 return -1;
154 bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
155
156 KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
157 if (ipfr_ipidtab == NULL)
158 return -1;
159 bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
160
161 RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock");
162 fr_frag_init = 1;
163
164 return 0;
165}
166
167
168/* ------------------------------------------------------------------------ */
169/* Function: fr_fragunload */
170/* Returns: Nil */
171/* Parameters: Nil */
172/* */
173/* Free all memory allocated whilst running and from initialisation. */
174/* ------------------------------------------------------------------------ */
175void fr_fragunload()
129{
176{
177 if (fr_frag_init == 1) {
178 fr_fragclear();
179
180 RW_DESTROY(&ipf_frag);
181 fr_frag_init = 0;
182 }
183
184 if (ipfr_heads != NULL)
185 KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *));
186 ipfr_heads = NULL;
187
188 if (ipfr_nattab != NULL)
189 KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
190 ipfr_nattab = NULL;
191
192 if (ipfr_ipidtab != NULL)
193 KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
194 ipfr_ipidtab = NULL;
195}
196
197
198/* ------------------------------------------------------------------------ */
199/* Function: fr_fragstats */
200/* Returns: ipfrstat_t* - pointer to struct with current frag stats */
201/* Parameters: Nil */
202/* */
203/* Updates ipfr_stats with current information and returns a pointer to it */
204/* ------------------------------------------------------------------------ */
205ipfrstat_t *fr_fragstats()
206{
130 ipfr_stats.ifs_table = ipfr_heads;
131 ipfr_stats.ifs_nattab = ipfr_nattab;
132 ipfr_stats.ifs_inuse = ipfr_inuse;
133 return &ipfr_stats;
134}
135
136
207 ipfr_stats.ifs_table = ipfr_heads;
208 ipfr_stats.ifs_nattab = ipfr_nattab;
209 ipfr_stats.ifs_inuse = ipfr_inuse;
210 return &ipfr_stats;
211}
212
213
137/*
138 * add a new entry to the fragment cache, registering it as having come
139 * through this box, with the result of the filter operation.
140 */
141static ipfr_t *ipfr_new(ip, fin, table)
142ip_t *ip;
214/* ------------------------------------------------------------------------ */
215/* Function: ipfr_newfrag */
216/* Returns: ipfr_t * - pointer to fragment cache state info or NULL */
217/* Parameters: fin(I) - pointer to packet information */
218/* table(I) - pointer to frag table to add to */
219/* */
220/* Add a new entry to the fragment cache, registering it as having come */
221/* through this box, with the result of the filter operation. */
222/* ------------------------------------------------------------------------ */
223static ipfr_t *ipfr_newfrag(fin, pass, table)
143fr_info_t *fin;
224fr_info_t *fin;
225u_32_t pass;
144ipfr_t *table[];
145{
226ipfr_t *table[];
227{
146 ipfr_t **fp, *fra, frag;
228 ipfr_t *fra, frag;
147 u_int idx, off;
229 u_int idx, off;
230 ip_t *ip;
148
149 if (ipfr_inuse >= IPFT_SIZE)
150 return NULL;
151
231
232 if (ipfr_inuse >= IPFT_SIZE)
233 return NULL;
234
152 if (!(fin->fin_fl & FI_FRAG))
235 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
153 return NULL;
154
236 return NULL;
237
238 ip = fin->fin_ip;
239
240 if (pass & FR_FRSTRICT)
241 if ((ip->ip_off & IP_OFFMASK) != 0)
242 return NULL;
243
155 frag.ipfr_p = ip->ip_p;
156 idx = ip->ip_p;
157 frag.ipfr_id = ip->ip_id;
158 idx += ip->ip_id;
159 frag.ipfr_tos = ip->ip_tos;
160 frag.ipfr_src.s_addr = ip->ip_src.s_addr;
161 idx += ip->ip_src.s_addr;
162 frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;

--- 4 unchanged lines hidden (view full) ---

167
168 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
169 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
170 frag.ipfr_auth = fin->fin_fi.fi_auth;
171
172 /*
173 * first, make sure it isn't already there...
174 */
244 frag.ipfr_p = ip->ip_p;
245 idx = ip->ip_p;
246 frag.ipfr_id = ip->ip_id;
247 idx += ip->ip_id;
248 frag.ipfr_tos = ip->ip_tos;
249 frag.ipfr_src.s_addr = ip->ip_src.s_addr;
250 idx += ip->ip_src.s_addr;
251 frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;

--- 4 unchanged lines hidden (view full) ---

256
257 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
258 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
259 frag.ipfr_auth = fin->fin_fi.fi_auth;
260
261 /*
262 * first, make sure it isn't already there...
263 */
175 for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next)
176 if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src,
264 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
265 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
177 IPFR_CMPSZ)) {
266 IPFR_CMPSZ)) {
178 ATOMIC_INCL(ipfr_stats.ifs_exists);
267 ipfr_stats.ifs_exists++;
179 return NULL;
180 }
181
182 /*
183 * allocate some memory, if possible, if not, just record that we
184 * failed to do so.
185 */
186 KMALLOC(fra, ipfr_t *);
187 if (fra == NULL) {
268 return NULL;
269 }
270
271 /*
272 * allocate some memory, if possible, if not, just record that we
273 * failed to do so.
274 */
275 KMALLOC(fra, ipfr_t *);
276 if (fra == NULL) {
188 ATOMIC_INCL(ipfr_stats.ifs_nomem);
277 ipfr_stats.ifs_nomem++;
189 return NULL;
190 }
191
278 return NULL;
279 }
280
192 if ((fra->ipfr_rule = fin->fin_fr) != NULL) {
193 ATOMIC_INC32(fin->fin_fr->fr_ref);
194 }
281 if ((fra->ipfr_rule = fin->fin_fr) != NULL)
282 fin->fin_fr->fr_ref++;
195
283
196
197 /*
198 * Insert the fragment into the fragment table, copy the struct used
199 * in the search using bcopy rather than reassign each field.
200 * Set the ttl to the default.
201 */
284 /*
285 * Insert the fragment into the fragment table, copy the struct used
286 * in the search using bcopy rather than reassign each field.
287 * Set the ttl to the default.
288 */
202 if ((fra->ipfr_next = table[idx]))
203 table[idx]->ipfr_prev = fra;
204 fra->ipfr_prev = NULL;
289 if ((fra->ipfr_hnext = table[idx]) != NULL)
290 table[idx]->ipfr_hprev = &fra->ipfr_hnext;
291 fra->ipfr_hprev = table + idx;
205 fra->ipfr_data = NULL;
206 table[idx] = fra;
292 fra->ipfr_data = NULL;
293 table[idx] = fra;
207 bcopy((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ);
208 fra->ipfr_ttl = fr_ipfrttl;
294 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
295 fra->ipfr_ttl = fr_ticks + fr_ipfrttl;
296
209 /*
210 * Compute the offset of the expected start of the next packet.
211 */
212 off = ip->ip_off & IP_OFFMASK;
297 /*
298 * Compute the offset of the expected start of the next packet.
299 */
300 off = ip->ip_off & IP_OFFMASK;
213 if (!off)
301 if (off == 0)
214 fra->ipfr_seen0 = 1;
215 fra->ipfr_off = off + (fin->fin_dlen >> 3);
302 fra->ipfr_seen0 = 1;
303 fra->ipfr_off = off + (fin->fin_dlen >> 3);
216 ATOMIC_INCL(ipfr_stats.ifs_new);
217 ATOMIC_INC32(ipfr_inuse);
304 fra->ipfr_pass = pass;
305 ipfr_stats.ifs_new++;
306 ipfr_inuse++;
218 return fra;
219}
220
221
307 return fra;
308}
309
310
222int ipfr_newfrag(ip, fin)
223ip_t *ip;
311/* ------------------------------------------------------------------------ */
312/* Function: fr_newfrag */
313/* Returns: int - 0 == success, -1 == error */
314/* Parameters: fin(I) - pointer to packet information */
315/* */
316/* Add a new entry to the fragment cache table based on the current packet */
317/* ------------------------------------------------------------------------ */
318int fr_newfrag(fin, pass)
319u_32_t pass;
224fr_info_t *fin;
225{
320fr_info_t *fin;
321{
226 ipfr_t *ipf;
322 ipfr_t *fra;
227
323
228 if ((ip->ip_v != 4) || (fr_frag_lock))
324 if ((fin->fin_v != 4) || (fr_frag_lock != 0))
229 return -1;
325 return -1;
326
230 WRITE_ENTER(&ipf_frag);
327 WRITE_ENTER(&ipf_frag);
231 ipf = ipfr_new(ip, fin, ipfr_heads);
232 RWLOCK_EXIT(&ipf_frag);
233 if (ipf == NULL) {
234 ATOMIC_INCL(frstats[fin->fin_out].fr_bnfr);
235 return -1;
328 fra = ipfr_newfrag(fin, pass, ipfr_heads);
329 if (fra != NULL) {
330 *ipfr_tail = fra;
331 fra->ipfr_prev = ipfr_tail;
332 ipfr_tail = &fra->ipfr_next;
333 if (ipfr_list == NULL)
334 ipfr_list = fra;
335 fra->ipfr_next = NULL;
236 }
336 }
237 ATOMIC_INCL(frstats[fin->fin_out].fr_nfr);
238 return 0;
337 RWLOCK_EXIT(&ipf_frag);
338 return fra ? 0 : -1;
239}
240
241
339}
340
341
242int ipfr_nat_newfrag(ip, fin, nat)
243ip_t *ip;
342/* ------------------------------------------------------------------------ */
343/* Function: fr_nat_newfrag */
344/* Returns: int - 0 == success, -1 == error */
345/* Parameters: fin(I) - pointer to packet information */
346/* nat(I) - pointer to NAT structure */
347/* */
348/* Create a new NAT fragment cache entry based on the current packet and */
349/* the NAT structure for this "session". */
350/* ------------------------------------------------------------------------ */
351int fr_nat_newfrag(fin, pass, nat)
244fr_info_t *fin;
352fr_info_t *fin;
353u_32_t pass;
245nat_t *nat;
246{
354nat_t *nat;
355{
247 ipfr_t *ipf;
248 int off;
356 ipfr_t *fra;
249
357
250 if ((ip->ip_v != 4) || (fr_frag_lock))
251 return -1;
358 if ((fin->fin_v != 4) || (fr_frag_lock != 0))
359 return 0;
252
360
253 off = fin->fin_off;
254 off <<= 3;
255 if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0))
256 return -1;
257
258 WRITE_ENTER(&ipf_natfrag);
361 WRITE_ENTER(&ipf_natfrag);
259 ipf = ipfr_new(ip, fin, ipfr_nattab);
260 if (ipf != NULL) {
261 ipf->ipfr_data = nat;
262 nat->nat_data = ipf;
362 fra = ipfr_newfrag(fin, pass, ipfr_nattab);
363 if (fra != NULL) {
364 fra->ipfr_data = nat;
365 nat->nat_data = fra;
366 *ipfr_nattail = fra;
367 fra->ipfr_prev = ipfr_nattail;
368 ipfr_nattail = &fra->ipfr_next;
369 fra->ipfr_next = NULL;
263 }
264 RWLOCK_EXIT(&ipf_natfrag);
370 }
371 RWLOCK_EXIT(&ipf_natfrag);
265 return ipf ? 0 : -1;
372 return fra ? 0 : -1;
266}
267
268
373}
374
375
269/*
270 * check the fragment cache to see if there is already a record of this packet
271 * with its filter result known.
272 */
273static ipfr_t *ipfr_lookup(ip, fin, table)
274ip_t *ip;
376/* ------------------------------------------------------------------------ */
377/* Function: fr_ipid_newfrag */
378/* Returns: int - 0 == success, -1 == error */
379/* Parameters: fin(I) - pointer to packet information */
380/* ipid(I) - new IP ID for this fragmented packet */
381/* */
382/* Create a new fragment cache entry for this packet and store, as a data */
383/* pointer, the new IP ID value. */
384/* ------------------------------------------------------------------------ */
385int fr_ipid_newfrag(fin, ipid)
275fr_info_t *fin;
386fr_info_t *fin;
387u_32_t ipid;
388{
389 ipfr_t *fra;
390
391 if ((fin->fin_v != 4) || (fr_frag_lock))
392 return 0;
393
394 WRITE_ENTER(&ipf_ipidfrag);
395 fra = ipfr_newfrag(fin, 0, ipfr_ipidtab);
396 if (fra != NULL) {
397 fra->ipfr_data = (void *)ipid;
398 *ipfr_ipidtail = fra;
399 fra->ipfr_prev = ipfr_ipidtail;
400 ipfr_ipidtail = &fra->ipfr_next;
401 fra->ipfr_next = NULL;
402 }
403 RWLOCK_EXIT(&ipf_ipidfrag);
404 return fra ? 0 : -1;
405}
406
407
408/* ------------------------------------------------------------------------ */
409/* Function: fr_fraglookup */
410/* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */
411/* matching entry in the frag table, else NULL */
412/* Parameters: fin(I) - pointer to packet information */
413/* table(I) - pointer to fragment cache table to search */
414/* */
415/* Check the fragment cache to see if there is already a record of this */
416/* packet with its filter result known. */
417/* ------------------------------------------------------------------------ */
418static ipfr_t *fr_fraglookup(fin, table)
419fr_info_t *fin;
276ipfr_t *table[];
277{
420ipfr_t *table[];
421{
278 ipfr_t *f, frag;
279 u_int idx;
422 ipfr_t *f, frag;
423 u_int idx;
424 ip_t *ip;
280
425
426 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
427 return NULL;
428
281 /*
282 * For fragments, we record protocol, packet id, TOS and both IP#'s
283 * (these should all be the same for all fragments of a packet).
284 *
285 * build up a hash value to index the table with.
286 */
429 /*
430 * For fragments, we record protocol, packet id, TOS and both IP#'s
431 * (these should all be the same for all fragments of a packet).
432 *
433 * build up a hash value to index the table with.
434 */
435 ip = fin->fin_ip;
287 frag.ipfr_p = ip->ip_p;
288 idx = ip->ip_p;
289 frag.ipfr_id = ip->ip_id;
290 idx += ip->ip_id;
291 frag.ipfr_tos = ip->ip_tos;
292 frag.ipfr_src.s_addr = ip->ip_src.s_addr;
293 idx += ip->ip_src.s_addr;
294 frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;

--- 4 unchanged lines hidden (view full) ---

299
300 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
301 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
302 frag.ipfr_auth = fin->fin_fi.fi_auth;
303
304 /*
305 * check the table, careful to only compare the right amount of data
306 */
436 frag.ipfr_p = ip->ip_p;
437 idx = ip->ip_p;
438 frag.ipfr_id = ip->ip_id;
439 idx += ip->ip_id;
440 frag.ipfr_tos = ip->ip_tos;
441 frag.ipfr_src.s_addr = ip->ip_src.s_addr;
442 idx += ip->ip_src.s_addr;
443 frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;

--- 4 unchanged lines hidden (view full) ---

448
449 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
450 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
451 frag.ipfr_auth = fin->fin_fi.fi_auth;
452
453 /*
454 * check the table, careful to only compare the right amount of data
455 */
307 for (f = table[idx]; f; f = f->ipfr_next)
308 if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src,
456 for (f = table[idx]; f; f = f->ipfr_hnext)
457 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
309 IPFR_CMPSZ)) {
458 IPFR_CMPSZ)) {
310 u_short atoff, off;
459 u_short off;
311
460
312 off = fin->fin_off;
461 /*
462 * We don't want to let short packets match because
463 * they could be compromising the security of other
464 * rules that want to match on layer 4 fields (and
465 * can't because they have been fragmented off.)
466 * Why do this check here? The counter acts as an
467 * indicator of this kind of attack, whereas if it was
468 * elsewhere, it wouldn't know if other matching
469 * packets had been seen.
470 */
471 if (fin->fin_flx & FI_SHORT) {
472 ATOMIC_INCL(ipfr_stats.ifs_short);
473 continue;
474 }
313
314 /*
315 * XXX - We really need to be guarding against the
316 * retransmission of (src,dst,id,offset-range) here
317 * because a fragmented packet is never resent with
475
476 /*
477 * XXX - We really need to be guarding against the
478 * retransmission of (src,dst,id,offset-range) here
479 * because a fragmented packet is never resent with
318 * the same IP ID#.
480 * the same IP ID# (or shouldn't).
319 */
481 */
482 off = ip->ip_off & IP_OFFMASK;
320 if (f->ipfr_seen0) {
483 if (f->ipfr_seen0) {
321 if (!off || (fin->fin_fl & FI_SHORT))
484 if (off == 0) {
485 ATOMIC_INCL(ipfr_stats.ifs_retrans0);
322 continue;
486 continue;
323 } else if (!off)
487 }
488 } else if (off == 0)
324 f->ipfr_seen0 = 1;
325
326 if (f != table[idx]) {
489 f->ipfr_seen0 = 1;
490
491 if (f != table[idx]) {
492 ipfr_t **fp;
493
327 /*
494 /*
328 * move fragment info. to the top of the list
329 * to speed up searches.
495 * Move fragment info. to the top of the list
496 * to speed up searches. First, delink...
330 */
497 */
331 if ((f->ipfr_prev->ipfr_next = f->ipfr_next))
332 f->ipfr_next->ipfr_prev = f->ipfr_prev;
333 f->ipfr_next = table[idx];
334 table[idx]->ipfr_prev = f;
335 f->ipfr_prev = NULL;
498 fp = f->ipfr_hprev;
499 (*fp) = f->ipfr_hnext;
500 if (f->ipfr_hnext != NULL)
501 f->ipfr_hnext->ipfr_hprev = fp;
502 /*
503 * Then put back at the top of the chain.
504 */
505 f->ipfr_hnext = table[idx];
506 table[idx]->ipfr_hprev = &f->ipfr_hnext;
507 f->ipfr_hprev = table + idx;
336 table[idx] = f;
337 }
508 table[idx] = f;
509 }
338 atoff = off + (fin->fin_dlen >> 3);
510
339 /*
340 * If we've follwed the fragments, and this is the
341 * last (in order), shrink expiration time.
342 */
343 if (off == f->ipfr_off) {
344 if (!(ip->ip_off & IP_MF))
511 /*
512 * If we've follwed the fragments, and this is the
513 * last (in order), shrink expiration time.
514 */
515 if (off == f->ipfr_off) {
516 if (!(ip->ip_off & IP_MF))
345 f->ipfr_ttl = 1;
346 else
347 f->ipfr_off = atoff;
348 }
517 f->ipfr_ttl = fr_ticks + 1;
518 f->ipfr_off = (fin->fin_dlen >> 3) + off;
519 } else if (f->ipfr_pass & FR_FRSTRICT)
520 continue;
349 ATOMIC_INCL(ipfr_stats.ifs_hits);
350 return f;
351 }
352 return NULL;
353}
354
355
521 ATOMIC_INCL(ipfr_stats.ifs_hits);
522 return f;
523 }
524 return NULL;
525}
526
527
356/*
357 * functional interface for NAT lookups of the NAT fragment cache
358 */
359nat_t *ipfr_nat_knownfrag(ip, fin)
360ip_t *ip;
528/* ------------------------------------------------------------------------ */
529/* Function: fr_nat_knownfrag */
530/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */
531/* match found, else NULL */
532/* Parameters: fin(I) - pointer to packet information */
533/* */
534/* Functional interface for NAT lookups of the NAT fragment cache */
535/* ------------------------------------------------------------------------ */
536nat_t *fr_nat_knownfrag(fin)
361fr_info_t *fin;
362{
537fr_info_t *fin;
538{
363 ipfr_t *ipf;
364 nat_t *nat;
365 int off;
539 nat_t *nat;
540 ipfr_t *ipf;
366
541
367 if ((fin->fin_v != 4) || (fr_frag_lock))
542 if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist)
368 return NULL;
543 return NULL;
369
370 off = fin->fin_off;
371 off <<= 3;
372 if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0))
373 return NULL;
374
375 READ_ENTER(&ipf_natfrag);
544 READ_ENTER(&ipf_natfrag);
376 ipf = ipfr_lookup(ip, fin, ipfr_nattab);
545 ipf = fr_fraglookup(fin, ipfr_nattab);
377 if (ipf != NULL) {
378 nat = ipf->ipfr_data;
379 /*
380 * This is the last fragment for this packet.
381 */
546 if (ipf != NULL) {
547 nat = ipf->ipfr_data;
548 /*
549 * This is the last fragment for this packet.
550 */
382 if ((ipf->ipfr_ttl == 1) && (nat != NULL)) {
551 if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) {
383 nat->nat_data = NULL;
384 ipf->ipfr_data = NULL;
385 }
386 } else
387 nat = NULL;
388 RWLOCK_EXIT(&ipf_natfrag);
389 return nat;
390}
391
392
552 nat->nat_data = NULL;
553 ipf->ipfr_data = NULL;
554 }
555 } else
556 nat = NULL;
557 RWLOCK_EXIT(&ipf_natfrag);
558 return nat;
559}
560
561
393/*
394 * functional interface for normal lookups of the fragment cache
395 */
396frentry_t *ipfr_knownfrag(ip, fin)
397ip_t *ip;
562/* ------------------------------------------------------------------------ */
563/* Function: fr_ipid_knownfrag */
564/* Returns: u_32_t - IPv4 ID for this packet if match found, else */
565/* return 0xfffffff to indicate no match. */
566/* Parameters: fin(I) - pointer to packet information */
567/* */
568/* Functional interface for IP ID lookups of the IP ID fragment cache */
569/* ------------------------------------------------------------------------ */
570u_32_t fr_ipid_knownfrag(fin)
398fr_info_t *fin;
399{
571fr_info_t *fin;
572{
400 frentry_t *fr;
401 ipfr_t *fra;
402 int off;
573 ipfr_t *ipf;
574 u_32_t id;
403
575
404 if ((fin->fin_v != 4) || (fr_frag_lock))
405 return NULL;
576 if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist)
577 return 0xffffffff;
406
578
407 off = fin->fin_off;
408 off <<= 3;
409 if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0))
579 READ_ENTER(&ipf_ipidfrag);
580 ipf = fr_fraglookup(fin, ipfr_ipidtab);
581 if (ipf != NULL)
582 id = (u_32_t)ipf->ipfr_data;
583 else
584 id = 0xffffffff;
585 RWLOCK_EXIT(&ipf_ipidfrag);
586 return id;
587}
588
589
590/* ------------------------------------------------------------------------ */
591/* Function: fr_knownfrag */
592/* Returns: frentry_t* - pointer to filter rule if a match is found in */
593/* the frag cache table, else NULL. */
594/* Parameters: fin(I) - pointer to packet information */
595/* passp(O) - pointer to where to store rule flags resturned */
596/* */
597/* Functional interface for normal lookups of the fragment cache. If a */
598/* match is found, return the rule pointer and flags from the rule, except */
599/* that if FR_LOGFIRST is set, reset FR_LOG. */
600/* ------------------------------------------------------------------------ */
601frentry_t *fr_knownfrag(fin, passp)
602fr_info_t *fin;
603u_32_t *passp;
604{
605 frentry_t *fr = NULL;
606 ipfr_t *fra;
607 u_32_t pass;
608
609 if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL))
410 return NULL;
411
412 READ_ENTER(&ipf_frag);
610 return NULL;
611
612 READ_ENTER(&ipf_frag);
413 fra = ipfr_lookup(ip, fin, ipfr_heads);
414 if (fra != NULL)
613 fra = fr_fraglookup(fin, ipfr_heads);
614 if (fra != NULL) {
415 fr = fra->ipfr_rule;
615 fr = fra->ipfr_rule;
416 else
417 fr = NULL;
616 fin->fin_fr = fr;
617 if (fr != NULL) {
618 pass = fr->fr_flags;
619 if ((pass & FR_LOGFIRST) != 0)
620 pass &= ~(FR_LOGFIRST|FR_LOG);
621 *passp = pass;
622 }
623 }
418 RWLOCK_EXIT(&ipf_frag);
419 return fr;
420}
421
422
624 RWLOCK_EXIT(&ipf_frag);
625 return fr;
626}
627
628
423/*
424 * forget any references to this external object.
425 */
426void ipfr_forget(ptr)
629/* ------------------------------------------------------------------------ */
630/* Function: fr_forget */
631/* Returns: Nil */
632/* Parameters: ptr(I) - pointer to data structure */
633/* */
634/* Search through all of the fragment cache entries and wherever a pointer */
635/* is found to match ptr, reset it to NULL. */
636/* ------------------------------------------------------------------------ */
637void fr_forget(ptr)
427void *ptr;
428{
429 ipfr_t *fr;
638void *ptr;
639{
640 ipfr_t *fr;
430 int idx;
431
432 WRITE_ENTER(&ipf_frag);
641
642 WRITE_ENTER(&ipf_frag);
433 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
434 for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next)
435 if (fr->ipfr_data == ptr)
436 fr->ipfr_data = NULL;
437
643 for (fr = ipfr_list; fr; fr = fr->ipfr_next)
644 if (fr->ipfr_data == ptr)
645 fr->ipfr_data = NULL;
438 RWLOCK_EXIT(&ipf_frag);
439}
440
441
646 RWLOCK_EXIT(&ipf_frag);
647}
648
649
442/*
443 * forget any references to this external object.
444 */
445void ipfr_forgetnat(nat)
446void *nat;
650/* ------------------------------------------------------------------------ */
651/* Function: fr_forgetnat */
652/* Returns: Nil */
653/* Parameters: ptr(I) - pointer to data structure */
654/* */
655/* Search through all of the fragment cache entries for NAT and wherever a */
656/* pointer is found to match ptr, reset it to NULL. */
657/* ------------------------------------------------------------------------ */
658void fr_forgetnat(ptr)
659void *ptr;
447{
448 ipfr_t *fr;
660{
661 ipfr_t *fr;
449 int idx;
450
451 WRITE_ENTER(&ipf_natfrag);
662
663 WRITE_ENTER(&ipf_natfrag);
452 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
453 for (fr = ipfr_nattab[idx]; fr; fr = fr->ipfr_next)
454 if (fr->ipfr_data == nat)
455 fr->ipfr_data = NULL;
456
664 for (fr = ipfr_natlist; fr; fr = fr->ipfr_next)
665 if (fr->ipfr_data == ptr)
666 fr->ipfr_data = NULL;
457 RWLOCK_EXIT(&ipf_natfrag);
458}
459
460
667 RWLOCK_EXIT(&ipf_natfrag);
668}
669
670
461static void ipfr_delete(fra)
462ipfr_t *fra;
671/* ------------------------------------------------------------------------ */
672/* Function: fr_fragdelete */
673/* Returns: Nil */
674/* Parameters: fra(I) - pointer to fragment structure to delete */
675/* tail(IO) - pointer to the pointer to the tail of the frag */
676/* list */
677/* */
678/* Remove a fragment cache table entry from the table & list. Also free */
679/* the filter rule it is associated with it if it is no longer used as a */
680/* result of decreasing the reference count. */
681/* ------------------------------------------------------------------------ */
682static void fr_fragdelete(fra, tail)
683ipfr_t *fra, ***tail;
463{
464 frentry_t *fr;
465
466 fr = fra->ipfr_rule;
684{
685 frentry_t *fr;
686
687 fr = fra->ipfr_rule;
467 if (fr != NULL) {
468 ATOMIC_DEC32(fr->fr_ref);
469 if (fr->fr_ref == 0)
470 KFREE(fr);
471 }
472 if (fra->ipfr_prev)
473 fra->ipfr_prev->ipfr_next = fra->ipfr_next;
688 if (fr != NULL)
689 (void)fr_derefrule(&fr);
690
474 if (fra->ipfr_next)
475 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
691 if (fra->ipfr_next)
692 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
693 *fra->ipfr_prev = fra->ipfr_next;
694 if (*tail == &fra->ipfr_next)
695 *tail = fra->ipfr_prev;
696
697 if (fra->ipfr_hnext)
698 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
699 *fra->ipfr_hprev = fra->ipfr_hnext;
476 KFREE(fra);
477}
478
479
700 KFREE(fra);
701}
702
703
480/*
481 * Free memory in use by fragment state info. kept.
482 */
483void ipfr_unload()
704/* ------------------------------------------------------------------------ */
705/* Function: fr_fragclear */
706/* Returns: Nil */
707/* Parameters: Nil */
708/* */
709/* Free memory in use by fragment state information kept. Do the normal */
710/* fragment state stuff first and then the NAT-fragment table. */
711/* ------------------------------------------------------------------------ */
712void fr_fragclear()
484{
713{
485 ipfr_t **fp, *fra;
714 ipfr_t *fra;
486 nat_t *nat;
715 nat_t *nat;
487 int idx;
488
489 WRITE_ENTER(&ipf_frag);
716
717 WRITE_ENTER(&ipf_frag);
490 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
491 for (fp = &ipfr_heads[idx]; (fra = *fp); ) {
492 *fp = fra->ipfr_next;
493 ipfr_delete(fra);
494 }
718 while ((fra = ipfr_list) != NULL)
719 fr_fragdelete(fra, &ipfr_tail);
720 ipfr_tail = &ipfr_list;
495 RWLOCK_EXIT(&ipf_frag);
496
497 WRITE_ENTER(&ipf_nat);
498 WRITE_ENTER(&ipf_natfrag);
721 RWLOCK_EXIT(&ipf_frag);
722
723 WRITE_ENTER(&ipf_nat);
724 WRITE_ENTER(&ipf_natfrag);
499 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
500 for (fp = &ipfr_nattab[idx]; (fra = *fp); ) {
501 *fp = fra->ipfr_next;
502 nat = fra->ipfr_data;
503 if (nat != NULL) {
504 if (nat->nat_data == fra)
505 nat->nat_data = NULL;
506 }
507 ipfr_delete(fra);
725 while ((fra = ipfr_natlist) != NULL) {
726 nat = fra->ipfr_data;
727 if (nat != NULL) {
728 if (nat->nat_data == fra)
729 nat->nat_data = NULL;
508 }
730 }
731 fr_fragdelete(fra, &ipfr_nattail);
732 }
733 ipfr_nattail = &ipfr_natlist;
509 RWLOCK_EXIT(&ipf_natfrag);
510 RWLOCK_EXIT(&ipf_nat);
511}
512
513
734 RWLOCK_EXIT(&ipf_natfrag);
735 RWLOCK_EXIT(&ipf_nat);
736}
737
738
514void ipfr_fragexpire()
739/* ------------------------------------------------------------------------ */
740/* Function: fr_fragexpire */
741/* Returns: Nil */
742/* Parameters: Nil */
743/* */
744/* Expire entries in the fragment cache table that have been there too long */
745/* ------------------------------------------------------------------------ */
746void fr_fragexpire()
515{
516 ipfr_t **fp, *fra;
517 nat_t *nat;
747{
748 ipfr_t **fp, *fra;
749 nat_t *nat;
518 int idx;
519#if defined(_KERNEL)
520# if !SOLARIS
750#if defined(USE_SPL) && defined(_KERNEL)
521 int s;
751 int s;
522# endif
523#endif
524
525 if (fr_frag_lock)
526 return;
527
528 SPL_NET(s);
529 WRITE_ENTER(&ipf_frag);
752#endif
753
754 if (fr_frag_lock)
755 return;
756
757 SPL_NET(s);
758 WRITE_ENTER(&ipf_frag);
530
531 /*
532 * Go through the entire table, looking for entries to expire,
759 /*
760 * Go through the entire table, looking for entries to expire,
533 * decreasing the ttl by one for each entry. If it reaches 0,
534 * remove it from the chain and free it.
761 * which is indicated by the ttl being less than or equal to fr_ticks.
535 */
762 */
536 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
537 for (fp = &ipfr_heads[idx]; (fra = *fp); ) {
538 --fra->ipfr_ttl;
539 if (fra->ipfr_ttl == 0) {
540 *fp = fra->ipfr_next;
541 ipfr_delete(fra);
542 ATOMIC_INCL(ipfr_stats.ifs_expire);
543 ATOMIC_DEC32(ipfr_inuse);
544 } else
545 fp = &fra->ipfr_next;
546 }
763 for (fp = &ipfr_list; ((fra = *fp) != NULL); ) {
764 if (fra->ipfr_ttl > fr_ticks)
765 break;
766 fr_fragdelete(fra, &ipfr_tail);
767 ipfr_stats.ifs_expire++;
768 ipfr_inuse--;
769 }
547 RWLOCK_EXIT(&ipf_frag);
548
770 RWLOCK_EXIT(&ipf_frag);
771
772 WRITE_ENTER(&ipf_ipidfrag);
773 for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) {
774 if (fra->ipfr_ttl > fr_ticks)
775 break;
776 fr_fragdelete(fra, &ipfr_ipidtail);
777 ipfr_stats.ifs_expire++;
778 ipfr_inuse--;
779 }
780 RWLOCK_EXIT(&ipf_ipidfrag);
781
549 /*
550 * Same again for the NAT table, except that if the structure also
551 * still points to a NAT structure, and the NAT structure points back
552 * at the one to be free'd, NULL the reference from the NAT struct.
553 * NOTE: We need to grab both mutex's early, and in this order so as
554 * to prevent a deadlock if both try to expire at the same time.
555 */
556 WRITE_ENTER(&ipf_nat);
557 WRITE_ENTER(&ipf_natfrag);
782 /*
783 * Same again for the NAT table, except that if the structure also
784 * still points to a NAT structure, and the NAT structure points back
785 * at the one to be free'd, NULL the reference from the NAT struct.
786 * NOTE: We need to grab both mutex's early, and in this order so as
787 * to prevent a deadlock if both try to expire at the same time.
788 */
789 WRITE_ENTER(&ipf_nat);
790 WRITE_ENTER(&ipf_natfrag);
558 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
559 for (fp = &ipfr_nattab[idx]; (fra = *fp); ) {
560 --fra->ipfr_ttl;
561 if (fra->ipfr_ttl == 0) {
562 ATOMIC_INCL(ipfr_stats.ifs_expire);
563 ATOMIC_DEC32(ipfr_inuse);
564 nat = fra->ipfr_data;
565 if (nat != NULL) {
566 if (nat->nat_data == fra)
567 nat->nat_data = NULL;
568 }
569 *fp = fra->ipfr_next;
570 ipfr_delete(fra);
571 } else
572 fp = &fra->ipfr_next;
791 for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) {
792 if (fra->ipfr_ttl > fr_ticks)
793 break;
794 nat = fra->ipfr_data;
795 if (nat != NULL) {
796 if (nat->nat_data == fra)
797 nat->nat_data = NULL;
573 }
798 }
799 fr_fragdelete(fra, &ipfr_nattail);
800 ipfr_stats.ifs_expire++;
801 ipfr_inuse--;
802 }
574 RWLOCK_EXIT(&ipf_natfrag);
575 RWLOCK_EXIT(&ipf_nat);
576 SPL_X(s);
577}
578
579
803 RWLOCK_EXIT(&ipf_natfrag);
804 RWLOCK_EXIT(&ipf_nat);
805 SPL_X(s);
806}
807
808
580/*
581 * Slowly expire held state for fragments. Timeouts are set * in expectation
582 * of this being called twice per second.
583 */
584#ifdef _KERNEL
585# if (BSD >= 199306) || SOLARIS || defined(__sgi)
586# if defined(SOLARIS2) && (SOLARIS2 < 7)
587void ipfr_slowtimer()
588# else
589void ipfr_slowtimer __P((void *ptr))
590# endif
809/* ------------------------------------------------------------------------ */
810/* Function: fr_slowtimer */
811/* Returns: Nil */
812/* Parameters: Nil */
813/* */
814/* Slowly expire held state for fragments. Timeouts are set * in */
815/* expectation of this being called twice per second. */
816/* ------------------------------------------------------------------------ */
817#if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
818 !defined(__osf__))
819# if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
820void fr_slowtimer __P((void *ptr))
591# else
821# else
592int ipfr_slowtimer()
822int fr_slowtimer()
593# endif
823# endif
594#else
595void ipfr_slowtimer()
596#endif
597{
824{
598#if defined(_KERNEL) && SOLARIS
599 extern int fr_running;
825 READ_ENTER(&ipf_global);
600
826
601 if (fr_running <= 0)
602 return;
603 READ_ENTER(&ipf_solaris);
604#endif
605
606#if defined(__sgi) && defined(_KERNEL)
607 ipfilter_sgi_intfsync();
608#endif
609
610 ipfr_fragexpire();
827 fr_fragexpire();
611 fr_timeoutstate();
828 fr_timeoutstate();
612 ip_natexpire();
829 fr_natexpire();
613 fr_authexpire();
830 fr_authexpire();
614#if defined(_KERNEL)
615# if SOLARIS
616 ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000));
617 RWLOCK_EXIT(&ipf_solaris);
618# else
831 fr_ticks++;
832 if (fr_running <= 0)
833 goto done;
834# ifdef _KERNEL
619# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
835# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
620 callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL);
836 callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
621# else
837# else
622# if (__FreeBSD_version >= 300000)
623 ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2);
838# if defined(__OpenBSD__)
839 timeout_add(&fr_slowtimer_ch, hz/2);
624# else
840# else
625# if defined(__OpenBSD__)
626 timeout_add(&ipfr_slowtimer_ch, hz/2);
841# if (__FreeBSD_version >= 300000)
842 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
627# else
843# else
628 timeout(ipfr_slowtimer, NULL, hz/2);
629# endif
630# endif
631# if (BSD < 199306) && !defined(__sgi)
632 return 0;
633# endif /* FreeBSD */
844# ifdef linux
845 ;
846# else
847 timeout(fr_slowtimer, NULL, hz/2);
848# endif
849# endif /* FreeBSD */
850# endif /* OpenBSD */
634# endif /* NetBSD */
851# endif /* NetBSD */
635# endif /* SOLARIS */
636#endif /* defined(_KERNEL) */
852# endif
853done:
854 RWLOCK_EXIT(&ipf_global);
855# if (BSD < 199103) || !defined(_KERNEL)
856 return 0;
857# endif
637}
858}
859#endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */