ip_auth.c revision 98004
113978Smrkam/*
213978Smrkam * Copyright (C) 1998-2001 by Darren Reed & Guido van Rooij.
313978Smrkam *
413978Smrkam * See the IPFILTER.LICENCE file for details on licencing.
513978Smrkam */
613978Smrkam#ifdef __sgi
713978Smrkam# include <sys/ptimers.h>
813978Smrkam#endif
913978Smrkam#include <sys/errno.h>
1013978Smrkam#include <sys/types.h>
1113978Smrkam#include <sys/param.h>
1213978Smrkam#include <sys/time.h>
1313978Smrkam#include <sys/file.h>
1413978Smrkam#if !defined(_KERNEL) && !defined(KERNEL)
1513978Smrkam# include <stdio.h>
1613978Smrkam# include <stdlib.h>
1713978Smrkam# include <string.h>
1813978Smrkam#endif
1913978Smrkam#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000)
2013978Smrkam# include <sys/filio.h>
2113978Smrkam# include <sys/fcntl.h>
2213978Smrkam#else
2313978Smrkam# include <sys/ioctl.h>
2413978Smrkam#endif
2513978Smrkam#ifndef linux
2613978Smrkam# include <sys/protosw.h>
2713978Smrkam#endif
2813978Smrkam#include <sys/socket.h>
2913978Smrkam#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
3013978Smrkam# include <sys/systm.h>
3113978Smrkam#endif
3213978Smrkam#if !defined(__SVR4) && !defined(__svr4__)
3313978Smrkam# ifndef linux
3413978Smrkam#  include <sys/mbuf.h>
3513978Smrkam# endif
3613978Smrkam#else
3713978Smrkam# include <sys/filio.h>
3813978Smrkam# include <sys/byteorder.h>
3913978Smrkam# ifdef _KERNEL
4013978Smrkam#  include <sys/dditypes.h>
4113978Smrkam# endif
4213978Smrkam# include <sys/stream.h>
4313978Smrkam# include <sys/kmem.h>
4413978Smrkam#endif
4513978Smrkam#if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000)
4613978Smrkam# include <sys/queue.h>
4713978Smrkam#endif
4813978Smrkam#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
4913978Smrkam# include <machine/cpu.h>
5013978Smrkam#endif
5113978Smrkam#include <net/if.h>
5213978Smrkam#ifdef sun
5313978Smrkam# include <net/af.h>
5413978Smrkam#endif
5513978Smrkam#include <net/route.h>
5613978Smrkam#include <netinet/in.h>
5713978Smrkam#include <netinet/in_systm.h>
5813978Smrkam#include <netinet/ip.h>
5913978Smrkam#ifndef	KERNEL
6013978Smrkam# define	KERNEL
6113978Smrkam# define	NOT_KERNEL
6213978Smrkam#endif
6313978Smrkam#ifndef linux
6413978Smrkam# include <netinet/ip_var.h>
6513978Smrkam#endif
6613978Smrkam#ifdef	NOT_KERNEL
6713978Smrkam# undef	KERNEL
6813978Smrkam#endif
6913978Smrkam#ifdef __sgi
7013978Smrkam# ifdef IFF_DRVRLOCK /* IRIX6 */
7113978Smrkam#  include <sys/hashing.h>
7213978Smrkam# endif
7313978Smrkam#endif
7413978Smrkam#include <netinet/tcp.h>
7513978Smrkam#if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */
7613978Smrkamextern struct ifqueue   ipintrq;		/* ip packet input queue */
7713978Smrkam#else
7813978Smrkam# ifndef linux
7913978Smrkam#  if __FreeBSD_version >= 300000
8013978Smrkam#   include <net/if_var.h>
8113978Smrkam#  endif
8213978Smrkam#  include <netinet/in_var.h>
8313978Smrkam#  include <netinet/tcp_fsm.h>
8413978Smrkam# endif
8513978Smrkam#endif
8613978Smrkam#include <netinet/udp.h>
8713978Smrkam#include <netinet/ip_icmp.h>
8813978Smrkam#include "netinet/ip_compat.h"
8913978Smrkam#include <netinet/tcpip.h>
9013978Smrkam#include "netinet/ip_fil.h"
9113978Smrkam#include "netinet/ip_auth.h"
9213978Smrkam#if !SOLARIS && !defined(linux)
9313978Smrkam# include <net/netisr.h>
9413978Smrkam# ifdef __FreeBSD__
9513978Smrkam#  include <machine/cpufunc.h>
9613978Smrkam# endif
9713978Smrkam#endif
9813978Smrkam#if (__FreeBSD_version >= 300000)
9913978Smrkam# include <sys/malloc.h>
10013978Smrkam# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM)
10113978Smrkam#  include <sys/libkern.h>
10213978Smrkam#  include <sys/systm.h>
10313978Smrkam# endif
10413978Smrkam#endif
10513978Smrkam
10613978Smrkam#if !defined(lint)
10713978Smrkam/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.12 2001/07/18 14:57:08 darrenr Exp $"; */
10813978Smrkamstatic const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_auth.c 98004 2002-06-07 08:56:30Z darrenr $";
10913978Smrkam#endif
11013978Smrkam
11113978Smrkam
11213978Smrkam#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
11313978Smrkamextern KRWLOCK_T ipf_auth, ipf_mutex;
11413978Smrkamextern kmutex_t ipf_authmx;
11513978Smrkam# if SOLARIS
11613978Smrkamextern kcondvar_t ipfauthwait;
11713978Smrkam# endif
11813978Smrkam#endif
11913978Smrkam#ifdef linux
12013978Smrkamstatic struct wait_queue *ipfauthwait = NULL;
12113978Smrkam#endif
12213978Smrkam
12313978Smrkamint	fr_authsize = FR_NUMAUTH;
12413978Smrkamint	fr_authused = 0;
12513978Smrkamint	fr_defaultauthage = 600;
12613978Smrkamint	fr_auth_lock = 0;
12713978Smrkamfr_authstat_t	fr_authstats;
12813978Smrkamstatic frauth_t fr_auth[FR_NUMAUTH];
12913978Smrkammb_t	*fr_authpkts[FR_NUMAUTH];
13013978Smrkamstatic int	fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
13113978Smrkamstatic frauthent_t	*fae_list = NULL;
13213978Smrkamfrentry_t	*ipauth = NULL,
13313978Smrkam		*fr_authlist = NULL;
13413978Smrkam
13513978Smrkam
13613978Smrkam/*
13713978Smrkam * Check if a packet has authorization.  If the packet is found to match an
13813978Smrkam * authorization result and that would result in a feedback loop (i.e. it
13913978Smrkam * will end up returning FR_AUTH) then return FR_BLOCK instead.
14013978Smrkam */
14113978Smrkamu_32_t fr_checkauth(ip, fin)
14213978Smrkamip_t *ip;
14313978Smrkamfr_info_t *fin;
14413978Smrkam{
14513978Smrkam	u_short id = ip->ip_id;
14613978Smrkam	frentry_t *fr;
14713978Smrkam	frauth_t *fra;
14813978Smrkam	u_32_t pass;
14913978Smrkam	int i;
15013978Smrkam
15113978Smrkam	if (fr_auth_lock || !fr_authused)
15213978Smrkam		return 0;
15313978Smrkam
15413978Smrkam	READ_ENTER(&ipf_auth);
15513978Smrkam	for (i = fr_authstart; i != fr_authend; ) {
15613978Smrkam		/*
15713978Smrkam		 * index becomes -2 only after an SIOCAUTHW.  Check this in
15813978Smrkam		 * case the same packet gets sent again and it hasn't yet been
15913978Smrkam		 * auth'd.
16013978Smrkam		 */
16113978Smrkam		fra = fr_auth + i;
16213978Smrkam		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
16313978Smrkam		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
16413978Smrkam			/*
16513978Smrkam			 * Avoid feedback loop.
16613978Smrkam			 */
16713978Smrkam			if (!(pass = fra->fra_pass) || (pass & FR_AUTH))
16813978Smrkam				pass = FR_BLOCK;
16913978Smrkam			/*
17013978Smrkam			 * Create a dummy rule for the stateful checking to
17113978Smrkam			 * use and return.  Zero out any values we don't
17213978Smrkam			 * trust from userland!
17313978Smrkam			 */
17413978Smrkam			if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
17513978Smrkam			     (fin->fin_fi.fi_fl & FI_FRAG))) {
17613978Smrkam				KMALLOC(fr, frentry_t *);
17713978Smrkam				if (fr) {
17813978Smrkam					bcopy((char *)fra->fra_info.fin_fr,
17913978Smrkam					      fr, sizeof(*fr));
18013978Smrkam					fr->fr_grp = NULL;
18113978Smrkam					fr->fr_ifa = fin->fin_ifp;
18213978Smrkam					fr->fr_func = NULL;
18313978Smrkam					fr->fr_ref = 1;
18413978Smrkam					fr->fr_flags = pass;
18513978Smrkam#if BSD >= 199306
18613978Smrkam					fr->fr_oifa = NULL;
18713978Smrkam#endif
18813978Smrkam				}
18913978Smrkam			} else
19013978Smrkam				fr = fra->fra_info.fin_fr;
19113978Smrkam			fin->fin_fr = fr;
19213978Smrkam			RWLOCK_EXIT(&ipf_auth);
19313978Smrkam			WRITE_ENTER(&ipf_auth);
19413978Smrkam			if (fr && fr != fra->fra_info.fin_fr) {
19513978Smrkam				fr->fr_next = fr_authlist;
19613978Smrkam				fr_authlist = fr;
19713978Smrkam			}
19813978Smrkam			fr_authstats.fas_hits++;
19913978Smrkam			fra->fra_index = -1;
20013978Smrkam			fr_authused--;
20113978Smrkam			if (i == fr_authstart) {
20213978Smrkam				while (fra->fra_index == -1) {
20313978Smrkam					i++;
20413978Smrkam					fra++;
20513978Smrkam					if (i == FR_NUMAUTH) {
20613978Smrkam						i = 0;
20713978Smrkam						fra = fr_auth;
20813978Smrkam					}
20913978Smrkam					fr_authstart = i;
21013978Smrkam					if (i == fr_authend)
21113978Smrkam						break;
21213978Smrkam				}
21313978Smrkam				if (fr_authstart == fr_authend) {
21413978Smrkam					fr_authnext = 0;
21513978Smrkam					fr_authstart = fr_authend = 0;
21613978Smrkam				}
21713978Smrkam			}
21813978Smrkam			RWLOCK_EXIT(&ipf_auth);
21913978Smrkam			return pass;
22013978Smrkam		}
22113978Smrkam		i++;
22213978Smrkam		if (i == FR_NUMAUTH)
22313978Smrkam			i = 0;
22413978Smrkam	}
22513978Smrkam	fr_authstats.fas_miss++;
22613978Smrkam	RWLOCK_EXIT(&ipf_auth);
22713978Smrkam	return 0;
22813978Smrkam}
22913978Smrkam
23013978Smrkam
23113978Smrkam/*
23213978Smrkam * Check if we have room in the auth array to hold details for another packet.
23313978Smrkam * If we do, store it and wake up any user programs which are waiting to
23413978Smrkam * hear about these events.
23513978Smrkam */
23613978Smrkamint fr_newauth(m, fin, ip)
23713978Smrkammb_t *m;
23813978Smrkamfr_info_t *fin;
23913978Smrkamip_t *ip;
24013978Smrkam{
24113978Smrkam#if defined(_KERNEL) && SOLARIS
24213978Smrkam	qif_t *qif = fin->fin_qif;
24313978Smrkam#endif
24413978Smrkam	frauth_t *fra;
24513978Smrkam	int i;
24613978Smrkam
24713978Smrkam	if (fr_auth_lock)
24813978Smrkam		return 0;
24913978Smrkam
25013978Smrkam	WRITE_ENTER(&ipf_auth);
25113978Smrkam	if (fr_authstart > fr_authend) {
25213978Smrkam		fr_authstats.fas_nospace++;
25313978Smrkam		RWLOCK_EXIT(&ipf_auth);
25413978Smrkam		return 0;
25513978Smrkam	} else {
25613978Smrkam		if (fr_authused == FR_NUMAUTH) {
25713978Smrkam			fr_authstats.fas_nospace++;
25813978Smrkam			RWLOCK_EXIT(&ipf_auth);
25913978Smrkam			return 0;
26013978Smrkam		}
26113978Smrkam	}
26213978Smrkam
26313978Smrkam	fr_authstats.fas_added++;
26413978Smrkam	fr_authused++;
26513978Smrkam	i = fr_authend++;
26613978Smrkam	if (fr_authend == FR_NUMAUTH)
26713978Smrkam		fr_authend = 0;
26813978Smrkam	RWLOCK_EXIT(&ipf_auth);
26913978Smrkam	fra = fr_auth + i;
27013978Smrkam	fra->fra_index = i;
27113978Smrkam	fra->fra_pass = 0;
27213978Smrkam	fra->fra_age = fr_defaultauthage;
27313978Smrkam	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
27413978Smrkam#if SOLARIS && defined(_KERNEL)
27513978Smrkam# if !defined(sparc)
27613978Smrkam	/*
27713978Smrkam	 * No need to copyback here as we want to undo the changes, not keep
27813978Smrkam	 * them.
27913978Smrkam	 */
28013978Smrkam	if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4))
28113978Smrkam	{
28213978Smrkam		register u_short bo;
28313978Smrkam
28413978Smrkam		bo = ip->ip_len;
28513978Smrkam		ip->ip_len = htons(bo);
28613978Smrkam# if !SOLARIS && !defined(__NetBSD__) && !defined(__FreeBSD__)
28713978Smrkam		/* 4.4BSD converts this ip_input.c, but I don't in solaris.c */
28813978Smrkam		bo = ip->ip_id;
28913978Smrkam		ip->ip_id = htons(bo);
29013978Smrkam# endif
29113978Smrkam		bo = ip->ip_off;
29213978Smrkam		ip->ip_off = htons(bo);
29313978Smrkam	}
29413978Smrkam# endif
29513978Smrkam	m->b_rptr -= qif->qf_off;
29613978Smrkam	fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
29713978Smrkam	fra->fra_q = qif->qf_q;
29813978Smrkam	cv_signal(&ipfauthwait);
29913978Smrkam#else
30013978Smrkam# if defined(BSD) && !defined(sparc) && (BSD >= 199306)
30113978Smrkam	if (!fin->fin_out) {
30213978Smrkam		ip->ip_len = htons(ip->ip_len);
30313978Smrkam		ip->ip_off = htons(ip->ip_off);
30413978Smrkam	}
30513978Smrkam# endif
30613978Smrkam	fr_authpkts[i] = m;
30713978Smrkam	WAKEUP(&fr_authnext);
30813978Smrkam#endif
30913978Smrkam	return 1;
31013978Smrkam}
31113978Smrkam
31213978Smrkam
31313978Smrkamint fr_auth_ioctl(data, mode, cmd, fr, frptr)
31413978Smrkamcaddr_t data;
31513978Smrkamint mode;
31613978Smrkam#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
31713978Smrkamu_long cmd;
31813978Smrkam#else
31913978Smrkamint cmd;
32013978Smrkam#endif
32113978Smrkamfrentry_t *fr, **frptr;
32213978Smrkam{
32313978Smrkam	mb_t *m;
32413978Smrkam#if defined(_KERNEL) && !SOLARIS
32513978Smrkam	int s;
32613978Smrkam#endif
32713978Smrkam	frauth_t auth, *au = &auth, *fra;
32813978Smrkam	frauthent_t *fae, **faep;
32913978Smrkam	int i, error = 0;
33013978Smrkam
33113978Smrkam	switch (cmd)
33213978Smrkam	{
33313978Smrkam	case SIOCSTLCK :
33413978Smrkam		error = fr_lock(data, &fr_auth_lock);
33513978Smrkam		break;
33613978Smrkam	case SIOCINIFR :
33713978Smrkam	case SIOCRMIFR :
33813978Smrkam	case SIOCADIFR :
33913978Smrkam		error = EINVAL;
34013978Smrkam		break;
34113978Smrkam	case SIOCINAFR :
34213978Smrkam		error = EINVAL;
34313978Smrkam		break;
34413978Smrkam	case SIOCRMAFR :
34513978Smrkam	case SIOCADAFR :
34613978Smrkam		for (faep = &fae_list; (fae = *faep); )
34713978Smrkam			if (&fae->fae_fr == fr)
34813978Smrkam				break;
34913978Smrkam			else
35013978Smrkam				faep = &fae->fae_next;
35113978Smrkam		if (cmd == SIOCRMAFR) {
35213978Smrkam			if (!fr || !frptr)
35313978Smrkam				error = EINVAL;
35413978Smrkam			else if (!fae)
35513978Smrkam				error = ESRCH;
35613978Smrkam			else {
35713978Smrkam				WRITE_ENTER(&ipf_auth);
35813978Smrkam				SPL_NET(s);
35913978Smrkam				*faep = fae->fae_next;
36013978Smrkam				*frptr = fr->fr_next;
36113978Smrkam				SPL_X(s);
36213978Smrkam				RWLOCK_EXIT(&ipf_auth);
36313978Smrkam				KFREE(fae);
36413978Smrkam			}
36513978Smrkam		} else if (fr && frptr) {
36613978Smrkam			KMALLOC(fae, frauthent_t *);
36713978Smrkam			if (fae != NULL) {
36813978Smrkam				bcopy((char *)fr, (char *)&fae->fae_fr,
36913978Smrkam				      sizeof(*fr));
37013978Smrkam				WRITE_ENTER(&ipf_auth);
37113978Smrkam				SPL_NET(s);
37213978Smrkam				fae->fae_age = fr_defaultauthage;
37313978Smrkam				fae->fae_fr.fr_hits = 0;
37413978Smrkam				fae->fae_fr.fr_next = *frptr;
37513978Smrkam				*frptr = &fae->fae_fr;
37613978Smrkam				fae->fae_next = *faep;
37713978Smrkam				*faep = fae;
37813978Smrkam				ipauth = &fae_list->fae_fr;
37913978Smrkam				SPL_X(s);
38013978Smrkam				RWLOCK_EXIT(&ipf_auth);
38113978Smrkam			} else
38213978Smrkam				error = ENOMEM;
38313978Smrkam		} else
38413978Smrkam			error = EINVAL;
38513978Smrkam		break;
38613978Smrkam	case SIOCATHST:
38713978Smrkam		fr_authstats.fas_faelist = fae_list;
38813978Smrkam		error = IWCOPYPTR((char *)&fr_authstats, data,
38913978Smrkam				   sizeof(fr_authstats));
39013978Smrkam		break;
39113978Smrkam	case SIOCAUTHW:
39213978Smrkam		if (!(mode & FWRITE)) {
39313978Smrkam			error = EPERM;
39413978Smrkam			break;
39513978Smrkam		}
39613978Smrkamfr_authioctlloop:
39713978Smrkam		READ_ENTER(&ipf_auth);
39813978Smrkam		if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) {
39913978Smrkam			error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data,
40013978Smrkam					  sizeof(frauth_t));
40113978Smrkam			RWLOCK_EXIT(&ipf_auth);
40213978Smrkam			if (error)
40313978Smrkam				break;
40413978Smrkam			WRITE_ENTER(&ipf_auth);
40513978Smrkam			SPL_NET(s);
40613978Smrkam			fr_authnext++;
40713978Smrkam			if (fr_authnext == FR_NUMAUTH)
40813978Smrkam				fr_authnext = 0;
40913978Smrkam			SPL_X(s);
41013978Smrkam			RWLOCK_EXIT(&ipf_auth);
41113978Smrkam			return 0;
41213978Smrkam		}
41313978Smrkam		RWLOCK_EXIT(&ipf_auth);
41413978Smrkam#ifdef	_KERNEL
41513978Smrkam# if	SOLARIS
41613978Smrkam		mutex_enter(&ipf_authmx);
41713978Smrkam		if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) {
41813978Smrkam			mutex_exit(&ipf_authmx);
41913978Smrkam			return EINTR;
42013978Smrkam		}
42113978Smrkam		mutex_exit(&ipf_authmx);
42213978Smrkam# else
42313978Smrkam		error = SLEEP(&fr_authnext, "fr_authnext");
42413978Smrkam# endif
42513978Smrkam#endif
42613978Smrkam		if (!error)
42713978Smrkam			goto fr_authioctlloop;
42813978Smrkam		break;
42913978Smrkam	case SIOCAUTHR:
43013978Smrkam		if (!(mode & FWRITE)) {
43113978Smrkam			error = EPERM;
43213978Smrkam			break;
43313978Smrkam		}
43413978Smrkam		error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth));
43513978Smrkam		if (error)
43613978Smrkam			return error;
43713978Smrkam		WRITE_ENTER(&ipf_auth);
43813978Smrkam		SPL_NET(s);
43913978Smrkam		i = au->fra_index;
44013978Smrkam		fra = fr_auth + i;
44113978Smrkam		if ((i < 0) || (i > FR_NUMAUTH) ||
44213978Smrkam		    (fra->fra_info.fin_id != au->fra_info.fin_id)) {
44313978Smrkam			SPL_X(s);
44413978Smrkam			RWLOCK_EXIT(&ipf_auth);
44513978Smrkam			return EINVAL;
44613978Smrkam		}
44713978Smrkam		m = fr_authpkts[i];
44813978Smrkam		fra->fra_index = -2;
44913978Smrkam		fra->fra_pass = au->fra_pass;
45013978Smrkam		fr_authpkts[i] = NULL;
45113978Smrkam		RWLOCK_EXIT(&ipf_auth);
45213978Smrkam#ifdef	_KERNEL
45313978Smrkam		if (m && au->fra_info.fin_out) {
45413978Smrkam# if SOLARIS
45513978Smrkam			error = (fr_qout(fra->fra_q, m) == 0) ? EINVAL : 0;
45613978Smrkam# else /* SOLARIS */
45713978Smrkam			struct route ro;
45813978Smrkam
45913978Smrkam			bzero((char *)&ro, sizeof(ro));
46013978Smrkam#  if ((_BSDI_VERSION >= 199802) && (_BSDI_VERSION < 200005)) || \
46113978Smrkam       defined(__OpenBSD__) || (defined(IRIX) && (IRIX >= 605))
46213978Smrkam			error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL,
46313978Smrkam					  NULL);
46413978Smrkam#  else
46513978Smrkam			error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL);
46613978Smrkam#  endif
46713978Smrkam			if (ro.ro_rt) {
46813978Smrkam				RTFREE(ro.ro_rt);
46913978Smrkam			}
47013978Smrkam# endif /* SOLARIS */
47113978Smrkam			if (error)
47213978Smrkam				fr_authstats.fas_sendfail++;
47313978Smrkam			else
47413978Smrkam				fr_authstats.fas_sendok++;
47513978Smrkam		} else if (m) {
47613978Smrkam# if SOLARIS
47713978Smrkam			error = (fr_qin(fra->fra_q, m) == 0) ? EINVAL : 0;
47813978Smrkam# else /* SOLARIS */
47913978Smrkam			if (! IF_HANDOFF(&ipintrq, m, NULL))
48013978Smrkam				error = ENOBUFS;
48113978Smrkam			else
48213978Smrkam				schednetisr(NETISR_IP);
48313978Smrkam# endif /* SOLARIS */
48413978Smrkam			if (error)
48513978Smrkam				fr_authstats.fas_quefail++;
48613978Smrkam			else
48713978Smrkam				fr_authstats.fas_queok++;
48813978Smrkam		} else
48913978Smrkam			error = EINVAL;
49013978Smrkam# if SOLARIS
49113978Smrkam		if (error)
49213978Smrkam			error = EINVAL;
49313978Smrkam# else
49413978Smrkam		/*
49513978Smrkam		 * If we experience an error which will result in the packet
49613978Smrkam		 * not being processed, make sure we advance to the next one.
49713978Smrkam		 */
49813978Smrkam		if (error == ENOBUFS) {
49913978Smrkam			fr_authused--;
50013978Smrkam			fra->fra_index = -1;
50113978Smrkam			fra->fra_pass = 0;
50213978Smrkam			if (i == fr_authstart) {
50313978Smrkam				while (fra->fra_index == -1) {
50413978Smrkam					i++;
50513978Smrkam					if (i == FR_NUMAUTH)
50613978Smrkam						i = 0;
50713978Smrkam					fr_authstart = i;
50813978Smrkam					if (i == fr_authend)
50913978Smrkam						break;
51013978Smrkam				}
51113978Smrkam				if (fr_authstart == fr_authend) {
51213978Smrkam					fr_authnext = 0;
51313978Smrkam					fr_authstart = fr_authend = 0;
51413978Smrkam				}
51513978Smrkam			}
51613978Smrkam		}
51713978Smrkam# endif
51813978Smrkam#endif /* _KERNEL */
51913978Smrkam		SPL_X(s);
52013978Smrkam		break;
52113978Smrkam	default :
52213978Smrkam		error = EINVAL;
52313978Smrkam		break;
52413978Smrkam	}
52513978Smrkam	return error;
52613978Smrkam}
52713978Smrkam
52813978Smrkam
52913978Smrkam/*
53013978Smrkam * Free all network buffer memory used to keep saved packets.
53113978Smrkam */
53213978Smrkamvoid fr_authunload()
53313978Smrkam{
53413978Smrkam	register int i;
53513978Smrkam	register frauthent_t *fae, **faep;
53613978Smrkam	frentry_t *fr, **frp;
53713978Smrkam	mb_t *m;
53813978Smrkam
53913978Smrkam	WRITE_ENTER(&ipf_auth);
54013978Smrkam	for (i = 0; i < FR_NUMAUTH; i++) {
54113978Smrkam		if ((m = fr_authpkts[i])) {
54213978Smrkam			FREE_MB_T(m);
54313978Smrkam			fr_authpkts[i] = NULL;
54413978Smrkam			fr_auth[i].fra_index = -1;
54513978Smrkam		}
54613978Smrkam	}
54713978Smrkam
54813978Smrkam
54913978Smrkam	for (faep = &fae_list; (fae = *faep); ) {
55013978Smrkam		*faep = fae->fae_next;
55113978Smrkam		KFREE(fae);
55213978Smrkam	}
55313978Smrkam	ipauth = NULL;
55413978Smrkam	RWLOCK_EXIT(&ipf_auth);
55513978Smrkam
55613978Smrkam	if (fr_authlist) {
55713978Smrkam		/*
55813978Smrkam		 * We *MuST* reget ipf_auth because otherwise we won't get the
55913978Smrkam		 * locks in the right order and risk deadlock.
56013978Smrkam		 * We need ipf_mutex here to prevent a rule from using it
56113978Smrkam		 * inside fr_check().
56213978Smrkam		 */
56313978Smrkam		WRITE_ENTER(&ipf_mutex);
56413978Smrkam		WRITE_ENTER(&ipf_auth);
56513978Smrkam		for (frp = &fr_authlist; (fr = *frp); ) {
56613978Smrkam			if (fr->fr_ref == 1) {
56713978Smrkam				*frp = fr->fr_next;
56813978Smrkam				KFREE(fr);
56913978Smrkam			} else
57013978Smrkam				frp = &fr->fr_next;
57113978Smrkam		}
57213978Smrkam		RWLOCK_EXIT(&ipf_auth);
57313978Smrkam		RWLOCK_EXIT(&ipf_mutex);
57413978Smrkam	}
57513978Smrkam}
57613978Smrkam
57713978Smrkam
57813978Smrkam/*
57913978Smrkam * Slowly expire held auth records.  Timeouts are set
58013978Smrkam * in expectation of this being called twice per second.
58113978Smrkam */
58213978Smrkamvoid fr_authexpire()
58313978Smrkam{
58413978Smrkam	register int i;
58513978Smrkam	register frauth_t *fra;
58613978Smrkam	register frauthent_t *fae, **faep;
58713978Smrkam	register frentry_t *fr, **frp;
58813978Smrkam	mb_t *m;
58913978Smrkam#if !SOLARIS && defined(_KERNEL)
59013978Smrkam	int s;
59113978Smrkam#endif
59213978Smrkam
59313978Smrkam	if (fr_auth_lock)
59413978Smrkam		return;
59513978Smrkam
59613978Smrkam	SPL_NET(s);
59713978Smrkam	WRITE_ENTER(&ipf_auth);
59813978Smrkam	for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) {
59913978Smrkam		if ((!--fra->fra_age) && (m = fr_authpkts[i])) {
60013978Smrkam			FREE_MB_T(m);
60113978Smrkam			fr_authpkts[i] = NULL;
60213978Smrkam			fr_auth[i].fra_index = -1;
60313978Smrkam			fr_authstats.fas_expire++;
60413978Smrkam			fr_authused--;
60513978Smrkam		}
60613978Smrkam	}
60713978Smrkam
60813978Smrkam	for (faep = &fae_list; (fae = *faep); ) {
60913978Smrkam		if (!--fae->fae_age) {
61013978Smrkam			*faep = fae->fae_next;
61113978Smrkam			KFREE(fae);
61213978Smrkam			fr_authstats.fas_expire++;
61313978Smrkam		} else
61413978Smrkam			faep = &fae->fae_next;
61513978Smrkam	}
61613978Smrkam	if (fae_list != NULL)
61713978Smrkam		ipauth = &fae_list->fae_fr;
61813978Smrkam	else
61913978Smrkam		ipauth = NULL;
62013978Smrkam
62113978Smrkam	for (frp = &fr_authlist; (fr = *frp); ) {
62213978Smrkam		if (fr->fr_ref == 1) {
62313978Smrkam			*frp = fr->fr_next;
62413978Smrkam			KFREE(fr);
62513978Smrkam		} else
62613978Smrkam			frp = &fr->fr_next;
62713978Smrkam	}
62813978Smrkam	RWLOCK_EXIT(&ipf_auth);
62913978Smrkam	SPL_X(s);
63013978Smrkam}
63113978Smrkam