4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 #if defined(KERNEL) || defined(_KERNEL)
14 #include <sys/errno.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
20 # include <sys/timeout.h>
33 #if defined(_KERNEL) && \
34 defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
35 # include <sys/filio.h>
36 # include <sys/fcntl.h>
38 # include <sys/ioctl.h>
41 # include <sys/protosw.h>
43 #include <sys/socket.h>
45 # include <sys/systm.h>
46 # if !defined(__SVR4) && !defined(__svr4__)
47 # include <sys/mbuf.h>
50 #if !defined(__SVR4) && !defined(__svr4__)
51 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
52 # include <sys/kernel.h>
55 # include <sys/byteorder.h>
57 # include <sys/dditypes.h>
59 # include <sys/stream.h>
60 # include <sys/kmem.h>
66 #include <netinet/in.h>
67 #include <netinet/in_systm.h>
68 #include <netinet/ip.h>
70 # include <netinet/ip_var.h>
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_lookup.h"
83 #include "netinet/ip_proxy.h"
84 #include "netinet/ip_sync.h"
88 static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
89 static const char rcsid[] = "@(#)$FreeBSD$";
90 /* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; */
95 static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
96 fr_info_t *, u_32_t, ipfr_t **,
98 static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *));
99 static void ipf_frag_deref __P((void *, ipfr_t **, ipfrwlock_t *));
100 static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
101 ipfr_t **, ipfrwlock_t *));
103 static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
104 fr_info_t *, u_32_t, ipfr_t **));
105 static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **));
106 static void ipf_frag_deref __P((void *, ipfr_t **));
107 static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
110 static void ipf_frag_delete __P((ipf_main_softc_t *, ipfr_t *, ipfr_t ***));
111 static void ipf_frag_free __P((ipf_frag_softc_t *, ipfr_t *));
113 static frentry_t ipfr_block;
115 static ipftuneable_t ipf_frag_tuneables[] = {
116 { { (void *)offsetof(ipf_frag_softc_t, ipfr_size) },
117 "frag_size", 1, 0x7fffffff,
118 stsizeof(ipf_frag_softc_t, ipfr_size),
119 IPFT_WRDISABLED, NULL, NULL },
120 { { (void *)offsetof(ipf_frag_softc_t, ipfr_ttl) },
121 "frag_ttl", 1, 0x7fffffff,
122 stsizeof(ipf_frag_softc_t, ipfr_ttl),
130 #define FBUMP(x) softf->ipfr_stats.x++
131 #define FBUMPD(x) do { softf->ipfr_stats.x++; DT(x); } while (0)
134 /* ------------------------------------------------------------------------ */
135 /* Function: ipf_frag_main_load */
136 /* Returns: int - 0 == success, -1 == error */
137 /* Parameters: Nil */
139 /* Initialise the filter rule associted with blocked packets - everyone can */
141 /* ------------------------------------------------------------------------ */
145 bzero((char *)&ipfr_block, sizeof(ipfr_block));
146 ipfr_block.fr_flags = FR_BLOCK|FR_QUICK;
147 ipfr_block.fr_ref = 1;
153 /* ------------------------------------------------------------------------ */
154 /* Function: ipf_frag_main_unload */
155 /* Returns: int - 0 == success, -1 == error */
156 /* Parameters: Nil */
158 /* A null-op function that exists as a placeholder so that the flow in */
159 /* other functions is obvious. */
160 /* ------------------------------------------------------------------------ */
162 ipf_frag_main_unload()
168 /* ------------------------------------------------------------------------ */
169 /* Function: ipf_frag_soft_create */
170 /* Returns: void * - NULL = failure, else pointer to local context */
171 /* Parameters: softc(I) - pointer to soft context main structure */
173 /* Allocate a new soft context structure to track fragment related info. */
174 /* ------------------------------------------------------------------------ */
177 ipf_frag_soft_create(softc)
178 ipf_main_softc_t *softc;
180 ipf_frag_softc_t *softf;
182 KMALLOC(softf, ipf_frag_softc_t *);
186 bzero((char *)softf, sizeof(*softf));
188 RWLOCK_INIT(&softf->ipfr_ipidfrag, "frag ipid lock");
189 RWLOCK_INIT(&softf->ipfr_frag, "ipf fragment rwlock");
190 RWLOCK_INIT(&softf->ipfr_natfrag, "ipf NAT fragment rwlock");
192 softf->ipf_frag_tune = ipf_tune_array_copy(softf,
193 sizeof(ipf_frag_tuneables),
195 if (softf->ipf_frag_tune == NULL) {
196 ipf_frag_soft_destroy(softc, softf);
199 if (ipf_tune_array_link(softc, softf->ipf_frag_tune) == -1) {
200 ipf_frag_soft_destroy(softc, softf);
204 softf->ipfr_size = IPFT_SIZE;
205 softf->ipfr_ttl = IPF_TTLVAL(60);
206 softf->ipfr_lock = 1;
207 softf->ipfr_tail = &softf->ipfr_list;
208 softf->ipfr_nattail = &softf->ipfr_natlist;
209 softf->ipfr_ipidtail = &softf->ipfr_ipidlist;
215 /* ------------------------------------------------------------------------ */
216 /* Function: ipf_frag_soft_destroy */
218 /* Parameters: softc(I) - pointer to soft context main structure */
219 /* arg(I) - pointer to local context to use */
221 /* Initialise the hash tables for the fragment cache lookups. */
222 /* ------------------------------------------------------------------------ */
224 ipf_frag_soft_destroy(softc, arg)
225 ipf_main_softc_t *softc;
228 ipf_frag_softc_t *softf = arg;
230 RW_DESTROY(&softf->ipfr_ipidfrag);
231 RW_DESTROY(&softf->ipfr_frag);
232 RW_DESTROY(&softf->ipfr_natfrag);
234 if (softf->ipf_frag_tune != NULL) {
235 ipf_tune_array_unlink(softc, softf->ipf_frag_tune);
236 KFREES(softf->ipf_frag_tune, sizeof(ipf_frag_tuneables));
237 softf->ipf_frag_tune = NULL;
244 /* ------------------------------------------------------------------------ */
245 /* Function: ipf_frag_soft_init */
246 /* Returns: int - 0 == success, -1 == error */
247 /* Parameters: softc(I) - pointer to soft context main structure */
248 /* arg(I) - pointer to local context to use */
250 /* Initialise the hash tables for the fragment cache lookups. */
251 /* ------------------------------------------------------------------------ */
254 ipf_frag_soft_init(softc, arg)
255 ipf_main_softc_t *softc;
258 ipf_frag_softc_t *softf = arg;
260 KMALLOCS(softf->ipfr_heads, ipfr_t **,
261 softf->ipfr_size * sizeof(ipfr_t *));
262 if (softf->ipfr_heads == NULL)
265 bzero((char *)softf->ipfr_heads, softf->ipfr_size * sizeof(ipfr_t *));
267 KMALLOCS(softf->ipfr_nattab, ipfr_t **,
268 softf->ipfr_size * sizeof(ipfr_t *));
269 if (softf->ipfr_nattab == NULL)
272 bzero((char *)softf->ipfr_nattab, softf->ipfr_size * sizeof(ipfr_t *));
274 KMALLOCS(softf->ipfr_ipidtab, ipfr_t **,
275 softf->ipfr_size * sizeof(ipfr_t *));
276 if (softf->ipfr_ipidtab == NULL)
279 bzero((char *)softf->ipfr_ipidtab,
280 softf->ipfr_size * sizeof(ipfr_t *));
282 softf->ipfr_lock = 0;
283 softf->ipfr_inited = 1;
289 /* ------------------------------------------------------------------------ */
290 /* Function: ipf_frag_soft_fini */
291 /* Returns: int - 0 == success, -1 == error */
292 /* Parameters: softc(I) - pointer to soft context main structure */
293 /* arg(I) - pointer to local context to use */
295 /* Free all memory allocated whilst running and from initialisation. */
296 /* ------------------------------------------------------------------------ */
298 ipf_frag_soft_fini(softc, arg)
299 ipf_main_softc_t *softc;
302 ipf_frag_softc_t *softf = arg;
304 softf->ipfr_lock = 1;
306 if (softf->ipfr_inited == 1) {
307 ipf_frag_clear(softc);
309 softf->ipfr_inited = 0;
312 if (softf->ipfr_heads != NULL)
313 KFREES(softf->ipfr_heads,
314 softf->ipfr_size * sizeof(ipfr_t *));
315 softf->ipfr_heads = NULL;
317 if (softf->ipfr_nattab != NULL)
318 KFREES(softf->ipfr_nattab,
319 softf->ipfr_size * sizeof(ipfr_t *));
320 softf->ipfr_nattab = NULL;
322 if (softf->ipfr_ipidtab != NULL)
323 KFREES(softf->ipfr_ipidtab,
324 softf->ipfr_size * sizeof(ipfr_t *));
325 softf->ipfr_ipidtab = NULL;
331 /* ------------------------------------------------------------------------ */
332 /* Function: ipf_frag_set_lock */
334 /* Parameters: arg(I) - pointer to local context to use */
335 /* tmp(I) - new value for lock */
337 /* Stub function that allows for external manipulation of ipfr_lock */
338 /* ------------------------------------------------------------------------ */
340 ipf_frag_setlock(arg, tmp)
344 ipf_frag_softc_t *softf = arg;
346 softf->ipfr_lock = tmp;
350 /* ------------------------------------------------------------------------ */
351 /* Function: ipf_frag_stats */
352 /* Returns: ipfrstat_t* - pointer to struct with current frag stats */
353 /* Parameters: arg(I) - pointer to local context to use */
355 /* Updates ipfr_stats with current information and returns a pointer to it */
356 /* ------------------------------------------------------------------------ */
361 ipf_frag_softc_t *softf = arg;
363 softf->ipfr_stats.ifs_table = softf->ipfr_heads;
364 softf->ipfr_stats.ifs_nattab = softf->ipfr_nattab;
365 return &softf->ipfr_stats;
369 /* ------------------------------------------------------------------------ */
370 /* Function: ipfr_frag_new */
371 /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */
372 /* Parameters: fin(I) - pointer to packet information */
373 /* table(I) - pointer to frag table to add to */
374 /* lock(I) - pointer to lock to get a write hold of */
376 /* Add a new entry to the fragment cache, registering it as having come */
377 /* through this box, with the result of the filter operation. */
379 /* If this function succeeds, it returns with a write lock held on "lock". */
380 /* If it fails, no lock is held on return. */
381 /* ------------------------------------------------------------------------ */
383 ipfr_frag_new(softc, softf, fin, pass, table
388 ipf_main_softc_t *softc;
389 ipf_frag_softc_t *softf;
397 ipfr_t *fra, frag, *fran;
401 if (softf->ipfr_stats.ifs_inuse >= softf->ipfr_size) {
406 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) {
411 if (pass & FR_FRSTRICT) {
412 if (fin->fin_off != 0) {
413 FBUMPD(ifs_newrestrictnot0);
418 frag.ipfr_v = fin->fin_v;
420 frag.ipfr_p = fin->fin_p;
422 frag.ipfr_id = fin->fin_id;
424 frag.ipfr_source = fin->fin_fi.fi_src;
425 idx += frag.ipfr_src.s_addr;
426 frag.ipfr_dest = fin->fin_fi.fi_dst;
427 idx += frag.ipfr_dst.s_addr;
428 frag.ipfr_ifp = fin->fin_ifp;
430 idx %= softf->ipfr_size;
432 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
433 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
434 frag.ipfr_auth = fin->fin_fi.fi_auth;
436 off = fin->fin_off >> 3;
442 if (fin->fin_v == 6) {
444 ptr = (char *)fin->fin_fraghdr +
445 sizeof(struct ip6_frag);
451 end = fin->fin_plen - (ptr - (char *)fin->fin_ip);
452 frag.ipfr_firstend = end >> 3;
454 frag.ipfr_firstend = 0;
458 * allocate some memory, if possible, if not, just record that we
461 KMALLOC(fran, ipfr_t *);
470 * first, make sure it isn't already there...
472 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
473 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
486 MUTEX_ENTER(&fr->fr_lock);
488 MUTEX_EXIT(&fr->fr_lock);
492 * Insert the fragment into the fragment table, copy the struct used
493 * in the search using bcopy rather than reassign each field.
494 * Set the ttl to the default.
496 if ((fra->ipfr_hnext = table[idx]) != NULL)
497 table[idx]->ipfr_hprev = &fra->ipfr_hnext;
498 fra->ipfr_hprev = table + idx;
499 fra->ipfr_data = NULL;
501 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
502 fra->ipfr_v = fin->fin_v;
503 fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl;
504 fra->ipfr_firstend = frag.ipfr_firstend;
507 * Compute the offset of the expected start of the next packet.
511 fra->ipfr_off = off + (fin->fin_dlen >> 3);
512 fra->ipfr_pass = pass;
515 fra->ipfr_bytes = fin->fin_plen;
522 /* ------------------------------------------------------------------------ */
523 /* Function: ipf_frag_new */
524 /* Returns: int - 0 == success, -1 == error */
525 /* Parameters: fin(I) - pointer to packet information */
527 /* Add a new entry to the fragment cache table based on the current packet */
528 /* ------------------------------------------------------------------------ */
530 ipf_frag_new(softc, fin, pass)
531 ipf_main_softc_t *softc;
535 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
538 if (softf->ipfr_lock != 0)
542 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag);
544 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads);
547 *softf->ipfr_tail = fra;
548 fra->ipfr_prev = softf->ipfr_tail;
549 softf->ipfr_tail = &fra->ipfr_next;
550 fra->ipfr_next = NULL;
551 RWLOCK_EXIT(&softc->ipf_frag);
557 /* ------------------------------------------------------------------------ */
558 /* Function: ipf_frag_natnew */
559 /* Returns: int - 0 == success, -1 == error */
560 /* Parameters: fin(I) - pointer to packet information */
561 /* nat(I) - pointer to NAT structure */
563 /* Create a new NAT fragment cache entry based on the current packet and */
564 /* the NAT structure for this "session". */
565 /* ------------------------------------------------------------------------ */
567 ipf_frag_natnew(softc, fin, pass, nat)
568 ipf_main_softc_t *softc;
573 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
576 if (softf->ipfr_lock != 0)
580 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab,
581 &softf->ipfr_natfrag);
583 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab);
586 fra->ipfr_data = nat;
588 *softf->ipfr_nattail = fra;
589 fra->ipfr_prev = softf->ipfr_nattail;
590 softf->ipfr_nattail = &fra->ipfr_next;
591 fra->ipfr_next = NULL;
592 RWLOCK_EXIT(&softf->ipfr_natfrag);
599 /* ------------------------------------------------------------------------ */
600 /* Function: ipf_frag_ipidnew */
601 /* Returns: int - 0 == success, -1 == error */
602 /* Parameters: fin(I) - pointer to packet information */
603 /* ipid(I) - new IP ID for this fragmented packet */
605 /* Create a new fragment cache entry for this packet and store, as a data */
606 /* pointer, the new IP ID value. */
607 /* ------------------------------------------------------------------------ */
609 ipf_frag_ipidnew(fin, ipid)
613 ipf_main_softc_t *softc = fin->fin_main_soft;
614 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
617 if (softf->ipfr_lock)
621 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag);
623 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab);
626 fra->ipfr_data = (void *)(intptr_t)ipid;
627 *softf->ipfr_ipidtail = fra;
628 fra->ipfr_prev = softf->ipfr_ipidtail;
629 softf->ipfr_ipidtail = &fra->ipfr_next;
630 fra->ipfr_next = NULL;
631 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
637 /* ------------------------------------------------------------------------ */
638 /* Function: ipf_frag_lookup */
639 /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */
640 /* matching entry in the frag table, else NULL */
641 /* Parameters: fin(I) - pointer to packet information */
642 /* table(I) - pointer to fragment cache table to search */
644 /* Check the fragment cache to see if there is already a record of this */
645 /* packet with its filter result known. */
647 /* If this function succeeds, it returns with a write lock held on "lock". */
648 /* If it fails, no lock is held on return. */
649 /* ------------------------------------------------------------------------ */
651 ipf_frag_lookup(softc, softf, fin, table
656 ipf_main_softc_t *softc;
657 ipf_frag_softc_t *softf;
668 * We don't want to let short packets match because they could be
669 * compromising the security of other rules that want to match on
670 * layer 4 fields (and can't because they have been fragmented off.)
671 * Why do this check here? The counter acts as an indicator of this
672 * kind of attack, whereas if it was elsewhere, it wouldn't know if
673 * other matching packets had been seen.
675 if (fin->fin_flx & FI_SHORT) {
680 if ((fin->fin_flx & FI_BAD) != 0) {
686 * For fragments, we record protocol, packet id, TOS and both IP#'s
687 * (these should all be the same for all fragments of a packet).
689 * build up a hash value to index the table with.
691 frag.ipfr_v = fin->fin_v;
693 frag.ipfr_p = fin->fin_p;
695 frag.ipfr_id = fin->fin_id;
697 frag.ipfr_source = fin->fin_fi.fi_src;
698 idx += frag.ipfr_src.s_addr;
699 frag.ipfr_dest = fin->fin_fi.fi_dst;
700 idx += frag.ipfr_dst.s_addr;
701 frag.ipfr_ifp = fin->fin_ifp;
703 idx %= softf->ipfr_size;
705 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
706 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
707 frag.ipfr_auth = fin->fin_fi.fi_auth;
712 * check the table, careful to only compare the right amount of data
714 for (f = table[idx]; f; f = f->ipfr_hnext) {
715 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
720 * XXX - We really need to be guarding against the
721 * retransmission of (src,dst,id,offset-range) here
722 * because a fragmented packet is never resent with
723 * the same IP ID# (or shouldn't).
725 off = fin->fin_off >> 3;
728 FBUMPD(ifs_retrans0);
733 * Case 3. See comment for frpr_fragment6.
735 if ((f->ipfr_firstend != 0) &&
736 (off < f->ipfr_firstend)) {
738 DT2(ifs_overlap, u_short, off,
740 fin->fin_flx |= FI_BAD;
746 if (f != table[idx] && MUTEX_TRY_UPGRADE(lock)) {
750 * Move fragment info. to the top of the list
751 * to speed up searches. First, delink...
754 (*fp) = f->ipfr_hnext;
755 if (f->ipfr_hnext != NULL)
756 f->ipfr_hnext->ipfr_hprev = fp;
758 * Then put back at the top of the chain.
760 f->ipfr_hnext = table[idx];
761 table[idx]->ipfr_hprev = &f->ipfr_hnext;
762 f->ipfr_hprev = table + idx;
764 MUTEX_DOWNGRADE(lock);
768 * If we've follwed the fragments, and this is the
769 * last (in order), shrink expiration time.
771 if (off == f->ipfr_off) {
772 f->ipfr_off = (fin->fin_dlen >> 3) + off;
775 * Well, we could shrink the expiration time
776 * but only if every fragment has been seen
777 * in order upto this, the last. ipfr_badorder
778 * is used here to count those out of order
779 * and if it equals 0 when we get to the last
780 * fragment then we can assume all of the
781 * fragments have been seen and in order.
785 * Doing this properly requires moving it to
786 * the head of the list which is infesible.
788 if ((more == 0) && (f->ipfr_badorder == 0))
789 f->ipfr_ttl = softc->ipf_ticks + 1;
793 FBUMPD(ifs_unordered);
794 if (f->ipfr_pass & FR_FRSTRICT) {
800 f->ipfr_bytes += fin->fin_plen;
812 /* ------------------------------------------------------------------------ */
813 /* Function: ipf_frag_natknown */
814 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */
815 /* match found, else NULL */
816 /* Parameters: fin(I) - pointer to packet information */
818 /* Functional interface for NAT lookups of the NAT fragment cache */
819 /* ------------------------------------------------------------------------ */
821 ipf_frag_natknown(fin)
824 ipf_main_softc_t *softc = fin->fin_main_soft;
825 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
829 if ((softf->ipfr_lock) || !softf->ipfr_natlist)
832 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab,
833 &softf->ipfr_natfrag);
835 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab);
838 nat = ipf->ipfr_data;
840 * This is the last fragment for this packet.
842 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) {
843 nat->nat_data = NULL;
844 ipf->ipfr_data = NULL;
846 RWLOCK_EXIT(&softf->ipfr_natfrag);
853 /* ------------------------------------------------------------------------ */
854 /* Function: ipf_frag_ipidknown */
855 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */
856 /* return 0xfffffff to indicate no match. */
857 /* Parameters: fin(I) - pointer to packet information */
859 /* Functional interface for IP ID lookups of the IP ID fragment cache */
860 /* ------------------------------------------------------------------------ */
862 ipf_frag_ipidknown(fin)
865 ipf_main_softc_t *softc = fin->fin_main_soft;
866 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
870 if (softf->ipfr_lock || !softf->ipfr_ipidlist)
874 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab,
875 &softf->ipfr_ipidfrag);
877 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab);
880 id = (u_32_t)(intptr_t)ipf->ipfr_data;
881 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
888 /* ------------------------------------------------------------------------ */
889 /* Function: ipf_frag_known */
890 /* Returns: frentry_t* - pointer to filter rule if a match is found in */
891 /* the frag cache table, else NULL. */
892 /* Parameters: fin(I) - pointer to packet information */
893 /* passp(O) - pointer to where to store rule flags resturned */
895 /* Functional interface for normal lookups of the fragment cache. If a */
896 /* match is found, return the rule pointer and flags from the rule, except */
897 /* that if FR_LOGFIRST is set, reset FR_LOG. */
898 /* ------------------------------------------------------------------------ */
900 ipf_frag_known(fin, passp)
904 ipf_main_softc_t *softc = fin->fin_main_soft;
905 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
906 frentry_t *fr = NULL;
910 if ((softf->ipfr_lock) || (softf->ipfr_list == NULL))
914 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads,
917 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads);
920 if (fin->fin_flx & FI_BAD) {
922 fin->fin_reason = FRB_BADFRAG;
929 if ((pass & FR_KEEPSTATE) != 0) {
930 fin->fin_flx |= FI_STATE;
932 * Reset the keep state flag here so that we
933 * don't try and add a new state entry because
934 * of a match here. That leads to blocking of
935 * the packet later because the add fails.
937 pass &= ~FR_KEEPSTATE;
939 if ((pass & FR_LOGFIRST) != 0)
940 pass &= ~(FR_LOGFIRST|FR_LOG);
943 RWLOCK_EXIT(&softc->ipf_frag);
949 /* ------------------------------------------------------------------------ */
950 /* Function: ipf_frag_natforget */
952 /* Parameters: softc(I) - pointer to soft context main structure */
953 /* ptr(I) - pointer to data structure */
955 /* Search through all of the fragment cache entries for NAT and wherever a */
956 /* pointer is found to match ptr, reset it to NULL. */
957 /* ------------------------------------------------------------------------ */
959 ipf_frag_natforget(softc, ptr)
960 ipf_main_softc_t *softc;
963 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
966 WRITE_ENTER(&softf->ipfr_natfrag);
967 for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next)
968 if (fr->ipfr_data == ptr)
969 fr->ipfr_data = NULL;
970 RWLOCK_EXIT(&softf->ipfr_natfrag);
974 /* ------------------------------------------------------------------------ */
975 /* Function: ipf_frag_delete */
977 /* Parameters: softc(I) - pointer to soft context main structure */
978 /* fra(I) - pointer to fragment structure to delete */
979 /* tail(IO) - pointer to the pointer to the tail of the frag */
982 /* Remove a fragment cache table entry from the table & list. Also free */
983 /* the filter rule it is associated with it if it is no longer used as a */
984 /* result of decreasing the reference count. */
985 /* ------------------------------------------------------------------------ */
987 ipf_frag_delete(softc, fra, tail)
988 ipf_main_softc_t *softc;
989 ipfr_t *fra, ***tail;
991 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
994 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
995 *fra->ipfr_prev = fra->ipfr_next;
996 if (*tail == &fra->ipfr_next)
997 *tail = fra->ipfr_prev;
1000 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
1001 *fra->ipfr_hprev = fra->ipfr_hnext;
1003 if (fra->ipfr_rule != NULL) {
1004 (void) ipf_derefrule(softc, &fra->ipfr_rule);
1007 if (fra->ipfr_ref <= 0)
1008 ipf_frag_free(softf, fra);
1012 /* ------------------------------------------------------------------------ */
1013 /* Function: ipf_frag_free */
1015 /* Parameters: softf(I) - pointer to fragment context information */
1016 /* fra(I) - pointer to fragment structure to free */
1018 /* Free up a fragment cache entry and bump relevent statistics. */
1019 /* ------------------------------------------------------------------------ */
1021 ipf_frag_free(softf, fra)
1022 ipf_frag_softc_t *softf;
1027 softf->ipfr_stats.ifs_inuse--;
1031 /* ------------------------------------------------------------------------ */
1032 /* Function: ipf_frag_clear */
1034 /* Parameters: softc(I) - pointer to soft context main structure */
1036 /* Free memory in use by fragment state information kept. Do the normal */
1037 /* fragment state stuff first and then the NAT-fragment table. */
1038 /* ------------------------------------------------------------------------ */
1040 ipf_frag_clear(softc)
1041 ipf_main_softc_t *softc;
1043 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1047 WRITE_ENTER(&softc->ipf_frag);
1048 while ((fra = softf->ipfr_list) != NULL) {
1050 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1052 softf->ipfr_tail = &softf->ipfr_list;
1053 RWLOCK_EXIT(&softc->ipf_frag);
1055 WRITE_ENTER(&softc->ipf_nat);
1056 WRITE_ENTER(&softf->ipfr_natfrag);
1057 while ((fra = softf->ipfr_natlist) != NULL) {
1058 nat = fra->ipfr_data;
1060 if (nat->nat_data == fra)
1061 nat->nat_data = NULL;
1064 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1066 softf->ipfr_nattail = &softf->ipfr_natlist;
1067 RWLOCK_EXIT(&softf->ipfr_natfrag);
1068 RWLOCK_EXIT(&softc->ipf_nat);
1072 /* ------------------------------------------------------------------------ */
1073 /* Function: ipf_frag_expire */
1075 /* Parameters: softc(I) - pointer to soft context main structure */
1077 /* Expire entries in the fragment cache table that have been there too long */
1078 /* ------------------------------------------------------------------------ */
1080 ipf_frag_expire(softc)
1081 ipf_main_softc_t *softc;
1083 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1088 if (softf->ipfr_lock)
1092 WRITE_ENTER(&softc->ipf_frag);
1094 * Go through the entire table, looking for entries to expire,
1095 * which is indicated by the ttl being less than or equal to ipf_ticks.
1097 for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) {
1098 if (fra->ipfr_ttl > softc->ipf_ticks)
1101 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1103 RWLOCK_EXIT(&softc->ipf_frag);
1105 WRITE_ENTER(&softf->ipfr_ipidfrag);
1106 for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) {
1107 if (fra->ipfr_ttl > softc->ipf_ticks)
1110 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail);
1112 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
1115 * Same again for the NAT table, except that if the structure also
1116 * still points to a NAT structure, and the NAT structure points back
1117 * at the one to be free'd, NULL the reference from the NAT struct.
1118 * NOTE: We need to grab both mutex's early, and in this order so as
1119 * to prevent a deadlock if both try to expire at the same time.
1120 * The extra if() statement here is because it locks out all NAT
1121 * operations - no need to do that if there are no entries in this
1124 if (softf->ipfr_natlist != NULL) {
1125 WRITE_ENTER(&softc->ipf_nat);
1126 WRITE_ENTER(&softf->ipfr_natfrag);
1127 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) {
1128 if (fra->ipfr_ttl > softc->ipf_ticks)
1130 nat = fra->ipfr_data;
1132 if (nat->nat_data == fra)
1133 nat->nat_data = NULL;
1136 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1138 RWLOCK_EXIT(&softf->ipfr_natfrag);
1139 RWLOCK_EXIT(&softc->ipf_nat);
1145 /* ------------------------------------------------------------------------ */
1146 /* Function: ipf_frag_pkt_next */
1147 /* Returns: int - 0 == success, else error */
1148 /* Parameters: softc(I) - pointer to soft context main structure */
1149 /* token(I) - pointer to token information for this caller */
1150 /* itp(I) - pointer to generic iterator from caller */
1152 /* This function is used to step through the fragment cache list used for */
1153 /* filter rules. The hard work is done by the more generic ipf_frag_next. */
1154 /* ------------------------------------------------------------------------ */
1156 ipf_frag_pkt_next(softc, token, itp)
1157 ipf_main_softc_t *softc;
1161 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1164 return ipf_frag_next(softc, token, itp, &softf->ipfr_list,
1167 return ipf_frag_next(softc, token, itp, &softf->ipfr_list);
1172 /* ------------------------------------------------------------------------ */
1173 /* Function: ipf_frag_nat_next */
1174 /* Returns: int - 0 == success, else error */
1175 /* Parameters: softc(I) - pointer to soft context main structure */
1176 /* token(I) - pointer to token information for this caller */
1177 /* itp(I) - pointer to generic iterator from caller */
1179 /* This function is used to step through the fragment cache list used for */
1180 /* NAT. The hard work is done by the more generic ipf_frag_next. */
1181 /* ------------------------------------------------------------------------ */
1183 ipf_frag_nat_next(softc, token, itp)
1184 ipf_main_softc_t *softc;
1188 ipf_frag_softc_t *softf = softc->ipf_frag_soft;;
1191 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist,
1192 &softf->ipfr_natfrag);
1194 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist);
1198 /* ------------------------------------------------------------------------ */
1199 /* Function: ipf_frag_next */
1200 /* Returns: int - 0 == success, else error */
1201 /* Parameters: softc(I) - pointer to soft context main structure */
1202 /* token(I) - pointer to token information for this caller */
1203 /* itp(I) - pointer to generic iterator from caller */
1204 /* top(I) - top of the fragment list */
1205 /* lock(I) - fragment cache lock */
1207 /* This function is used to interate through the list of entries in the */
1208 /* fragment cache. It increases the reference count on the one currently */
1209 /* being returned so that the caller can come back and resume from it later.*/
1211 /* This function is used for both the NAT fragment cache as well as the ipf */
1212 /* fragment cache - hence the reason for passing in top and lock. */
1213 /* ------------------------------------------------------------------------ */
1215 ipf_frag_next(softc, token, itp, top
1220 ipf_main_softc_t *softc;
1228 ipfr_t *frag, *next, zero;
1231 if (itp->igi_data == NULL) {
1236 if (itp->igi_nitems != 1) {
1241 frag = token->ipt_data;
1248 next = frag->ipfr_next;
1251 ATOMIC_INC(next->ipfr_ref);
1252 token->ipt_data = next;
1254 bzero(&zero, sizeof(zero));
1256 token->ipt_data = NULL;
1258 if (next->ipfr_next == NULL)
1259 ipf_token_mark_complete(token);
1263 error = COPYOUT(next, itp->igi_data, sizeof(*next));
1269 ipf_frag_deref(softc, &frag, lock);
1271 ipf_frag_deref(softc, &frag);
1278 /* ------------------------------------------------------------------------ */
1279 /* Function: ipf_frag_pkt_deref */
1281 /* Parameters: softc(I) - pointer to soft context main structure */
1282 /* data(I) - pointer to frag cache pointer */
1284 /* This function is the external interface for dropping a reference to a */
1285 /* fragment cache entry used by filter rules. */
1286 /* ------------------------------------------------------------------------ */
1288 ipf_frag_pkt_deref(softc, data)
1289 ipf_main_softc_t *softc;
1292 ipfr_t **frp = data;
1295 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1297 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag);
1299 ipf_frag_deref(softc->ipf_frag_soft, frp);
1304 /* ------------------------------------------------------------------------ */
1305 /* Function: ipf_frag_nat_deref */
1307 /* Parameters: softc(I) - pointer to soft context main structure */
1308 /* data(I) - pointer to frag cache pointer */
1310 /* This function is the external interface for dropping a reference to a */
1311 /* fragment cache entry used by NAT table entries. */
1312 /* ------------------------------------------------------------------------ */
1314 ipf_frag_nat_deref(softc, data)
1315 ipf_main_softc_t *softc;
1318 ipfr_t **frp = data;
1321 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1323 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag);
1325 ipf_frag_deref(softc->ipf_frag_soft, frp);
1330 /* ------------------------------------------------------------------------ */
1331 /* Function: ipf_frag_deref */
1333 /* Parameters: frp(IO) - pointer to fragment structure to deference */
1334 /* lock(I) - lock associated with the fragment */
1336 /* This function dereferences a fragment structure (ipfr_t). The pointer */
1337 /* passed in will always be reset back to NULL, even if the structure is */
1338 /* not freed, to enforce the notion that the caller is no longer entitled */
1339 /* to use the pointer it is dropping the reference to. */
1340 /* ------------------------------------------------------------------------ */
1342 ipf_frag_deref(arg, frp
1353 ipf_frag_softc_t *softf = arg;
1361 if (fra->ipfr_ref <= 0)
1362 ipf_frag_free(softf, fra);