1*2393Syz155240 /* 2*2393Syz155240 * Copyright (C) 1993-2003 by Darren Reed. 3*2393Syz155240 * 4*2393Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 5*2393Syz155240 * 6*2393Syz155240 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 7*2393Syz155240 * Use is subject to license terms. 8*2393Syz155240 */ 9*2393Syz155240 10*2393Syz155240 #pragma ident "%Z%%M% %I% %E% SMI" 11*2393Syz155240 12*2393Syz155240 #if defined(KERNEL) || defined(_KERNEL) 13*2393Syz155240 # undef KERNEL 14*2393Syz155240 # undef _KERNEL 15*2393Syz155240 # define KERNEL 1 16*2393Syz155240 # define _KERNEL 1 17*2393Syz155240 #endif 18*2393Syz155240 #include <sys/errno.h> 19*2393Syz155240 #include <sys/types.h> 20*2393Syz155240 #include <sys/param.h> 21*2393Syz155240 #include <sys/time.h> 22*2393Syz155240 #include <sys/file.h> 23*2393Syz155240 #ifdef __hpux 24*2393Syz155240 # include <sys/timeout.h> 25*2393Syz155240 #endif 26*2393Syz155240 #if !defined(_KERNEL) 27*2393Syz155240 # include <stdio.h> 28*2393Syz155240 # include <string.h> 29*2393Syz155240 # include <stdlib.h> 30*2393Syz155240 # define _KERNEL 31*2393Syz155240 # ifdef __OpenBSD__ 32*2393Syz155240 struct file; 33*2393Syz155240 # endif 34*2393Syz155240 # include <sys/uio.h> 35*2393Syz155240 # undef _KERNEL 36*2393Syz155240 #endif 37*2393Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 38*2393Syz155240 # include <sys/filio.h> 39*2393Syz155240 # include <sys/fcntl.h> 40*2393Syz155240 #else 41*2393Syz155240 # include <sys/ioctl.h> 42*2393Syz155240 #endif 43*2393Syz155240 #if !defined(linux) 44*2393Syz155240 # include <sys/protosw.h> 45*2393Syz155240 #endif 46*2393Syz155240 #include <sys/socket.h> 47*2393Syz155240 #if defined(_KERNEL) 48*2393Syz155240 # include <sys/systm.h> 49*2393Syz155240 # if !defined(__SVR4) && !defined(__svr4__) 50*2393Syz155240 # include <sys/mbuf.h> 51*2393Syz155240 # endif 52*2393Syz155240 #endif 53*2393Syz155240 #if !defined(__SVR4) && !defined(__svr4__) 54*2393Syz155240 # if defined(_KERNEL) && !defined(__sgi) && !defined(AIX) 55*2393Syz155240 # include <sys/kernel.h> 56*2393Syz155240 # endif 57*2393Syz155240 #else 58*2393Syz155240 # include <sys/byteorder.h> 59*2393Syz155240 # ifdef _KERNEL 60*2393Syz155240 # include <sys/dditypes.h> 61*2393Syz155240 # endif 62*2393Syz155240 # include <sys/stream.h> 63*2393Syz155240 # include <sys/kmem.h> 64*2393Syz155240 #endif 65*2393Syz155240 #include <net/if.h> 66*2393Syz155240 #ifdef sun 67*2393Syz155240 # include <net/af.h> 68*2393Syz155240 #endif 69*2393Syz155240 #include <net/route.h> 70*2393Syz155240 #include <netinet/in.h> 71*2393Syz155240 #include <netinet/in_systm.h> 72*2393Syz155240 #include <netinet/ip.h> 73*2393Syz155240 #if !defined(linux) 74*2393Syz155240 # include <netinet/ip_var.h> 75*2393Syz155240 #endif 76*2393Syz155240 #include <netinet/tcp.h> 77*2393Syz155240 #include <netinet/udp.h> 78*2393Syz155240 #include <netinet/ip_icmp.h> 79*2393Syz155240 #include "netinet/ip_compat.h" 80*2393Syz155240 #include <netinet/tcpip.h> 81*2393Syz155240 #include "netinet/ip_fil.h" 82*2393Syz155240 #include "netinet/ip_nat.h" 83*2393Syz155240 #include "netinet/ip_frag.h" 84*2393Syz155240 #include "netinet/ip_state.h" 85*2393Syz155240 #include "netinet/ip_auth.h" 86*2393Syz155240 #include "netinet/ip_proxy.h" 87*2393Syz155240 #if (__FreeBSD_version >= 300000) 88*2393Syz155240 # include <sys/malloc.h> 89*2393Syz155240 # if defined(_KERNEL) 90*2393Syz155240 # ifndef IPFILTER_LKM 91*2393Syz155240 # include <sys/libkern.h> 92*2393Syz155240 # include <sys/systm.h> 93*2393Syz155240 # endif 94*2393Syz155240 extern struct callout_handle fr_slowtimer_ch; 95*2393Syz155240 # endif 96*2393Syz155240 #endif 97*2393Syz155240 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 98*2393Syz155240 # include <sys/callout.h> 99*2393Syz155240 extern struct callout fr_slowtimer_ch; 100*2393Syz155240 #endif 101*2393Syz155240 #if defined(__OpenBSD__) 102*2393Syz155240 # include <sys/timeout.h> 103*2393Syz155240 extern struct timeout fr_slowtimer_ch; 104*2393Syz155240 #endif 105*2393Syz155240 /* END OF INCLUDES */ 106*2393Syz155240 107*2393Syz155240 #if !defined(lint) 108*2393Syz155240 static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; 109*2393Syz155240 static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2005/08/11 14:33:10 darrenr Exp $"; 110*2393Syz155240 #endif 111*2393Syz155240 112*2393Syz155240 113*2393Syz155240 static ipfr_t *ipfr_list = NULL; 114*2393Syz155240 static ipfr_t **ipfr_tail = &ipfr_list; 115*2393Syz155240 static ipfr_t **ipfr_heads; 116*2393Syz155240 117*2393Syz155240 static ipfr_t *ipfr_natlist = NULL; 118*2393Syz155240 static ipfr_t **ipfr_nattail = &ipfr_natlist; 119*2393Syz155240 static ipfr_t **ipfr_nattab; 120*2393Syz155240 121*2393Syz155240 static ipfr_t *ipfr_ipidlist = NULL; 122*2393Syz155240 static ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; 123*2393Syz155240 static ipfr_t **ipfr_ipidtab; 124*2393Syz155240 125*2393Syz155240 static ipfrstat_t ipfr_stats; 126*2393Syz155240 static int ipfr_inuse = 0; 127*2393Syz155240 int ipfr_size = IPFT_SIZE; 128*2393Syz155240 129*2393Syz155240 int fr_ipfrttl = 120; /* 60 seconds */ 130*2393Syz155240 int fr_frag_lock = 0; 131*2393Syz155240 int fr_frag_init = 0; 132*2393Syz155240 u_long fr_ticks = 0; 133*2393Syz155240 134*2393Syz155240 135*2393Syz155240 static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); 136*2393Syz155240 static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); 137*2393Syz155240 static void fr_fragdelete __P((ipfr_t *, ipfr_t ***)); 138*2393Syz155240 139*2393Syz155240 static frentry_t frblock; 140*2393Syz155240 141*2393Syz155240 /* ------------------------------------------------------------------------ */ 142*2393Syz155240 /* Function: fr_fraginit */ 143*2393Syz155240 /* Returns: int - 0 == success, -1 == error */ 144*2393Syz155240 /* Parameters: Nil */ 145*2393Syz155240 /* */ 146*2393Syz155240 /* Initialise the hash tables for the fragment cache lookups. */ 147*2393Syz155240 /* ------------------------------------------------------------------------ */ 148*2393Syz155240 int fr_fraginit() 149*2393Syz155240 { 150*2393Syz155240 KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); 151*2393Syz155240 if (ipfr_heads == NULL) 152*2393Syz155240 return -1; 153*2393Syz155240 bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *)); 154*2393Syz155240 155*2393Syz155240 KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); 156*2393Syz155240 if (ipfr_nattab == NULL) 157*2393Syz155240 return -1; 158*2393Syz155240 bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); 159*2393Syz155240 160*2393Syz155240 KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); 161*2393Syz155240 if (ipfr_ipidtab == NULL) 162*2393Syz155240 return -1; 163*2393Syz155240 bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); 164*2393Syz155240 165*2393Syz155240 RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock"); 166*2393Syz155240 167*2393Syz155240 /* Initialise frblock with "block in all" */ 168*2393Syz155240 bzero((char *)&frblock, sizeof(frblock)); 169*2393Syz155240 frblock.fr_flags = FR_BLOCK|FR_INQUE; /* block in */ 170*2393Syz155240 frblock.fr_ref = 1; 171*2393Syz155240 172*2393Syz155240 fr_frag_init = 1; 173*2393Syz155240 174*2393Syz155240 return 0; 175*2393Syz155240 } 176*2393Syz155240 177*2393Syz155240 178*2393Syz155240 /* ------------------------------------------------------------------------ */ 179*2393Syz155240 /* Function: fr_fragunload */ 180*2393Syz155240 /* Returns: Nil */ 181*2393Syz155240 /* Parameters: Nil */ 182*2393Syz155240 /* */ 183*2393Syz155240 /* Free all memory allocated whilst running and from initialisation. */ 184*2393Syz155240 /* ------------------------------------------------------------------------ */ 185*2393Syz155240 void fr_fragunload() 186*2393Syz155240 { 187*2393Syz155240 if (fr_frag_init == 1) { 188*2393Syz155240 fr_fragclear(); 189*2393Syz155240 190*2393Syz155240 RW_DESTROY(&ipf_frag); 191*2393Syz155240 fr_frag_init = 0; 192*2393Syz155240 } 193*2393Syz155240 194*2393Syz155240 if (ipfr_heads != NULL) 195*2393Syz155240 KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *)); 196*2393Syz155240 ipfr_heads = NULL; 197*2393Syz155240 198*2393Syz155240 if (ipfr_nattab != NULL) 199*2393Syz155240 KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); 200*2393Syz155240 ipfr_nattab = NULL; 201*2393Syz155240 202*2393Syz155240 if (ipfr_ipidtab != NULL) 203*2393Syz155240 KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); 204*2393Syz155240 ipfr_ipidtab = NULL; 205*2393Syz155240 } 206*2393Syz155240 207*2393Syz155240 208*2393Syz155240 /* ------------------------------------------------------------------------ */ 209*2393Syz155240 /* Function: fr_fragstats */ 210*2393Syz155240 /* Returns: ipfrstat_t* - pointer to struct with current frag stats */ 211*2393Syz155240 /* Parameters: Nil */ 212*2393Syz155240 /* */ 213*2393Syz155240 /* Updates ipfr_stats with current information and returns a pointer to it */ 214*2393Syz155240 /* ------------------------------------------------------------------------ */ 215*2393Syz155240 ipfrstat_t *fr_fragstats() 216*2393Syz155240 { 217*2393Syz155240 ipfr_stats.ifs_table = ipfr_heads; 218*2393Syz155240 ipfr_stats.ifs_nattab = ipfr_nattab; 219*2393Syz155240 ipfr_stats.ifs_inuse = ipfr_inuse; 220*2393Syz155240 return &ipfr_stats; 221*2393Syz155240 } 222*2393Syz155240 223*2393Syz155240 224*2393Syz155240 /* ------------------------------------------------------------------------ */ 225*2393Syz155240 /* Function: ipfr_newfrag */ 226*2393Syz155240 /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ 227*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 228*2393Syz155240 /* table(I) - pointer to frag table to add to */ 229*2393Syz155240 /* */ 230*2393Syz155240 /* Add a new entry to the fragment cache, registering it as having come */ 231*2393Syz155240 /* through this box, with the result of the filter operation. */ 232*2393Syz155240 /* ------------------------------------------------------------------------ */ 233*2393Syz155240 static ipfr_t *ipfr_newfrag(fin, pass, table) 234*2393Syz155240 fr_info_t *fin; 235*2393Syz155240 u_32_t pass; 236*2393Syz155240 ipfr_t *table[]; 237*2393Syz155240 { 238*2393Syz155240 ipfr_t *fra, frag; 239*2393Syz155240 u_int idx, off; 240*2393Syz155240 241*2393Syz155240 if (ipfr_inuse >= IPFT_SIZE) 242*2393Syz155240 return NULL; 243*2393Syz155240 244*2393Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 245*2393Syz155240 return NULL; 246*2393Syz155240 247*2393Syz155240 if (pass & FR_FRSTRICT) 248*2393Syz155240 if (fin->fin_off != 0) 249*2393Syz155240 return NULL; 250*2393Syz155240 251*2393Syz155240 frag.ipfr_p = fin->fin_p; 252*2393Syz155240 idx = fin->fin_p; 253*2393Syz155240 frag.ipfr_id = fin->fin_id; 254*2393Syz155240 idx += fin->fin_id; 255*2393Syz155240 frag.ipfr_source = fin->fin_fi.fi_src; 256*2393Syz155240 idx += frag.ipfr_src.s_addr; 257*2393Syz155240 frag.ipfr_dest = fin->fin_fi.fi_dst; 258*2393Syz155240 idx += frag.ipfr_dst.s_addr; 259*2393Syz155240 frag.ipfr_ifp = fin->fin_ifp; 260*2393Syz155240 idx *= 127; 261*2393Syz155240 idx %= IPFT_SIZE; 262*2393Syz155240 263*2393Syz155240 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 264*2393Syz155240 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 265*2393Syz155240 frag.ipfr_auth = fin->fin_fi.fi_auth; 266*2393Syz155240 267*2393Syz155240 /* 268*2393Syz155240 * first, make sure it isn't already there... 269*2393Syz155240 */ 270*2393Syz155240 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 271*2393Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, 272*2393Syz155240 IPFR_CMPSZ)) { 273*2393Syz155240 ipfr_stats.ifs_exists++; 274*2393Syz155240 return NULL; 275*2393Syz155240 } 276*2393Syz155240 277*2393Syz155240 /* 278*2393Syz155240 * allocate some memory, if possible, if not, just record that we 279*2393Syz155240 * failed to do so. 280*2393Syz155240 */ 281*2393Syz155240 KMALLOC(fra, ipfr_t *); 282*2393Syz155240 if (fra == NULL) { 283*2393Syz155240 ipfr_stats.ifs_nomem++; 284*2393Syz155240 return NULL; 285*2393Syz155240 } 286*2393Syz155240 287*2393Syz155240 fra->ipfr_rule = fin->fin_fr; 288*2393Syz155240 if (fra->ipfr_rule != NULL) { 289*2393Syz155240 290*2393Syz155240 frentry_t *fr; 291*2393Syz155240 292*2393Syz155240 fr = fin->fin_fr; 293*2393Syz155240 MUTEX_ENTER(&fr->fr_lock); 294*2393Syz155240 fr->fr_ref++; 295*2393Syz155240 MUTEX_EXIT(&fr->fr_lock); 296*2393Syz155240 } 297*2393Syz155240 298*2393Syz155240 /* 299*2393Syz155240 * Insert the fragment into the fragment table, copy the struct used 300*2393Syz155240 * in the search using bcopy rather than reassign each field. 301*2393Syz155240 * Set the ttl to the default. 302*2393Syz155240 */ 303*2393Syz155240 if ((fra->ipfr_hnext = table[idx]) != NULL) 304*2393Syz155240 table[idx]->ipfr_hprev = &fra->ipfr_hnext; 305*2393Syz155240 fra->ipfr_hprev = table + idx; 306*2393Syz155240 fra->ipfr_data = NULL; 307*2393Syz155240 table[idx] = fra; 308*2393Syz155240 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 309*2393Syz155240 fra->ipfr_ttl = fr_ticks + fr_ipfrttl; 310*2393Syz155240 311*2393Syz155240 /* 312*2393Syz155240 * Compute the offset of the expected start of the next packet. 313*2393Syz155240 */ 314*2393Syz155240 off = fin->fin_off; 315*2393Syz155240 if (off == 0) { 316*2393Syz155240 fra->ipfr_seen0 = 1; 317*2393Syz155240 fra->ipfr_firstend = fin->fin_flen; 318*2393Syz155240 } else { 319*2393Syz155240 fra->ipfr_seen0 = 0; 320*2393Syz155240 fra->ipfr_firstend = 0; 321*2393Syz155240 } 322*2393Syz155240 fra->ipfr_off = off + fin->fin_dlen; 323*2393Syz155240 fra->ipfr_pass = pass; 324*2393Syz155240 ipfr_stats.ifs_new++; 325*2393Syz155240 ipfr_inuse++; 326*2393Syz155240 return fra; 327*2393Syz155240 } 328*2393Syz155240 329*2393Syz155240 330*2393Syz155240 /* ------------------------------------------------------------------------ */ 331*2393Syz155240 /* Function: fr_newfrag */ 332*2393Syz155240 /* Returns: int - 0 == success, -1 == error */ 333*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 334*2393Syz155240 /* */ 335*2393Syz155240 /* Add a new entry to the fragment cache table based on the current packet */ 336*2393Syz155240 /* ------------------------------------------------------------------------ */ 337*2393Syz155240 int fr_newfrag(fin, pass) 338*2393Syz155240 u_32_t pass; 339*2393Syz155240 fr_info_t *fin; 340*2393Syz155240 { 341*2393Syz155240 ipfr_t *fra; 342*2393Syz155240 343*2393Syz155240 if (fr_frag_lock != 0) 344*2393Syz155240 return -1; 345*2393Syz155240 346*2393Syz155240 WRITE_ENTER(&ipf_frag); 347*2393Syz155240 fra = ipfr_newfrag(fin, pass, ipfr_heads); 348*2393Syz155240 if (fra != NULL) { 349*2393Syz155240 *ipfr_tail = fra; 350*2393Syz155240 fra->ipfr_prev = ipfr_tail; 351*2393Syz155240 ipfr_tail = &fra->ipfr_next; 352*2393Syz155240 if (ipfr_list == NULL) 353*2393Syz155240 ipfr_list = fra; 354*2393Syz155240 fra->ipfr_next = NULL; 355*2393Syz155240 } 356*2393Syz155240 RWLOCK_EXIT(&ipf_frag); 357*2393Syz155240 return fra ? 0 : -1; 358*2393Syz155240 } 359*2393Syz155240 360*2393Syz155240 361*2393Syz155240 /* ------------------------------------------------------------------------ */ 362*2393Syz155240 /* Function: fr_nat_newfrag */ 363*2393Syz155240 /* Returns: int - 0 == success, -1 == error */ 364*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 365*2393Syz155240 /* nat(I) - pointer to NAT structure */ 366*2393Syz155240 /* */ 367*2393Syz155240 /* Create a new NAT fragment cache entry based on the current packet and */ 368*2393Syz155240 /* the NAT structure for this "session". */ 369*2393Syz155240 /* ------------------------------------------------------------------------ */ 370*2393Syz155240 int fr_nat_newfrag(fin, pass, nat) 371*2393Syz155240 fr_info_t *fin; 372*2393Syz155240 u_32_t pass; 373*2393Syz155240 nat_t *nat; 374*2393Syz155240 { 375*2393Syz155240 ipfr_t *fra; 376*2393Syz155240 377*2393Syz155240 if ((fin->fin_v != 4) || (fr_frag_lock != 0)) 378*2393Syz155240 return 0; 379*2393Syz155240 380*2393Syz155240 WRITE_ENTER(&ipf_natfrag); 381*2393Syz155240 fra = ipfr_newfrag(fin, pass, ipfr_nattab); 382*2393Syz155240 if (fra != NULL) { 383*2393Syz155240 fra->ipfr_data = nat; 384*2393Syz155240 nat->nat_data = fra; 385*2393Syz155240 *ipfr_nattail = fra; 386*2393Syz155240 fra->ipfr_prev = ipfr_nattail; 387*2393Syz155240 ipfr_nattail = &fra->ipfr_next; 388*2393Syz155240 fra->ipfr_next = NULL; 389*2393Syz155240 } 390*2393Syz155240 RWLOCK_EXIT(&ipf_natfrag); 391*2393Syz155240 return fra ? 0 : -1; 392*2393Syz155240 } 393*2393Syz155240 394*2393Syz155240 395*2393Syz155240 /* ------------------------------------------------------------------------ */ 396*2393Syz155240 /* Function: fr_ipid_newfrag */ 397*2393Syz155240 /* Returns: int - 0 == success, -1 == error */ 398*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 399*2393Syz155240 /* ipid(I) - new IP ID for this fragmented packet */ 400*2393Syz155240 /* */ 401*2393Syz155240 /* Create a new fragment cache entry for this packet and store, as a data */ 402*2393Syz155240 /* pointer, the new IP ID value. */ 403*2393Syz155240 /* ------------------------------------------------------------------------ */ 404*2393Syz155240 int fr_ipid_newfrag(fin, ipid) 405*2393Syz155240 fr_info_t *fin; 406*2393Syz155240 u_32_t ipid; 407*2393Syz155240 { 408*2393Syz155240 ipfr_t *fra; 409*2393Syz155240 410*2393Syz155240 if (fr_frag_lock) 411*2393Syz155240 return 0; 412*2393Syz155240 413*2393Syz155240 WRITE_ENTER(&ipf_ipidfrag); 414*2393Syz155240 fra = ipfr_newfrag(fin, 0, ipfr_ipidtab); 415*2393Syz155240 if (fra != NULL) { 416*2393Syz155240 fra->ipfr_data = (void *)(uintptr_t)ipid; 417*2393Syz155240 *ipfr_ipidtail = fra; 418*2393Syz155240 fra->ipfr_prev = ipfr_ipidtail; 419*2393Syz155240 ipfr_ipidtail = &fra->ipfr_next; 420*2393Syz155240 fra->ipfr_next = NULL; 421*2393Syz155240 } 422*2393Syz155240 RWLOCK_EXIT(&ipf_ipidfrag); 423*2393Syz155240 return fra ? 0 : -1; 424*2393Syz155240 } 425*2393Syz155240 426*2393Syz155240 427*2393Syz155240 /* ------------------------------------------------------------------------ */ 428*2393Syz155240 /* Function: fr_fraglookup */ 429*2393Syz155240 /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 430*2393Syz155240 /* matching entry in the frag table, else NULL */ 431*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 432*2393Syz155240 /* table(I) - pointer to fragment cache table to search */ 433*2393Syz155240 /* */ 434*2393Syz155240 /* Check the fragment cache to see if there is already a record of this */ 435*2393Syz155240 /* packet with its filter result known. */ 436*2393Syz155240 /* ------------------------------------------------------------------------ */ 437*2393Syz155240 static ipfr_t *fr_fraglookup(fin, table) 438*2393Syz155240 fr_info_t *fin; 439*2393Syz155240 ipfr_t *table[]; 440*2393Syz155240 { 441*2393Syz155240 ipfr_t *f, frag; 442*2393Syz155240 u_int idx; 443*2393Syz155240 444*2393Syz155240 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 445*2393Syz155240 return NULL; 446*2393Syz155240 447*2393Syz155240 /* 448*2393Syz155240 * For fragments, we record protocol, packet id, TOS and both IP#'s 449*2393Syz155240 * (these should all be the same for all fragments of a packet). 450*2393Syz155240 * 451*2393Syz155240 * build up a hash value to index the table with. 452*2393Syz155240 */ 453*2393Syz155240 frag.ipfr_p = fin->fin_p; 454*2393Syz155240 idx = fin->fin_p; 455*2393Syz155240 frag.ipfr_id = fin->fin_id; 456*2393Syz155240 idx += fin->fin_id; 457*2393Syz155240 frag.ipfr_source = fin->fin_fi.fi_src; 458*2393Syz155240 idx += frag.ipfr_src.s_addr; 459*2393Syz155240 frag.ipfr_dest = fin->fin_fi.fi_dst; 460*2393Syz155240 idx += frag.ipfr_dst.s_addr; 461*2393Syz155240 frag.ipfr_ifp = fin->fin_ifp; 462*2393Syz155240 idx *= 127; 463*2393Syz155240 idx %= IPFT_SIZE; 464*2393Syz155240 465*2393Syz155240 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 466*2393Syz155240 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 467*2393Syz155240 frag.ipfr_auth = fin->fin_fi.fi_auth; 468*2393Syz155240 469*2393Syz155240 /* 470*2393Syz155240 * check the table, careful to only compare the right amount of data 471*2393Syz155240 */ 472*2393Syz155240 for (f = table[idx]; f; f = f->ipfr_hnext) 473*2393Syz155240 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, 474*2393Syz155240 IPFR_CMPSZ)) { 475*2393Syz155240 u_short off; 476*2393Syz155240 477*2393Syz155240 /* 478*2393Syz155240 * We don't want to let short packets match because 479*2393Syz155240 * they could be compromising the security of other 480*2393Syz155240 * rules that want to match on layer 4 fields (and 481*2393Syz155240 * can't because they have been fragmented off.) 482*2393Syz155240 * Why do this check here? The counter acts as an 483*2393Syz155240 * indicator of this kind of attack, whereas if it was 484*2393Syz155240 * elsewhere, it wouldn't know if other matching 485*2393Syz155240 * packets had been seen. 486*2393Syz155240 */ 487*2393Syz155240 if (fin->fin_flx & FI_SHORT) { 488*2393Syz155240 ATOMIC_INCL(ipfr_stats.ifs_short); 489*2393Syz155240 continue; 490*2393Syz155240 } 491*2393Syz155240 492*2393Syz155240 /* 493*2393Syz155240 * XXX - We really need to be guarding against the 494*2393Syz155240 * retransmission of (src,dst,id,offset-range) here 495*2393Syz155240 * because a fragmented packet is never resent with 496*2393Syz155240 * the same IP ID# (or shouldn't). 497*2393Syz155240 */ 498*2393Syz155240 off = fin->fin_off; /* same as in ipfr_newfrag() */ 499*2393Syz155240 if (f->ipfr_seen0) { 500*2393Syz155240 if (off == 0) { 501*2393Syz155240 ATOMIC_INCL(ipfr_stats.ifs_retrans0); 502*2393Syz155240 continue; 503*2393Syz155240 } 504*2393Syz155240 } else if (off == 0) { 505*2393Syz155240 f->ipfr_seen0 = 1; 506*2393Syz155240 f->ipfr_firstend = fin->fin_flen; 507*2393Syz155240 } 508*2393Syz155240 509*2393Syz155240 if (f != table[idx]) { 510*2393Syz155240 ipfr_t **fp; 511*2393Syz155240 512*2393Syz155240 /* 513*2393Syz155240 * Move fragment info. to the top of the list 514*2393Syz155240 * to speed up searches. First, delink... 515*2393Syz155240 */ 516*2393Syz155240 fp = f->ipfr_hprev; 517*2393Syz155240 (*fp) = f->ipfr_hnext; 518*2393Syz155240 if (f->ipfr_hnext != NULL) 519*2393Syz155240 f->ipfr_hnext->ipfr_hprev = fp; 520*2393Syz155240 /* 521*2393Syz155240 * Then put back at the top of the chain. 522*2393Syz155240 */ 523*2393Syz155240 f->ipfr_hnext = table[idx]; 524*2393Syz155240 table[idx]->ipfr_hprev = &f->ipfr_hnext; 525*2393Syz155240 f->ipfr_hprev = table + idx; 526*2393Syz155240 table[idx] = f; 527*2393Syz155240 } 528*2393Syz155240 529*2393Syz155240 if (fin->fin_v == 6) { 530*2393Syz155240 if (f->ipfr_seen0 && (off < f->ipfr_firstend)) 531*2393Syz155240 fin->fin_flx |= FI_BAD; 532*2393Syz155240 } 533*2393Syz155240 /* 534*2393Syz155240 * If we've follwed the fragments, and this is the 535*2393Syz155240 * last (in order), shrink expiration time. 536*2393Syz155240 */ 537*2393Syz155240 if (off == f->ipfr_off) { 538*2393Syz155240 if (!(fin->fin_ip->ip_off & IP_MF)) 539*2393Syz155240 f->ipfr_ttl = fr_ticks + 1; 540*2393Syz155240 f->ipfr_off = fin->fin_dlen + off; 541*2393Syz155240 } else if (f->ipfr_pass & FR_FRSTRICT) 542*2393Syz155240 continue; 543*2393Syz155240 ATOMIC_INCL(ipfr_stats.ifs_hits); 544*2393Syz155240 return f; 545*2393Syz155240 } 546*2393Syz155240 return NULL; 547*2393Syz155240 } 548*2393Syz155240 549*2393Syz155240 550*2393Syz155240 /* ------------------------------------------------------------------------ */ 551*2393Syz155240 /* Function: fr_nat_knownfrag */ 552*2393Syz155240 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 553*2393Syz155240 /* match found, else NULL */ 554*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 555*2393Syz155240 /* */ 556*2393Syz155240 /* Functional interface for NAT lookups of the NAT fragment cache */ 557*2393Syz155240 /* ------------------------------------------------------------------------ */ 558*2393Syz155240 nat_t *fr_nat_knownfrag(fin) 559*2393Syz155240 fr_info_t *fin; 560*2393Syz155240 { 561*2393Syz155240 nat_t *nat; 562*2393Syz155240 ipfr_t *ipf; 563*2393Syz155240 564*2393Syz155240 if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist) 565*2393Syz155240 return NULL; 566*2393Syz155240 READ_ENTER(&ipf_natfrag); 567*2393Syz155240 ipf = fr_fraglookup(fin, ipfr_nattab); 568*2393Syz155240 if (ipf != NULL) { 569*2393Syz155240 nat = ipf->ipfr_data; 570*2393Syz155240 /* 571*2393Syz155240 * This is the last fragment for this packet. 572*2393Syz155240 */ 573*2393Syz155240 if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) { 574*2393Syz155240 nat->nat_data = NULL; 575*2393Syz155240 ipf->ipfr_data = NULL; 576*2393Syz155240 } 577*2393Syz155240 } else 578*2393Syz155240 nat = NULL; 579*2393Syz155240 RWLOCK_EXIT(&ipf_natfrag); 580*2393Syz155240 return nat; 581*2393Syz155240 } 582*2393Syz155240 583*2393Syz155240 584*2393Syz155240 /* ------------------------------------------------------------------------ */ 585*2393Syz155240 /* Function: fr_ipid_knownfrag */ 586*2393Syz155240 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 587*2393Syz155240 /* return 0xfffffff to indicate no match. */ 588*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 589*2393Syz155240 /* */ 590*2393Syz155240 /* Functional interface for IP ID lookups of the IP ID fragment cache */ 591*2393Syz155240 /* ------------------------------------------------------------------------ */ 592*2393Syz155240 u_32_t fr_ipid_knownfrag(fin) 593*2393Syz155240 fr_info_t *fin; 594*2393Syz155240 { 595*2393Syz155240 ipfr_t *ipf; 596*2393Syz155240 u_32_t id; 597*2393Syz155240 598*2393Syz155240 if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist) 599*2393Syz155240 return 0xffffffff; 600*2393Syz155240 601*2393Syz155240 READ_ENTER(&ipf_ipidfrag); 602*2393Syz155240 ipf = fr_fraglookup(fin, ipfr_ipidtab); 603*2393Syz155240 if (ipf != NULL) 604*2393Syz155240 id = (u_32_t)(uintptr_t)ipf->ipfr_data; 605*2393Syz155240 else 606*2393Syz155240 id = 0xffffffff; 607*2393Syz155240 RWLOCK_EXIT(&ipf_ipidfrag); 608*2393Syz155240 return id; 609*2393Syz155240 } 610*2393Syz155240 611*2393Syz155240 612*2393Syz155240 /* ------------------------------------------------------------------------ */ 613*2393Syz155240 /* Function: fr_knownfrag */ 614*2393Syz155240 /* Returns: frentry_t* - pointer to filter rule if a match is found in */ 615*2393Syz155240 /* the frag cache table, else NULL. */ 616*2393Syz155240 /* Parameters: fin(I) - pointer to packet information */ 617*2393Syz155240 /* passp(O) - pointer to where to store rule flags resturned */ 618*2393Syz155240 /* */ 619*2393Syz155240 /* Functional interface for normal lookups of the fragment cache. If a */ 620*2393Syz155240 /* match is found, return the rule pointer and flags from the rule, except */ 621*2393Syz155240 /* that if FR_LOGFIRST is set, reset FR_LOG. */ 622*2393Syz155240 /* ------------------------------------------------------------------------ */ 623*2393Syz155240 frentry_t *fr_knownfrag(fin, passp) 624*2393Syz155240 fr_info_t *fin; 625*2393Syz155240 u_32_t *passp; 626*2393Syz155240 { 627*2393Syz155240 frentry_t *fr = NULL; 628*2393Syz155240 ipfr_t *fra; 629*2393Syz155240 u_32_t pass, oflx; 630*2393Syz155240 631*2393Syz155240 if ((fr_frag_lock) || (ipfr_list == NULL)) 632*2393Syz155240 return NULL; 633*2393Syz155240 634*2393Syz155240 READ_ENTER(&ipf_frag); 635*2393Syz155240 oflx = fin->fin_flx; 636*2393Syz155240 fra = fr_fraglookup(fin, ipfr_heads); 637*2393Syz155240 if (fra != NULL) { 638*2393Syz155240 fr = fra->ipfr_rule; 639*2393Syz155240 fin->fin_fr = fr; 640*2393Syz155240 if (fr != NULL) { 641*2393Syz155240 pass = fr->fr_flags; 642*2393Syz155240 if ((pass & FR_LOGFIRST) != 0) 643*2393Syz155240 pass &= ~(FR_LOGFIRST|FR_LOG); 644*2393Syz155240 *passp = pass; 645*2393Syz155240 } 646*2393Syz155240 } 647*2393Syz155240 if (!(oflx & FI_BAD) && (fin->fin_flx & FI_BAD)) { 648*2393Syz155240 *passp &= ~FR_CMDMASK; 649*2393Syz155240 *passp |= FR_BLOCK; 650*2393Syz155240 fr = &frblock; 651*2393Syz155240 } 652*2393Syz155240 RWLOCK_EXIT(&ipf_frag); 653*2393Syz155240 return fr; 654*2393Syz155240 } 655*2393Syz155240 656*2393Syz155240 657*2393Syz155240 /* ------------------------------------------------------------------------ */ 658*2393Syz155240 /* Function: fr_forget */ 659*2393Syz155240 /* Returns: Nil */ 660*2393Syz155240 /* Parameters: ptr(I) - pointer to data structure */ 661*2393Syz155240 /* */ 662*2393Syz155240 /* Search through all of the fragment cache entries and wherever a pointer */ 663*2393Syz155240 /* is found to match ptr, reset it to NULL. */ 664*2393Syz155240 /* ------------------------------------------------------------------------ */ 665*2393Syz155240 void fr_forget(ptr) 666*2393Syz155240 void *ptr; 667*2393Syz155240 { 668*2393Syz155240 ipfr_t *fr; 669*2393Syz155240 670*2393Syz155240 WRITE_ENTER(&ipf_frag); 671*2393Syz155240 for (fr = ipfr_list; fr; fr = fr->ipfr_next) 672*2393Syz155240 if (fr->ipfr_data == ptr) 673*2393Syz155240 fr->ipfr_data = NULL; 674*2393Syz155240 RWLOCK_EXIT(&ipf_frag); 675*2393Syz155240 } 676*2393Syz155240 677*2393Syz155240 678*2393Syz155240 /* ------------------------------------------------------------------------ */ 679*2393Syz155240 /* Function: fr_forgetnat */ 680*2393Syz155240 /* Returns: Nil */ 681*2393Syz155240 /* Parameters: ptr(I) - pointer to data structure */ 682*2393Syz155240 /* */ 683*2393Syz155240 /* Search through all of the fragment cache entries for NAT and wherever a */ 684*2393Syz155240 /* pointer is found to match ptr, reset it to NULL. */ 685*2393Syz155240 /* ------------------------------------------------------------------------ */ 686*2393Syz155240 void fr_forgetnat(ptr) 687*2393Syz155240 void *ptr; 688*2393Syz155240 { 689*2393Syz155240 ipfr_t *fr; 690*2393Syz155240 691*2393Syz155240 WRITE_ENTER(&ipf_natfrag); 692*2393Syz155240 for (fr = ipfr_natlist; fr; fr = fr->ipfr_next) 693*2393Syz155240 if (fr->ipfr_data == ptr) 694*2393Syz155240 fr->ipfr_data = NULL; 695*2393Syz155240 RWLOCK_EXIT(&ipf_natfrag); 696*2393Syz155240 } 697*2393Syz155240 698*2393Syz155240 699*2393Syz155240 /* ------------------------------------------------------------------------ */ 700*2393Syz155240 /* Function: fr_fragdelete */ 701*2393Syz155240 /* Returns: Nil */ 702*2393Syz155240 /* Parameters: fra(I) - pointer to fragment structure to delete */ 703*2393Syz155240 /* tail(IO) - pointer to the pointer to the tail of the frag */ 704*2393Syz155240 /* list */ 705*2393Syz155240 /* */ 706*2393Syz155240 /* Remove a fragment cache table entry from the table & list. Also free */ 707*2393Syz155240 /* the filter rule it is associated with it if it is no longer used as a */ 708*2393Syz155240 /* result of decreasing the reference count. */ 709*2393Syz155240 /* ------------------------------------------------------------------------ */ 710*2393Syz155240 static void fr_fragdelete(fra, tail) 711*2393Syz155240 ipfr_t *fra, ***tail; 712*2393Syz155240 { 713*2393Syz155240 frentry_t *fr; 714*2393Syz155240 715*2393Syz155240 fr = fra->ipfr_rule; 716*2393Syz155240 if (fr != NULL) 717*2393Syz155240 (void)fr_derefrule(&fr); 718*2393Syz155240 719*2393Syz155240 if (fra->ipfr_next) 720*2393Syz155240 fra->ipfr_next->ipfr_prev = fra->ipfr_prev; 721*2393Syz155240 *fra->ipfr_prev = fra->ipfr_next; 722*2393Syz155240 if (*tail == &fra->ipfr_next) 723*2393Syz155240 *tail = fra->ipfr_prev; 724*2393Syz155240 725*2393Syz155240 if (fra->ipfr_hnext) 726*2393Syz155240 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 727*2393Syz155240 *fra->ipfr_hprev = fra->ipfr_hnext; 728*2393Syz155240 KFREE(fra); 729*2393Syz155240 } 730*2393Syz155240 731*2393Syz155240 732*2393Syz155240 /* ------------------------------------------------------------------------ */ 733*2393Syz155240 /* Function: fr_fragclear */ 734*2393Syz155240 /* Returns: Nil */ 735*2393Syz155240 /* Parameters: Nil */ 736*2393Syz155240 /* */ 737*2393Syz155240 /* Free memory in use by fragment state information kept. Do the normal */ 738*2393Syz155240 /* fragment state stuff first and then the NAT-fragment table. */ 739*2393Syz155240 /* ------------------------------------------------------------------------ */ 740*2393Syz155240 void fr_fragclear() 741*2393Syz155240 { 742*2393Syz155240 ipfr_t *fra; 743*2393Syz155240 nat_t *nat; 744*2393Syz155240 745*2393Syz155240 WRITE_ENTER(&ipf_frag); 746*2393Syz155240 while ((fra = ipfr_list) != NULL) 747*2393Syz155240 fr_fragdelete(fra, &ipfr_tail); 748*2393Syz155240 ipfr_tail = &ipfr_list; 749*2393Syz155240 RWLOCK_EXIT(&ipf_frag); 750*2393Syz155240 751*2393Syz155240 WRITE_ENTER(&ipf_nat); 752*2393Syz155240 WRITE_ENTER(&ipf_natfrag); 753*2393Syz155240 while ((fra = ipfr_natlist) != NULL) { 754*2393Syz155240 nat = fra->ipfr_data; 755*2393Syz155240 if (nat != NULL) { 756*2393Syz155240 if (nat->nat_data == fra) 757*2393Syz155240 nat->nat_data = NULL; 758*2393Syz155240 } 759*2393Syz155240 fr_fragdelete(fra, &ipfr_nattail); 760*2393Syz155240 } 761*2393Syz155240 ipfr_nattail = &ipfr_natlist; 762*2393Syz155240 RWLOCK_EXIT(&ipf_natfrag); 763*2393Syz155240 RWLOCK_EXIT(&ipf_nat); 764*2393Syz155240 } 765*2393Syz155240 766*2393Syz155240 767*2393Syz155240 /* ------------------------------------------------------------------------ */ 768*2393Syz155240 /* Function: fr_fragexpire */ 769*2393Syz155240 /* Returns: Nil */ 770*2393Syz155240 /* Parameters: Nil */ 771*2393Syz155240 /* */ 772*2393Syz155240 /* Expire entries in the fragment cache table that have been there too long */ 773*2393Syz155240 /* ------------------------------------------------------------------------ */ 774*2393Syz155240 void fr_fragexpire() 775*2393Syz155240 { 776*2393Syz155240 ipfr_t **fp, *fra; 777*2393Syz155240 nat_t *nat; 778*2393Syz155240 SPL_INT(s); 779*2393Syz155240 780*2393Syz155240 if (fr_frag_lock) 781*2393Syz155240 return; 782*2393Syz155240 783*2393Syz155240 SPL_NET(s); 784*2393Syz155240 WRITE_ENTER(&ipf_frag); 785*2393Syz155240 /* 786*2393Syz155240 * Go through the entire table, looking for entries to expire, 787*2393Syz155240 * which is indicated by the ttl being less than or equal to fr_ticks. 788*2393Syz155240 */ 789*2393Syz155240 for (fp = &ipfr_list; ((fra = *fp) != NULL); ) { 790*2393Syz155240 if (fra->ipfr_ttl > fr_ticks) 791*2393Syz155240 break; 792*2393Syz155240 fr_fragdelete(fra, &ipfr_tail); 793*2393Syz155240 ipfr_stats.ifs_expire++; 794*2393Syz155240 ipfr_inuse--; 795*2393Syz155240 } 796*2393Syz155240 RWLOCK_EXIT(&ipf_frag); 797*2393Syz155240 798*2393Syz155240 WRITE_ENTER(&ipf_ipidfrag); 799*2393Syz155240 for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) { 800*2393Syz155240 if (fra->ipfr_ttl > fr_ticks) 801*2393Syz155240 break; 802*2393Syz155240 fr_fragdelete(fra, &ipfr_ipidtail); 803*2393Syz155240 ipfr_stats.ifs_expire++; 804*2393Syz155240 ipfr_inuse--; 805*2393Syz155240 } 806*2393Syz155240 RWLOCK_EXIT(&ipf_ipidfrag); 807*2393Syz155240 808*2393Syz155240 /* 809*2393Syz155240 * Same again for the NAT table, except that if the structure also 810*2393Syz155240 * still points to a NAT structure, and the NAT structure points back 811*2393Syz155240 * at the one to be free'd, NULL the reference from the NAT struct. 812*2393Syz155240 * NOTE: We need to grab both mutex's early, and in this order so as 813*2393Syz155240 * to prevent a deadlock if both try to expire at the same time. 814*2393Syz155240 */ 815*2393Syz155240 WRITE_ENTER(&ipf_nat); 816*2393Syz155240 WRITE_ENTER(&ipf_natfrag); 817*2393Syz155240 for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { 818*2393Syz155240 if (fra->ipfr_ttl > fr_ticks) 819*2393Syz155240 break; 820*2393Syz155240 nat = fra->ipfr_data; 821*2393Syz155240 if (nat != NULL) { 822*2393Syz155240 if (nat->nat_data == fra) 823*2393Syz155240 nat->nat_data = NULL; 824*2393Syz155240 } 825*2393Syz155240 fr_fragdelete(fra, &ipfr_nattail); 826*2393Syz155240 ipfr_stats.ifs_expire++; 827*2393Syz155240 ipfr_inuse--; 828*2393Syz155240 } 829*2393Syz155240 RWLOCK_EXIT(&ipf_natfrag); 830*2393Syz155240 RWLOCK_EXIT(&ipf_nat); 831*2393Syz155240 SPL_X(s); 832*2393Syz155240 } 833*2393Syz155240 834*2393Syz155240 835*2393Syz155240 /* ------------------------------------------------------------------------ */ 836*2393Syz155240 /* Function: fr_slowtimer */ 837*2393Syz155240 /* Returns: Nil */ 838*2393Syz155240 /* Parameters: Nil */ 839*2393Syz155240 /* */ 840*2393Syz155240 /* Slowly expire held state for fragments. Timeouts are set * in */ 841*2393Syz155240 /* expectation of this being called twice per second. */ 842*2393Syz155240 /* ------------------------------------------------------------------------ */ 843*2393Syz155240 #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ 844*2393Syz155240 !defined(__osf__) && !defined(linux)) 845*2393Syz155240 # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) 846*2393Syz155240 void fr_slowtimer __P((void *ptr)) 847*2393Syz155240 # else 848*2393Syz155240 int fr_slowtimer() 849*2393Syz155240 # endif 850*2393Syz155240 { 851*2393Syz155240 READ_ENTER(&ipf_global); 852*2393Syz155240 853*2393Syz155240 fr_fragexpire(); 854*2393Syz155240 fr_timeoutstate(); 855*2393Syz155240 fr_natexpire(); 856*2393Syz155240 fr_authexpire(); 857*2393Syz155240 fr_ticks++; 858*2393Syz155240 if (fr_running <= 0) 859*2393Syz155240 goto done; 860*2393Syz155240 # ifdef _KERNEL 861*2393Syz155240 # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) 862*2393Syz155240 callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); 863*2393Syz155240 # else 864*2393Syz155240 # if defined(__OpenBSD__) 865*2393Syz155240 timeout_add(&fr_slowtimer_ch, hz/2); 866*2393Syz155240 # else 867*2393Syz155240 # if (__FreeBSD_version >= 300000) 868*2393Syz155240 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); 869*2393Syz155240 # else 870*2393Syz155240 # ifdef linux 871*2393Syz155240 ; 872*2393Syz155240 # else 873*2393Syz155240 timeout(fr_slowtimer, NULL, hz/2); 874*2393Syz155240 # endif 875*2393Syz155240 # endif /* FreeBSD */ 876*2393Syz155240 # endif /* OpenBSD */ 877*2393Syz155240 # endif /* NetBSD */ 878*2393Syz155240 # endif 879*2393Syz155240 done: 880*2393Syz155240 RWLOCK_EXIT(&ipf_global); 881*2393Syz155240 # if (BSD < 199103) || !defined(_KERNEL) 882*2393Syz155240 return 0; 883*2393Syz155240 # endif 884*2393Syz155240 } 885*2393Syz155240 #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ 886