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 DT3(ipf_fi_bad_ifs_overlap, fr_info_t *, fin, u_short, off,
742 fin->fin_flx |= FI_BAD;
748 if (f != table[idx] && MUTEX_TRY_UPGRADE(lock)) {
752 * Move fragment info. to the top of the list
753 * to speed up searches. First, delink...
756 (*fp) = f->ipfr_hnext;
757 if (f->ipfr_hnext != NULL)
758 f->ipfr_hnext->ipfr_hprev = fp;
760 * Then put back at the top of the chain.
762 f->ipfr_hnext = table[idx];
763 table[idx]->ipfr_hprev = &f->ipfr_hnext;
764 f->ipfr_hprev = table + idx;
766 MUTEX_DOWNGRADE(lock);
770 * If we've follwed the fragments, and this is the
771 * last (in order), shrink expiration time.
773 if (off == f->ipfr_off) {
774 f->ipfr_off = (fin->fin_dlen >> 3) + off;
777 * Well, we could shrink the expiration time
778 * but only if every fragment has been seen
779 * in order upto this, the last. ipfr_badorder
780 * is used here to count those out of order
781 * and if it equals 0 when we get to the last
782 * fragment then we can assume all of the
783 * fragments have been seen and in order.
787 * Doing this properly requires moving it to
788 * the head of the list which is infesible.
790 if ((more == 0) && (f->ipfr_badorder == 0))
791 f->ipfr_ttl = softc->ipf_ticks + 1;
795 FBUMPD(ifs_unordered);
796 if (f->ipfr_pass & FR_FRSTRICT) {
802 f->ipfr_bytes += fin->fin_plen;
814 /* ------------------------------------------------------------------------ */
815 /* Function: ipf_frag_natknown */
816 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */
817 /* match found, else NULL */
818 /* Parameters: fin(I) - pointer to packet information */
820 /* Functional interface for NAT lookups of the NAT fragment cache */
821 /* ------------------------------------------------------------------------ */
823 ipf_frag_natknown(fin)
826 ipf_main_softc_t *softc = fin->fin_main_soft;
827 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
831 if ((softf->ipfr_lock) || !softf->ipfr_natlist)
834 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab,
835 &softf->ipfr_natfrag);
837 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab);
840 nat = ipf->ipfr_data;
842 * This is the last fragment for this packet.
844 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) {
845 nat->nat_data = NULL;
846 ipf->ipfr_data = NULL;
848 RWLOCK_EXIT(&softf->ipfr_natfrag);
855 /* ------------------------------------------------------------------------ */
856 /* Function: ipf_frag_ipidknown */
857 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */
858 /* return 0xfffffff to indicate no match. */
859 /* Parameters: fin(I) - pointer to packet information */
861 /* Functional interface for IP ID lookups of the IP ID fragment cache */
862 /* ------------------------------------------------------------------------ */
864 ipf_frag_ipidknown(fin)
867 ipf_main_softc_t *softc = fin->fin_main_soft;
868 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
872 if (softf->ipfr_lock || !softf->ipfr_ipidlist)
876 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab,
877 &softf->ipfr_ipidfrag);
879 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab);
882 id = (u_32_t)(intptr_t)ipf->ipfr_data;
883 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
890 /* ------------------------------------------------------------------------ */
891 /* Function: ipf_frag_known */
892 /* Returns: frentry_t* - pointer to filter rule if a match is found in */
893 /* the frag cache table, else NULL. */
894 /* Parameters: fin(I) - pointer to packet information */
895 /* passp(O) - pointer to where to store rule flags resturned */
897 /* Functional interface for normal lookups of the fragment cache. If a */
898 /* match is found, return the rule pointer and flags from the rule, except */
899 /* that if FR_LOGFIRST is set, reset FR_LOG. */
900 /* ------------------------------------------------------------------------ */
902 ipf_frag_known(fin, passp)
906 ipf_main_softc_t *softc = fin->fin_main_soft;
907 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
908 frentry_t *fr = NULL;
912 if ((softf->ipfr_lock) || (softf->ipfr_list == NULL))
916 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads,
919 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads);
922 if (fin->fin_flx & FI_BAD) {
924 fin->fin_reason = FRB_BADFRAG;
925 DT2(ipf_frb_badfrag, fr_info_t *, fin, uint, fra);
932 if ((pass & FR_KEEPSTATE) != 0) {
933 fin->fin_flx |= FI_STATE;
935 * Reset the keep state flag here so that we
936 * don't try and add a new state entry because
937 * of a match here. That leads to blocking of
938 * the packet later because the add fails.
940 pass &= ~FR_KEEPSTATE;
942 if ((pass & FR_LOGFIRST) != 0)
943 pass &= ~(FR_LOGFIRST|FR_LOG);
946 RWLOCK_EXIT(&softc->ipf_frag);
952 /* ------------------------------------------------------------------------ */
953 /* Function: ipf_frag_natforget */
955 /* Parameters: softc(I) - pointer to soft context main structure */
956 /* ptr(I) - pointer to data structure */
958 /* Search through all of the fragment cache entries for NAT and wherever a */
959 /* pointer is found to match ptr, reset it to NULL. */
960 /* ------------------------------------------------------------------------ */
962 ipf_frag_natforget(softc, ptr)
963 ipf_main_softc_t *softc;
966 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
969 WRITE_ENTER(&softf->ipfr_natfrag);
970 for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next)
971 if (fr->ipfr_data == ptr)
972 fr->ipfr_data = NULL;
973 RWLOCK_EXIT(&softf->ipfr_natfrag);
977 /* ------------------------------------------------------------------------ */
978 /* Function: ipf_frag_delete */
980 /* Parameters: softc(I) - pointer to soft context main structure */
981 /* fra(I) - pointer to fragment structure to delete */
982 /* tail(IO) - pointer to the pointer to the tail of the frag */
985 /* Remove a fragment cache table entry from the table & list. Also free */
986 /* the filter rule it is associated with it if it is no longer used as a */
987 /* result of decreasing the reference count. */
988 /* ------------------------------------------------------------------------ */
990 ipf_frag_delete(softc, fra, tail)
991 ipf_main_softc_t *softc;
992 ipfr_t *fra, ***tail;
994 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
997 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
998 *fra->ipfr_prev = fra->ipfr_next;
999 if (*tail == &fra->ipfr_next)
1000 *tail = fra->ipfr_prev;
1002 if (fra->ipfr_hnext)
1003 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
1004 *fra->ipfr_hprev = fra->ipfr_hnext;
1006 if (fra->ipfr_rule != NULL) {
1007 (void) ipf_derefrule(softc, &fra->ipfr_rule);
1010 if (fra->ipfr_ref <= 0)
1011 ipf_frag_free(softf, fra);
1015 /* ------------------------------------------------------------------------ */
1016 /* Function: ipf_frag_free */
1018 /* Parameters: softf(I) - pointer to fragment context information */
1019 /* fra(I) - pointer to fragment structure to free */
1021 /* Free up a fragment cache entry and bump relevent statistics. */
1022 /* ------------------------------------------------------------------------ */
1024 ipf_frag_free(softf, fra)
1025 ipf_frag_softc_t *softf;
1030 softf->ipfr_stats.ifs_inuse--;
1034 /* ------------------------------------------------------------------------ */
1035 /* Function: ipf_frag_clear */
1037 /* Parameters: softc(I) - pointer to soft context main structure */
1039 /* Free memory in use by fragment state information kept. Do the normal */
1040 /* fragment state stuff first and then the NAT-fragment table. */
1041 /* ------------------------------------------------------------------------ */
1043 ipf_frag_clear(softc)
1044 ipf_main_softc_t *softc;
1046 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1050 WRITE_ENTER(&softc->ipf_frag);
1051 while ((fra = softf->ipfr_list) != NULL) {
1053 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1055 softf->ipfr_tail = &softf->ipfr_list;
1056 RWLOCK_EXIT(&softc->ipf_frag);
1058 WRITE_ENTER(&softc->ipf_nat);
1059 WRITE_ENTER(&softf->ipfr_natfrag);
1060 while ((fra = softf->ipfr_natlist) != NULL) {
1061 nat = fra->ipfr_data;
1063 if (nat->nat_data == fra)
1064 nat->nat_data = NULL;
1067 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1069 softf->ipfr_nattail = &softf->ipfr_natlist;
1070 RWLOCK_EXIT(&softf->ipfr_natfrag);
1071 RWLOCK_EXIT(&softc->ipf_nat);
1075 /* ------------------------------------------------------------------------ */
1076 /* Function: ipf_frag_expire */
1078 /* Parameters: softc(I) - pointer to soft context main structure */
1080 /* Expire entries in the fragment cache table that have been there too long */
1081 /* ------------------------------------------------------------------------ */
1083 ipf_frag_expire(softc)
1084 ipf_main_softc_t *softc;
1086 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1091 if (softf->ipfr_lock)
1095 WRITE_ENTER(&softc->ipf_frag);
1097 * Go through the entire table, looking for entries to expire,
1098 * which is indicated by the ttl being less than or equal to ipf_ticks.
1100 for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) {
1101 if (fra->ipfr_ttl > softc->ipf_ticks)
1104 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1106 RWLOCK_EXIT(&softc->ipf_frag);
1108 WRITE_ENTER(&softf->ipfr_ipidfrag);
1109 for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) {
1110 if (fra->ipfr_ttl > softc->ipf_ticks)
1113 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail);
1115 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
1118 * Same again for the NAT table, except that if the structure also
1119 * still points to a NAT structure, and the NAT structure points back
1120 * at the one to be free'd, NULL the reference from the NAT struct.
1121 * NOTE: We need to grab both mutex's early, and in this order so as
1122 * to prevent a deadlock if both try to expire at the same time.
1123 * The extra if() statement here is because it locks out all NAT
1124 * operations - no need to do that if there are no entries in this
1127 if (softf->ipfr_natlist != NULL) {
1128 WRITE_ENTER(&softc->ipf_nat);
1129 WRITE_ENTER(&softf->ipfr_natfrag);
1130 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) {
1131 if (fra->ipfr_ttl > softc->ipf_ticks)
1133 nat = fra->ipfr_data;
1135 if (nat->nat_data == fra)
1136 nat->nat_data = NULL;
1139 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1141 RWLOCK_EXIT(&softf->ipfr_natfrag);
1142 RWLOCK_EXIT(&softc->ipf_nat);
1148 /* ------------------------------------------------------------------------ */
1149 /* Function: ipf_frag_pkt_next */
1150 /* Returns: int - 0 == success, else error */
1151 /* Parameters: softc(I) - pointer to soft context main structure */
1152 /* token(I) - pointer to token information for this caller */
1153 /* itp(I) - pointer to generic iterator from caller */
1155 /* This function is used to step through the fragment cache list used for */
1156 /* filter rules. The hard work is done by the more generic ipf_frag_next. */
1157 /* ------------------------------------------------------------------------ */
1159 ipf_frag_pkt_next(softc, token, itp)
1160 ipf_main_softc_t *softc;
1164 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1167 return ipf_frag_next(softc, token, itp, &softf->ipfr_list,
1170 return ipf_frag_next(softc, token, itp, &softf->ipfr_list);
1175 /* ------------------------------------------------------------------------ */
1176 /* Function: ipf_frag_nat_next */
1177 /* Returns: int - 0 == success, else error */
1178 /* Parameters: softc(I) - pointer to soft context main structure */
1179 /* token(I) - pointer to token information for this caller */
1180 /* itp(I) - pointer to generic iterator from caller */
1182 /* This function is used to step through the fragment cache list used for */
1183 /* NAT. The hard work is done by the more generic ipf_frag_next. */
1184 /* ------------------------------------------------------------------------ */
1186 ipf_frag_nat_next(softc, token, itp)
1187 ipf_main_softc_t *softc;
1191 ipf_frag_softc_t *softf = softc->ipf_frag_soft;;
1194 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist,
1195 &softf->ipfr_natfrag);
1197 return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist);
1201 /* ------------------------------------------------------------------------ */
1202 /* Function: ipf_frag_next */
1203 /* Returns: int - 0 == success, else error */
1204 /* Parameters: softc(I) - pointer to soft context main structure */
1205 /* token(I) - pointer to token information for this caller */
1206 /* itp(I) - pointer to generic iterator from caller */
1207 /* top(I) - top of the fragment list */
1208 /* lock(I) - fragment cache lock */
1210 /* This function is used to interate through the list of entries in the */
1211 /* fragment cache. It increases the reference count on the one currently */
1212 /* being returned so that the caller can come back and resume from it later.*/
1214 /* This function is used for both the NAT fragment cache as well as the ipf */
1215 /* fragment cache - hence the reason for passing in top and lock. */
1216 /* ------------------------------------------------------------------------ */
1218 ipf_frag_next(softc, token, itp, top
1223 ipf_main_softc_t *softc;
1231 ipfr_t *frag, *next, zero;
1234 if (itp->igi_data == NULL) {
1239 if (itp->igi_nitems != 1) {
1244 frag = token->ipt_data;
1251 next = frag->ipfr_next;
1254 ATOMIC_INC(next->ipfr_ref);
1255 token->ipt_data = next;
1257 bzero(&zero, sizeof(zero));
1259 token->ipt_data = NULL;
1261 if (next->ipfr_next == NULL)
1262 ipf_token_mark_complete(token);
1266 error = COPYOUT(next, itp->igi_data, sizeof(*next));
1272 ipf_frag_deref(softc, &frag, lock);
1274 ipf_frag_deref(softc, &frag);
1281 /* ------------------------------------------------------------------------ */
1282 /* Function: ipf_frag_pkt_deref */
1284 /* Parameters: softc(I) - pointer to soft context main structure */
1285 /* data(I) - pointer to frag cache pointer */
1287 /* This function is the external interface for dropping a reference to a */
1288 /* fragment cache entry used by filter rules. */
1289 /* ------------------------------------------------------------------------ */
1291 ipf_frag_pkt_deref(softc, data)
1292 ipf_main_softc_t *softc;
1295 ipfr_t **frp = data;
1298 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1300 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag);
1302 ipf_frag_deref(softc->ipf_frag_soft, frp);
1307 /* ------------------------------------------------------------------------ */
1308 /* Function: ipf_frag_nat_deref */
1310 /* Parameters: softc(I) - pointer to soft context main structure */
1311 /* data(I) - pointer to frag cache pointer */
1313 /* This function is the external interface for dropping a reference to a */
1314 /* fragment cache entry used by NAT table entries. */
1315 /* ------------------------------------------------------------------------ */
1317 ipf_frag_nat_deref(softc, data)
1318 ipf_main_softc_t *softc;
1321 ipfr_t **frp = data;
1324 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1326 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag);
1328 ipf_frag_deref(softc->ipf_frag_soft, frp);
1333 /* ------------------------------------------------------------------------ */
1334 /* Function: ipf_frag_deref */
1336 /* Parameters: frp(IO) - pointer to fragment structure to deference */
1337 /* lock(I) - lock associated with the fragment */
1339 /* This function dereferences a fragment structure (ipfr_t). The pointer */
1340 /* passed in will always be reset back to NULL, even if the structure is */
1341 /* not freed, to enforce the notion that the caller is no longer entitled */
1342 /* to use the pointer it is dropping the reference to. */
1343 /* ------------------------------------------------------------------------ */
1345 ipf_frag_deref(arg, frp
1356 ipf_frag_softc_t *softf = arg;
1364 if (fra->ipfr_ref <= 0)
1365 ipf_frag_free(softf, fra);