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