ip_auth.c revision 80482
153642Sguido/* 280482Sdarrenr * Copyright (C) 1998-2001 by Darren Reed & Guido van Rooij. 353642Sguido * 480482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 553642Sguido */ 653642Sguido#include <sys/errno.h> 753642Sguido#include <sys/types.h> 853642Sguido#include <sys/param.h> 953642Sguido#include <sys/time.h> 1053642Sguido#include <sys/file.h> 1153642Sguido#if !defined(_KERNEL) && !defined(KERNEL) 1253642Sguido# include <stdio.h> 1353642Sguido# include <stdlib.h> 1453642Sguido# include <string.h> 1553642Sguido#endif 1660850Sdarrenr#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) 1753642Sguido# include <sys/filio.h> 1853642Sguido# include <sys/fcntl.h> 1953642Sguido#else 2053642Sguido# include <sys/ioctl.h> 2153642Sguido#endif 2253642Sguido#include <sys/uio.h> 2353642Sguido#ifndef linux 2453642Sguido# include <sys/protosw.h> 2553642Sguido#endif 2653642Sguido#include <sys/socket.h> 2757096Sguido#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) 2853642Sguido# include <sys/systm.h> 2953642Sguido#endif 3053642Sguido#if !defined(__SVR4) && !defined(__svr4__) 3153642Sguido# ifndef linux 3253642Sguido# include <sys/mbuf.h> 3353642Sguido# endif 3453642Sguido#else 3553642Sguido# include <sys/filio.h> 3653642Sguido# include <sys/byteorder.h> 3753642Sguido# ifdef _KERNEL 3853642Sguido# include <sys/dditypes.h> 3953642Sguido# endif 4053642Sguido# include <sys/stream.h> 4153642Sguido# include <sys/kmem.h> 4253642Sguido#endif 4364105Sroberto#if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) 4453642Sguido# include <sys/queue.h> 4553642Sguido#endif 4653642Sguido#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 4753642Sguido# include <machine/cpu.h> 4853642Sguido#endif 4953642Sguido#include <net/if.h> 5053642Sguido#ifdef sun 5153642Sguido# include <net/af.h> 5253642Sguido#endif 5353642Sguido#include <net/route.h> 5453642Sguido#include <netinet/in.h> 5553642Sguido#include <netinet/in_systm.h> 5653642Sguido#include <netinet/ip.h> 5753642Sguido#ifndef KERNEL 5853642Sguido# define KERNEL 5953642Sguido# define NOT_KERNEL 6053642Sguido#endif 6153642Sguido#ifndef linux 6253642Sguido# include <netinet/ip_var.h> 6353642Sguido#endif 6453642Sguido#ifdef NOT_KERNEL 6553642Sguido# undef KERNEL 6653642Sguido#endif 6753642Sguido#ifdef __sgi 6853642Sguido# ifdef IFF_DRVRLOCK /* IRIX6 */ 6953642Sguido# include <sys/hashing.h> 7053642Sguido# endif 7153642Sguido#endif 7253642Sguido#include <netinet/tcp.h> 7353642Sguido#if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */ 7480482Sdarrenrextern struct ifqueue ipintrq; /* ip packet input queue */ 7553642Sguido#else 7653642Sguido# ifndef linux 7753642Sguido# if __FreeBSD_version >= 300000 7853642Sguido# include <net/if_var.h> 7953642Sguido# endif 8053642Sguido# include <netinet/in_var.h> 8153642Sguido# include <netinet/tcp_fsm.h> 8253642Sguido# endif 8353642Sguido#endif 8453642Sguido#include <netinet/udp.h> 8553642Sguido#include <netinet/ip_icmp.h> 8653642Sguido#include "netinet/ip_compat.h" 8753642Sguido#include <netinet/tcpip.h> 8853642Sguido#include "netinet/ip_fil.h" 8953642Sguido#include "netinet/ip_auth.h" 9053642Sguido#if !SOLARIS && !defined(linux) 9153642Sguido# include <net/netisr.h> 9253642Sguido# ifdef __FreeBSD__ 9353642Sguido# include <machine/cpufunc.h> 9453642Sguido# endif 9553642Sguido#endif 9653642Sguido#if (__FreeBSD_version >= 300000) 9753642Sguido# include <sys/malloc.h> 9853642Sguido# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) 9953642Sguido# include <sys/libkern.h> 10053642Sguido# include <sys/systm.h> 10153642Sguido# endif 10253642Sguido#endif 10353642Sguido 10480482Sdarrenr#if !defined(lint) 10580482Sdarrenr/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.12 2001/07/18 14:57:08 darrenr Exp $"; */ 10680482Sdarrenrstatic const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_auth.c 80482 2001-07-28 11:58:26Z darrenr $"; 10780482Sdarrenr#endif 10853642Sguido 10953642Sguido 11053642Sguido#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) 11180482Sdarrenrextern KRWLOCK_T ipf_auth, ipf_mutex; 11253642Sguidoextern kmutex_t ipf_authmx; 11353642Sguido# if SOLARIS 11453642Sguidoextern kcondvar_t ipfauthwait; 11553642Sguido# endif 11653642Sguido#endif 11753642Sguido#ifdef linux 11853642Sguidostatic struct wait_queue *ipfauthwait = NULL; 11953642Sguido#endif 12053642Sguido 12153642Sguidoint fr_authsize = FR_NUMAUTH; 12253642Sguidoint fr_authused = 0; 12353642Sguidoint fr_defaultauthage = 600; 12460850Sdarrenrint fr_auth_lock = 0; 12553642Sguidofr_authstat_t fr_authstats; 12660850Sdarrenrstatic frauth_t fr_auth[FR_NUMAUTH]; 12753642Sguidomb_t *fr_authpkts[FR_NUMAUTH]; 12860850Sdarrenrstatic int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; 12960850Sdarrenrstatic frauthent_t *fae_list = NULL; 13080482Sdarrenrfrentry_t *ipauth = NULL, 13180482Sdarrenr *fr_authlist = NULL; 13253642Sguido 13353642Sguido 13453642Sguido/* 13553642Sguido * Check if a packet has authorization. If the packet is found to match an 13653642Sguido * authorization result and that would result in a feedback loop (i.e. it 13753642Sguido * will end up returning FR_AUTH) then return FR_BLOCK instead. 13853642Sguido */ 13953642Sguidou_32_t fr_checkauth(ip, fin) 14053642Sguidoip_t *ip; 14153642Sguidofr_info_t *fin; 14253642Sguido{ 14353642Sguido u_short id = ip->ip_id; 14480482Sdarrenr frentry_t *fr; 14580482Sdarrenr frauth_t *fra; 14653642Sguido u_32_t pass; 14753642Sguido int i; 14853642Sguido 14980482Sdarrenr if (fr_auth_lock || !fr_authused) 15060850Sdarrenr return 0; 15160850Sdarrenr 15253642Sguido READ_ENTER(&ipf_auth); 15353642Sguido for (i = fr_authstart; i != fr_authend; ) { 15453642Sguido /* 15553642Sguido * index becomes -2 only after an SIOCAUTHW. Check this in 15653642Sguido * case the same packet gets sent again and it hasn't yet been 15753642Sguido * auth'd. 15853642Sguido */ 15980482Sdarrenr fra = fr_auth + i; 16080482Sdarrenr if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 16180482Sdarrenr !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 16253642Sguido /* 16353642Sguido * Avoid feedback loop. 16453642Sguido */ 16580482Sdarrenr if (!(pass = fra->fra_pass) || (pass & FR_AUTH)) 16653642Sguido pass = FR_BLOCK; 16780482Sdarrenr /* 16880482Sdarrenr * Create a dummy rule for the stateful checking to 16980482Sdarrenr * use and return. Zero out any values we don't 17080482Sdarrenr * trust from userland! 17180482Sdarrenr */ 17280482Sdarrenr if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 17380482Sdarrenr (fin->fin_fi.fi_fl & FI_FRAG))) { 17480482Sdarrenr KMALLOC(fr, frentry_t *); 17580482Sdarrenr if (fr) { 17680482Sdarrenr bcopy((char *)fra->fra_info.fin_fr, 17780482Sdarrenr fr, sizeof(*fr)); 17880482Sdarrenr fr->fr_grp = NULL; 17980482Sdarrenr fr->fr_ifa = fin->fin_ifp; 18080482Sdarrenr fr->fr_func = NULL; 18180482Sdarrenr fr->fr_ref = 1; 18280482Sdarrenr fr->fr_flags = pass; 18380482Sdarrenr#if BSD >= 199306 18480482Sdarrenr fr->fr_oifa = NULL; 18580482Sdarrenr#endif 18680482Sdarrenr } 18780482Sdarrenr } else 18880482Sdarrenr fr = fra->fra_info.fin_fr; 18980482Sdarrenr fin->fin_fr = fr; 19053642Sguido RWLOCK_EXIT(&ipf_auth); 19153642Sguido WRITE_ENTER(&ipf_auth); 19280482Sdarrenr if (fr && fr != fra->fra_info.fin_fr) { 19380482Sdarrenr fr->fr_next = fr_authlist; 19480482Sdarrenr fr_authlist = fr; 19580482Sdarrenr } 19653642Sguido fr_authstats.fas_hits++; 19780482Sdarrenr fra->fra_index = -1; 19853642Sguido fr_authused--; 19953642Sguido if (i == fr_authstart) { 20080482Sdarrenr while (fra->fra_index == -1) { 20153642Sguido i++; 20280482Sdarrenr fra++; 20380482Sdarrenr if (i == FR_NUMAUTH) { 20453642Sguido i = 0; 20580482Sdarrenr fra = fr_auth; 20680482Sdarrenr } 20753642Sguido fr_authstart = i; 20853642Sguido if (i == fr_authend) 20953642Sguido break; 21053642Sguido } 21153642Sguido if (fr_authstart == fr_authend) { 21253642Sguido fr_authnext = 0; 21353642Sguido fr_authstart = fr_authend = 0; 21453642Sguido } 21553642Sguido } 21653642Sguido RWLOCK_EXIT(&ipf_auth); 21753642Sguido return pass; 21853642Sguido } 21953642Sguido i++; 22053642Sguido if (i == FR_NUMAUTH) 22153642Sguido i = 0; 22253642Sguido } 22353642Sguido fr_authstats.fas_miss++; 22453642Sguido RWLOCK_EXIT(&ipf_auth); 22553642Sguido return 0; 22653642Sguido} 22753642Sguido 22853642Sguido 22953642Sguido/* 23053642Sguido * Check if we have room in the auth array to hold details for another packet. 23153642Sguido * If we do, store it and wake up any user programs which are waiting to 23253642Sguido * hear about these events. 23353642Sguido */ 23460850Sdarrenrint fr_newauth(m, fin, ip) 23553642Sguidomb_t *m; 23653642Sguidofr_info_t *fin; 23753642Sguidoip_t *ip; 23853642Sguido{ 23960850Sdarrenr#if defined(_KERNEL) && SOLARIS 24060850Sdarrenr qif_t *qif = fin->fin_qif; 24160850Sdarrenr#endif 24280482Sdarrenr frauth_t *fra; 24353642Sguido int i; 24453642Sguido 24560850Sdarrenr if (fr_auth_lock) 24660850Sdarrenr return 0; 24760850Sdarrenr 24853642Sguido WRITE_ENTER(&ipf_auth); 24953642Sguido if (fr_authstart > fr_authend) { 25053642Sguido fr_authstats.fas_nospace++; 25153642Sguido RWLOCK_EXIT(&ipf_auth); 25253642Sguido return 0; 25353642Sguido } else { 25480482Sdarrenr if (fr_authused == FR_NUMAUTH) { 25553642Sguido fr_authstats.fas_nospace++; 25653642Sguido RWLOCK_EXIT(&ipf_auth); 25753642Sguido return 0; 25853642Sguido } 25953642Sguido } 26053642Sguido 26153642Sguido fr_authstats.fas_added++; 26253642Sguido fr_authused++; 26353642Sguido i = fr_authend++; 26453642Sguido if (fr_authend == FR_NUMAUTH) 26553642Sguido fr_authend = 0; 26653642Sguido RWLOCK_EXIT(&ipf_auth); 26780482Sdarrenr fra = fr_auth + i; 26880482Sdarrenr fra->fra_index = i; 26980482Sdarrenr fra->fra_pass = 0; 27080482Sdarrenr fra->fra_age = fr_defaultauthage; 27180482Sdarrenr bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 27280482Sdarrenr#if SOLARIS && defined(_KERNEL) 27380482Sdarrenr# if !defined(sparc) 27453642Sguido /* 27553642Sguido * No need to copyback here as we want to undo the changes, not keep 27653642Sguido * them. 27753642Sguido */ 27860850Sdarrenr if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4)) 27953642Sguido { 28053642Sguido register u_short bo; 28153642Sguido 28253642Sguido bo = ip->ip_len; 28353642Sguido ip->ip_len = htons(bo); 28465837Sru# if !SOLARIS && !defined(__NetBSD__) && !defined(__FreeBSD__) 28560850Sdarrenr /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ 28653642Sguido bo = ip->ip_id; 28753642Sguido ip->ip_id = htons(bo); 28853642Sguido# endif 28953642Sguido bo = ip->ip_off; 29053642Sguido ip->ip_off = htons(bo); 29153642Sguido } 29280482Sdarrenr# endif 29353642Sguido m->b_rptr -= qif->qf_off; 29453642Sguido fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 29580482Sdarrenr fra->fra_q = qif->qf_q; 29653642Sguido cv_signal(&ipfauthwait); 29753642Sguido#else 29880482Sdarrenr# if defined(BSD) && !defined(sparc) && (BSD >= 199306) 29980482Sdarrenr if (!fin->fin_out) { 30080482Sdarrenr HTONS(ip->ip_len); 30180482Sdarrenr HTONS(ip->ip_off); 30280482Sdarrenr } 30380482Sdarrenr# endif 30453642Sguido fr_authpkts[i] = m; 30553642Sguido WAKEUP(&fr_authnext); 30653642Sguido#endif 30753642Sguido return 1; 30853642Sguido} 30953642Sguido 31053642Sguido 31180482Sdarrenrint fr_auth_ioctl(data, mode, cmd, fr, frptr) 31253642Sguidocaddr_t data; 31380482Sdarrenrint mode; 31460850Sdarrenr#if defined(__NetBSD__) || defined(__OpenBSD__) || (FreeBSD_version >= 300003) 31553642Sguidou_long cmd; 31653642Sguido#else 31753642Sguidoint cmd; 31853642Sguido#endif 31953642Sguidofrentry_t *fr, **frptr; 32053642Sguido{ 32153642Sguido mb_t *m; 32280482Sdarrenr#if defined(_KERNEL) && !SOLARIS 32380482Sdarrenr struct ifqueue *ifq; 32480482Sdarrenr int s; 32580482Sdarrenr#endif 32680482Sdarrenr frauth_t auth, *au = &auth, *fra; 32753642Sguido frauthent_t *fae, **faep; 32853642Sguido int i, error = 0; 32953642Sguido 33053642Sguido switch (cmd) 33153642Sguido { 33260850Sdarrenr case SIOCSTLCK : 33360850Sdarrenr error = fr_lock(data, &fr_auth_lock); 33460850Sdarrenr break; 33553642Sguido case SIOCINIFR : 33653642Sguido case SIOCRMIFR : 33753642Sguido case SIOCADIFR : 33853642Sguido error = EINVAL; 33953642Sguido break; 34053642Sguido case SIOCINAFR : 34160850Sdarrenr error = EINVAL; 34260850Sdarrenr break; 34353642Sguido case SIOCRMAFR : 34453642Sguido case SIOCADAFR : 34553642Sguido for (faep = &fae_list; (fae = *faep); ) 34653642Sguido if (&fae->fae_fr == fr) 34753642Sguido break; 34853642Sguido else 34953642Sguido faep = &fae->fae_next; 35053642Sguido if (cmd == SIOCRMAFR) { 35180482Sdarrenr if (!fr || !frptr) 35280482Sdarrenr error = EINVAL; 35380482Sdarrenr else if (!fae) 35453642Sguido error = ESRCH; 35553642Sguido else { 35653642Sguido WRITE_ENTER(&ipf_auth); 35780482Sdarrenr SPL_NET(s); 35853642Sguido *faep = fae->fae_next; 35953642Sguido *frptr = fr->fr_next; 36080482Sdarrenr SPL_X(s); 36153642Sguido RWLOCK_EXIT(&ipf_auth); 36253642Sguido KFREE(fae); 36353642Sguido } 36480482Sdarrenr } else if (fr && frptr) { 36553642Sguido KMALLOC(fae, frauthent_t *); 36653642Sguido if (fae != NULL) { 36760850Sdarrenr bcopy((char *)fr, (char *)&fae->fae_fr, 36860850Sdarrenr sizeof(*fr)); 36953642Sguido WRITE_ENTER(&ipf_auth); 37080482Sdarrenr SPL_NET(s); 37153642Sguido fae->fae_age = fr_defaultauthage; 37253642Sguido fae->fae_fr.fr_hits = 0; 37353642Sguido fae->fae_fr.fr_next = *frptr; 37453642Sguido *frptr = &fae->fae_fr; 37553642Sguido fae->fae_next = *faep; 37653642Sguido *faep = fae; 37753642Sguido ipauth = &fae_list->fae_fr; 37880482Sdarrenr SPL_X(s); 37953642Sguido RWLOCK_EXIT(&ipf_auth); 38053642Sguido } else 38153642Sguido error = ENOMEM; 38280482Sdarrenr } else 38380482Sdarrenr error = EINVAL; 38453642Sguido break; 38553642Sguido case SIOCATHST: 38653642Sguido READ_ENTER(&ipf_auth); 38753642Sguido fr_authstats.fas_faelist = fae_list; 38853642Sguido RWLOCK_EXIT(&ipf_auth); 38960850Sdarrenr error = IWCOPYPTR((char *)&fr_authstats, data, 39060850Sdarrenr sizeof(fr_authstats)); 39153642Sguido break; 39253642Sguido case SIOCAUTHW: 39380482Sdarrenr if (!(mode & FWRITE)) { 39480482Sdarrenr error = EPERM; 39580482Sdarrenr break; 39680482Sdarrenr } 39753642Sguidofr_authioctlloop: 39853642Sguido READ_ENTER(&ipf_auth); 39953642Sguido if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { 40060850Sdarrenr error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data, 40172006Sdarrenr sizeof(frauth_t)); 40253642Sguido RWLOCK_EXIT(&ipf_auth); 40360850Sdarrenr if (error) 40460850Sdarrenr break; 40553642Sguido WRITE_ENTER(&ipf_auth); 40680482Sdarrenr SPL_NET(s); 40753642Sguido fr_authnext++; 40853642Sguido if (fr_authnext == FR_NUMAUTH) 40953642Sguido fr_authnext = 0; 41080482Sdarrenr SPL_X(s); 41153642Sguido RWLOCK_EXIT(&ipf_auth); 41253642Sguido return 0; 41353642Sguido } 41453642Sguido#ifdef _KERNEL 41553642Sguido# if SOLARIS 41653642Sguido mutex_enter(&ipf_authmx); 41753642Sguido if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) { 41853642Sguido mutex_exit(&ipf_authmx); 41953642Sguido return EINTR; 42053642Sguido } 42153642Sguido mutex_exit(&ipf_authmx); 42253642Sguido# else 42353642Sguido error = SLEEP(&fr_authnext, "fr_authnext"); 42453642Sguido# endif 42553642Sguido#endif 42653642Sguido RWLOCK_EXIT(&ipf_auth); 42753642Sguido if (!error) 42853642Sguido goto fr_authioctlloop; 42953642Sguido break; 43053642Sguido case SIOCAUTHR: 43180482Sdarrenr if (!(mode & FWRITE)) { 43280482Sdarrenr error = EPERM; 43380482Sdarrenr break; 43480482Sdarrenr } 43560850Sdarrenr error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth)); 43660850Sdarrenr if (error) 43760850Sdarrenr return error; 43853642Sguido WRITE_ENTER(&ipf_auth); 43980482Sdarrenr SPL_NET(s); 44060857Sdarrenr i = au->fra_index; 44180482Sdarrenr fra = fr_auth + i; 44253642Sguido if ((i < 0) || (i > FR_NUMAUTH) || 44380482Sdarrenr (fra->fra_info.fin_id != au->fra_info.fin_id)) { 44480482Sdarrenr SPL_X(s); 44553642Sguido RWLOCK_EXIT(&ipf_auth); 44653642Sguido return EINVAL; 44753642Sguido } 44853642Sguido m = fr_authpkts[i]; 44980482Sdarrenr fra->fra_index = -2; 45080482Sdarrenr fra->fra_pass = au->fra_pass; 45153642Sguido fr_authpkts[i] = NULL; 45280482Sdarrenr RWLOCK_EXIT(&ipf_auth); 45353642Sguido#ifdef _KERNEL 45453642Sguido if (m && au->fra_info.fin_out) { 45580482Sdarrenr# if SOLARIS 45680482Sdarrenr error = fr_qout(fra->fra_q, m); 45780482Sdarrenr# else /* SOLARIS */ 45880482Sdarrenr struct route ro; 45980482Sdarrenr 46080482Sdarrenr bzero((char *)&ro, sizeof(ro)); 46180482Sdarrenr# if ((_BSDI_VERSION >= 199802) && (_BSDI_VERSION < 200005)) || \ 46280482Sdarrenr defined(__OpenBSD__) 46380482Sdarrenr error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL, 46453642Sguido NULL); 46580482Sdarrenr# else 46680482Sdarrenr error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL); 46780482Sdarrenr# endif 46880482Sdarrenr if (ro.ro_rt) { 46980482Sdarrenr RTFREE(ro.ro_rt); 47080482Sdarrenr } 47180482Sdarrenr# endif /* SOLARIS */ 47253642Sguido if (error) 47353642Sguido fr_authstats.fas_sendfail++; 47453642Sguido else 47553642Sguido fr_authstats.fas_sendok++; 47653642Sguido } else if (m) { 47753642Sguido# if SOLARIS 47880482Sdarrenr error = fr_qin(fra->fra_q, m); 47953642Sguido# else /* SOLARIS */ 48069152Sjlemon if (! IF_HANDOFF(&ipintrq, m, NULL)) 48153642Sguido error = ENOBUFS; 48269152Sjlemon else 48353642Sguido schednetisr(NETISR_IP); 48453642Sguido# endif /* SOLARIS */ 48553642Sguido if (error) 48653642Sguido fr_authstats.fas_quefail++; 48753642Sguido else 48853642Sguido fr_authstats.fas_queok++; 48953642Sguido } else 49053642Sguido error = EINVAL; 49153642Sguido# if SOLARIS 49253642Sguido if (error) 49353642Sguido error = EINVAL; 49453642Sguido# else 49553642Sguido /* 49653642Sguido * If we experience an error which will result in the packet 49753642Sguido * not being processed, make sure we advance to the next one. 49853642Sguido */ 49953642Sguido if (error == ENOBUFS) { 50053642Sguido fr_authused--; 50180482Sdarrenr fra->fra_index = -1; 50280482Sdarrenr fra->fra_pass = 0; 50353642Sguido if (i == fr_authstart) { 50480482Sdarrenr while (fra->fra_index == -1) { 50553642Sguido i++; 50653642Sguido if (i == FR_NUMAUTH) 50753642Sguido i = 0; 50853642Sguido fr_authstart = i; 50953642Sguido if (i == fr_authend) 51053642Sguido break; 51153642Sguido } 51253642Sguido if (fr_authstart == fr_authend) { 51353642Sguido fr_authnext = 0; 51453642Sguido fr_authstart = fr_authend = 0; 51553642Sguido } 51653642Sguido } 51753642Sguido } 51853642Sguido# endif 51953642Sguido#endif /* _KERNEL */ 52080482Sdarrenr SPL_X(s); 52153642Sguido break; 52253642Sguido default : 52353642Sguido error = EINVAL; 52453642Sguido break; 52553642Sguido } 52653642Sguido return error; 52753642Sguido} 52853642Sguido 52953642Sguido 53053642Sguido#ifdef _KERNEL 53153642Sguido/* 53253642Sguido * Free all network buffer memory used to keep saved packets. 53353642Sguido */ 53453642Sguidovoid fr_authunload() 53553642Sguido{ 53653642Sguido register int i; 53753642Sguido register frauthent_t *fae, **faep; 53880482Sdarrenr frentry_t *fr, **frp; 53953642Sguido mb_t *m; 54053642Sguido 54153642Sguido WRITE_ENTER(&ipf_auth); 54253642Sguido for (i = 0; i < FR_NUMAUTH; i++) { 54353642Sguido if ((m = fr_authpkts[i])) { 54453642Sguido FREE_MB_T(m); 54553642Sguido fr_authpkts[i] = NULL; 54653642Sguido fr_auth[i].fra_index = -1; 54753642Sguido } 54853642Sguido } 54953642Sguido 55053642Sguido 55153642Sguido for (faep = &fae_list; (fae = *faep); ) { 55253642Sguido *faep = fae->fae_next; 55353642Sguido KFREE(fae); 55453642Sguido } 55553642Sguido ipauth = NULL; 55653642Sguido RWLOCK_EXIT(&ipf_auth); 55780482Sdarrenr 55880482Sdarrenr if (fr_authlist) { 55980482Sdarrenr /* 56080482Sdarrenr * We *MuST* reget ipf_auth because otherwise we won't get the 56180482Sdarrenr * locks in the right order and risk deadlock. 56280482Sdarrenr * We need ipf_mutex here to prevent a rule from using it 56380482Sdarrenr * inside fr_check(). 56480482Sdarrenr */ 56580482Sdarrenr WRITE_ENTER(&ipf_mutex); 56680482Sdarrenr WRITE_ENTER(&ipf_auth); 56780482Sdarrenr for (frp = &fr_authlist; (fr = *frp); ) { 56880482Sdarrenr if (fr->fr_ref == 1) { 56980482Sdarrenr *frp = fr->fr_next; 57080482Sdarrenr KFREE(fr); 57180482Sdarrenr } else 57280482Sdarrenr frp = &fr->fr_next; 57380482Sdarrenr } 57480482Sdarrenr RWLOCK_EXIT(&ipf_auth); 57580482Sdarrenr RWLOCK_EXIT(&ipf_mutex); 57680482Sdarrenr } 57753642Sguido} 57853642Sguido 57953642Sguido 58053642Sguido/* 58153642Sguido * Slowly expire held auth records. Timeouts are set 58253642Sguido * in expectation of this being called twice per second. 58353642Sguido */ 58453642Sguidovoid fr_authexpire() 58553642Sguido{ 58653642Sguido register int i; 58753642Sguido register frauth_t *fra; 58853642Sguido register frauthent_t *fae, **faep; 58980482Sdarrenr register frentry_t *fr, **frp; 59053642Sguido mb_t *m; 59153642Sguido#if !SOLARIS 59253642Sguido int s; 59353642Sguido#endif 59453642Sguido 59560850Sdarrenr if (fr_auth_lock) 59660850Sdarrenr return; 59760850Sdarrenr 59853642Sguido SPL_NET(s); 59953642Sguido WRITE_ENTER(&ipf_auth); 60053642Sguido for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { 60153642Sguido if ((!--fra->fra_age) && (m = fr_authpkts[i])) { 60253642Sguido FREE_MB_T(m); 60353642Sguido fr_authpkts[i] = NULL; 60453642Sguido fr_auth[i].fra_index = -1; 60553642Sguido fr_authstats.fas_expire++; 60653642Sguido fr_authused--; 60753642Sguido } 60853642Sguido } 60953642Sguido 61053642Sguido for (faep = &fae_list; (fae = *faep); ) { 61153642Sguido if (!--fae->fae_age) { 61253642Sguido *faep = fae->fae_next; 61353642Sguido KFREE(fae); 61453642Sguido fr_authstats.fas_expire++; 61553642Sguido } else 61653642Sguido faep = &fae->fae_next; 61753642Sguido } 61853642Sguido ipauth = &fae_list->fae_fr; 61980482Sdarrenr 62080482Sdarrenr for (frp = &fr_authlist; (fr = *frp); ) { 62180482Sdarrenr if (fr->fr_ref == 1) { 62280482Sdarrenr *frp = fr->fr_next; 62380482Sdarrenr KFREE(fr); 62480482Sdarrenr } else 62580482Sdarrenr frp = &fr->fr_next; 62680482Sdarrenr } 62753642Sguido RWLOCK_EXIT(&ipf_auth); 62853642Sguido SPL_X(s); 62953642Sguido} 63053642Sguido#endif 631