xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_frag.c (revision af5f29dd)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 1993-2003 by Darren Reed.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
5ab25eeb5Syz  *
672680cf5SDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
77c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
87c478bd9Sstevel@tonic-gate  */
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL)
117c478bd9Sstevel@tonic-gate # undef KERNEL
127c478bd9Sstevel@tonic-gate # undef _KERNEL
137c478bd9Sstevel@tonic-gate # define        KERNEL	1
147c478bd9Sstevel@tonic-gate # define        _KERNEL	1
157c478bd9Sstevel@tonic-gate #endif
167c478bd9Sstevel@tonic-gate #include <sys/errno.h>
177c478bd9Sstevel@tonic-gate #include <sys/types.h>
187c478bd9Sstevel@tonic-gate #include <sys/param.h>
197c478bd9Sstevel@tonic-gate #include <sys/time.h>
207c478bd9Sstevel@tonic-gate #include <sys/file.h>
217c478bd9Sstevel@tonic-gate #ifdef __hpux
227c478bd9Sstevel@tonic-gate # include <sys/timeout.h>
237c478bd9Sstevel@tonic-gate #endif
247c478bd9Sstevel@tonic-gate #if !defined(_KERNEL)
257c478bd9Sstevel@tonic-gate # include <stdio.h>
267c478bd9Sstevel@tonic-gate # include <string.h>
277c478bd9Sstevel@tonic-gate # include <stdlib.h>
287c478bd9Sstevel@tonic-gate # define _KERNEL
297c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__
307c478bd9Sstevel@tonic-gate struct file;
317c478bd9Sstevel@tonic-gate # endif
327c478bd9Sstevel@tonic-gate # include <sys/uio.h>
337c478bd9Sstevel@tonic-gate # undef _KERNEL
347c478bd9Sstevel@tonic-gate #endif
357c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
367c478bd9Sstevel@tonic-gate # include <sys/filio.h>
377c478bd9Sstevel@tonic-gate # include <sys/fcntl.h>
387c478bd9Sstevel@tonic-gate #else
397c478bd9Sstevel@tonic-gate # include <sys/ioctl.h>
407c478bd9Sstevel@tonic-gate #endif
41ab25eeb5Syz #if !defined(linux)
42ab25eeb5Syz # include <sys/protosw.h>
43ab25eeb5Syz #endif
447c478bd9Sstevel@tonic-gate #include <sys/socket.h>
457c478bd9Sstevel@tonic-gate #if defined(_KERNEL)
467c478bd9Sstevel@tonic-gate # include <sys/systm.h>
477c478bd9Sstevel@tonic-gate # if !defined(__SVR4) && !defined(__svr4__)
487c478bd9Sstevel@tonic-gate #  include <sys/mbuf.h>
497c478bd9Sstevel@tonic-gate # endif
507c478bd9Sstevel@tonic-gate #endif
517c478bd9Sstevel@tonic-gate #if !defined(__SVR4) && !defined(__svr4__)
52ab25eeb5Syz # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
537c478bd9Sstevel@tonic-gate #  include <sys/kernel.h>
547c478bd9Sstevel@tonic-gate # endif
557c478bd9Sstevel@tonic-gate #else
567c478bd9Sstevel@tonic-gate # include <sys/byteorder.h>
577c478bd9Sstevel@tonic-gate # ifdef _KERNEL
587c478bd9Sstevel@tonic-gate #  include <sys/dditypes.h>
597c478bd9Sstevel@tonic-gate # endif
607c478bd9Sstevel@tonic-gate # include <sys/stream.h>
617c478bd9Sstevel@tonic-gate # include <sys/kmem.h>
627c478bd9Sstevel@tonic-gate #endif
637c478bd9Sstevel@tonic-gate #include <net/if.h>
647c478bd9Sstevel@tonic-gate #ifdef sun
657c478bd9Sstevel@tonic-gate # include <net/af.h>
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate #include <net/route.h>
687c478bd9Sstevel@tonic-gate #include <netinet/in.h>
697c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
707c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
71ab25eeb5Syz #if !defined(linux)
72ab25eeb5Syz # include <netinet/ip_var.h>
73ab25eeb5Syz #endif
747c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
757c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
767c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
777c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h"
78ab25eeb5Syz #include <netinet/tcpip.h>
797c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h"
807c478bd9Sstevel@tonic-gate #include "netinet/ip_nat.h"
817c478bd9Sstevel@tonic-gate #include "netinet/ip_frag.h"
827c478bd9Sstevel@tonic-gate #include "netinet/ip_state.h"
837c478bd9Sstevel@tonic-gate #include "netinet/ip_auth.h"
84f4b3ec61Sdh #include "netinet/ipf_stack.h"
857c478bd9Sstevel@tonic-gate #if (__FreeBSD_version >= 300000)
867c478bd9Sstevel@tonic-gate # include <sys/malloc.h>
877c478bd9Sstevel@tonic-gate # if defined(_KERNEL)
887c478bd9Sstevel@tonic-gate #  ifndef IPFILTER_LKM
897c478bd9Sstevel@tonic-gate #   include <sys/libkern.h>
907c478bd9Sstevel@tonic-gate #   include <sys/systm.h>
917c478bd9Sstevel@tonic-gate #  endif
927c478bd9Sstevel@tonic-gate extern struct callout_handle fr_slowtimer_ch;
937c478bd9Sstevel@tonic-gate # endif
947c478bd9Sstevel@tonic-gate #endif
957c478bd9Sstevel@tonic-gate #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
967c478bd9Sstevel@tonic-gate # include <sys/callout.h>
977c478bd9Sstevel@tonic-gate extern struct callout fr_slowtimer_ch;
987c478bd9Sstevel@tonic-gate #endif
997c478bd9Sstevel@tonic-gate #if defined(__OpenBSD__)
1007c478bd9Sstevel@tonic-gate # include <sys/timeout.h>
1017c478bd9Sstevel@tonic-gate extern struct timeout fr_slowtimer_ch;
1027c478bd9Sstevel@tonic-gate #endif
103ab25eeb5Syz /* END OF INCLUDES */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #if !defined(lint)
1067c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)ip_frag.c	1.11 3/24/96 (C) 1993-2000 Darren Reed";
107ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $";
1087c478bd9Sstevel@tonic-gate #endif
1097c478bd9Sstevel@tonic-gate 
11072680cf5SDarren Reed static INLINE int ipfr_index __P((fr_info_t *, ipfr_t *));
1117c478bd9Sstevel@tonic-gate static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
1127c478bd9Sstevel@tonic-gate static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
113f4b3ec61Sdh static void fr_fragdelete __P((ipfr_t *, ipfr_t ***, ipf_stack_t *));
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
1167c478bd9Sstevel@tonic-gate /* Function:    fr_fraginit                                                 */
1177c478bd9Sstevel@tonic-gate /* Returns:     int - 0 == success, -1 == error                             */
1187c478bd9Sstevel@tonic-gate /* Parameters:  Nil                                                         */
1197c478bd9Sstevel@tonic-gate /*                                                                          */
1207c478bd9Sstevel@tonic-gate /* Initialise the hash tables for the fragment cache lookups.               */
1217c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_fraginit(ifs)122f4b3ec61Sdh int fr_fraginit(ifs)
123f4b3ec61Sdh ipf_stack_t *ifs;
1247c478bd9Sstevel@tonic-gate {
125f4b3ec61Sdh 	ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list;
126f4b3ec61Sdh 	ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist;
127f4b3ec61Sdh 	ifs->ifs_ipfr_ipidtail = &ifs->ifs_ipfr_ipidlist;
1288128a42dSan 	/* the IP frag related variables are set in ipftuneable_setdefs() to
1298128a42dSan 	 * their default values
1308128a42dSan 	 */
131f4b3ec61Sdh 
132f4b3ec61Sdh 	KMALLOCS(ifs->ifs_ipfr_heads, ipfr_t **,
133f4b3ec61Sdh 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
134f4b3ec61Sdh 	if (ifs->ifs_ipfr_heads == NULL)
1357c478bd9Sstevel@tonic-gate 		return -1;
136f4b3ec61Sdh 	bzero((char *)ifs->ifs_ipfr_heads,
137f4b3ec61Sdh 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1387c478bd9Sstevel@tonic-gate 
139f4b3ec61Sdh 	KMALLOCS(ifs->ifs_ipfr_nattab, ipfr_t **,
140f4b3ec61Sdh 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
141f4b3ec61Sdh 	if (ifs->ifs_ipfr_nattab == NULL)
1427c478bd9Sstevel@tonic-gate 		return -1;
143f4b3ec61Sdh 	bzero((char *)ifs->ifs_ipfr_nattab,
144f4b3ec61Sdh 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1457c478bd9Sstevel@tonic-gate 
146f4b3ec61Sdh 	KMALLOCS(ifs->ifs_ipfr_ipidtab, ipfr_t **,
147f4b3ec61Sdh 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
148f4b3ec61Sdh 	if (ifs->ifs_ipfr_ipidtab == NULL)
1497c478bd9Sstevel@tonic-gate 		return -1;
150f4b3ec61Sdh 	bzero((char *)ifs->ifs_ipfr_ipidtab,
151f4b3ec61Sdh 	    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1527c478bd9Sstevel@tonic-gate 
153f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ipf_frag, "ipf fragment rwlock");
1547663b816Sml 
1557663b816Sml 	/* Initialise frblock with "block in all" */
156f4b3ec61Sdh 	bzero((char *)&ifs->ifs_frblock, sizeof(ifs->ifs_frblock));
157f4b3ec61Sdh 	ifs->ifs_frblock.fr_flags = FR_BLOCK|FR_INQUE;	/* block in */
158f4b3ec61Sdh 	ifs->ifs_frblock.fr_ref = 1;
1597663b816Sml 
160f4b3ec61Sdh 	ifs->ifs_fr_frag_init = 1;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	return 0;
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
1677c478bd9Sstevel@tonic-gate /* Function:    fr_fragunload                                               */
1687c478bd9Sstevel@tonic-gate /* Returns:     Nil                                                         */
1697c478bd9Sstevel@tonic-gate /* Parameters:  Nil                                                         */
1707c478bd9Sstevel@tonic-gate /*                                                                          */
1717c478bd9Sstevel@tonic-gate /* Free all memory allocated whilst running and from initialisation.        */
1727c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_fragunload(ifs)173f4b3ec61Sdh void fr_fragunload(ifs)
174f4b3ec61Sdh ipf_stack_t *ifs;
1757c478bd9Sstevel@tonic-gate {
176f4b3ec61Sdh 	if (ifs->ifs_fr_frag_init == 1) {
177f4b3ec61Sdh 		fr_fragclear(ifs);
1787c478bd9Sstevel@tonic-gate 
179f4b3ec61Sdh 		RW_DESTROY(&ifs->ifs_ipf_frag);
180f4b3ec61Sdh 		ifs->ifs_fr_frag_init = 0;
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
183f4b3ec61Sdh 	if (ifs->ifs_ipfr_heads != NULL) {
184f4b3ec61Sdh 		KFREES(ifs->ifs_ipfr_heads,
185f4b3ec61Sdh 		    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
186f4b3ec61Sdh 	}
187f4b3ec61Sdh 	ifs->ifs_ipfr_heads = NULL;
1887c478bd9Sstevel@tonic-gate 
189f4b3ec61Sdh 	if (ifs->ifs_ipfr_nattab != NULL) {
190f4b3ec61Sdh 		KFREES(ifs->ifs_ipfr_nattab,
191f4b3ec61Sdh 		    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
192f4b3ec61Sdh 	}
193f4b3ec61Sdh 	ifs->ifs_ipfr_nattab = NULL;
1947c478bd9Sstevel@tonic-gate 
195f4b3ec61Sdh 	if (ifs->ifs_ipfr_ipidtab != NULL) {
196f4b3ec61Sdh 		KFREES(ifs->ifs_ipfr_ipidtab,
197f4b3ec61Sdh 		    ifs->ifs_ipfr_size * sizeof(ipfr_t *));
198f4b3ec61Sdh 	}
199f4b3ec61Sdh 	ifs->ifs_ipfr_ipidtab = NULL;
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
2047c478bd9Sstevel@tonic-gate /* Function:    fr_fragstats                                                */
205ab25eeb5Syz /* Returns:     ipfrstat_t* - pointer to struct with current frag stats     */
2067c478bd9Sstevel@tonic-gate /* Parameters:  Nil                                                         */
2077c478bd9Sstevel@tonic-gate /*                                                                          */
2087c478bd9Sstevel@tonic-gate /* Updates ipfr_stats with current information and returns a pointer to it  */
2097c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_fragstats(ifs)210f4b3ec61Sdh ipfrstat_t *fr_fragstats(ifs)
211f4b3ec61Sdh ipf_stack_t *ifs;
2127c478bd9Sstevel@tonic-gate {
213f4b3ec61Sdh 	ifs->ifs_ipfr_stats.ifs_table = ifs->ifs_ipfr_heads;
214f4b3ec61Sdh 	ifs->ifs_ipfr_stats.ifs_nattab = ifs->ifs_ipfr_nattab;
215f4b3ec61Sdh 	ifs->ifs_ipfr_stats.ifs_inuse = ifs->ifs_ipfr_inuse;
216f4b3ec61Sdh 	return &ifs->ifs_ipfr_stats;
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 
22072680cf5SDarren Reed /* ------------------------------------------------------------------------ */
22172680cf5SDarren Reed /* Function:    ipfr_index                                                  */
22272680cf5SDarren Reed /* Returns:     int     - index in fragment table for given packet          */
22372680cf5SDarren Reed /* Parameters:  fin(I)  - pointer to packet information                     */
22472680cf5SDarren Reed /*              frag(O) - pointer to ipfr_t structure to fill               */
22572680cf5SDarren Reed /*                                                                          */
22672680cf5SDarren Reed /* Compute the index in the fragment table while filling the per packet     */
22772680cf5SDarren Reed /* part of the fragment state.                                              */
22872680cf5SDarren Reed /* ------------------------------------------------------------------------ */
ipfr_index(fin,frag)22972680cf5SDarren Reed static INLINE int ipfr_index(fin, frag)
23072680cf5SDarren Reed fr_info_t *fin;
23172680cf5SDarren Reed ipfr_t *frag;
23272680cf5SDarren Reed {
23372680cf5SDarren Reed 	u_int idx;
23472680cf5SDarren Reed 
23572680cf5SDarren Reed 	/*
23672680cf5SDarren Reed 	 * For fragments, we record protocol, packet id, TOS and both IP#'s
23772680cf5SDarren Reed 	 * (these should all be the same for all fragments of a packet).
23872680cf5SDarren Reed 	 *
23972680cf5SDarren Reed 	 * build up a hash value to index the table with.
24072680cf5SDarren Reed 	 */
24172680cf5SDarren Reed 
24272680cf5SDarren Reed #ifdef	USE_INET6
24372680cf5SDarren Reed 	if (fin->fin_v == 6) {
24472680cf5SDarren Reed 		ip6_t *ip6 = (ip6_t *)fin->fin_ip;
24572680cf5SDarren Reed 
24672680cf5SDarren Reed 		frag->ipfr_p = fin->fin_fi.fi_p;
24772680cf5SDarren Reed 		frag->ipfr_id = fin->fin_id;
24872680cf5SDarren Reed 		frag->ipfr_tos = ip6->ip6_flow & IPV6_FLOWINFO_MASK;
24972680cf5SDarren Reed 		frag->ipfr_src.in6 = ip6->ip6_src;
25072680cf5SDarren Reed 		frag->ipfr_dst.in6 = ip6->ip6_dst;
25172680cf5SDarren Reed 	} else
25272680cf5SDarren Reed #endif
25372680cf5SDarren Reed 	{
25472680cf5SDarren Reed 		ip_t *ip = fin->fin_ip;
25572680cf5SDarren Reed 
25672680cf5SDarren Reed 		frag->ipfr_p = ip->ip_p;
25772680cf5SDarren Reed 		frag->ipfr_id = ip->ip_id;
25872680cf5SDarren Reed 		frag->ipfr_tos = ip->ip_tos;
25972680cf5SDarren Reed 		frag->ipfr_src.in4.s_addr = ip->ip_src.s_addr;
26072680cf5SDarren Reed 		frag->ipfr_src.i6[1] = 0;
26172680cf5SDarren Reed 		frag->ipfr_src.i6[2] = 0;
26272680cf5SDarren Reed 		frag->ipfr_src.i6[3] = 0;
26372680cf5SDarren Reed 		frag->ipfr_dst.in4.s_addr = ip->ip_dst.s_addr;
26472680cf5SDarren Reed 		frag->ipfr_dst.i6[1] = 0;
26572680cf5SDarren Reed 		frag->ipfr_dst.i6[2] = 0;
26672680cf5SDarren Reed 		frag->ipfr_dst.i6[3] = 0;
26772680cf5SDarren Reed 	}
26872680cf5SDarren Reed 	frag->ipfr_ifp = fin->fin_ifp;
26972680cf5SDarren Reed 	frag->ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
27072680cf5SDarren Reed 	frag->ipfr_secmsk = fin->fin_fi.fi_secmsk;
27172680cf5SDarren Reed 	frag->ipfr_auth = fin->fin_fi.fi_auth;
27272680cf5SDarren Reed 
27372680cf5SDarren Reed 	idx = frag->ipfr_p;
27472680cf5SDarren Reed 	idx += frag->ipfr_id;
27572680cf5SDarren Reed 	idx += frag->ipfr_src.i6[0];
27672680cf5SDarren Reed 	idx += frag->ipfr_src.i6[1];
27772680cf5SDarren Reed 	idx += frag->ipfr_src.i6[2];
27872680cf5SDarren Reed 	idx += frag->ipfr_src.i6[3];
27972680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[0];
28072680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[1];
28172680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[2];
28272680cf5SDarren Reed 	idx += frag->ipfr_dst.i6[3];
28372680cf5SDarren Reed 	idx *= 127;
28472680cf5SDarren Reed 	idx %= IPFT_SIZE;
28572680cf5SDarren Reed 
28672680cf5SDarren Reed 	return idx;
28772680cf5SDarren Reed }
28872680cf5SDarren Reed 
28972680cf5SDarren Reed 
2907c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
2917c478bd9Sstevel@tonic-gate /* Function:    ipfr_newfrag                                                */
2927c478bd9Sstevel@tonic-gate /* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
2937c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)   - pointer to packet information                    */
2947c478bd9Sstevel@tonic-gate /*              table(I) - pointer to frag table to add to                  */
2957c478bd9Sstevel@tonic-gate /*                                                                          */
2967c478bd9Sstevel@tonic-gate /* Add a new entry to the fragment cache, registering it as having come     */
2977c478bd9Sstevel@tonic-gate /* through this box, with the result of the filter operation.               */
2987c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
ipfr_newfrag(fin,pass,table)2997c478bd9Sstevel@tonic-gate static ipfr_t *ipfr_newfrag(fin, pass, table)
3007c478bd9Sstevel@tonic-gate fr_info_t *fin;
3017c478bd9Sstevel@tonic-gate u_32_t pass;
3027c478bd9Sstevel@tonic-gate ipfr_t *table[];
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate 	ipfr_t *fra, frag;
3057c478bd9Sstevel@tonic-gate 	u_int idx, off;
306f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
3077c478bd9Sstevel@tonic-gate 
308bd5ba10fSan 	if (ifs->ifs_ipfr_inuse >= ifs->ifs_ipfr_size)
3097c478bd9Sstevel@tonic-gate 		return NULL;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
3127c478bd9Sstevel@tonic-gate 		return NULL;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	if (pass & FR_FRSTRICT)
3157663b816Sml 		if (fin->fin_off != 0)
3167c478bd9Sstevel@tonic-gate 			return NULL;
3177c478bd9Sstevel@tonic-gate 
31872680cf5SDarren Reed 	idx = ipfr_index(fin, &frag);
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/*
3217c478bd9Sstevel@tonic-gate 	 * first, make sure it isn't already there...
3227c478bd9Sstevel@tonic-gate 	 */
3237c478bd9Sstevel@tonic-gate 	for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
3247c478bd9Sstevel@tonic-gate 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
3257c478bd9Sstevel@tonic-gate 			  IPFR_CMPSZ)) {
326f4b3ec61Sdh 			ifs->ifs_ipfr_stats.ifs_exists++;
3277c478bd9Sstevel@tonic-gate 			return NULL;
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * allocate some memory, if possible, if not, just record that we
3327c478bd9Sstevel@tonic-gate 	 * failed to do so.
3337c478bd9Sstevel@tonic-gate 	 */
3347c478bd9Sstevel@tonic-gate 	KMALLOC(fra, ipfr_t *);
3357c478bd9Sstevel@tonic-gate 	if (fra == NULL) {
336f4b3ec61Sdh 		ifs->ifs_ipfr_stats.ifs_nomem++;
3377c478bd9Sstevel@tonic-gate 		return NULL;
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
340ab25eeb5Syz 	fra->ipfr_rule = fin->fin_fr;
341ab25eeb5Syz 	if (fra->ipfr_rule != NULL) {
342ab25eeb5Syz 
343ab25eeb5Syz 		frentry_t *fr;
344ab25eeb5Syz 
345ab25eeb5Syz 		fr = fin->fin_fr;
346ab25eeb5Syz 		MUTEX_ENTER(&fr->fr_lock);
347ab25eeb5Syz 		fr->fr_ref++;
348ab25eeb5Syz 		MUTEX_EXIT(&fr->fr_lock);
3497663b816Sml 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/*
3527c478bd9Sstevel@tonic-gate 	 * Insert the fragment into the fragment table, copy the struct used
3537c478bd9Sstevel@tonic-gate 	 * in the search using bcopy rather than reassign each field.
3547c478bd9Sstevel@tonic-gate 	 * Set the ttl to the default.
3557c478bd9Sstevel@tonic-gate 	 */
3567c478bd9Sstevel@tonic-gate 	if ((fra->ipfr_hnext = table[idx]) != NULL)
3577c478bd9Sstevel@tonic-gate 		table[idx]->ipfr_hprev = &fra->ipfr_hnext;
3587c478bd9Sstevel@tonic-gate 	fra->ipfr_hprev = table + idx;
3597c478bd9Sstevel@tonic-gate 	fra->ipfr_data = NULL;
3607c478bd9Sstevel@tonic-gate 	table[idx] = fra;
3617c478bd9Sstevel@tonic-gate 	bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
362f4b3ec61Sdh 	fra->ipfr_ttl = ifs->ifs_fr_ticks + ifs->ifs_fr_ipfrttl;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/*
3657c478bd9Sstevel@tonic-gate 	 * Compute the offset of the expected start of the next packet.
3667c478bd9Sstevel@tonic-gate 	 */
36772680cf5SDarren Reed 	off = fin->fin_off >> 3;
3687663b816Sml 	if (off == 0) {
3697c478bd9Sstevel@tonic-gate 		fra->ipfr_seen0 = 1;
3707663b816Sml 	} else {
3717663b816Sml 		fra->ipfr_seen0 = 0;
3727663b816Sml 	}
373ab25eeb5Syz 	fra->ipfr_off = off + fin->fin_dlen;
3747c478bd9Sstevel@tonic-gate 	fra->ipfr_pass = pass;
375f4b3ec61Sdh 	fra->ipfr_ref = 1;
376f4b3ec61Sdh 	ifs->ifs_ipfr_stats.ifs_new++;
377f4b3ec61Sdh 	ifs->ifs_ipfr_inuse++;
3787c478bd9Sstevel@tonic-gate 	return fra;
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
3837c478bd9Sstevel@tonic-gate /* Function:    fr_newfrag                                                  */
3847c478bd9Sstevel@tonic-gate /* Returns:     int - 0 == success, -1 == error                             */
3857c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)  - pointer to packet information                     */
3867c478bd9Sstevel@tonic-gate /*                                                                          */
3877c478bd9Sstevel@tonic-gate /* Add a new entry to the fragment cache table based on the current packet  */
3887c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_newfrag(fin,pass)3897c478bd9Sstevel@tonic-gate int fr_newfrag(fin, pass)
3907c478bd9Sstevel@tonic-gate u_32_t pass;
3917c478bd9Sstevel@tonic-gate fr_info_t *fin;
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate 	ipfr_t	*fra;
394f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
3957c478bd9Sstevel@tonic-gate 
396f4b3ec61Sdh 	if (ifs->ifs_fr_frag_lock != 0)
397ab25eeb5Syz 		return -1;
3987c478bd9Sstevel@tonic-gate 
399f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_frag);
400f4b3ec61Sdh 	fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_heads);
4017c478bd9Sstevel@tonic-gate 	if (fra != NULL) {
402f4b3ec61Sdh 		*ifs->ifs_ipfr_tail = fra;
403f4b3ec61Sdh 		fra->ipfr_prev = ifs->ifs_ipfr_tail;
404f4b3ec61Sdh 		ifs->ifs_ipfr_tail = &fra->ipfr_next;
405f4b3ec61Sdh 		if (ifs->ifs_ipfr_list == NULL)
406f4b3ec61Sdh 			ifs->ifs_ipfr_list = fra;
4077c478bd9Sstevel@tonic-gate 		fra->ipfr_next = NULL;
4087c478bd9Sstevel@tonic-gate 	}
409f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
4107c478bd9Sstevel@tonic-gate 	return fra ? 0 : -1;
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
4157c478bd9Sstevel@tonic-gate /* Function:    fr_nat_newfrag                                              */
4167c478bd9Sstevel@tonic-gate /* Returns:     int - 0 == success, -1 == error                             */
4177c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)  - pointer to packet information                     */
4187c478bd9Sstevel@tonic-gate /*              nat(I)  - pointer to NAT structure                          */
4197c478bd9Sstevel@tonic-gate /*                                                                          */
4207c478bd9Sstevel@tonic-gate /* Create a new NAT fragment cache entry based on the current packet and    */
4217c478bd9Sstevel@tonic-gate /* the NAT structure for this "session".                                    */
4227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_nat_newfrag(fin,pass,nat)4237c478bd9Sstevel@tonic-gate int fr_nat_newfrag(fin, pass, nat)
4247c478bd9Sstevel@tonic-gate fr_info_t *fin;
4257c478bd9Sstevel@tonic-gate u_32_t pass;
4267c478bd9Sstevel@tonic-gate nat_t *nat;
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	ipfr_t	*fra;
429f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
4307c478bd9Sstevel@tonic-gate 
43172680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock != 0)
4327c478bd9Sstevel@tonic-gate 		return 0;
4337c478bd9Sstevel@tonic-gate 
434f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
435f4b3ec61Sdh 	fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_nattab);
4367c478bd9Sstevel@tonic-gate 	if (fra != NULL) {
4377c478bd9Sstevel@tonic-gate 		fra->ipfr_data = nat;
4387c478bd9Sstevel@tonic-gate 		nat->nat_data = fra;
439f4b3ec61Sdh 		*ifs->ifs_ipfr_nattail = fra;
440f4b3ec61Sdh 		fra->ipfr_prev = ifs->ifs_ipfr_nattail;
441f4b3ec61Sdh 		ifs->ifs_ipfr_nattail = &fra->ipfr_next;
4427c478bd9Sstevel@tonic-gate 		fra->ipfr_next = NULL;
4437c478bd9Sstevel@tonic-gate 	}
444f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
4457c478bd9Sstevel@tonic-gate 	return fra ? 0 : -1;
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
4507c478bd9Sstevel@tonic-gate /* Function:    fr_ipid_newfrag                                             */
4517c478bd9Sstevel@tonic-gate /* Returns:     int - 0 == success, -1 == error                             */
4527c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)  - pointer to packet information                     */
4537c478bd9Sstevel@tonic-gate /*              ipid(I) - new IP ID for this fragmented packet              */
4547c478bd9Sstevel@tonic-gate /*                                                                          */
4557c478bd9Sstevel@tonic-gate /* Create a new fragment cache entry for this packet and store, as a data   */
4567c478bd9Sstevel@tonic-gate /* pointer, the new IP ID value.                                            */
4577c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_ipid_newfrag(fin,ipid)4587c478bd9Sstevel@tonic-gate int fr_ipid_newfrag(fin, ipid)
4597c478bd9Sstevel@tonic-gate fr_info_t *fin;
4607c478bd9Sstevel@tonic-gate u_32_t ipid;
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate 	ipfr_t	*fra;
463f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
4647c478bd9Sstevel@tonic-gate 
465f4b3ec61Sdh 	if (ifs->ifs_fr_frag_lock)
4667c478bd9Sstevel@tonic-gate 		return 0;
4677c478bd9Sstevel@tonic-gate 
468f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_ipidfrag);
469f4b3ec61Sdh 	fra = ipfr_newfrag(fin, 0, ifs->ifs_ipfr_ipidtab);
4707c478bd9Sstevel@tonic-gate 	if (fra != NULL) {
4717c478bd9Sstevel@tonic-gate 		fra->ipfr_data = (void *)(uintptr_t)ipid;
472f4b3ec61Sdh 		*ifs->ifs_ipfr_ipidtail = fra;
473f4b3ec61Sdh 		fra->ipfr_prev = ifs->ifs_ipfr_ipidtail;
474f4b3ec61Sdh 		ifs->ifs_ipfr_ipidtail = &fra->ipfr_next;
4757c478bd9Sstevel@tonic-gate 		fra->ipfr_next = NULL;
4767c478bd9Sstevel@tonic-gate 	}
477f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
4787c478bd9Sstevel@tonic-gate 	return fra ? 0 : -1;
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
4837c478bd9Sstevel@tonic-gate /* Function:    fr_fraglookup                                               */
4847c478bd9Sstevel@tonic-gate /* Returns:     ipfr_t * - pointer to ipfr_t structure if there's a         */
4857c478bd9Sstevel@tonic-gate /*                         matching entry in the frag table, else NULL      */
4867c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)   - pointer to packet information                    */
4877c478bd9Sstevel@tonic-gate /*              table(I) - pointer to fragment cache table to search        */
4887c478bd9Sstevel@tonic-gate /*                                                                          */
4897c478bd9Sstevel@tonic-gate /* Check the fragment cache to see if there is already a record of this     */
4907c478bd9Sstevel@tonic-gate /* packet with its filter result known.                                     */
4917c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_fraglookup(fin,table)4927c478bd9Sstevel@tonic-gate static ipfr_t *fr_fraglookup(fin, table)
4937c478bd9Sstevel@tonic-gate fr_info_t *fin;
4947c478bd9Sstevel@tonic-gate ipfr_t *table[];
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate 	ipfr_t *f, frag;
4977c478bd9Sstevel@tonic-gate 	u_int idx;
498f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
5017c478bd9Sstevel@tonic-gate 		return NULL;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/*
5047c478bd9Sstevel@tonic-gate 	 * For fragments, we record protocol, packet id, TOS and both IP#'s
5057c478bd9Sstevel@tonic-gate 	 * (these should all be the same for all fragments of a packet).
5067c478bd9Sstevel@tonic-gate 	 *
5077c478bd9Sstevel@tonic-gate 	 * build up a hash value to index the table with.
5087c478bd9Sstevel@tonic-gate 	 */
50972680cf5SDarren Reed 	idx = ipfr_index(fin, &frag);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	/*
5127c478bd9Sstevel@tonic-gate 	 * check the table, careful to only compare the right amount of data
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	for (f = table[idx]; f; f = f->ipfr_hnext)
5157c478bd9Sstevel@tonic-gate 		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
5167c478bd9Sstevel@tonic-gate 			  IPFR_CMPSZ)) {
5177c478bd9Sstevel@tonic-gate 			u_short	off;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 			/*
5207c478bd9Sstevel@tonic-gate 			 * We don't want to let short packets match because
5217c478bd9Sstevel@tonic-gate 			 * they could be compromising the security of other
5227c478bd9Sstevel@tonic-gate 			 * rules that want to match on layer 4 fields (and
5237c478bd9Sstevel@tonic-gate 			 * can't because they have been fragmented off.)
5247c478bd9Sstevel@tonic-gate 			 * Why do this check here?  The counter acts as an
5257c478bd9Sstevel@tonic-gate 			 * indicator of this kind of attack, whereas if it was
5267c478bd9Sstevel@tonic-gate 			 * elsewhere, it wouldn't know if other matching
5277c478bd9Sstevel@tonic-gate 			 * packets had been seen.
5287c478bd9Sstevel@tonic-gate 			 */
5297c478bd9Sstevel@tonic-gate 			if (fin->fin_flx & FI_SHORT) {
530f4b3ec61Sdh 				ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_short);
5317c478bd9Sstevel@tonic-gate 				continue;
5327c478bd9Sstevel@tonic-gate 			}
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 			/*
5357c478bd9Sstevel@tonic-gate 			 * XXX - We really need to be guarding against the
5367c478bd9Sstevel@tonic-gate 			 * retransmission of (src,dst,id,offset-range) here
5377c478bd9Sstevel@tonic-gate 			 * because a fragmented packet is never resent with
5387c478bd9Sstevel@tonic-gate 			 * the same IP ID# (or shouldn't).
5397c478bd9Sstevel@tonic-gate 			 */
54072680cf5SDarren Reed 			off = fin->fin_off >> 3;
5417c478bd9Sstevel@tonic-gate 			if (f->ipfr_seen0) {
5427c478bd9Sstevel@tonic-gate 				if (off == 0) {
543f4b3ec61Sdh 					ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_retrans0);
5447c478bd9Sstevel@tonic-gate 					continue;
5457c478bd9Sstevel@tonic-gate 				}
5467663b816Sml 			} else if (off == 0) {
5477c478bd9Sstevel@tonic-gate 				f->ipfr_seen0 = 1;
5487663b816Sml 			}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 			if (f != table[idx]) {
5517c478bd9Sstevel@tonic-gate 				ipfr_t **fp;
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 				/*
5547c478bd9Sstevel@tonic-gate 				 * Move fragment info. to the top of the list
5557c478bd9Sstevel@tonic-gate 				 * to speed up searches.  First, delink...
5567c478bd9Sstevel@tonic-gate 				 */
5577c478bd9Sstevel@tonic-gate 				fp = f->ipfr_hprev;
5587c478bd9Sstevel@tonic-gate 				(*fp) = f->ipfr_hnext;
5597c478bd9Sstevel@tonic-gate 				if (f->ipfr_hnext != NULL)
5607c478bd9Sstevel@tonic-gate 					f->ipfr_hnext->ipfr_hprev = fp;
5617c478bd9Sstevel@tonic-gate 				/*
5627c478bd9Sstevel@tonic-gate 				 * Then put back at the top of the chain.
5637c478bd9Sstevel@tonic-gate 				 */
5647c478bd9Sstevel@tonic-gate 				f->ipfr_hnext = table[idx];
5657c478bd9Sstevel@tonic-gate 				table[idx]->ipfr_hprev = &f->ipfr_hnext;
5667c478bd9Sstevel@tonic-gate 				f->ipfr_hprev = table + idx;
5677c478bd9Sstevel@tonic-gate 				table[idx] = f;
5687c478bd9Sstevel@tonic-gate 			}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 			/*
5717c478bd9Sstevel@tonic-gate 			 * If we've follwed the fragments, and this is the
5727c478bd9Sstevel@tonic-gate 			 * last (in order), shrink expiration time.
5737c478bd9Sstevel@tonic-gate 			 */
5747c478bd9Sstevel@tonic-gate 			if (off == f->ipfr_off) {
57572680cf5SDarren Reed 				if (!(fin->fin_flx & FI_MOREFRAG))
576f4b3ec61Sdh 					f->ipfr_ttl = ifs->ifs_fr_ticks + 1;
577ab25eeb5Syz 				f->ipfr_off = fin->fin_dlen + off;
5787c478bd9Sstevel@tonic-gate 			} else if (f->ipfr_pass & FR_FRSTRICT)
5797c478bd9Sstevel@tonic-gate 				continue;
580f4b3ec61Sdh 			ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_hits);
5817c478bd9Sstevel@tonic-gate 			return f;
5827c478bd9Sstevel@tonic-gate 		}
5837c478bd9Sstevel@tonic-gate 	return NULL;
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
5887c478bd9Sstevel@tonic-gate /* Function:    fr_nat_knownfrag                                            */
5897c478bd9Sstevel@tonic-gate /* Returns:     nat_t* - pointer to 'parent' NAT structure if frag table    */
5907c478bd9Sstevel@tonic-gate /*                       match found, else NULL                             */
5917c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)  - pointer to packet information                     */
5927c478bd9Sstevel@tonic-gate /*                                                                          */
5937c478bd9Sstevel@tonic-gate /* Functional interface for NAT lookups of the NAT fragment cache           */
5947c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_nat_knownfrag(fin)5957c478bd9Sstevel@tonic-gate nat_t *fr_nat_knownfrag(fin)
5967c478bd9Sstevel@tonic-gate fr_info_t *fin;
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	nat_t	*nat;
5997c478bd9Sstevel@tonic-gate 	ipfr_t	*ipf;
600f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
6017c478bd9Sstevel@tonic-gate 
60272680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_natlist)
6037c478bd9Sstevel@tonic-gate 		return NULL;
604f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_natfrag);
605f4b3ec61Sdh 	ipf = fr_fraglookup(fin, ifs->ifs_ipfr_nattab);
6067c478bd9Sstevel@tonic-gate 	if (ipf != NULL) {
6077c478bd9Sstevel@tonic-gate 		nat = ipf->ipfr_data;
6087c478bd9Sstevel@tonic-gate 		/*
6097c478bd9Sstevel@tonic-gate 		 * This is the last fragment for this packet.
6107c478bd9Sstevel@tonic-gate 		 */
611f4b3ec61Sdh 		if ((ipf->ipfr_ttl == ifs->ifs_fr_ticks + 1) && (nat != NULL)) {
6127c478bd9Sstevel@tonic-gate 			nat->nat_data = NULL;
6137c478bd9Sstevel@tonic-gate 			ipf->ipfr_data = NULL;
6147c478bd9Sstevel@tonic-gate 		}
6157c478bd9Sstevel@tonic-gate 	} else
6167c478bd9Sstevel@tonic-gate 		nat = NULL;
617f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
6187c478bd9Sstevel@tonic-gate 	return nat;
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
6237c478bd9Sstevel@tonic-gate /* Function:    fr_ipid_knownfrag                                           */
6247c478bd9Sstevel@tonic-gate /* Returns:     u_32_t - IPv4 ID for this packet if match found, else       */
6257c478bd9Sstevel@tonic-gate /*                       return 0xfffffff to indicate no match.             */
6267c478bd9Sstevel@tonic-gate /* Parameters:  fin(I) - pointer to packet information                      */
6277c478bd9Sstevel@tonic-gate /*                                                                          */
6287c478bd9Sstevel@tonic-gate /* Functional interface for IP ID lookups of the IP ID fragment cache       */
6297c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_ipid_knownfrag(fin)6307c478bd9Sstevel@tonic-gate u_32_t fr_ipid_knownfrag(fin)
6317c478bd9Sstevel@tonic-gate fr_info_t *fin;
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate 	ipfr_t	*ipf;
6347c478bd9Sstevel@tonic-gate 	u_32_t	id;
635f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
6367c478bd9Sstevel@tonic-gate 
63772680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_ipidlist)
6387c478bd9Sstevel@tonic-gate 		return 0xffffffff;
6397c478bd9Sstevel@tonic-gate 
640f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_ipidfrag);
641f4b3ec61Sdh 	ipf = fr_fraglookup(fin, ifs->ifs_ipfr_ipidtab);
6427c478bd9Sstevel@tonic-gate 	if (ipf != NULL)
6437c478bd9Sstevel@tonic-gate 		id = (u_32_t)(uintptr_t)ipf->ipfr_data;
6447c478bd9Sstevel@tonic-gate 	else
6457c478bd9Sstevel@tonic-gate 		id = 0xffffffff;
646f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
6477c478bd9Sstevel@tonic-gate 	return id;
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
6527c478bd9Sstevel@tonic-gate /* Function:    fr_knownfrag                                                */
6537c478bd9Sstevel@tonic-gate /* Returns:     frentry_t* - pointer to filter rule if a match is found in  */
6547c478bd9Sstevel@tonic-gate /*                           the frag cache table, else NULL.               */
6557c478bd9Sstevel@tonic-gate /* Parameters:  fin(I)   - pointer to packet information                    */
6567c478bd9Sstevel@tonic-gate /*              passp(O) - pointer to where to store rule flags resturned   */
6577c478bd9Sstevel@tonic-gate /*                                                                          */
6587c478bd9Sstevel@tonic-gate /* Functional interface for normal lookups of the fragment cache.  If a     */
6597c478bd9Sstevel@tonic-gate /* match is found, return the rule pointer and flags from the rule, except  */
6607c478bd9Sstevel@tonic-gate /* that if FR_LOGFIRST is set, reset FR_LOG.                                */
6617c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_knownfrag(fin,passp)6627c478bd9Sstevel@tonic-gate frentry_t *fr_knownfrag(fin, passp)
6637c478bd9Sstevel@tonic-gate fr_info_t *fin;
6647c478bd9Sstevel@tonic-gate u_32_t *passp;
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	frentry_t *fr = NULL;
6677c478bd9Sstevel@tonic-gate 	ipfr_t	*fra;
6687663b816Sml 	u_32_t pass, oflx;
669f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
6707c478bd9Sstevel@tonic-gate 
67172680cf5SDarren Reed 	if (ifs->ifs_fr_frag_lock || (ifs->ifs_ipfr_list == NULL))
6727c478bd9Sstevel@tonic-gate 		return NULL;
6737c478bd9Sstevel@tonic-gate 
674f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_frag);
6757663b816Sml 	oflx = fin->fin_flx;
676f4b3ec61Sdh 	fra = fr_fraglookup(fin, ifs->ifs_ipfr_heads);
6777c478bd9Sstevel@tonic-gate 	if (fra != NULL) {
6787c478bd9Sstevel@tonic-gate 		fr = fra->ipfr_rule;
6797c478bd9Sstevel@tonic-gate 		fin->fin_fr = fr;
6807c478bd9Sstevel@tonic-gate 		if (fr != NULL) {
6817c478bd9Sstevel@tonic-gate 			pass = fr->fr_flags;
6827c478bd9Sstevel@tonic-gate 			if ((pass & FR_LOGFIRST) != 0)
6837c478bd9Sstevel@tonic-gate 				pass &= ~(FR_LOGFIRST|FR_LOG);
6847c478bd9Sstevel@tonic-gate 			*passp = pass;
6857c478bd9Sstevel@tonic-gate 		}
6867c478bd9Sstevel@tonic-gate 	}
6877663b816Sml 	if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) {
6887663b816Sml 		*passp &= ~FR_CMDMASK;
6897663b816Sml 		*passp |= FR_BLOCK;
690f4b3ec61Sdh 		fr = &ifs->ifs_frblock;
6917663b816Sml 	}
692f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
6937c478bd9Sstevel@tonic-gate 	return fr;
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
6987c478bd9Sstevel@tonic-gate /* Function:    fr_forget                                                   */
6997c478bd9Sstevel@tonic-gate /* Returns:     Nil                                                         */
7007c478bd9Sstevel@tonic-gate /* Parameters:  ptr(I) - pointer to data structure                          */
7017c478bd9Sstevel@tonic-gate /*                                                                          */
7027c478bd9Sstevel@tonic-gate /* Search through all of the fragment cache entries and wherever a pointer  */
7037c478bd9Sstevel@tonic-gate /* is found to match ptr, reset it to NULL.                                 */
7047c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_forget(ptr,ifs)705f4b3ec61Sdh void fr_forget(ptr, ifs)
7067c478bd9Sstevel@tonic-gate void *ptr;
707f4b3ec61Sdh ipf_stack_t *ifs;
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate 	ipfr_t	*fr;
7107c478bd9Sstevel@tonic-gate 
711f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_frag);
712f4b3ec61Sdh 	for (fr = ifs->ifs_ipfr_list; fr; fr = fr->ipfr_next)
7137c478bd9Sstevel@tonic-gate 		if (fr->ipfr_data == ptr)
7147c478bd9Sstevel@tonic-gate 			fr->ipfr_data = NULL;
715f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
7207c478bd9Sstevel@tonic-gate /* Function:    fr_forgetnat                                                */
7217c478bd9Sstevel@tonic-gate /* Returns:     Nil                                                         */
7227c478bd9Sstevel@tonic-gate /* Parameters:  ptr(I) - pointer to data structure                          */
7237c478bd9Sstevel@tonic-gate /*                                                                          */
7247c478bd9Sstevel@tonic-gate /* Search through all of the fragment cache entries for NAT and wherever a  */
7257c478bd9Sstevel@tonic-gate /* pointer  is found to match ptr, reset it to NULL.                        */
7267c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_forgetnat(ptr,ifs)727f4b3ec61Sdh void fr_forgetnat(ptr, ifs)
7287c478bd9Sstevel@tonic-gate void *ptr;
729f4b3ec61Sdh ipf_stack_t *ifs;
7307c478bd9Sstevel@tonic-gate {
7317c478bd9Sstevel@tonic-gate 	ipfr_t	*fr;
7327c478bd9Sstevel@tonic-gate 
733f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
734f4b3ec61Sdh 	for (fr = ifs->ifs_ipfr_natlist; fr; fr = fr->ipfr_next)
7357c478bd9Sstevel@tonic-gate 		if (fr->ipfr_data == ptr)
7367c478bd9Sstevel@tonic-gate 			fr->ipfr_data = NULL;
737f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
7427c478bd9Sstevel@tonic-gate /* Function:    fr_fragdelete                                               */
7437c478bd9Sstevel@tonic-gate /* Returns:     Nil                                                         */
7447c478bd9Sstevel@tonic-gate /* Parameters:  fra(I)   - pointer to fragment structure to delete          */
7457c478bd9Sstevel@tonic-gate /*              tail(IO) - pointer to the pointer to the tail of the frag   */
7467c478bd9Sstevel@tonic-gate /*                         list                                             */
7477c478bd9Sstevel@tonic-gate /*                                                                          */
7487c478bd9Sstevel@tonic-gate /* Remove a fragment cache table entry from the table & list.  Also free    */
7497c478bd9Sstevel@tonic-gate /* the filter rule it is associated with it if it is no longer used as a    */
7507c478bd9Sstevel@tonic-gate /* result of decreasing the reference count.                                */
7517c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_fragdelete(fra,tail,ifs)752f4b3ec61Sdh static void fr_fragdelete(fra, tail, ifs)
7537c478bd9Sstevel@tonic-gate ipfr_t *fra, ***tail;
754f4b3ec61Sdh ipf_stack_t *ifs;
7557c478bd9Sstevel@tonic-gate {
7567c478bd9Sstevel@tonic-gate 	frentry_t *fr;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	fr = fra->ipfr_rule;
7597c478bd9Sstevel@tonic-gate 	if (fr != NULL)
760f4b3ec61Sdh 	    (void)fr_derefrule(&fr, ifs);
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	if (fra->ipfr_next)
7637c478bd9Sstevel@tonic-gate 		fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
7647c478bd9Sstevel@tonic-gate 	*fra->ipfr_prev = fra->ipfr_next;
7657c478bd9Sstevel@tonic-gate 	if (*tail == &fra->ipfr_next)
7667c478bd9Sstevel@tonic-gate 		*tail = fra->ipfr_prev;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if (fra->ipfr_hnext)
7697c478bd9Sstevel@tonic-gate 		fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
7707c478bd9Sstevel@tonic-gate 	*fra->ipfr_hprev = fra->ipfr_hnext;
771f4b3ec61Sdh 
772f4b3ec61Sdh 	if (fra->ipfr_ref <= 0)
773f4b3ec61Sdh 		KFREE(fra);
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
7787c478bd9Sstevel@tonic-gate /* Function:    fr_fragclear                                                */
7797c478bd9Sstevel@tonic-gate /* Returns:     Nil                                                         */
7807c478bd9Sstevel@tonic-gate /* Parameters:  Nil                                                         */
7817c478bd9Sstevel@tonic-gate /*                                                                          */
7827c478bd9Sstevel@tonic-gate /* Free memory in use by fragment state information kept.  Do the normal    */
7837c478bd9Sstevel@tonic-gate /* fragment state stuff first and then the NAT-fragment table.              */
7847c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_fragclear(ifs)785f4b3ec61Sdh void fr_fragclear(ifs)
786f4b3ec61Sdh ipf_stack_t *ifs;
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate 	ipfr_t	*fra;
7897c478bd9Sstevel@tonic-gate 	nat_t	*nat;
7907c478bd9Sstevel@tonic-gate 
791f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_frag);
792f4b3ec61Sdh 	while ((fra = ifs->ifs_ipfr_list) != NULL) {
793f4b3ec61Sdh 		fra->ipfr_ref--;
794f4b3ec61Sdh 		fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs);
795f4b3ec61Sdh 	}
796f4b3ec61Sdh 	ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list;
797f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
7987c478bd9Sstevel@tonic-gate 
799f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_nat);
800f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
801f4b3ec61Sdh 	while ((fra = ifs->ifs_ipfr_natlist) != NULL) {
8027c478bd9Sstevel@tonic-gate 		nat = fra->ipfr_data;
8037c478bd9Sstevel@tonic-gate 		if (nat != NULL) {
8047c478bd9Sstevel@tonic-gate 			if (nat->nat_data == fra)
8057c478bd9Sstevel@tonic-gate 				nat->nat_data = NULL;
8067c478bd9Sstevel@tonic-gate 		}
807f4b3ec61Sdh 		fra->ipfr_ref--;
808f4b3ec61Sdh 		fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs);
8097c478bd9Sstevel@tonic-gate 	}
810f4b3ec61Sdh 	ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist;
811f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
812f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
8177c478bd9Sstevel@tonic-gate /* Function:    fr_fragexpire                                               */
8187c478bd9Sstevel@tonic-gate /* Returns:     Nil                                                         */
8197c478bd9Sstevel@tonic-gate /* Parameters:  Nil                                                         */
8207c478bd9Sstevel@tonic-gate /*                                                                          */
8217c478bd9Sstevel@tonic-gate /* Expire entries in the fragment cache table that have been there too long */
8227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
fr_fragexpire(ifs)823f4b3ec61Sdh void fr_fragexpire(ifs)
824f4b3ec61Sdh ipf_stack_t *ifs;
8257c478bd9Sstevel@tonic-gate {
8267c478bd9Sstevel@tonic-gate 	ipfr_t	**fp, *fra;
8277c478bd9Sstevel@tonic-gate 	nat_t	*nat;
828ab25eeb5Syz 	SPL_INT(s);
8297c478bd9Sstevel@tonic-gate 
830f4b3ec61Sdh 	if (ifs->ifs_fr_frag_lock)
8317c478bd9Sstevel@tonic-gate 		return;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	SPL_NET(s);
834f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_frag);
8357c478bd9Sstevel@tonic-gate 	/*
8367c478bd9Sstevel@tonic-gate 	 * Go through the entire table, looking for entries to expire,
837f4b3ec61Sdh 	 * which is indicated by the ttl being less than or equal to
838f4b3ec61Sdh 	 * ifs_fr_ticks.
8397c478bd9Sstevel@tonic-gate 	 */
840f4b3ec61Sdh 	for (fp = &ifs->ifs_ipfr_list; ((fra = *fp) != NULL); ) {
841f4b3ec61Sdh 		if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
8427c478bd9Sstevel@tonic-gate 			break;
843f4b3ec61Sdh 		fra->ipfr_ref--;
844f4b3ec61Sdh 		fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs);
845f4b3ec61Sdh 		ifs->ifs_ipfr_stats.ifs_expire++;
846f4b3ec61Sdh 		ifs->ifs_ipfr_inuse--;
8477c478bd9Sstevel@tonic-gate 	}
848f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_frag);
8497c478bd9Sstevel@tonic-gate 
850f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_ipidfrag);
851f4b3ec61Sdh 	for (fp = &ifs->ifs_ipfr_ipidlist; ((fra = *fp) != NULL); ) {
852f4b3ec61Sdh 		if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
8537c478bd9Sstevel@tonic-gate 			break;
854f4b3ec61Sdh 		fra->ipfr_ref--;
855f4b3ec61Sdh 		fr_fragdelete(fra, &ifs->ifs_ipfr_ipidtail, ifs);
856f4b3ec61Sdh 		ifs->ifs_ipfr_stats.ifs_expire++;
857f4b3ec61Sdh 		ifs->ifs_ipfr_inuse--;
8587c478bd9Sstevel@tonic-gate 	}
859f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	/*
8627c478bd9Sstevel@tonic-gate 	 * Same again for the NAT table, except that if the structure also
8637c478bd9Sstevel@tonic-gate 	 * still points to a NAT structure, and the NAT structure points back
8647c478bd9Sstevel@tonic-gate 	 * at the one to be free'd, NULL the reference from the NAT struct.
8657c478bd9Sstevel@tonic-gate 	 * NOTE: We need to grab both mutex's early, and in this order so as
8667c478bd9Sstevel@tonic-gate 	 * to prevent a deadlock if both try to expire at the same time.
8677c478bd9Sstevel@tonic-gate 	 */
868f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_nat);
869f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_natfrag);
870f4b3ec61Sdh 	for (fp = &ifs->ifs_ipfr_natlist; ((fra = *fp) != NULL); ) {
871f4b3ec61Sdh 		if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
8727c478bd9Sstevel@tonic-gate 			break;
8737c478bd9Sstevel@tonic-gate 		nat = fra->ipfr_data;
8747c478bd9Sstevel@tonic-gate 		if (nat != NULL) {
8757c478bd9Sstevel@tonic-gate 			if (nat->nat_data == fra)
8767c478bd9Sstevel@tonic-gate 				nat->nat_data = NULL;
8777c478bd9Sstevel@tonic-gate 		}
878f4b3ec61Sdh 		fra->ipfr_ref--;
879f4b3ec61Sdh 		fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs);
880f4b3ec61Sdh 		ifs->ifs_ipfr_stats.ifs_expire++;
881f4b3ec61Sdh 		ifs->ifs_ipfr_inuse--;
8827c478bd9Sstevel@tonic-gate 	}
883f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
884f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
8857c478bd9Sstevel@tonic-gate 	SPL_X(s);
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
8907c478bd9Sstevel@tonic-gate /* Function:    fr_slowtimer                                                */
8917c478bd9Sstevel@tonic-gate /* Returns:     Nil                                                         */
8927c478bd9Sstevel@tonic-gate /* Parameters:  Nil                                                         */
8937c478bd9Sstevel@tonic-gate /*                                                                          */
8947c478bd9Sstevel@tonic-gate /* Slowly expire held state for fragments.  Timeouts are set * in           */
8957c478bd9Sstevel@tonic-gate /* expectation of this being called twice per second.                       */
8967c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */
897*af5f29ddSToomas Soome #if !defined(_KERNEL) || (!defined(SOLARIS) && !defined(__hpux) && \
898*af5f29ddSToomas Soome 	!defined(__sgi) && !defined(__osf__) && !defined(linux))
8997c478bd9Sstevel@tonic-gate # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
fr_slowtimer(void * arg)900f4b3ec61Sdh void fr_slowtimer __P((void *arg))
9017c478bd9Sstevel@tonic-gate # else
902f4b3ec61Sdh int fr_slowtimer(void *arg)
9037c478bd9Sstevel@tonic-gate # endif
9047c478bd9Sstevel@tonic-gate {
905f4b3ec61Sdh 	ipf_stack_t *ifs = arg;
906f4b3ec61Sdh 
907f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_global);
908f4b3ec61Sdh 
909f4b3ec61Sdh 	fr_fragexpire(ifs);
910f4b3ec61Sdh 	fr_timeoutstate(ifs);
911f4b3ec61Sdh 	fr_natexpire(ifs);
912f4b3ec61Sdh 	fr_authexpire(ifs);
913f4b3ec61Sdh 	ifs->ifs_fr_ticks++;
914f4b3ec61Sdh 	if (ifs->ifs_fr_running <= 0)
9157c478bd9Sstevel@tonic-gate 		goto done;
9167c478bd9Sstevel@tonic-gate # ifdef _KERNEL
9177c478bd9Sstevel@tonic-gate #  if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
9187c478bd9Sstevel@tonic-gate 	callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
9197c478bd9Sstevel@tonic-gate #  else
9207c478bd9Sstevel@tonic-gate #   if defined(__OpenBSD__)
9217c478bd9Sstevel@tonic-gate 	timeout_add(&fr_slowtimer_ch, hz/2);
9227c478bd9Sstevel@tonic-gate #   else
9237c478bd9Sstevel@tonic-gate #    if (__FreeBSD_version >= 300000)
9247c478bd9Sstevel@tonic-gate 	fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
9257c478bd9Sstevel@tonic-gate #    else
926ab25eeb5Syz #     ifdef linux
927ab25eeb5Syz 	;
928ab25eeb5Syz #     else
9297c478bd9Sstevel@tonic-gate 	timeout(fr_slowtimer, NULL, hz/2);
930ab25eeb5Syz #     endif
9317c478bd9Sstevel@tonic-gate #    endif /* FreeBSD */
9327c478bd9Sstevel@tonic-gate #   endif /* OpenBSD */
9337c478bd9Sstevel@tonic-gate #  endif /* NetBSD */
9347c478bd9Sstevel@tonic-gate # endif
9357c478bd9Sstevel@tonic-gate done:
936f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_global);
9377c478bd9Sstevel@tonic-gate # if (BSD < 199103) || !defined(_KERNEL)
9387c478bd9Sstevel@tonic-gate 	return 0;
9397c478bd9Sstevel@tonic-gate # endif
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
942f4b3ec61Sdh 
943f4b3ec61Sdh /*ARGSUSED*/
fr_nextfrag(token,itp,top,tail,lock,ifs)944f4b3ec61Sdh int fr_nextfrag(token, itp, top, tail, lock, ifs)
945f4b3ec61Sdh ipftoken_t *token;
946f4b3ec61Sdh ipfgeniter_t *itp;
947f4b3ec61Sdh ipfr_t **top, ***tail;
948f4b3ec61Sdh ipfrwlock_t *lock;
949f4b3ec61Sdh ipf_stack_t *ifs;
950f4b3ec61Sdh {
951f4b3ec61Sdh 	ipfr_t *frag, *next, zero;
952f4b3ec61Sdh 	int error = 0;
953f4b3ec61Sdh 
954f4b3ec61Sdh 	READ_ENTER(lock);
955786c7074Sjojemann 
956786c7074Sjojemann 	/*
957786c7074Sjojemann 	 * Retrieve "previous" entry from token and find the next entry.
958786c7074Sjojemann 	 */
959786c7074Sjojemann 	frag = token->ipt_data;
960f4b3ec61Sdh 	if (frag == NULL)
961f4b3ec61Sdh 		next = *top;
962f4b3ec61Sdh 	else
963f4b3ec61Sdh 		next = frag->ipfr_next;
964f4b3ec61Sdh 
965786c7074Sjojemann 	/*
966786c7074Sjojemann 	 * If we found an entry, add reference to it and update token.
967786c7074Sjojemann 	 * Otherwise, zero out data to be returned and NULL out token.
968786c7074Sjojemann 	 */
969f4b3ec61Sdh 	if (next != NULL) {
970f4b3ec61Sdh 		ATOMIC_INC(next->ipfr_ref);
971f4b3ec61Sdh 		token->ipt_data = next;
972f4b3ec61Sdh 	} else {
973f4b3ec61Sdh 		bzero(&zero, sizeof(zero));
974f4b3ec61Sdh 		next = &zero;
975786c7074Sjojemann 		token->ipt_data = NULL;
976f4b3ec61Sdh 	}
977f4b3ec61Sdh 
978786c7074Sjojemann 	/*
979786c7074Sjojemann 	 * Now that we have ref, it's save to give up lock.
980786c7074Sjojemann 	 */
981786c7074Sjojemann 	RWLOCK_EXIT(lock);
982f4b3ec61Sdh 
983786c7074Sjojemann 	/*
984786c7074Sjojemann 	 * Copy out data and clean up references and token as needed.
985786c7074Sjojemann 	 */
986f4b3ec61Sdh 	error = COPYOUT(next, itp->igi_data, sizeof(*next));
987f4b3ec61Sdh 	if (error != 0)
988f4b3ec61Sdh 		error = EFAULT;
989786c7074Sjojemann 	if (token->ipt_data == NULL) {
990786c7074Sjojemann 		ipf_freetoken(token, ifs);
991786c7074Sjojemann 	} else {
992786c7074Sjojemann 		if (frag != NULL)
993786c7074Sjojemann 			fr_fragderef(&frag, lock, ifs);
994786c7074Sjojemann 		if (next->ipfr_next == NULL)
995786c7074Sjojemann 			ipf_freetoken(token, ifs);
996786c7074Sjojemann 	}
997f4b3ec61Sdh 	return error;
998f4b3ec61Sdh }
999f4b3ec61Sdh 
1000f4b3ec61Sdh 
fr_fragderef(frp,lock,ifs)1001f4b3ec61Sdh void fr_fragderef(frp, lock, ifs)
1002f4b3ec61Sdh ipfr_t **frp;
1003f4b3ec61Sdh ipfrwlock_t *lock;
1004f4b3ec61Sdh ipf_stack_t *ifs;
1005f4b3ec61Sdh {
1006f4b3ec61Sdh 	ipfr_t *fra;
1007f4b3ec61Sdh 
1008f4b3ec61Sdh 	fra = *frp;
1009f4b3ec61Sdh 	*frp = NULL;
1010f4b3ec61Sdh 
1011f4b3ec61Sdh 	WRITE_ENTER(lock);
1012f4b3ec61Sdh 	fra->ipfr_ref--;
1013f4b3ec61Sdh 	if (fra->ipfr_ref <= 0) {
1014f4b3ec61Sdh 		KFREE(fra);
1015f4b3ec61Sdh 		ifs->ifs_ipfr_stats.ifs_expire++;
1016f4b3ec61Sdh 		ifs->ifs_ipfr_inuse--;
1017f4b3ec61Sdh 	}
1018f4b3ec61Sdh 	RWLOCK_EXIT(lock);
1019f4b3ec61Sdh }
1020