4 * Copyright (C) 1993-2003 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Copyright 2008 Sun Microsystems, Inc.
10 #if defined(KERNEL) || defined(_KERNEL)
16 #include <sys/errno.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
22 # include <sys/timeout.h>
35 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
36 # include <sys/filio.h>
37 # include <sys/fcntl.h>
39 # include <sys/ioctl.h>
42 # include <sys/protosw.h>
44 #include <sys/socket.h>
46 # include <sys/systm.h>
47 # if !defined(__SVR4) && !defined(__svr4__)
48 # include <sys/mbuf.h>
51 #if !defined(__SVR4) && !defined(__svr4__)
52 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
53 # include <sys/kernel.h>
56 # include <sys/byteorder.h>
58 # include <sys/dditypes.h>
60 # include <sys/stream.h>
61 # include <sys/kmem.h>
67 #include <netinet/in.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/ip.h>
71 # include <netinet/ip_var.h>
73 #include <netinet/tcp.h>
74 #include <netinet/udp.h>
75 #include <netinet/ip_icmp.h>
76 #include "netinet/ip_compat.h"
77 #include <netinet/tcpip.h>
78 #include "netinet/ip_fil.h"
79 #include "netinet/ip_nat.h"
80 #include "netinet/ip_frag.h"
81 #include "netinet/ip_state.h"
82 #include "netinet/ip_auth.h"
83 #include "netinet/ip_proxy.h"
84 #if (__FreeBSD_version >= 300000)
85 # include <sys/malloc.h>
88 # include <sys/libkern.h>
89 # include <sys/systm.h>
91 extern struct callout_handle fr_slowtimer_ch
;
94 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
95 # include <sys/callout.h>
96 extern struct callout fr_slowtimer_ch
;
98 #if defined(__OpenBSD__)
99 # include <sys/timeout.h>
100 extern struct timeout fr_slowtimer_ch
;
102 /* END OF INCLUDES */
105 #if defined(__NetBSD__)
106 #include <sys/cdefs.h>
107 __KERNEL_RCSID(0, "$NetBSD$");
109 static const char sccsid
[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
110 static const char rcsid
[] = "@(#)Id: ip_frag.c,v 2.77.2.17 2009/05/13 19:10:57 darrenr Exp";
115 ipfr_t
*ipfr_list
= NULL
;
116 ipfr_t
**ipfr_tail
= &ipfr_list
;
118 ipfr_t
*ipfr_natlist
= NULL
;
119 ipfr_t
**ipfr_nattail
= &ipfr_natlist
;
121 ipfr_t
*ipfr_ipidlist
= NULL
;
122 ipfr_t
**ipfr_ipidtail
= &ipfr_ipidlist
;
124 static ipfr_t
**ipfr_heads
;
125 static ipfr_t
**ipfr_nattab
;
126 static ipfr_t
**ipfr_ipidtab
;
128 static ipfrstat_t ipfr_stats
;
129 static int ipfr_inuse
= 0;
130 int ipfr_size
= IPFT_SIZE
;
132 int fr_ipfrttl
= 120; /* 60 seconds */
133 int fr_frag_lock
= 0;
134 int fr_frag_init
= 0;
138 static INLINE
int ipfr_index
__P((fr_info_t
*, ipfr_t
*));
139 static ipfr_t
*ipfr_newfrag
__P((fr_info_t
*, u_32_t
, ipfr_t
**));
140 static ipfr_t
*fr_fraglookup
__P((fr_info_t
*, ipfr_t
**));
141 static void fr_fragdelete
__P((ipfr_t
*, ipfr_t
***));
142 static void fr_fragfree
__P((ipfr_t
*));
145 /* ------------------------------------------------------------------------ */
146 /* Function: fr_fraginit */
147 /* Returns: int - 0 == success, -1 == error */
148 /* Parameters: Nil */
150 /* Initialise the hash tables for the fragment cache lookups. */
151 /* ------------------------------------------------------------------------ */
154 KMALLOCS(ipfr_heads
, ipfr_t
**, ipfr_size
* sizeof(ipfr_t
*));
155 if (ipfr_heads
== NULL
)
157 bzero((char *)ipfr_heads
, ipfr_size
* sizeof(ipfr_t
*));
159 KMALLOCS(ipfr_nattab
, ipfr_t
**, ipfr_size
* sizeof(ipfr_t
*));
160 if (ipfr_nattab
== NULL
)
162 bzero((char *)ipfr_nattab
, ipfr_size
* sizeof(ipfr_t
*));
164 KMALLOCS(ipfr_ipidtab
, ipfr_t
**, ipfr_size
* sizeof(ipfr_t
*));
165 if (ipfr_ipidtab
== NULL
)
167 bzero((char *)ipfr_ipidtab
, ipfr_size
* sizeof(ipfr_t
*));
169 RWLOCK_INIT(&ipf_frag
, "ipf fragment rwlock");
176 /* ------------------------------------------------------------------------ */
177 /* Function: fr_fragunload */
179 /* Parameters: Nil */
181 /* Free all memory allocated whilst running and from initialisation. */
182 /* ------------------------------------------------------------------------ */
185 if (fr_frag_init
== 1) {
188 RW_DESTROY(&ipf_frag
);
192 if (ipfr_heads
!= NULL
)
193 KFREES(ipfr_heads
, ipfr_size
* sizeof(ipfr_t
*));
196 if (ipfr_nattab
!= NULL
)
197 KFREES(ipfr_nattab
, ipfr_size
* sizeof(ipfr_t
*));
200 if (ipfr_ipidtab
!= NULL
)
201 KFREES(ipfr_ipidtab
, ipfr_size
* sizeof(ipfr_t
*));
206 /* ------------------------------------------------------------------------ */
207 /* Function: fr_fragstats */
208 /* Returns: ipfrstat_t* - pointer to struct with current frag stats */
209 /* Parameters: Nil */
211 /* Updates ipfr_stats with current information and returns a pointer to it */
212 /* ------------------------------------------------------------------------ */
213 ipfrstat_t
*fr_fragstats()
215 ipfr_stats
.ifs_table
= ipfr_heads
;
216 ipfr_stats
.ifs_nattab
= ipfr_nattab
;
217 ipfr_stats
.ifs_inuse
= ipfr_inuse
;
222 /* ------------------------------------------------------------------------ */
223 /* Function: ipfr_index */
224 /* Returns: int - index in fragment table for given packet */
225 /* Parameters: fin(I) - pointer to packet information */
226 /* frag(O) - pointer to ipfr_t structure to fill */
228 /* Compute the index in the fragment table while filling the per packet */
229 /* part of the fragment state. */
230 /* ------------------------------------------------------------------------ */
231 static INLINE
int ipfr_index(fin
, frag
)
238 * For fragments, we record protocol, packet id, TOS and both IP#'s
239 * (these should all be the same for all fragments of a packet).
241 * build up a hash value to index the table with.
245 if (fin
->fin_v
== 6) {
246 ip6_t
*ip6
= (ip6_t
*)fin
->fin_ip
;
248 frag
->ipfr_p
= fin
->fin_fi
.fi_p
;
249 frag
->ipfr_id
= fin
->fin_id
;
250 frag
->ipfr_tos
= ip6
->ip6_flow
& IPV6_FLOWINFO_MASK
;
251 frag
->ipfr_src
.in6
= ip6
->ip6_src
;
252 frag
->ipfr_dst
.in6
= ip6
->ip6_dst
;
256 ip_t
*ip
= fin
->fin_ip
;
258 frag
->ipfr_p
= ip
->ip_p
;
259 frag
->ipfr_id
= ip
->ip_id
;
260 frag
->ipfr_tos
= ip
->ip_tos
;
261 frag
->ipfr_src
.in4
.s_addr
= ip
->ip_src
.s_addr
;
262 frag
->ipfr_src
.i6
[1] = 0;
263 frag
->ipfr_src
.i6
[2] = 0;
264 frag
->ipfr_src
.i6
[3] = 0;
265 frag
->ipfr_dst
.in4
.s_addr
= ip
->ip_dst
.s_addr
;
266 frag
->ipfr_dst
.i6
[1] = 0;
267 frag
->ipfr_dst
.i6
[2] = 0;
268 frag
->ipfr_dst
.i6
[3] = 0;
270 frag
->ipfr_ifp
= fin
->fin_ifp
;
271 frag
->ipfr_optmsk
= fin
->fin_fi
.fi_optmsk
& IPF_OPTCOPY
;
272 frag
->ipfr_secmsk
= fin
->fin_fi
.fi_secmsk
;
273 frag
->ipfr_auth
= fin
->fin_fi
.fi_auth
;
276 idx
+= frag
->ipfr_id
;
277 idx
+= frag
->ipfr_src
.i6
[0];
278 idx
+= frag
->ipfr_src
.i6
[1];
279 idx
+= frag
->ipfr_src
.i6
[2];
280 idx
+= frag
->ipfr_src
.i6
[3];
281 idx
+= frag
->ipfr_dst
.i6
[0];
282 idx
+= frag
->ipfr_dst
.i6
[1];
283 idx
+= frag
->ipfr_dst
.i6
[2];
284 idx
+= frag
->ipfr_dst
.i6
[3];
292 /* ------------------------------------------------------------------------ */
293 /* Function: ipfr_newfrag */
294 /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */
295 /* Parameters: fin(I) - pointer to packet information */
296 /* table(I) - pointer to frag table to add to */
298 /* Add a new entry to the fragment cache, registering it as having come */
299 /* through this box, with the result of the filter operation. */
300 /* ------------------------------------------------------------------------ */
301 static ipfr_t
*ipfr_newfrag(fin
, pass
, table
)
310 if (ipfr_inuse
>= ipfr_size
)
313 if ((fin
->fin_flx
& (FI_FRAG
|FI_BAD
)) != FI_FRAG
)
316 if (pass
& FR_FRSTRICT
)
317 if (fin
->fin_off
!= 0)
320 idx
= ipfr_index(fin
, &frag
);
323 * first, make sure it isn't already there...
325 for (fra
= table
[idx
]; (fra
!= NULL
); fra
= fra
->ipfr_hnext
)
326 if (!bcmp((char *)&frag
.ipfr_ifp
, (char *)&fra
->ipfr_ifp
,
328 ipfr_stats
.ifs_exists
++;
333 * allocate some memory, if possible, if not, just record that we
336 KMALLOC(fra
, ipfr_t
*);
338 ipfr_stats
.ifs_nomem
++;
345 MUTEX_ENTER(&fr
->fr_lock
);
347 MUTEX_EXIT(&fr
->fr_lock
);
351 * Insert the fragment into the fragment table, copy the struct used
352 * in the search using bcopy rather than reassign each field.
353 * Set the ttl to the default.
355 if ((fra
->ipfr_hnext
= table
[idx
]) != NULL
)
356 table
[idx
]->ipfr_hprev
= &fra
->ipfr_hnext
;
357 fra
->ipfr_hprev
= table
+ idx
;
358 fra
->ipfr_data
= NULL
;
360 bcopy((char *)&frag
.ipfr_ifp
, (char *)&fra
->ipfr_ifp
, IPFR_CMPSZ
);
361 fra
->ipfr_ttl
= fr_ticks
+ fr_ipfrttl
;
364 * Compute the offset of the expected start of the next packet.
366 off
= fin
->fin_off
>> 3;
369 fra
->ipfr_off
= off
+ (fin
->fin_dlen
>> 3);
370 fra
->ipfr_pass
= pass
;
372 ipfr_stats
.ifs_new
++;
378 /* ------------------------------------------------------------------------ */
379 /* Function: fr_newfrag */
380 /* Returns: int - 0 == success, -1 == error */
381 /* Parameters: fin(I) - pointer to packet information */
383 /* Add a new entry to the fragment cache table based on the current packet */
384 /* ------------------------------------------------------------------------ */
385 int fr_newfrag(fin
, pass
)
391 if (fr_frag_lock
!= 0)
394 WRITE_ENTER(&ipf_frag
);
395 fra
= ipfr_newfrag(fin
, pass
, ipfr_heads
);
398 fra
->ipfr_prev
= ipfr_tail
;
399 ipfr_tail
= &fra
->ipfr_next
;
400 if (ipfr_list
== NULL
)
402 fra
->ipfr_next
= NULL
;
404 RWLOCK_EXIT(&ipf_frag
);
409 /* ------------------------------------------------------------------------ */
410 /* Function: fr_nat_newfrag */
411 /* Returns: int - 0 == success, -1 == error */
412 /* Parameters: fin(I) - pointer to packet information */
413 /* nat(I) - pointer to NAT structure */
415 /* Create a new NAT fragment cache entry based on the current packet and */
416 /* the NAT structure for this "session". */
417 /* ------------------------------------------------------------------------ */
418 int fr_nat_newfrag(fin
, pass
, nat
)
425 if (fr_frag_lock
!= 0)
428 WRITE_ENTER(&ipf_natfrag
);
429 fra
= ipfr_newfrag(fin
, pass
, ipfr_nattab
);
431 fra
->ipfr_data
= nat
;
434 fra
->ipfr_prev
= ipfr_nattail
;
435 ipfr_nattail
= &fra
->ipfr_next
;
436 fra
->ipfr_next
= NULL
;
438 RWLOCK_EXIT(&ipf_natfrag
);
443 /* ------------------------------------------------------------------------ */
444 /* Function: fr_ipid_newfrag */
445 /* Returns: int - 0 == success, -1 == error */
446 /* Parameters: fin(I) - pointer to packet information */
447 /* ipid(I) - new IP ID for this fragmented packet */
449 /* Create a new fragment cache entry for this packet and store, as a data */
450 /* pointer, the new IP ID value. */
451 /* ------------------------------------------------------------------------ */
452 int fr_ipid_newfrag(fin
, ipid
)
461 WRITE_ENTER(&ipf_ipidfrag
);
462 fra
= ipfr_newfrag(fin
, 0, ipfr_ipidtab
);
464 fra
->ipfr_data
= (void *)(intptr_t)ipid
;
465 *ipfr_ipidtail
= fra
;
466 fra
->ipfr_prev
= ipfr_ipidtail
;
467 ipfr_ipidtail
= &fra
->ipfr_next
;
468 fra
->ipfr_next
= NULL
;
470 RWLOCK_EXIT(&ipf_ipidfrag
);
475 /* ------------------------------------------------------------------------ */
476 /* Function: fr_fraglookup */
477 /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */
478 /* matching entry in the frag table, else NULL */
479 /* Parameters: fin(I) - pointer to packet information */
480 /* table(I) - pointer to fragment cache table to search */
482 /* Check the fragment cache to see if there is already a record of this */
483 /* packet with its filter result known. */
484 /* ------------------------------------------------------------------------ */
485 static ipfr_t
*fr_fraglookup(fin
, table
)
492 if ((fin
->fin_flx
& (FI_FRAG
|FI_BAD
)) != FI_FRAG
)
496 * For fragments, we record protocol, packet id, TOS and both IP#'s
497 * (these should all be the same for all fragments of a packet).
499 * build up a hash value to index the table with.
501 idx
= ipfr_index(fin
, &frag
);
503 frag
.ipfr_optmsk
= fin
->fin_fi
.fi_optmsk
& IPF_OPTCOPY
;
504 frag
.ipfr_secmsk
= fin
->fin_fi
.fi_secmsk
;
505 frag
.ipfr_auth
= fin
->fin_fi
.fi_auth
;
508 * check the table, careful to only compare the right amount of data
510 for (f
= table
[idx
]; f
; f
= f
->ipfr_hnext
)
511 if (!bcmp((char *)&frag
.ipfr_ifp
, (char *)&f
->ipfr_ifp
,
516 * We don't want to let short packets match because
517 * they could be compromising the security of other
518 * rules that want to match on layer 4 fields (and
519 * can't because they have been fragmented off.)
520 * Why do this check here? The counter acts as an
521 * indicator of this kind of attack, whereas if it was
522 * elsewhere, it wouldn't know if other matching
523 * packets had been seen.
525 if (fin
->fin_flx
& FI_SHORT
) {
526 ATOMIC_INCL(ipfr_stats
.ifs_short
);
531 * XXX - We really need to be guarding against the
532 * retransmission of (src,dst,id,offset-range) here
533 * because a fragmented packet is never resent with
534 * the same IP ID# (or shouldn't).
536 off
= fin
->fin_off
>> 3;
539 ATOMIC_INCL(ipfr_stats
.ifs_retrans0
);
545 if (f
!= table
[idx
]) {
549 * Move fragment info. to the top of the list
550 * to speed up searches. First, delink...
553 (*fp
) = f
->ipfr_hnext
;
554 if (f
->ipfr_hnext
!= NULL
)
555 f
->ipfr_hnext
->ipfr_hprev
= fp
;
557 * Then put back at the top of the chain.
559 f
->ipfr_hnext
= table
[idx
];
560 table
[idx
]->ipfr_hprev
= &f
->ipfr_hnext
;
561 f
->ipfr_hprev
= table
+ idx
;
566 * If we've follwed the fragments, and this is the
567 * last (in order), shrink expiration time.
569 if (off
== f
->ipfr_off
) {
570 if (!(fin
->fin_flx
& FI_MOREFRAG
))
571 f
->ipfr_ttl
= fr_ticks
+ 1;
572 f
->ipfr_off
= (fin
->fin_dlen
>> 3) + off
;
573 } else if (f
->ipfr_pass
& FR_FRSTRICT
)
575 ATOMIC_INCL(ipfr_stats
.ifs_hits
);
582 /* ------------------------------------------------------------------------ */
583 /* Function: fr_nat_knownfrag */
584 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */
585 /* match found, else NULL */
586 /* Parameters: fin(I) - pointer to packet information */
588 /* Functional interface for NAT lookups of the NAT fragment cache */
589 /* ------------------------------------------------------------------------ */
590 nat_t
*fr_nat_knownfrag(fin
)
596 if ((fr_frag_lock
) || !ipfr_natlist
)
598 READ_ENTER(&ipf_natfrag
);
599 ipf
= fr_fraglookup(fin
, ipfr_nattab
);
601 nat
= ipf
->ipfr_data
;
603 * This is the last fragment for this packet.
605 if ((ipf
->ipfr_ttl
== fr_ticks
+ 1) && (nat
!= NULL
)) {
606 nat
->nat_data
= NULL
;
607 ipf
->ipfr_data
= NULL
;
611 RWLOCK_EXIT(&ipf_natfrag
);
616 /* ------------------------------------------------------------------------ */
617 /* Function: fr_ipid_knownfrag */
618 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */
619 /* return 0xfffffff to indicate no match. */
620 /* Parameters: fin(I) - pointer to packet information */
622 /* Functional interface for IP ID lookups of the IP ID fragment cache */
623 /* ------------------------------------------------------------------------ */
624 u_32_t
fr_ipid_knownfrag(fin
)
630 if ((fr_frag_lock
) || !ipfr_ipidlist
)
633 READ_ENTER(&ipf_ipidfrag
);
634 ipf
= fr_fraglookup(fin
, ipfr_ipidtab
);
636 id
= (u_32_t
)(intptr_t)ipf
->ipfr_data
;
639 RWLOCK_EXIT(&ipf_ipidfrag
);
644 /* ------------------------------------------------------------------------ */
645 /* Function: fr_knownfrag */
646 /* Returns: frentry_t* - pointer to filter rule if a match is found in */
647 /* the frag cache table, else NULL. */
648 /* Parameters: fin(I) - pointer to packet information */
649 /* passp(O) - pointer to where to store rule flags resturned */
651 /* Functional interface for normal lookups of the fragment cache. If a */
652 /* match is found, return the rule pointer and flags from the rule, except */
653 /* that if FR_LOGFIRST is set, reset FR_LOG. */
654 /* ------------------------------------------------------------------------ */
655 frentry_t
*fr_knownfrag(fin
, passp
)
659 frentry_t
*fr
= NULL
;
663 if ((fr_frag_lock
) || (ipfr_list
== NULL
))
666 READ_ENTER(&ipf_frag
);
667 fra
= fr_fraglookup(fin
, ipfr_heads
);
673 if ((pass
& FR_LOGFIRST
) != 0)
674 pass
&= ~(FR_LOGFIRST
|FR_LOG
);
678 RWLOCK_EXIT(&ipf_frag
);
683 /* ------------------------------------------------------------------------ */
684 /* Function: fr_forget */
686 /* Parameters: ptr(I) - pointer to data structure */
688 /* Search through all of the fragment cache entries and wherever a pointer */
689 /* is found to match ptr, reset it to NULL. */
690 /* ------------------------------------------------------------------------ */
696 WRITE_ENTER(&ipf_frag
);
697 for (fr
= ipfr_list
; fr
; fr
= fr
->ipfr_next
)
698 if (fr
->ipfr_data
== ptr
)
699 fr
->ipfr_data
= NULL
;
700 RWLOCK_EXIT(&ipf_frag
);
704 /* ------------------------------------------------------------------------ */
705 /* Function: fr_forgetnat */
707 /* Parameters: ptr(I) - pointer to data structure */
709 /* Search through all of the fragment cache entries for NAT and wherever a */
710 /* pointer is found to match ptr, reset it to NULL. */
711 /* ------------------------------------------------------------------------ */
712 void fr_forgetnat(ptr
)
717 WRITE_ENTER(&ipf_natfrag
);
718 for (fr
= ipfr_natlist
; fr
; fr
= fr
->ipfr_next
)
719 if (fr
->ipfr_data
== ptr
)
720 fr
->ipfr_data
= NULL
;
721 RWLOCK_EXIT(&ipf_natfrag
);
725 /* ------------------------------------------------------------------------ */
726 /* Function: fr_fragdelete */
728 /* Parameters: fra(I) - pointer to fragment structure to delete */
729 /* tail(IO) - pointer to the pointer to the tail of the frag */
732 /* Remove a fragment cache table entry from the table & list. Also free */
733 /* the filter rule it is associated with it if it is no longer used as a */
734 /* result of decreasing the reference count. */
735 /* ------------------------------------------------------------------------ */
736 static void fr_fragdelete(fra
, tail
)
737 ipfr_t
*fra
, ***tail
;
741 fra
->ipfr_next
->ipfr_prev
= fra
->ipfr_prev
;
742 *fra
->ipfr_prev
= fra
->ipfr_next
;
743 if (*tail
== &fra
->ipfr_next
)
744 *tail
= fra
->ipfr_prev
;
747 fra
->ipfr_hnext
->ipfr_hprev
= fra
->ipfr_hprev
;
748 *fra
->ipfr_hprev
= fra
->ipfr_hnext
;
750 if (fra
->ipfr_rule
!= NULL
) {
751 (void) fr_derefrule(&fra
->ipfr_rule
);
754 if (fra
->ipfr_ref
<= 0)
759 /* ------------------------------------------------------------------------ */
760 /* Function: fr_fragfree */
762 /* Parameters: fra - pointer to frag structure to free */
764 /* Take care of the details associated with deleting an entry from the frag */
765 /* cache. Currently this just means bumping stats correctly after freeing */
766 /* ------------------------------------------------------------------------ */
767 static void fr_fragfree(fra
)
771 ipfr_stats
.ifs_expire
++;
776 /* ------------------------------------------------------------------------ */
777 /* Function: fr_fragclear */
779 /* Parameters: Nil */
781 /* Free memory in use by fragment state information kept. Do the normal */
782 /* fragment state stuff first and then the NAT-fragment table. */
783 /* ------------------------------------------------------------------------ */
789 WRITE_ENTER(&ipf_frag
);
790 while ((fra
= ipfr_list
) != NULL
) {
792 fr_fragdelete(fra
, &ipfr_tail
);
794 ipfr_tail
= &ipfr_list
;
795 RWLOCK_EXIT(&ipf_frag
);
797 WRITE_ENTER(&ipf_nat
);
798 WRITE_ENTER(&ipf_natfrag
);
799 while ((fra
= ipfr_natlist
) != NULL
) {
800 nat
= fra
->ipfr_data
;
802 if (nat
->nat_data
== fra
)
803 nat
->nat_data
= NULL
;
806 fr_fragdelete(fra
, &ipfr_nattail
);
808 ipfr_nattail
= &ipfr_natlist
;
809 RWLOCK_EXIT(&ipf_natfrag
);
810 RWLOCK_EXIT(&ipf_nat
);
814 /* ------------------------------------------------------------------------ */
815 /* Function: fr_fragexpire */
817 /* Parameters: Nil */
819 /* Expire entries in the fragment cache table that have been there too long */
820 /* ------------------------------------------------------------------------ */
831 WRITE_ENTER(&ipf_frag
);
833 * Go through the entire table, looking for entries to expire,
834 * which is indicated by the ttl being less than or equal to fr_ticks.
836 for (fp
= &ipfr_list
; ((fra
= *fp
) != NULL
); ) {
837 if (fra
->ipfr_ttl
> fr_ticks
)
840 fr_fragdelete(fra
, &ipfr_tail
);
842 RWLOCK_EXIT(&ipf_frag
);
844 WRITE_ENTER(&ipf_ipidfrag
);
845 for (fp
= &ipfr_ipidlist
; ((fra
= *fp
) != NULL
); ) {
846 if (fra
->ipfr_ttl
> fr_ticks
)
849 fr_fragdelete(fra
, &ipfr_ipidtail
);
851 RWLOCK_EXIT(&ipf_ipidfrag
);
854 * Same again for the NAT table, except that if the structure also
855 * still points to a NAT structure, and the NAT structure points back
856 * at the one to be free'd, NULL the reference from the NAT struct.
857 * NOTE: We need to grab both mutex's early, and in this order so as
858 * to prevent a deadlock if both try to expire at the same time.
859 * The extra if() statement here is because it locks out all NAT
860 * operations - no need to do that if there are no entries in this
863 if (ipfr_natlist
!= NULL
) {
864 WRITE_ENTER(&ipf_nat
);
865 WRITE_ENTER(&ipf_natfrag
);
866 for (fp
= &ipfr_natlist
; ((fra
= *fp
) != NULL
); ) {
867 if (fra
->ipfr_ttl
> fr_ticks
)
869 nat
= fra
->ipfr_data
;
871 if (nat
->nat_data
== fra
)
872 nat
->nat_data
= NULL
;
875 fr_fragdelete(fra
, &ipfr_nattail
);
877 RWLOCK_EXIT(&ipf_natfrag
);
878 RWLOCK_EXIT(&ipf_nat
);
884 /* ------------------------------------------------------------------------ */
885 /* Function: fr_slowtimer */
887 /* Parameters: Nil */
889 /* Slowly expire held state for fragments. Timeouts are set * in */
890 /* expectation of this being called twice per second. */
891 /* ------------------------------------------------------------------------ */
892 #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
893 !defined(__osf__) && !defined(linux))
894 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
895 void fr_slowtimer
__P((void *ptr
))
900 READ_ENTER(&ipf_global
);
911 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
912 callout_reset(&fr_slowtimer_ch
, hz
/ 2, fr_slowtimer
, NULL
);
914 # if defined(__OpenBSD__)
915 timeout_add(&fr_slowtimer_ch
, hz
/2);
917 # if (__FreeBSD_version >= 300000)
918 fr_slowtimer_ch
= timeout(fr_slowtimer
, NULL
, hz
/2);
923 timeout(fr_slowtimer
, NULL
, hz
/2);
925 # endif /* FreeBSD */
926 # endif /* OpenBSD */
930 RWLOCK_EXIT(&ipf_global
);
931 # if (BSD < 199103) || !defined(_KERNEL)
935 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
938 /* ------------------------------------------------------------------------ */
939 /* Function: fr_nextfrag */
940 /* Returns: int - 0 == success, else error */
941 /* Parameters: token(I) - pointer to token information for this caller */
942 /* itp(I) - pointer to generic iterator from caller */
943 /* top(I) - top of the fragment list */
944 /* tail(I) - tail of the fragment list */
945 /* lock(I) - fragment cache lock */
947 /* This function is used to interate through the list of entries in the */
948 /* fragment cache. It increases the reference count on the one currently */
949 /* being returned so that the caller can come back and resume from it later.*/
951 /* This function is used for both the NAT fragment cache as well as the ipf */
952 /* fragment cache - hence the reason for passing in top, tail and lock. */
953 /* ------------------------------------------------------------------------ */
954 int fr_nextfrag(token
, itp
, top
, tail
961 ipfr_t
**top
, ***tail
;
966 ipfr_t
*frag
, *next
, zero
;
972 * Retrieve "previous" entry from token and find the next entry.
974 frag
= token
->ipt_data
;
978 next
= frag
->ipfr_next
;
981 * If we found an entry, add reference to it and update token.
982 * Otherwise, zero out data to be returned and NULL out token.
985 ATOMIC_INC(next
->ipfr_ref
);
986 token
->ipt_data
= next
;
988 bzero(&zero
, sizeof(zero
));
990 token
->ipt_data
= NULL
;
994 * Now that we have ref, it's save to give up lock.
999 * Copy out data and clean up references and token as needed.
1001 error
= COPYOUT(next
, itp
->igi_data
, sizeof(*next
));
1004 if (token
->ipt_data
!= NULL
) {
1007 fr_fragderef(&frag
, lock
);
1009 fr_fragderef(&frag
);
1011 if (next
->ipfr_next
== NULL
)
1012 token
->ipt_data
= NULL
;
1018 /* ------------------------------------------------------------------------ */
1019 /* Function: fr_fragderef */
1021 /* Parameters: frp(IO) - pointer to fragment structure to deference */
1022 /* lock(I) - lock associated with the fragment */
1024 /* This function dereferences a fragment structure (ipfr_t). The pointer */
1025 /* passed in will always be reset back to NULL, even if the structure is */
1026 /* not freed, to enforce the notion that the caller is no longer entitled */
1027 /* to use the pointer it is dropping the reference to. */
1028 /* ------------------------------------------------------------------------ */
1029 void fr_fragderef(frp
1046 if (fra
->ipfr_ref
<= 0)