12393Syz155240 /*
22393Syz155240 * Copyright (C) 1993-2003 by Darren Reed.
32393Syz155240 *
42393Syz155240 * See the IPFILTER.LICENCE file for details on licencing.
52393Syz155240 *
6*9876SDarren.Reed@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
72393Syz155240 * Use is subject to license terms.
82393Syz155240 */
92393Syz155240
102393Syz155240 #if defined(KERNEL) || defined(_KERNEL)
112393Syz155240 # undef KERNEL
122393Syz155240 # undef _KERNEL
132393Syz155240 # define KERNEL 1
142393Syz155240 # define _KERNEL 1
152393Syz155240 #endif
162393Syz155240 #include <sys/errno.h>
172393Syz155240 #include <sys/types.h>
182393Syz155240 #include <sys/param.h>
192393Syz155240 #include <sys/time.h>
202393Syz155240 #include <sys/file.h>
212393Syz155240 #ifdef __hpux
222393Syz155240 # include <sys/timeout.h>
232393Syz155240 #endif
242393Syz155240 #if !defined(_KERNEL)
252393Syz155240 # include <stdio.h>
262393Syz155240 # include <string.h>
272393Syz155240 # include <stdlib.h>
282393Syz155240 # define _KERNEL
292393Syz155240 # ifdef __OpenBSD__
302393Syz155240 struct file;
312393Syz155240 # endif
322393Syz155240 # include <sys/uio.h>
332393Syz155240 # undef _KERNEL
342393Syz155240 #endif
352393Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
362393Syz155240 # include <sys/filio.h>
372393Syz155240 # include <sys/fcntl.h>
382393Syz155240 #else
392393Syz155240 # include <sys/ioctl.h>
402393Syz155240 #endif
412393Syz155240 #if !defined(linux)
422393Syz155240 # include <sys/protosw.h>
432393Syz155240 #endif
442393Syz155240 #include <sys/socket.h>
452393Syz155240 #if defined(_KERNEL)
462393Syz155240 # include <sys/systm.h>
472393Syz155240 # if !defined(__SVR4) && !defined(__svr4__)
482393Syz155240 # include <sys/mbuf.h>
492393Syz155240 # endif
502393Syz155240 #endif
512393Syz155240 #if !defined(__SVR4) && !defined(__svr4__)
522393Syz155240 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX)
532393Syz155240 # include <sys/kernel.h>
542393Syz155240 # endif
552393Syz155240 #else
562393Syz155240 # include <sys/byteorder.h>
572393Syz155240 # ifdef _KERNEL
582393Syz155240 # include <sys/dditypes.h>
592393Syz155240 # endif
602393Syz155240 # include <sys/stream.h>
612393Syz155240 # include <sys/kmem.h>
622393Syz155240 #endif
632393Syz155240 #include <net/if.h>
642393Syz155240 #ifdef sun
652393Syz155240 # include <net/af.h>
662393Syz155240 #endif
672393Syz155240 #include <net/route.h>
682393Syz155240 #include <netinet/in.h>
692393Syz155240 #include <netinet/in_systm.h>
702393Syz155240 #include <netinet/ip.h>
712393Syz155240 #if !defined(linux)
722393Syz155240 # include <netinet/ip_var.h>
732393Syz155240 #endif
742393Syz155240 #include <netinet/tcp.h>
752393Syz155240 #include <netinet/udp.h>
762393Syz155240 #include <netinet/ip_icmp.h>
772393Syz155240 #include "netinet/ip_compat.h"
782393Syz155240 #include <netinet/tcpip.h>
792393Syz155240 #include "netinet/ip_fil.h"
802393Syz155240 #include "netinet/ip_nat.h"
812393Syz155240 #include "netinet/ip_frag.h"
822393Syz155240 #include "netinet/ip_state.h"
832393Syz155240 #include "netinet/ip_auth.h"
843448Sdh155122 #include "netinet/ipf_stack.h"
852393Syz155240 #if (__FreeBSD_version >= 300000)
862393Syz155240 # include <sys/malloc.h>
872393Syz155240 # if defined(_KERNEL)
882393Syz155240 # ifndef IPFILTER_LKM
892393Syz155240 # include <sys/libkern.h>
902393Syz155240 # include <sys/systm.h>
912393Syz155240 # endif
922393Syz155240 extern struct callout_handle fr_slowtimer_ch;
932393Syz155240 # endif
942393Syz155240 #endif
952393Syz155240 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
962393Syz155240 # include <sys/callout.h>
972393Syz155240 extern struct callout fr_slowtimer_ch;
982393Syz155240 #endif
992393Syz155240 #if defined(__OpenBSD__)
1002393Syz155240 # include <sys/timeout.h>
1012393Syz155240 extern struct timeout fr_slowtimer_ch;
1022393Syz155240 #endif
1032393Syz155240 /* END OF INCLUDES */
1042393Syz155240
1052393Syz155240 #if !defined(lint)
1062393Syz155240 static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
1072393Syz155240 static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $";
1082393Syz155240 #endif
1092393Syz155240
110*9876SDarren.Reed@Sun.COM static INLINE int ipfr_index __P((fr_info_t *, ipfr_t *));
1112393Syz155240 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
1122393Syz155240 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
1133448Sdh155122 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***, ipf_stack_t *));
1142393Syz155240
1152393Syz155240 /* ------------------------------------------------------------------------ */
1162393Syz155240 /* Function: fr_fraginit */
1172393Syz155240 /* Returns: int - 0 == success, -1 == error */
1182393Syz155240 /* Parameters: Nil */
1192393Syz155240 /* */
1202393Syz155240 /* Initialise the hash tables for the fragment cache lookups. */
1212393Syz155240 /* ------------------------------------------------------------------------ */
fr_fraginit(ifs)1223448Sdh155122 int fr_fraginit(ifs)
1233448Sdh155122 ipf_stack_t *ifs;
1242393Syz155240 {
1253448Sdh155122 ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list;
1263448Sdh155122 ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist;
1273448Sdh155122 ifs->ifs_ipfr_ipidtail = &ifs->ifs_ipfr_ipidlist;
1284251San207044 /* the IP frag related variables are set in ipftuneable_setdefs() to
1294251San207044 * their default values
1304251San207044 */
1313448Sdh155122
1323448Sdh155122 KMALLOCS(ifs->ifs_ipfr_heads, ipfr_t **,
1333448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1343448Sdh155122 if (ifs->ifs_ipfr_heads == NULL)
1352393Syz155240 return -1;
1363448Sdh155122 bzero((char *)ifs->ifs_ipfr_heads,
1373448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1382393Syz155240
1393448Sdh155122 KMALLOCS(ifs->ifs_ipfr_nattab, ipfr_t **,
1403448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1413448Sdh155122 if (ifs->ifs_ipfr_nattab == NULL)
1422393Syz155240 return -1;
1433448Sdh155122 bzero((char *)ifs->ifs_ipfr_nattab,
1443448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1452393Syz155240
1463448Sdh155122 KMALLOCS(ifs->ifs_ipfr_ipidtab, ipfr_t **,
1473448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1483448Sdh155122 if (ifs->ifs_ipfr_ipidtab == NULL)
1492393Syz155240 return -1;
1503448Sdh155122 bzero((char *)ifs->ifs_ipfr_ipidtab,
1513448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1522393Syz155240
1533448Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_frag, "ipf fragment rwlock");
1542393Syz155240
1552393Syz155240 /* Initialise frblock with "block in all" */
1563448Sdh155122 bzero((char *)&ifs->ifs_frblock, sizeof(ifs->ifs_frblock));
1573448Sdh155122 ifs->ifs_frblock.fr_flags = FR_BLOCK|FR_INQUE; /* block in */
1583448Sdh155122 ifs->ifs_frblock.fr_ref = 1;
1592393Syz155240
1603448Sdh155122 ifs->ifs_fr_frag_init = 1;
1612393Syz155240
1622393Syz155240 return 0;
1632393Syz155240 }
1642393Syz155240
1652393Syz155240
1662393Syz155240 /* ------------------------------------------------------------------------ */
1672393Syz155240 /* Function: fr_fragunload */
1682393Syz155240 /* Returns: Nil */
1692393Syz155240 /* Parameters: Nil */
1702393Syz155240 /* */
1712393Syz155240 /* Free all memory allocated whilst running and from initialisation. */
1722393Syz155240 /* ------------------------------------------------------------------------ */
fr_fragunload(ifs)1733448Sdh155122 void fr_fragunload(ifs)
1743448Sdh155122 ipf_stack_t *ifs;
1752393Syz155240 {
1763448Sdh155122 if (ifs->ifs_fr_frag_init == 1) {
1773448Sdh155122 fr_fragclear(ifs);
1782393Syz155240
1793448Sdh155122 RW_DESTROY(&ifs->ifs_ipf_frag);
1803448Sdh155122 ifs->ifs_fr_frag_init = 0;
1812393Syz155240 }
1822393Syz155240
1833448Sdh155122 if (ifs->ifs_ipfr_heads != NULL) {
1843448Sdh155122 KFREES(ifs->ifs_ipfr_heads,
1853448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1863448Sdh155122 }
1873448Sdh155122 ifs->ifs_ipfr_heads = NULL;
1882393Syz155240
1893448Sdh155122 if (ifs->ifs_ipfr_nattab != NULL) {
1903448Sdh155122 KFREES(ifs->ifs_ipfr_nattab,
1913448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1923448Sdh155122 }
1933448Sdh155122 ifs->ifs_ipfr_nattab = NULL;
1942393Syz155240
1953448Sdh155122 if (ifs->ifs_ipfr_ipidtab != NULL) {
1963448Sdh155122 KFREES(ifs->ifs_ipfr_ipidtab,
1973448Sdh155122 ifs->ifs_ipfr_size * sizeof(ipfr_t *));
1983448Sdh155122 }
1993448Sdh155122 ifs->ifs_ipfr_ipidtab = NULL;
2002393Syz155240 }
2012393Syz155240
2022393Syz155240
2032393Syz155240 /* ------------------------------------------------------------------------ */
2042393Syz155240 /* Function: fr_fragstats */
2052393Syz155240 /* Returns: ipfrstat_t* - pointer to struct with current frag stats */
2062393Syz155240 /* Parameters: Nil */
2072393Syz155240 /* */
2082393Syz155240 /* Updates ipfr_stats with current information and returns a pointer to it */
2092393Syz155240 /* ------------------------------------------------------------------------ */
fr_fragstats(ifs)2103448Sdh155122 ipfrstat_t *fr_fragstats(ifs)
2113448Sdh155122 ipf_stack_t *ifs;
2122393Syz155240 {
2133448Sdh155122 ifs->ifs_ipfr_stats.ifs_table = ifs->ifs_ipfr_heads;
2143448Sdh155122 ifs->ifs_ipfr_stats.ifs_nattab = ifs->ifs_ipfr_nattab;
2153448Sdh155122 ifs->ifs_ipfr_stats.ifs_inuse = ifs->ifs_ipfr_inuse;
2163448Sdh155122 return &ifs->ifs_ipfr_stats;
2172393Syz155240 }
2182393Syz155240
2192393Syz155240
2202393Syz155240 /* ------------------------------------------------------------------------ */
221*9876SDarren.Reed@Sun.COM /* Function: ipfr_index */
222*9876SDarren.Reed@Sun.COM /* Returns: int - index in fragment table for given packet */
223*9876SDarren.Reed@Sun.COM /* Parameters: fin(I) - pointer to packet information */
224*9876SDarren.Reed@Sun.COM /* frag(O) - pointer to ipfr_t structure to fill */
225*9876SDarren.Reed@Sun.COM /* */
226*9876SDarren.Reed@Sun.COM /* Compute the index in the fragment table while filling the per packet */
227*9876SDarren.Reed@Sun.COM /* part of the fragment state. */
228*9876SDarren.Reed@Sun.COM /* ------------------------------------------------------------------------ */
ipfr_index(fin,frag)229*9876SDarren.Reed@Sun.COM static INLINE int ipfr_index(fin, frag)
230*9876SDarren.Reed@Sun.COM fr_info_t *fin;
231*9876SDarren.Reed@Sun.COM ipfr_t *frag;
232*9876SDarren.Reed@Sun.COM {
233*9876SDarren.Reed@Sun.COM u_int idx;
234*9876SDarren.Reed@Sun.COM
235*9876SDarren.Reed@Sun.COM /*
236*9876SDarren.Reed@Sun.COM * For fragments, we record protocol, packet id, TOS and both IP#'s
237*9876SDarren.Reed@Sun.COM * (these should all be the same for all fragments of a packet).
238*9876SDarren.Reed@Sun.COM *
239*9876SDarren.Reed@Sun.COM * build up a hash value to index the table with.
240*9876SDarren.Reed@Sun.COM */
241*9876SDarren.Reed@Sun.COM
242*9876SDarren.Reed@Sun.COM #ifdef USE_INET6
243*9876SDarren.Reed@Sun.COM if (fin->fin_v == 6) {
244*9876SDarren.Reed@Sun.COM ip6_t *ip6 = (ip6_t *)fin->fin_ip;
245*9876SDarren.Reed@Sun.COM
246*9876SDarren.Reed@Sun.COM frag->ipfr_p = fin->fin_fi.fi_p;
247*9876SDarren.Reed@Sun.COM frag->ipfr_id = fin->fin_id;
248*9876SDarren.Reed@Sun.COM frag->ipfr_tos = ip6->ip6_flow & IPV6_FLOWINFO_MASK;
249*9876SDarren.Reed@Sun.COM frag->ipfr_src.in6 = ip6->ip6_src;
250*9876SDarren.Reed@Sun.COM frag->ipfr_dst.in6 = ip6->ip6_dst;
251*9876SDarren.Reed@Sun.COM } else
252*9876SDarren.Reed@Sun.COM #endif
253*9876SDarren.Reed@Sun.COM {
254*9876SDarren.Reed@Sun.COM ip_t *ip = fin->fin_ip;
255*9876SDarren.Reed@Sun.COM
256*9876SDarren.Reed@Sun.COM frag->ipfr_p = ip->ip_p;
257*9876SDarren.Reed@Sun.COM frag->ipfr_id = ip->ip_id;
258*9876SDarren.Reed@Sun.COM frag->ipfr_tos = ip->ip_tos;
259*9876SDarren.Reed@Sun.COM frag->ipfr_src.in4.s_addr = ip->ip_src.s_addr;
260*9876SDarren.Reed@Sun.COM frag->ipfr_src.i6[1] = 0;
261*9876SDarren.Reed@Sun.COM frag->ipfr_src.i6[2] = 0;
262*9876SDarren.Reed@Sun.COM frag->ipfr_src.i6[3] = 0;
263*9876SDarren.Reed@Sun.COM frag->ipfr_dst.in4.s_addr = ip->ip_dst.s_addr;
264*9876SDarren.Reed@Sun.COM frag->ipfr_dst.i6[1] = 0;
265*9876SDarren.Reed@Sun.COM frag->ipfr_dst.i6[2] = 0;
266*9876SDarren.Reed@Sun.COM frag->ipfr_dst.i6[3] = 0;
267*9876SDarren.Reed@Sun.COM }
268*9876SDarren.Reed@Sun.COM frag->ipfr_ifp = fin->fin_ifp;
269*9876SDarren.Reed@Sun.COM frag->ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
270*9876SDarren.Reed@Sun.COM frag->ipfr_secmsk = fin->fin_fi.fi_secmsk;
271*9876SDarren.Reed@Sun.COM frag->ipfr_auth = fin->fin_fi.fi_auth;
272*9876SDarren.Reed@Sun.COM
273*9876SDarren.Reed@Sun.COM idx = frag->ipfr_p;
274*9876SDarren.Reed@Sun.COM idx += frag->ipfr_id;
275*9876SDarren.Reed@Sun.COM idx += frag->ipfr_src.i6[0];
276*9876SDarren.Reed@Sun.COM idx += frag->ipfr_src.i6[1];
277*9876SDarren.Reed@Sun.COM idx += frag->ipfr_src.i6[2];
278*9876SDarren.Reed@Sun.COM idx += frag->ipfr_src.i6[3];
279*9876SDarren.Reed@Sun.COM idx += frag->ipfr_dst.i6[0];
280*9876SDarren.Reed@Sun.COM idx += frag->ipfr_dst.i6[1];
281*9876SDarren.Reed@Sun.COM idx += frag->ipfr_dst.i6[2];
282*9876SDarren.Reed@Sun.COM idx += frag->ipfr_dst.i6[3];
283*9876SDarren.Reed@Sun.COM idx *= 127;
284*9876SDarren.Reed@Sun.COM idx %= IPFT_SIZE;
285*9876SDarren.Reed@Sun.COM
286*9876SDarren.Reed@Sun.COM return idx;
287*9876SDarren.Reed@Sun.COM }
288*9876SDarren.Reed@Sun.COM
289*9876SDarren.Reed@Sun.COM
290*9876SDarren.Reed@Sun.COM /* ------------------------------------------------------------------------ */
2912393Syz155240 /* Function: ipfr_newfrag */
2922393Syz155240 /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */
2932393Syz155240 /* Parameters: fin(I) - pointer to packet information */
2942393Syz155240 /* table(I) - pointer to frag table to add to */
2952393Syz155240 /* */
2962393Syz155240 /* Add a new entry to the fragment cache, registering it as having come */
2972393Syz155240 /* through this box, with the result of the filter operation. */
2982393Syz155240 /* ------------------------------------------------------------------------ */
ipfr_newfrag(fin,pass,table)2992393Syz155240 static ipfr_t *ipfr_newfrag(fin, pass, table)
3002393Syz155240 fr_info_t *fin;
3012393Syz155240 u_32_t pass;
3022393Syz155240 ipfr_t *table[];
3032393Syz155240 {
3042393Syz155240 ipfr_t *fra, frag;
3052393Syz155240 u_int idx, off;
3063448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
3072393Syz155240
3086254San207044 if (ifs->ifs_ipfr_inuse >= ifs->ifs_ipfr_size)
3092393Syz155240 return NULL;
3102393Syz155240
3112393Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
3122393Syz155240 return NULL;
3132393Syz155240
3142393Syz155240 if (pass & FR_FRSTRICT)
3152393Syz155240 if (fin->fin_off != 0)
3162393Syz155240 return NULL;
3172393Syz155240
318*9876SDarren.Reed@Sun.COM idx = ipfr_index(fin, &frag);
3192393Syz155240
3202393Syz155240 /*
3212393Syz155240 * first, make sure it isn't already there...
3222393Syz155240 */
3232393Syz155240 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
3242393Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
3252393Syz155240 IPFR_CMPSZ)) {
3263448Sdh155122 ifs->ifs_ipfr_stats.ifs_exists++;
3272393Syz155240 return NULL;
3282393Syz155240 }
3292393Syz155240
3302393Syz155240 /*
3312393Syz155240 * allocate some memory, if possible, if not, just record that we
3322393Syz155240 * failed to do so.
3332393Syz155240 */
3342393Syz155240 KMALLOC(fra, ipfr_t *);
3352393Syz155240 if (fra == NULL) {
3363448Sdh155122 ifs->ifs_ipfr_stats.ifs_nomem++;
3372393Syz155240 return NULL;
3382393Syz155240 }
3392393Syz155240
3402393Syz155240 fra->ipfr_rule = fin->fin_fr;
3412393Syz155240 if (fra->ipfr_rule != NULL) {
3422393Syz155240
3432393Syz155240 frentry_t *fr;
3442393Syz155240
3452393Syz155240 fr = fin->fin_fr;
3462393Syz155240 MUTEX_ENTER(&fr->fr_lock);
3472393Syz155240 fr->fr_ref++;
3482393Syz155240 MUTEX_EXIT(&fr->fr_lock);
3492393Syz155240 }
3502393Syz155240
3512393Syz155240 /*
3522393Syz155240 * Insert the fragment into the fragment table, copy the struct used
3532393Syz155240 * in the search using bcopy rather than reassign each field.
3542393Syz155240 * Set the ttl to the default.
3552393Syz155240 */
3562393Syz155240 if ((fra->ipfr_hnext = table[idx]) != NULL)
3572393Syz155240 table[idx]->ipfr_hprev = &fra->ipfr_hnext;
3582393Syz155240 fra->ipfr_hprev = table + idx;
3592393Syz155240 fra->ipfr_data = NULL;
3602393Syz155240 table[idx] = fra;
3612393Syz155240 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
3623448Sdh155122 fra->ipfr_ttl = ifs->ifs_fr_ticks + ifs->ifs_fr_ipfrttl;
3632393Syz155240
3642393Syz155240 /*
3652393Syz155240 * Compute the offset of the expected start of the next packet.
3662393Syz155240 */
367*9876SDarren.Reed@Sun.COM off = fin->fin_off >> 3;
3682393Syz155240 if (off == 0) {
3692393Syz155240 fra->ipfr_seen0 = 1;
3702393Syz155240 } else {
3712393Syz155240 fra->ipfr_seen0 = 0;
3722393Syz155240 }
3732393Syz155240 fra->ipfr_off = off + fin->fin_dlen;
3742393Syz155240 fra->ipfr_pass = pass;
3753448Sdh155122 fra->ipfr_ref = 1;
3763448Sdh155122 ifs->ifs_ipfr_stats.ifs_new++;
3773448Sdh155122 ifs->ifs_ipfr_inuse++;
3782393Syz155240 return fra;
3792393Syz155240 }
3802393Syz155240
3812393Syz155240
3822393Syz155240 /* ------------------------------------------------------------------------ */
3832393Syz155240 /* Function: fr_newfrag */
3842393Syz155240 /* Returns: int - 0 == success, -1 == error */
3852393Syz155240 /* Parameters: fin(I) - pointer to packet information */
3862393Syz155240 /* */
3872393Syz155240 /* Add a new entry to the fragment cache table based on the current packet */
3882393Syz155240 /* ------------------------------------------------------------------------ */
fr_newfrag(fin,pass)3892393Syz155240 int fr_newfrag(fin, pass)
3902393Syz155240 u_32_t pass;
3912393Syz155240 fr_info_t *fin;
3922393Syz155240 {
3932393Syz155240 ipfr_t *fra;
3943448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
3952393Syz155240
3963448Sdh155122 if (ifs->ifs_fr_frag_lock != 0)
3972393Syz155240 return -1;
3982393Syz155240
3993448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag);
4003448Sdh155122 fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_heads);
4012393Syz155240 if (fra != NULL) {
4023448Sdh155122 *ifs->ifs_ipfr_tail = fra;
4033448Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_tail;
4043448Sdh155122 ifs->ifs_ipfr_tail = &fra->ipfr_next;
4053448Sdh155122 if (ifs->ifs_ipfr_list == NULL)
4063448Sdh155122 ifs->ifs_ipfr_list = fra;
4072393Syz155240 fra->ipfr_next = NULL;
4082393Syz155240 }
4093448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag);
4102393Syz155240 return fra ? 0 : -1;
4112393Syz155240 }
4122393Syz155240
4132393Syz155240
4142393Syz155240 /* ------------------------------------------------------------------------ */
4152393Syz155240 /* Function: fr_nat_newfrag */
4162393Syz155240 /* Returns: int - 0 == success, -1 == error */
4172393Syz155240 /* Parameters: fin(I) - pointer to packet information */
4182393Syz155240 /* nat(I) - pointer to NAT structure */
4192393Syz155240 /* */
4202393Syz155240 /* Create a new NAT fragment cache entry based on the current packet and */
4212393Syz155240 /* the NAT structure for this "session". */
4222393Syz155240 /* ------------------------------------------------------------------------ */
fr_nat_newfrag(fin,pass,nat)4232393Syz155240 int fr_nat_newfrag(fin, pass, nat)
4242393Syz155240 fr_info_t *fin;
4252393Syz155240 u_32_t pass;
4262393Syz155240 nat_t *nat;
4272393Syz155240 {
4282393Syz155240 ipfr_t *fra;
4293448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
4302393Syz155240
431*9876SDarren.Reed@Sun.COM if (ifs->ifs_fr_frag_lock != 0)
4322393Syz155240 return 0;
4332393Syz155240
4343448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag);
4353448Sdh155122 fra = ipfr_newfrag(fin, pass, ifs->ifs_ipfr_nattab);
4362393Syz155240 if (fra != NULL) {
4372393Syz155240 fra->ipfr_data = nat;
4382393Syz155240 nat->nat_data = fra;
4393448Sdh155122 *ifs->ifs_ipfr_nattail = fra;
4403448Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_nattail;
4413448Sdh155122 ifs->ifs_ipfr_nattail = &fra->ipfr_next;
4422393Syz155240 fra->ipfr_next = NULL;
4432393Syz155240 }
4443448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
4452393Syz155240 return fra ? 0 : -1;
4462393Syz155240 }
4472393Syz155240
4482393Syz155240
4492393Syz155240 /* ------------------------------------------------------------------------ */
4502393Syz155240 /* Function: fr_ipid_newfrag */
4512393Syz155240 /* Returns: int - 0 == success, -1 == error */
4522393Syz155240 /* Parameters: fin(I) - pointer to packet information */
4532393Syz155240 /* ipid(I) - new IP ID for this fragmented packet */
4542393Syz155240 /* */
4552393Syz155240 /* Create a new fragment cache entry for this packet and store, as a data */
4562393Syz155240 /* pointer, the new IP ID value. */
4572393Syz155240 /* ------------------------------------------------------------------------ */
fr_ipid_newfrag(fin,ipid)4582393Syz155240 int fr_ipid_newfrag(fin, ipid)
4592393Syz155240 fr_info_t *fin;
4602393Syz155240 u_32_t ipid;
4612393Syz155240 {
4622393Syz155240 ipfr_t *fra;
4633448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
4642393Syz155240
4653448Sdh155122 if (ifs->ifs_fr_frag_lock)
4662393Syz155240 return 0;
4672393Syz155240
4683448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_ipidfrag);
4693448Sdh155122 fra = ipfr_newfrag(fin, 0, ifs->ifs_ipfr_ipidtab);
4702393Syz155240 if (fra != NULL) {
4712393Syz155240 fra->ipfr_data = (void *)(uintptr_t)ipid;
4723448Sdh155122 *ifs->ifs_ipfr_ipidtail = fra;
4733448Sdh155122 fra->ipfr_prev = ifs->ifs_ipfr_ipidtail;
4743448Sdh155122 ifs->ifs_ipfr_ipidtail = &fra->ipfr_next;
4752393Syz155240 fra->ipfr_next = NULL;
4762393Syz155240 }
4773448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
4782393Syz155240 return fra ? 0 : -1;
4792393Syz155240 }
4802393Syz155240
4812393Syz155240
4822393Syz155240 /* ------------------------------------------------------------------------ */
4832393Syz155240 /* Function: fr_fraglookup */
4842393Syz155240 /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */
4852393Syz155240 /* matching entry in the frag table, else NULL */
4862393Syz155240 /* Parameters: fin(I) - pointer to packet information */
4872393Syz155240 /* table(I) - pointer to fragment cache table to search */
4882393Syz155240 /* */
4892393Syz155240 /* Check the fragment cache to see if there is already a record of this */
4902393Syz155240 /* packet with its filter result known. */
4912393Syz155240 /* ------------------------------------------------------------------------ */
fr_fraglookup(fin,table)4922393Syz155240 static ipfr_t *fr_fraglookup(fin, table)
4932393Syz155240 fr_info_t *fin;
4942393Syz155240 ipfr_t *table[];
4952393Syz155240 {
4962393Syz155240 ipfr_t *f, frag;
4972393Syz155240 u_int idx;
4983448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
4992393Syz155240
5002393Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
5012393Syz155240 return NULL;
5022393Syz155240
5032393Syz155240 /*
5042393Syz155240 * For fragments, we record protocol, packet id, TOS and both IP#'s
5052393Syz155240 * (these should all be the same for all fragments of a packet).
5062393Syz155240 *
5072393Syz155240 * build up a hash value to index the table with.
5082393Syz155240 */
509*9876SDarren.Reed@Sun.COM idx = ipfr_index(fin, &frag);
5102393Syz155240
5112393Syz155240 /*
5122393Syz155240 * check the table, careful to only compare the right amount of data
5132393Syz155240 */
5142393Syz155240 for (f = table[idx]; f; f = f->ipfr_hnext)
5152393Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
5162393Syz155240 IPFR_CMPSZ)) {
5172393Syz155240 u_short off;
5182393Syz155240
5192393Syz155240 /*
5202393Syz155240 * We don't want to let short packets match because
5212393Syz155240 * they could be compromising the security of other
5222393Syz155240 * rules that want to match on layer 4 fields (and
5232393Syz155240 * can't because they have been fragmented off.)
5242393Syz155240 * Why do this check here? The counter acts as an
5252393Syz155240 * indicator of this kind of attack, whereas if it was
5262393Syz155240 * elsewhere, it wouldn't know if other matching
5272393Syz155240 * packets had been seen.
5282393Syz155240 */
5292393Syz155240 if (fin->fin_flx & FI_SHORT) {
5303448Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_short);
5312393Syz155240 continue;
5322393Syz155240 }
5332393Syz155240
5342393Syz155240 /*
5352393Syz155240 * XXX - We really need to be guarding against the
5362393Syz155240 * retransmission of (src,dst,id,offset-range) here
5372393Syz155240 * because a fragmented packet is never resent with
5382393Syz155240 * the same IP ID# (or shouldn't).
5392393Syz155240 */
540*9876SDarren.Reed@Sun.COM off = fin->fin_off >> 3;
5412393Syz155240 if (f->ipfr_seen0) {
5422393Syz155240 if (off == 0) {
5433448Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_retrans0);
5442393Syz155240 continue;
5452393Syz155240 }
5462393Syz155240 } else if (off == 0) {
5472393Syz155240 f->ipfr_seen0 = 1;
5482393Syz155240 }
5492393Syz155240
5502393Syz155240 if (f != table[idx]) {
5512393Syz155240 ipfr_t **fp;
5522393Syz155240
5532393Syz155240 /*
5542393Syz155240 * Move fragment info. to the top of the list
5552393Syz155240 * to speed up searches. First, delink...
5562393Syz155240 */
5572393Syz155240 fp = f->ipfr_hprev;
5582393Syz155240 (*fp) = f->ipfr_hnext;
5592393Syz155240 if (f->ipfr_hnext != NULL)
5602393Syz155240 f->ipfr_hnext->ipfr_hprev = fp;
5612393Syz155240 /*
5622393Syz155240 * Then put back at the top of the chain.
5632393Syz155240 */
5642393Syz155240 f->ipfr_hnext = table[idx];
5652393Syz155240 table[idx]->ipfr_hprev = &f->ipfr_hnext;
5662393Syz155240 f->ipfr_hprev = table + idx;
5672393Syz155240 table[idx] = f;
5682393Syz155240 }
5692393Syz155240
5702393Syz155240 /*
5712393Syz155240 * If we've follwed the fragments, and this is the
5722393Syz155240 * last (in order), shrink expiration time.
5732393Syz155240 */
5742393Syz155240 if (off == f->ipfr_off) {
575*9876SDarren.Reed@Sun.COM if (!(fin->fin_flx & FI_MOREFRAG))
5763448Sdh155122 f->ipfr_ttl = ifs->ifs_fr_ticks + 1;
5772393Syz155240 f->ipfr_off = fin->fin_dlen + off;
5782393Syz155240 } else if (f->ipfr_pass & FR_FRSTRICT)
5792393Syz155240 continue;
5803448Sdh155122 ATOMIC_INCL(ifs->ifs_ipfr_stats.ifs_hits);
5812393Syz155240 return f;
5822393Syz155240 }
5832393Syz155240 return NULL;
5842393Syz155240 }
5852393Syz155240
5862393Syz155240
5872393Syz155240 /* ------------------------------------------------------------------------ */
5882393Syz155240 /* Function: fr_nat_knownfrag */
5892393Syz155240 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */
5902393Syz155240 /* match found, else NULL */
5912393Syz155240 /* Parameters: fin(I) - pointer to packet information */
5922393Syz155240 /* */
5932393Syz155240 /* Functional interface for NAT lookups of the NAT fragment cache */
5942393Syz155240 /* ------------------------------------------------------------------------ */
fr_nat_knownfrag(fin)5952393Syz155240 nat_t *fr_nat_knownfrag(fin)
5962393Syz155240 fr_info_t *fin;
5972393Syz155240 {
5982393Syz155240 nat_t *nat;
5992393Syz155240 ipfr_t *ipf;
6003448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
6012393Syz155240
602*9876SDarren.Reed@Sun.COM if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_natlist)
6032393Syz155240 return NULL;
6043448Sdh155122 READ_ENTER(&ifs->ifs_ipf_natfrag);
6053448Sdh155122 ipf = fr_fraglookup(fin, ifs->ifs_ipfr_nattab);
6062393Syz155240 if (ipf != NULL) {
6072393Syz155240 nat = ipf->ipfr_data;
6082393Syz155240 /*
6092393Syz155240 * This is the last fragment for this packet.
6102393Syz155240 */
6113448Sdh155122 if ((ipf->ipfr_ttl == ifs->ifs_fr_ticks + 1) && (nat != NULL)) {
6122393Syz155240 nat->nat_data = NULL;
6132393Syz155240 ipf->ipfr_data = NULL;
6142393Syz155240 }
6152393Syz155240 } else
6162393Syz155240 nat = NULL;
6173448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
6182393Syz155240 return nat;
6192393Syz155240 }
6202393Syz155240
6212393Syz155240
6222393Syz155240 /* ------------------------------------------------------------------------ */
6232393Syz155240 /* Function: fr_ipid_knownfrag */
6242393Syz155240 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */
6252393Syz155240 /* return 0xfffffff to indicate no match. */
6262393Syz155240 /* Parameters: fin(I) - pointer to packet information */
6272393Syz155240 /* */
6282393Syz155240 /* Functional interface for IP ID lookups of the IP ID fragment cache */
6292393Syz155240 /* ------------------------------------------------------------------------ */
fr_ipid_knownfrag(fin)6302393Syz155240 u_32_t fr_ipid_knownfrag(fin)
6312393Syz155240 fr_info_t *fin;
6322393Syz155240 {
6332393Syz155240 ipfr_t *ipf;
6342393Syz155240 u_32_t id;
6353448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
6362393Syz155240
637*9876SDarren.Reed@Sun.COM if (ifs->ifs_fr_frag_lock || !ifs->ifs_ipfr_ipidlist)
6382393Syz155240 return 0xffffffff;
6392393Syz155240
6403448Sdh155122 READ_ENTER(&ifs->ifs_ipf_ipidfrag);
6413448Sdh155122 ipf = fr_fraglookup(fin, ifs->ifs_ipfr_ipidtab);
6422393Syz155240 if (ipf != NULL)
6432393Syz155240 id = (u_32_t)(uintptr_t)ipf->ipfr_data;
6442393Syz155240 else
6452393Syz155240 id = 0xffffffff;
6463448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
6472393Syz155240 return id;
6482393Syz155240 }
6492393Syz155240
6502393Syz155240
6512393Syz155240 /* ------------------------------------------------------------------------ */
6522393Syz155240 /* Function: fr_knownfrag */
6532393Syz155240 /* Returns: frentry_t* - pointer to filter rule if a match is found in */
6542393Syz155240 /* the frag cache table, else NULL. */
6552393Syz155240 /* Parameters: fin(I) - pointer to packet information */
6562393Syz155240 /* passp(O) - pointer to where to store rule flags resturned */
6572393Syz155240 /* */
6582393Syz155240 /* Functional interface for normal lookups of the fragment cache. If a */
6592393Syz155240 /* match is found, return the rule pointer and flags from the rule, except */
6602393Syz155240 /* that if FR_LOGFIRST is set, reset FR_LOG. */
6612393Syz155240 /* ------------------------------------------------------------------------ */
fr_knownfrag(fin,passp)6622393Syz155240 frentry_t *fr_knownfrag(fin, passp)
6632393Syz155240 fr_info_t *fin;
6642393Syz155240 u_32_t *passp;
6652393Syz155240 {
6662393Syz155240 frentry_t *fr = NULL;
6672393Syz155240 ipfr_t *fra;
6682393Syz155240 u_32_t pass, oflx;
6693448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs;
6702393Syz155240
671*9876SDarren.Reed@Sun.COM if (ifs->ifs_fr_frag_lock || (ifs->ifs_ipfr_list == NULL))
6722393Syz155240 return NULL;
6732393Syz155240
6743448Sdh155122 READ_ENTER(&ifs->ifs_ipf_frag);
6752393Syz155240 oflx = fin->fin_flx;
6763448Sdh155122 fra = fr_fraglookup(fin, ifs->ifs_ipfr_heads);
6772393Syz155240 if (fra != NULL) {
6782393Syz155240 fr = fra->ipfr_rule;
6792393Syz155240 fin->fin_fr = fr;
6802393Syz155240 if (fr != NULL) {
6812393Syz155240 pass = fr->fr_flags;
6822393Syz155240 if ((pass & FR_LOGFIRST) != 0)
6832393Syz155240 pass &= ~(FR_LOGFIRST|FR_LOG);
6842393Syz155240 *passp = pass;
6852393Syz155240 }
6862393Syz155240 }
6872393Syz155240 if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) {
6882393Syz155240 *passp &= ~FR_CMDMASK;
6892393Syz155240 *passp |= FR_BLOCK;
6903448Sdh155122 fr = &ifs->ifs_frblock;
6912393Syz155240 }
6923448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag);
6932393Syz155240 return fr;
6942393Syz155240 }
6952393Syz155240
6962393Syz155240
6972393Syz155240 /* ------------------------------------------------------------------------ */
6982393Syz155240 /* Function: fr_forget */
6992393Syz155240 /* Returns: Nil */
7002393Syz155240 /* Parameters: ptr(I) - pointer to data structure */
7012393Syz155240 /* */
7022393Syz155240 /* Search through all of the fragment cache entries and wherever a pointer */
7032393Syz155240 /* is found to match ptr, reset it to NULL. */
7042393Syz155240 /* ------------------------------------------------------------------------ */
fr_forget(ptr,ifs)7053448Sdh155122 void fr_forget(ptr, ifs)
7062393Syz155240 void *ptr;
7073448Sdh155122 ipf_stack_t *ifs;
7082393Syz155240 {
7092393Syz155240 ipfr_t *fr;
7102393Syz155240
7113448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag);
7123448Sdh155122 for (fr = ifs->ifs_ipfr_list; fr; fr = fr->ipfr_next)
7132393Syz155240 if (fr->ipfr_data == ptr)
7142393Syz155240 fr->ipfr_data = NULL;
7153448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag);
7162393Syz155240 }
7172393Syz155240
7182393Syz155240
7192393Syz155240 /* ------------------------------------------------------------------------ */
7202393Syz155240 /* Function: fr_forgetnat */
7212393Syz155240 /* Returns: Nil */
7222393Syz155240 /* Parameters: ptr(I) - pointer to data structure */
7232393Syz155240 /* */
7242393Syz155240 /* Search through all of the fragment cache entries for NAT and wherever a */
7252393Syz155240 /* pointer is found to match ptr, reset it to NULL. */
7262393Syz155240 /* ------------------------------------------------------------------------ */
fr_forgetnat(ptr,ifs)7273448Sdh155122 void fr_forgetnat(ptr, ifs)
7282393Syz155240 void *ptr;
7293448Sdh155122 ipf_stack_t *ifs;
7302393Syz155240 {
7312393Syz155240 ipfr_t *fr;
7322393Syz155240
7333448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag);
7343448Sdh155122 for (fr = ifs->ifs_ipfr_natlist; fr; fr = fr->ipfr_next)
7352393Syz155240 if (fr->ipfr_data == ptr)
7362393Syz155240 fr->ipfr_data = NULL;
7373448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
7382393Syz155240 }
7392393Syz155240
7402393Syz155240
7412393Syz155240 /* ------------------------------------------------------------------------ */
7422393Syz155240 /* Function: fr_fragdelete */
7432393Syz155240 /* Returns: Nil */
7442393Syz155240 /* Parameters: fra(I) - pointer to fragment structure to delete */
7452393Syz155240 /* tail(IO) - pointer to the pointer to the tail of the frag */
7462393Syz155240 /* list */
7472393Syz155240 /* */
7482393Syz155240 /* Remove a fragment cache table entry from the table & list. Also free */
7492393Syz155240 /* the filter rule it is associated with it if it is no longer used as a */
7502393Syz155240 /* result of decreasing the reference count. */
7512393Syz155240 /* ------------------------------------------------------------------------ */
fr_fragdelete(fra,tail,ifs)7523448Sdh155122 static void fr_fragdelete(fra, tail, ifs)
7532393Syz155240 ipfr_t *fra, ***tail;
7543448Sdh155122 ipf_stack_t *ifs;
7552393Syz155240 {
7562393Syz155240 frentry_t *fr;
7572393Syz155240
7582393Syz155240 fr = fra->ipfr_rule;
7592393Syz155240 if (fr != NULL)
7603448Sdh155122 (void)fr_derefrule(&fr, ifs);
7612393Syz155240
7622393Syz155240 if (fra->ipfr_next)
7632393Syz155240 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
7642393Syz155240 *fra->ipfr_prev = fra->ipfr_next;
7652393Syz155240 if (*tail == &fra->ipfr_next)
7662393Syz155240 *tail = fra->ipfr_prev;
7672393Syz155240
7682393Syz155240 if (fra->ipfr_hnext)
7692393Syz155240 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
7702393Syz155240 *fra->ipfr_hprev = fra->ipfr_hnext;
7713448Sdh155122
7723448Sdh155122 if (fra->ipfr_ref <= 0)
7733448Sdh155122 KFREE(fra);
7742393Syz155240 }
7752393Syz155240
7762393Syz155240
7772393Syz155240 /* ------------------------------------------------------------------------ */
7782393Syz155240 /* Function: fr_fragclear */
7792393Syz155240 /* Returns: Nil */
7802393Syz155240 /* Parameters: Nil */
7812393Syz155240 /* */
7822393Syz155240 /* Free memory in use by fragment state information kept. Do the normal */
7832393Syz155240 /* fragment state stuff first and then the NAT-fragment table. */
7842393Syz155240 /* ------------------------------------------------------------------------ */
fr_fragclear(ifs)7853448Sdh155122 void fr_fragclear(ifs)
7863448Sdh155122 ipf_stack_t *ifs;
7872393Syz155240 {
7882393Syz155240 ipfr_t *fra;
7892393Syz155240 nat_t *nat;
7902393Syz155240
7913448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag);
7923448Sdh155122 while ((fra = ifs->ifs_ipfr_list) != NULL) {
7933448Sdh155122 fra->ipfr_ref--;
7943448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs);
7953448Sdh155122 }
7963448Sdh155122 ifs->ifs_ipfr_tail = &ifs->ifs_ipfr_list;
7973448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag);
7982393Syz155240
7993448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat);
8003448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag);
8013448Sdh155122 while ((fra = ifs->ifs_ipfr_natlist) != NULL) {
8022393Syz155240 nat = fra->ipfr_data;
8032393Syz155240 if (nat != NULL) {
8042393Syz155240 if (nat->nat_data == fra)
8052393Syz155240 nat->nat_data = NULL;
8062393Syz155240 }
8073448Sdh155122 fra->ipfr_ref--;
8083448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs);
8092393Syz155240 }
8103448Sdh155122 ifs->ifs_ipfr_nattail = &ifs->ifs_ipfr_natlist;
8113448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
8123448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
8132393Syz155240 }
8142393Syz155240
8152393Syz155240
8162393Syz155240 /* ------------------------------------------------------------------------ */
8172393Syz155240 /* Function: fr_fragexpire */
8182393Syz155240 /* Returns: Nil */
8192393Syz155240 /* Parameters: Nil */
8202393Syz155240 /* */
8212393Syz155240 /* Expire entries in the fragment cache table that have been there too long */
8222393Syz155240 /* ------------------------------------------------------------------------ */
fr_fragexpire(ifs)8233448Sdh155122 void fr_fragexpire(ifs)
8243448Sdh155122 ipf_stack_t *ifs;
8252393Syz155240 {
8262393Syz155240 ipfr_t **fp, *fra;
8272393Syz155240 nat_t *nat;
8282393Syz155240 SPL_INT(s);
8292393Syz155240
8303448Sdh155122 if (ifs->ifs_fr_frag_lock)
8312393Syz155240 return;
8322393Syz155240
8332393Syz155240 SPL_NET(s);
8343448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_frag);
8352393Syz155240 /*
8362393Syz155240 * Go through the entire table, looking for entries to expire,
8373448Sdh155122 * which is indicated by the ttl being less than or equal to
8383448Sdh155122 * ifs_fr_ticks.
8392393Syz155240 */
8403448Sdh155122 for (fp = &ifs->ifs_ipfr_list; ((fra = *fp) != NULL); ) {
8413448Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
8422393Syz155240 break;
8433448Sdh155122 fra->ipfr_ref--;
8443448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_tail, ifs);
8453448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++;
8463448Sdh155122 ifs->ifs_ipfr_inuse--;
8472393Syz155240 }
8483448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_frag);
8492393Syz155240
8503448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_ipidfrag);
8513448Sdh155122 for (fp = &ifs->ifs_ipfr_ipidlist; ((fra = *fp) != NULL); ) {
8523448Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
8532393Syz155240 break;
8543448Sdh155122 fra->ipfr_ref--;
8553448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_ipidtail, ifs);
8563448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++;
8573448Sdh155122 ifs->ifs_ipfr_inuse--;
8582393Syz155240 }
8593448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_ipidfrag);
8602393Syz155240
8612393Syz155240 /*
8622393Syz155240 * Same again for the NAT table, except that if the structure also
8632393Syz155240 * still points to a NAT structure, and the NAT structure points back
8642393Syz155240 * at the one to be free'd, NULL the reference from the NAT struct.
8652393Syz155240 * NOTE: We need to grab both mutex's early, and in this order so as
8662393Syz155240 * to prevent a deadlock if both try to expire at the same time.
8672393Syz155240 */
8683448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_nat);
8693448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_natfrag);
8703448Sdh155122 for (fp = &ifs->ifs_ipfr_natlist; ((fra = *fp) != NULL); ) {
8713448Sdh155122 if (fra->ipfr_ttl > ifs->ifs_fr_ticks)
8722393Syz155240 break;
8732393Syz155240 nat = fra->ipfr_data;
8742393Syz155240 if (nat != NULL) {
8752393Syz155240 if (nat->nat_data == fra)
8762393Syz155240 nat->nat_data = NULL;
8772393Syz155240 }
8783448Sdh155122 fra->ipfr_ref--;
8793448Sdh155122 fr_fragdelete(fra, &ifs->ifs_ipfr_nattail, ifs);
8803448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++;
8813448Sdh155122 ifs->ifs_ipfr_inuse--;
8822393Syz155240 }
8833448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_natfrag);
8843448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
8852393Syz155240 SPL_X(s);
8862393Syz155240 }
8872393Syz155240
8882393Syz155240
8892393Syz155240 /* ------------------------------------------------------------------------ */
8902393Syz155240 /* Function: fr_slowtimer */
8912393Syz155240 /* Returns: Nil */
8922393Syz155240 /* Parameters: Nil */
8932393Syz155240 /* */
8942393Syz155240 /* Slowly expire held state for fragments. Timeouts are set * in */
8952393Syz155240 /* expectation of this being called twice per second. */
8962393Syz155240 /* ------------------------------------------------------------------------ */
8972393Syz155240 #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
8982393Syz155240 !defined(__osf__) && !defined(linux))
8992393Syz155240 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
fr_slowtimer(void * arg)9003448Sdh155122 void fr_slowtimer __P((void *arg))
9012393Syz155240 # else
9023448Sdh155122 int fr_slowtimer(void *arg)
9032393Syz155240 # endif
9042393Syz155240 {
9053448Sdh155122 ipf_stack_t *ifs = arg;
9063448Sdh155122
9073448Sdh155122 READ_ENTER(&ifs->ifs_ipf_global);
9082393Syz155240
9093448Sdh155122 fr_fragexpire(ifs);
9103448Sdh155122 fr_timeoutstate(ifs);
9113448Sdh155122 fr_natexpire(ifs);
9123448Sdh155122 fr_authexpire(ifs);
9133448Sdh155122 ifs->ifs_fr_ticks++;
9143448Sdh155122 if (ifs->ifs_fr_running <= 0)
9152393Syz155240 goto done;
9162393Syz155240 # ifdef _KERNEL
9172393Syz155240 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
9182393Syz155240 callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
9192393Syz155240 # else
9202393Syz155240 # if defined(__OpenBSD__)
9212393Syz155240 timeout_add(&fr_slowtimer_ch, hz/2);
9222393Syz155240 # else
9232393Syz155240 # if (__FreeBSD_version >= 300000)
9242393Syz155240 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
9252393Syz155240 # else
9262393Syz155240 # ifdef linux
9272393Syz155240 ;
9282393Syz155240 # else
9292393Syz155240 timeout(fr_slowtimer, NULL, hz/2);
9302393Syz155240 # endif
9312393Syz155240 # endif /* FreeBSD */
9322393Syz155240 # endif /* OpenBSD */
9332393Syz155240 # endif /* NetBSD */
9342393Syz155240 # endif
9352393Syz155240 done:
9363448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global);
9372393Syz155240 # if (BSD < 199103) || !defined(_KERNEL)
9382393Syz155240 return 0;
9392393Syz155240 # endif
9402393Syz155240 }
9412393Syz155240 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
9423448Sdh155122
9433448Sdh155122 /*ARGSUSED*/
fr_nextfrag(token,itp,top,tail,lock,ifs)9443448Sdh155122 int fr_nextfrag(token, itp, top, tail, lock, ifs)
9453448Sdh155122 ipftoken_t *token;
9463448Sdh155122 ipfgeniter_t *itp;
9473448Sdh155122 ipfr_t **top, ***tail;
9483448Sdh155122 ipfrwlock_t *lock;
9493448Sdh155122 ipf_stack_t *ifs;
9503448Sdh155122 {
9513448Sdh155122 ipfr_t *frag, *next, zero;
9523448Sdh155122 int error = 0;
9533448Sdh155122
9546518Sjojemann READ_ENTER(lock);
9556518Sjojemann
9566518Sjojemann /*
9576518Sjojemann * Retrieve "previous" entry from token and find the next entry.
9586518Sjojemann */
9593448Sdh155122 frag = token->ipt_data;
9603448Sdh155122 if (frag == NULL)
9613448Sdh155122 next = *top;
9623448Sdh155122 else
9633448Sdh155122 next = frag->ipfr_next;
9643448Sdh155122
9656518Sjojemann /*
9666518Sjojemann * If we found an entry, add reference to it and update token.
9676518Sjojemann * Otherwise, zero out data to be returned and NULL out token.
9686518Sjojemann */
9693448Sdh155122 if (next != NULL) {
9703448Sdh155122 ATOMIC_INC(next->ipfr_ref);
9713448Sdh155122 token->ipt_data = next;
9723448Sdh155122 } else {
9733448Sdh155122 bzero(&zero, sizeof(zero));
9743448Sdh155122 next = &zero;
9756518Sjojemann token->ipt_data = NULL;
9763448Sdh155122 }
9776518Sjojemann
9786518Sjojemann /*
9796518Sjojemann * Now that we have ref, it's save to give up lock.
9806518Sjojemann */
9813448Sdh155122 RWLOCK_EXIT(lock);
9823448Sdh155122
9836518Sjojemann /*
9846518Sjojemann * Copy out data and clean up references and token as needed.
9856518Sjojemann */
9863448Sdh155122 error = COPYOUT(next, itp->igi_data, sizeof(*next));
9873448Sdh155122 if (error != 0)
9883448Sdh155122 error = EFAULT;
9896518Sjojemann if (token->ipt_data == NULL) {
9906518Sjojemann ipf_freetoken(token, ifs);
9916518Sjojemann } else {
9926518Sjojemann if (frag != NULL)
9936518Sjojemann fr_fragderef(&frag, lock, ifs);
9946518Sjojemann if (next->ipfr_next == NULL)
9956518Sjojemann ipf_freetoken(token, ifs);
9966518Sjojemann }
9973448Sdh155122 return error;
9983448Sdh155122 }
9993448Sdh155122
10003448Sdh155122
fr_fragderef(frp,lock,ifs)10013448Sdh155122 void fr_fragderef(frp, lock, ifs)
10023448Sdh155122 ipfr_t **frp;
10033448Sdh155122 ipfrwlock_t *lock;
10043448Sdh155122 ipf_stack_t *ifs;
10053448Sdh155122 {
10063448Sdh155122 ipfr_t *fra;
10073448Sdh155122
10083448Sdh155122 fra = *frp;
10093448Sdh155122 *frp = NULL;
10103448Sdh155122
10113448Sdh155122 WRITE_ENTER(lock);
10123448Sdh155122 fra->ipfr_ref--;
10133448Sdh155122 if (fra->ipfr_ref <= 0) {
10143448Sdh155122 KFREE(fra);
10153448Sdh155122 ifs->ifs_ipfr_stats.ifs_expire++;
10163448Sdh155122 ifs->ifs_ipfr_inuse--;
10173448Sdh155122 }
10183448Sdh155122 RWLOCK_EXIT(lock);
10193448Sdh155122 }
1020