ip_auth.c revision 63523
1264790Sbapt/*
2264790Sbapt * Copyright (C) 1998-2000 by Darren Reed & Guido van Rooij.
3264790Sbapt *
4264790Sbapt * Redistribution and use in source and binary forms are permitted
5264790Sbapt * provided that this notice is preserved and due credit is given
6264790Sbapt * to the original author and the contributors.
7264790Sbapt */
8264790Sbapt#if !defined(lint)
9264790Sbapt/*static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.1.2.2 2000/01/16 10:12:14 darrenr Exp $";*/
10264790Sbaptstatic const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_auth.c 63523 2000-07-19 14:02:09Z darrenr $";
11264790Sbapt#endif
12264790Sbapt
13264790Sbapt#include <sys/errno.h>
14264790Sbapt#include <sys/types.h>
15264790Sbapt#include <sys/param.h>
16264790Sbapt#include <sys/time.h>
17264790Sbapt#include <sys/file.h>
18264790Sbapt#if !defined(_KERNEL) && !defined(KERNEL)
19264790Sbapt# include <stdio.h>
20264790Sbapt# include <stdlib.h>
21264790Sbapt# include <string.h>
22264790Sbapt#endif
23264790Sbapt#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000)
24264790Sbapt# include <sys/filio.h>
25264790Sbapt# include <sys/fcntl.h>
26264790Sbapt#else
27264790Sbapt# include <sys/ioctl.h>
28264790Sbapt#endif
29264790Sbapt#include <sys/uio.h>
30264790Sbapt#ifndef linux
31264790Sbapt# include <sys/protosw.h>
32264790Sbapt#endif
33264790Sbapt#include <sys/socket.h>
34264790Sbapt#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
35264790Sbapt# include <sys/systm.h>
36264790Sbapt#endif
37264790Sbapt#if !defined(__SVR4) && !defined(__svr4__)
38264790Sbapt# ifndef linux
39264790Sbapt#  include <sys/mbuf.h>
40264790Sbapt# endif
41264790Sbapt#else
42264790Sbapt# include <sys/filio.h>
43264790Sbapt# include <sys/byteorder.h>
44264790Sbapt# ifdef _KERNEL
45264790Sbapt#  include <sys/dditypes.h>
46264790Sbapt# endif
47264790Sbapt# include <sys/stream.h>
48264790Sbapt# include <sys/kmem.h>
49264790Sbapt#endif
50264790Sbapt#if (_BSDI_VERSION >= 199802) || (__FreeBSD_Version >= 400000)
51264790Sbapt# include <sys/queue.h>
52264790Sbapt#endif
53264790Sbapt#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
54264790Sbapt# include <machine/cpu.h>
55264790Sbapt#endif
56264790Sbapt#include <net/if.h>
57264790Sbapt#ifdef sun
58264790Sbapt# include <net/af.h>
59264790Sbapt#endif
60264790Sbapt#include <net/route.h>
61264790Sbapt#include <netinet/in.h>
62264790Sbapt#include <netinet/in_systm.h>
63264790Sbapt#include <netinet/ip.h>
64264790Sbapt#ifndef	KERNEL
65264790Sbapt# define	KERNEL
66264790Sbapt# define	NOT_KERNEL
67264790Sbapt#endif
68264790Sbapt#ifndef linux
69264790Sbapt# include <netinet/ip_var.h>
70264790Sbapt#endif
71264790Sbapt#ifdef	NOT_KERNEL
72264790Sbapt# undef	KERNEL
73264790Sbapt#endif
74264790Sbapt#ifdef __sgi
75264790Sbapt# ifdef IFF_DRVRLOCK /* IRIX6 */
76264790Sbapt#  include <sys/hashing.h>
77264790Sbapt# endif
78264790Sbapt#endif
79264790Sbapt#include <netinet/tcp.h>
80264790Sbapt#if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */
81264790Sbaptextern struct ifqueue   ipintrq;                /* ip packet input queue */
82264790Sbapt#else
83264790Sbapt# ifndef linux
84264790Sbapt#  if __FreeBSD_version >= 300000
85264790Sbapt#   include <net/if_var.h>
86264790Sbapt#  endif
87264790Sbapt#  include <netinet/in_var.h>
88264790Sbapt#  include <netinet/tcp_fsm.h>
89264790Sbapt# endif
90264790Sbapt#endif
91264790Sbapt#include <netinet/udp.h>
92264790Sbapt#include <netinet/ip_icmp.h>
93264790Sbapt#include "netinet/ip_compat.h"
94264790Sbapt#include <netinet/tcpip.h>
95264790Sbapt#include "netinet/ip_fil.h"
96264790Sbapt#include "netinet/ip_auth.h"
97264790Sbapt#if !SOLARIS && !defined(linux)
98264790Sbapt# include <net/netisr.h>
99264790Sbapt# ifdef __FreeBSD__
100264790Sbapt#  include <machine/cpufunc.h>
101264790Sbapt# endif
102264790Sbapt#endif
103264790Sbapt#if (__FreeBSD_version >= 300000)
104264790Sbapt# include <sys/malloc.h>
105264790Sbapt# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM)
106264790Sbapt#  include <sys/libkern.h>
107264790Sbapt#  include <sys/systm.h>
108264790Sbapt# endif
109264790Sbapt#endif
110264790Sbapt
111264790Sbapt
112264790Sbapt
113264790Sbapt#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
114264790Sbaptextern KRWLOCK_T ipf_auth;
115264790Sbaptextern kmutex_t ipf_authmx;
116264790Sbapt# if SOLARIS
117264790Sbaptextern kcondvar_t ipfauthwait;
118264790Sbapt# endif
119264790Sbapt#endif
120264790Sbapt#ifdef linux
121264790Sbaptstatic struct wait_queue *ipfauthwait = NULL;
122264790Sbapt#endif
123264790Sbapt
124264790Sbaptint	fr_authsize = FR_NUMAUTH;
125264790Sbaptint	fr_authused = 0;
126264790Sbaptint	fr_defaultauthage = 600;
127264790Sbaptint	fr_auth_lock = 0;
128264790Sbaptfr_authstat_t	fr_authstats;
129264790Sbaptstatic frauth_t fr_auth[FR_NUMAUTH];
130264790Sbaptmb_t	*fr_authpkts[FR_NUMAUTH];
131264790Sbaptstatic int	fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
132264790Sbaptstatic frauthent_t	*fae_list = NULL;
133264790Sbaptfrentry_t	*ipauth = NULL;
134264790Sbapt
135264790Sbapt
136264790Sbapt/*
137264790Sbapt * Check if a packet has authorization.  If the packet is found to match an
138264790Sbapt * authorization result and that would result in a feedback loop (i.e. it
139264790Sbapt * will end up returning FR_AUTH) then return FR_BLOCK instead.
140264790Sbapt */
141264790Sbaptu_32_t fr_checkauth(ip, fin)
142264790Sbaptip_t *ip;
143264790Sbaptfr_info_t *fin;
144264790Sbapt{
145264790Sbapt	u_short id = ip->ip_id;
146264790Sbapt	u_32_t pass;
147264790Sbapt	int i;
148264790Sbapt
149264790Sbapt	if (fr_auth_lock)
150264790Sbapt		return 0;
151264790Sbapt
152264790Sbapt	READ_ENTER(&ipf_auth);
153264790Sbapt	for (i = fr_authstart; i != fr_authend; ) {
154264790Sbapt		/*
155264790Sbapt		 * index becomes -2 only after an SIOCAUTHW.  Check this in
156264790Sbapt		 * case the same packet gets sent again and it hasn't yet been
157264790Sbapt		 * auth'd.
158264790Sbapt		 */
159264790Sbapt		if ((fr_auth[i].fra_index == -2) &&
160264790Sbapt		    (id == fr_auth[i].fra_info.fin_id) &&
161264790Sbapt		    !bcmp((char *)fin,(char *)&fr_auth[i].fra_info,FI_CSIZE)) {
162264790Sbapt			/*
163264790Sbapt			 * Avoid feedback loop.
164264790Sbapt			 */
165264790Sbapt			if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH))
166264790Sbapt				pass = FR_BLOCK;
167264790Sbapt			RWLOCK_EXIT(&ipf_auth);
168264790Sbapt			WRITE_ENTER(&ipf_auth);
169264790Sbapt			fr_authstats.fas_hits++;
170264790Sbapt			fr_auth[i].fra_index = -1;
171264790Sbapt			fr_authused--;
172264790Sbapt			if (i == fr_authstart) {
173264790Sbapt				while (fr_auth[i].fra_index == -1) {
174264790Sbapt					i++;
175264790Sbapt					if (i == FR_NUMAUTH)
176264790Sbapt						i = 0;
177264790Sbapt					fr_authstart = i;
178264790Sbapt					if (i == fr_authend)
179264790Sbapt						break;
180264790Sbapt				}
181264790Sbapt				if (fr_authstart == fr_authend) {
182264790Sbapt					fr_authnext = 0;
183264790Sbapt					fr_authstart = fr_authend = 0;
184264790Sbapt				}
185264790Sbapt			}
186264790Sbapt			RWLOCK_EXIT(&ipf_auth);
187264790Sbapt			return pass;
188264790Sbapt		}
189264790Sbapt		i++;
190264790Sbapt		if (i == FR_NUMAUTH)
191264790Sbapt			i = 0;
192264790Sbapt	}
193264790Sbapt	fr_authstats.fas_miss++;
194264790Sbapt	RWLOCK_EXIT(&ipf_auth);
195264790Sbapt	return 0;
196264790Sbapt}
197264790Sbapt
198264790Sbapt
199264790Sbapt/*
200264790Sbapt * Check if we have room in the auth array to hold details for another packet.
201264790Sbapt * If we do, store it and wake up any user programs which are waiting to
202264790Sbapt * hear about these events.
203264790Sbapt */
204264790Sbaptint fr_newauth(m, fin, ip)
205264790Sbaptmb_t *m;
206264790Sbaptfr_info_t *fin;
207264790Sbaptip_t *ip;
208264790Sbapt{
209264790Sbapt#if defined(_KERNEL) && SOLARIS
210264790Sbapt	qif_t *qif = fin->fin_qif;
211264790Sbapt#endif
212264790Sbapt	int i;
213264790Sbapt
214264790Sbapt	if (fr_auth_lock)
215264790Sbapt		return 0;
216264790Sbapt
217264790Sbapt	WRITE_ENTER(&ipf_auth);
218264790Sbapt	if (fr_authstart > fr_authend) {
219264790Sbapt		fr_authstats.fas_nospace++;
220264790Sbapt		RWLOCK_EXIT(&ipf_auth);
221264790Sbapt		return 0;
222264790Sbapt	} else {
223264790Sbapt		if ((fr_authstart == 0) && (fr_authend == FR_NUMAUTH - 1)) {
224264790Sbapt			fr_authstats.fas_nospace++;
225264790Sbapt			RWLOCK_EXIT(&ipf_auth);
226264790Sbapt			return 0;
227264790Sbapt		}
228264790Sbapt	}
229264790Sbapt
230264790Sbapt	fr_authstats.fas_added++;
231264790Sbapt	fr_authused++;
232264790Sbapt	i = fr_authend++;
233264790Sbapt	if (fr_authend == FR_NUMAUTH)
234264790Sbapt		fr_authend = 0;
235264790Sbapt	RWLOCK_EXIT(&ipf_auth);
236264790Sbapt	fr_auth[i].fra_index = i;
237264790Sbapt	fr_auth[i].fra_pass = 0;
238264790Sbapt	fr_auth[i].fra_age = fr_defaultauthage;
239264790Sbapt	bcopy((char *)fin, (char *)&fr_auth[i].fra_info, sizeof(*fin));
240264790Sbapt#if !defined(sparc) && !defined(m68k)
241264790Sbapt	/*
242264790Sbapt	 * No need to copyback here as we want to undo the changes, not keep
243264790Sbapt	 * them.
244264790Sbapt	 */
245264790Sbapt# if SOLARIS && defined(_KERNEL)
246264790Sbapt	if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4))
247264790Sbapt# endif
248264790Sbapt	{
249264790Sbapt		register u_short bo;
250264790Sbapt
251264790Sbapt		bo = ip->ip_len;
252264790Sbapt		ip->ip_len = htons(bo);
253264790Sbapt# if !SOLARIS && !defined(__NetBSD__)
254264790Sbapt		/* 4.4BSD converts this ip_input.c, but I don't in solaris.c */
255264790Sbapt		bo = ip->ip_id;
256264790Sbapt		ip->ip_id = htons(bo);
257264790Sbapt# endif
258264790Sbapt		bo = ip->ip_off;
259264790Sbapt		ip->ip_off = htons(bo);
260264790Sbapt	}
261264790Sbapt#endif
262264790Sbapt#if SOLARIS && defined(_KERNEL)
263264790Sbapt	m->b_rptr -= qif->qf_off;
264264790Sbapt	fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
265264790Sbapt	fr_auth[i].fra_q = qif->qf_q;
266264790Sbapt	cv_signal(&ipfauthwait);
267264790Sbapt#else
268264790Sbapt	fr_authpkts[i] = m;
269264790Sbapt# if defined(linux) && defined(_KERNEL)
270264790Sbapt	wake_up_interruptible(&ipfauthwait);
271264790Sbapt# else
272264790Sbapt	WAKEUP(&fr_authnext);
273264790Sbapt# endif
274264790Sbapt#endif
275264790Sbapt	return 1;
276264790Sbapt}
277264790Sbapt
278264790Sbapt
279264790Sbaptint fr_auth_ioctl(data, cmd, fr, frptr)
280264790Sbaptcaddr_t data;
281264790Sbapt#if defined(__NetBSD__) || defined(__OpenBSD__) || (FreeBSD_version >= 300003)
282264790Sbaptu_long cmd;
283264790Sbapt#else
284264790Sbaptint cmd;
285264790Sbapt#endif
286264790Sbaptfrentry_t *fr, **frptr;
287264790Sbapt{
288264790Sbapt	mb_t *m;
289264790Sbapt#if defined(_KERNEL) && !SOLARIS
290264790Sbapt	struct ifqueue *ifq;
291264790Sbapt#endif
292264790Sbapt	frauth_t auth, *au = &auth;
293264790Sbapt	frauthent_t *fae, **faep;
294264790Sbapt	int i, error = 0;
295264790Sbapt
296264790Sbapt	switch (cmd)
297264790Sbapt	{
298264790Sbapt	case SIOCSTLCK :
299264790Sbapt		error = fr_lock(data, &fr_auth_lock);
300264790Sbapt		break;
301264790Sbapt	case SIOCINIFR :
302264790Sbapt	case SIOCRMIFR :
303264790Sbapt	case SIOCADIFR :
304264790Sbapt		error = EINVAL;
305264790Sbapt		break;
306264790Sbapt	case SIOCINAFR :
307264790Sbapt		error = EINVAL;
308264790Sbapt		break;
309264790Sbapt	case SIOCRMAFR :
310264790Sbapt	case SIOCADAFR :
311264790Sbapt		for (faep = &fae_list; (fae = *faep); )
312264790Sbapt			if (&fae->fae_fr == fr)
313264790Sbapt				break;
314264790Sbapt			else
315264790Sbapt				faep = &fae->fae_next;
316264790Sbapt		if (cmd == SIOCRMAFR) {
317264790Sbapt			if (!fae)
318264790Sbapt				error = ESRCH;
319264790Sbapt			else {
320264790Sbapt				WRITE_ENTER(&ipf_auth);
321264790Sbapt				*faep = fae->fae_next;
322264790Sbapt				*frptr = fr->fr_next;
323264790Sbapt				RWLOCK_EXIT(&ipf_auth);
324264790Sbapt				KFREE(fae);
325264790Sbapt			}
326264790Sbapt		} else {
327264790Sbapt			KMALLOC(fae, frauthent_t *);
328264790Sbapt			if (fae != NULL) {
329264790Sbapt				bcopy((char *)fr, (char *)&fae->fae_fr,
330264790Sbapt				      sizeof(*fr));
331264790Sbapt				WRITE_ENTER(&ipf_auth);
332264790Sbapt				fae->fae_age = fr_defaultauthage;
333264790Sbapt				fae->fae_fr.fr_hits = 0;
334264790Sbapt				fae->fae_fr.fr_next = *frptr;
335264790Sbapt				*frptr = &fae->fae_fr;
336264790Sbapt				fae->fae_next = *faep;
337264790Sbapt				*faep = fae;
338264790Sbapt				ipauth = &fae_list->fae_fr;
339264790Sbapt				RWLOCK_EXIT(&ipf_auth);
340264790Sbapt			} else
341264790Sbapt				error = ENOMEM;
342264790Sbapt		}
343264790Sbapt		break;
344264790Sbapt	case SIOCATHST:
345264790Sbapt		READ_ENTER(&ipf_auth);
346264790Sbapt		fr_authstats.fas_faelist = fae_list;
347264790Sbapt		RWLOCK_EXIT(&ipf_auth);
348264790Sbapt		error = IWCOPYPTR((char *)&fr_authstats, data,
349264790Sbapt				   sizeof(fr_authstats));
350264790Sbapt		break;
351264790Sbapt	case SIOCAUTHW:
352264790Sbaptfr_authioctlloop:
353264790Sbapt		READ_ENTER(&ipf_auth);
354264790Sbapt		if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) {
355264790Sbapt			error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data,
356264790Sbapt					  sizeof(fr_info_t));
357264790Sbapt			RWLOCK_EXIT(&ipf_auth);
358264790Sbapt			if (error)
359264790Sbapt				break;
360264790Sbapt			WRITE_ENTER(&ipf_auth);
361264790Sbapt			fr_authnext++;
362264790Sbapt			if (fr_authnext == FR_NUMAUTH)
363264790Sbapt				fr_authnext = 0;
364264790Sbapt			RWLOCK_EXIT(&ipf_auth);
365264790Sbapt			return 0;
366264790Sbapt		}
367264790Sbapt#ifdef	_KERNEL
368264790Sbapt# if	SOLARIS
369264790Sbapt		mutex_enter(&ipf_authmx);
370264790Sbapt		if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) {
371264790Sbapt			mutex_exit(&ipf_authmx);
372264790Sbapt			return EINTR;
373264790Sbapt		}
374264790Sbapt		mutex_exit(&ipf_authmx);
375264790Sbapt# else
376264790Sbapt#  ifdef linux
377264790Sbapt		interruptible_sleep_on(&ipfauthwait);
378264790Sbapt		if (current->signal & ~current->blocked)
379264790Sbapt			error = -EINTR;
380264790Sbapt#  else
381264790Sbapt		error = SLEEP(&fr_authnext, "fr_authnext");
382264790Sbapt# endif
383264790Sbapt# endif
384264790Sbapt#endif
385264790Sbapt		RWLOCK_EXIT(&ipf_auth);
386264790Sbapt		if (!error)
387264790Sbapt			goto fr_authioctlloop;
388264790Sbapt		break;
389264790Sbapt	case SIOCAUTHR:
390264790Sbapt		error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth));
391264790Sbapt		if (error)
392264790Sbapt			return error;
393264790Sbapt		WRITE_ENTER(&ipf_auth);
394264790Sbapt		i = au->fra_index;
395264790Sbapt		if ((i < 0) || (i > FR_NUMAUTH) ||
396264790Sbapt		    (fr_auth[i].fra_info.fin_id != au->fra_info.fin_id)) {
397264790Sbapt			RWLOCK_EXIT(&ipf_auth);
398264790Sbapt			return EINVAL;
399264790Sbapt		}
400264790Sbapt		m = fr_authpkts[i];
401264790Sbapt		fr_auth[i].fra_index = -2;
402264790Sbapt		fr_auth[i].fra_pass = au->fra_pass;
403264790Sbapt		fr_authpkts[i] = NULL;
404264790Sbapt#ifdef	_KERNEL
405264790Sbapt		RWLOCK_EXIT(&ipf_auth);
406264790Sbapt# ifndef linux
407264790Sbapt		if (m && au->fra_info.fin_out) {
408264790Sbapt#  if SOLARIS
409264790Sbapt			error = fr_qout(fr_auth[i].fra_q, m);
410264790Sbapt#  else /* SOLARIS */
411264790Sbapt#   if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__)
412264790Sbapt			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL,
413264790Sbapt					  NULL);
414264790Sbapt#   else
415264790Sbapt			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
416264790Sbapt#   endif
417264790Sbapt#  endif /* SOLARIS */
418264790Sbapt			if (error)
419264790Sbapt				fr_authstats.fas_sendfail++;
420264790Sbapt			else
421264790Sbapt				fr_authstats.fas_sendok++;
422264790Sbapt		} else if (m) {
423264790Sbapt# if SOLARIS
424264790Sbapt			error = fr_qin(fr_auth[i].fra_q, m);
425264790Sbapt# else /* SOLARIS */
426264790Sbapt			ifq = &ipintrq;
427264790Sbapt			if (IF_QFULL(ifq)) {
428264790Sbapt				IF_DROP(ifq);
429264790Sbapt				m_freem(m);
430264790Sbapt				error = ENOBUFS;
431264790Sbapt			} else {
432264790Sbapt				IF_ENQUEUE(ifq, m);
433264790Sbapt				schednetisr(NETISR_IP);
434264790Sbapt			}
435264790Sbapt# endif /* SOLARIS */
436264790Sbapt			if (error)
437264790Sbapt				fr_authstats.fas_quefail++;
438264790Sbapt			else
439264790Sbapt				fr_authstats.fas_queok++;
440264790Sbapt		} else
441264790Sbapt			error = EINVAL;
442264790Sbapt# endif
443264790Sbapt# if SOLARIS
444264790Sbapt		if (error)
445264790Sbapt			error = EINVAL;
446264790Sbapt# else
447264790Sbapt		/*
448264790Sbapt		 * If we experience an error which will result in the packet
449264790Sbapt		 * not being processed, make sure we advance to the next one.
450264790Sbapt		 */
451264790Sbapt		if (error == ENOBUFS) {
452264790Sbapt			fr_authused--;
453264790Sbapt			fr_auth[i].fra_index = -1;
454264790Sbapt			fr_auth[i].fra_pass = 0;
455264790Sbapt			if (i == fr_authstart) {
456264790Sbapt				while (fr_auth[i].fra_index == -1) {
457264790Sbapt					i++;
458264790Sbapt					if (i == FR_NUMAUTH)
459264790Sbapt						i = 0;
460264790Sbapt					fr_authstart = i;
461264790Sbapt					if (i == fr_authend)
462264790Sbapt						break;
463264790Sbapt				}
464264790Sbapt				if (fr_authstart == fr_authend) {
465264790Sbapt					fr_authnext = 0;
466264790Sbapt					fr_authstart = fr_authend = 0;
467264790Sbapt				}
468264790Sbapt			}
469264790Sbapt		}
470264790Sbapt# endif
471264790Sbapt#endif /* _KERNEL */
472264790Sbapt		break;
473264790Sbapt	default :
474264790Sbapt		error = EINVAL;
475264790Sbapt		break;
476264790Sbapt	}
477264790Sbapt	return error;
478264790Sbapt}
479264790Sbapt
480264790Sbapt
481264790Sbapt#ifdef	_KERNEL
482264790Sbapt/*
483264790Sbapt * Free all network buffer memory used to keep saved packets.
484264790Sbapt */
485264790Sbaptvoid fr_authunload()
486264790Sbapt{
487264790Sbapt	register int i;
488264790Sbapt	register frauthent_t *fae, **faep;
489264790Sbapt	mb_t *m;
490264790Sbapt
491264790Sbapt	WRITE_ENTER(&ipf_auth);
492264790Sbapt	for (i = 0; i < FR_NUMAUTH; i++) {
493264790Sbapt		if ((m = fr_authpkts[i])) {
494264790Sbapt			FREE_MB_T(m);
495264790Sbapt			fr_authpkts[i] = NULL;
496264790Sbapt			fr_auth[i].fra_index = -1;
497264790Sbapt		}
498264790Sbapt	}
499264790Sbapt
500264790Sbapt
501264790Sbapt	for (faep = &fae_list; (fae = *faep); ) {
502264790Sbapt		*faep = fae->fae_next;
503264790Sbapt		KFREE(fae);
504264790Sbapt	}
505264790Sbapt	ipauth = NULL;
506264790Sbapt	RWLOCK_EXIT(&ipf_auth);
507264790Sbapt}
508264790Sbapt
509264790Sbapt
510264790Sbapt/*
511264790Sbapt * Slowly expire held auth records.  Timeouts are set
512264790Sbapt * in expectation of this being called twice per second.
513264790Sbapt */
514264790Sbaptvoid fr_authexpire()
515264790Sbapt{
516264790Sbapt	register int i;
517264790Sbapt	register frauth_t *fra;
518264790Sbapt	register frauthent_t *fae, **faep;
519264790Sbapt	mb_t *m;
520264790Sbapt#if !SOLARIS
521264790Sbapt	int s;
522264790Sbapt#endif
523264790Sbapt
524264790Sbapt	if (fr_auth_lock)
525264790Sbapt		return;
526264790Sbapt
527264790Sbapt	SPL_NET(s);
528264790Sbapt	WRITE_ENTER(&ipf_auth);
529264790Sbapt	for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) {
530264790Sbapt		if ((!--fra->fra_age) && (m = fr_authpkts[i])) {
531264790Sbapt			FREE_MB_T(m);
532264790Sbapt			fr_authpkts[i] = NULL;
533264790Sbapt			fr_auth[i].fra_index = -1;
534264790Sbapt			fr_authstats.fas_expire++;
535264790Sbapt			fr_authused--;
536264790Sbapt		}
537264790Sbapt	}
538264790Sbapt
539264790Sbapt	for (faep = &fae_list; (fae = *faep); ) {
540264790Sbapt		if (!--fae->fae_age) {
541264790Sbapt			*faep = fae->fae_next;
542264790Sbapt			KFREE(fae);
543264790Sbapt			fr_authstats.fas_expire++;
544264790Sbapt		} else
545264790Sbapt			faep = &fae->fae_next;
546264790Sbapt	}
547264790Sbapt	ipauth = &fae_list->fae_fr;
548264790Sbapt	RWLOCK_EXIT(&ipf_auth);
549264790Sbapt	SPL_X(s);
550264790Sbapt}
551264790Sbapt#endif
552264790Sbapt