xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_auth.c (revision ab25eeb551a4be927a4b6ae2cf8aff7ed17decb4)
1*ab25eeb5Syz155240 /*
2*ab25eeb5Syz155240  * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
3*ab25eeb5Syz155240  *
4*ab25eeb5Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
5*ab25eeb5Syz155240  */
6*ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL)
7*ab25eeb5Syz155240 # undef KERNEL
8*ab25eeb5Syz155240 # undef _KERNEL
9*ab25eeb5Syz155240 # define        KERNEL	1
10*ab25eeb5Syz155240 # define        _KERNEL	1
11*ab25eeb5Syz155240 #endif
12*ab25eeb5Syz155240 #include <sys/errno.h>
13*ab25eeb5Syz155240 #include <sys/types.h>
14*ab25eeb5Syz155240 #include <sys/param.h>
15*ab25eeb5Syz155240 #include <sys/time.h>
16*ab25eeb5Syz155240 #include <sys/file.h>
17*ab25eeb5Syz155240 #if !defined(_KERNEL)
18*ab25eeb5Syz155240 # include <stdio.h>
19*ab25eeb5Syz155240 # include <stdlib.h>
20*ab25eeb5Syz155240 # include <string.h>
21*ab25eeb5Syz155240 # define _KERNEL
22*ab25eeb5Syz155240 # ifdef __OpenBSD__
23*ab25eeb5Syz155240 struct file;
24*ab25eeb5Syz155240 # endif
25*ab25eeb5Syz155240 # include <sys/uio.h>
26*ab25eeb5Syz155240 # undef _KERNEL
27*ab25eeb5Syz155240 #endif
28*ab25eeb5Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
29*ab25eeb5Syz155240 # include <sys/filio.h>
30*ab25eeb5Syz155240 # include <sys/fcntl.h>
31*ab25eeb5Syz155240 #else
32*ab25eeb5Syz155240 # include <sys/ioctl.h>
33*ab25eeb5Syz155240 #endif
34*ab25eeb5Syz155240 #if !defined(linux)
35*ab25eeb5Syz155240 # include <sys/protosw.h>
36*ab25eeb5Syz155240 #endif
37*ab25eeb5Syz155240 #include <sys/socket.h>
38*ab25eeb5Syz155240 #if defined(_KERNEL)
39*ab25eeb5Syz155240 # include <sys/systm.h>
40*ab25eeb5Syz155240 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux)
41*ab25eeb5Syz155240 #  include <sys/mbuf.h>
42*ab25eeb5Syz155240 # endif
43*ab25eeb5Syz155240 #endif
44*ab25eeb5Syz155240 #if defined(__SVR4) || defined(__svr4__)
45*ab25eeb5Syz155240 # include <sys/filio.h>
46*ab25eeb5Syz155240 # include <sys/byteorder.h>
47*ab25eeb5Syz155240 # ifdef _KERNEL
48*ab25eeb5Syz155240 #  include <sys/dditypes.h>
49*ab25eeb5Syz155240 # endif
50*ab25eeb5Syz155240 # include <sys/stream.h>
51*ab25eeb5Syz155240 # include <sys/kmem.h>
52*ab25eeb5Syz155240 #endif
53*ab25eeb5Syz155240 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000)
54*ab25eeb5Syz155240 # include <sys/queue.h>
55*ab25eeb5Syz155240 #endif
56*ab25eeb5Syz155240 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
57*ab25eeb5Syz155240 # include <machine/cpu.h>
58*ab25eeb5Syz155240 #endif
59*ab25eeb5Syz155240 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
60*ab25eeb5Syz155240 # include <sys/proc.h>
61*ab25eeb5Syz155240 #endif
62*ab25eeb5Syz155240 #include <net/if.h>
63*ab25eeb5Syz155240 #ifdef sun
64*ab25eeb5Syz155240 # include <net/af.h>
65*ab25eeb5Syz155240 #endif
66*ab25eeb5Syz155240 #include <net/route.h>
67*ab25eeb5Syz155240 #include <netinet/in.h>
68*ab25eeb5Syz155240 #include <netinet/in_systm.h>
69*ab25eeb5Syz155240 #include <netinet/ip.h>
70*ab25eeb5Syz155240 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi)
71*ab25eeb5Syz155240 # define	KERNEL
72*ab25eeb5Syz155240 # define	_KERNEL
73*ab25eeb5Syz155240 # define	NOT_KERNEL
74*ab25eeb5Syz155240 #endif
75*ab25eeb5Syz155240 #if !defined(linux)
76*ab25eeb5Syz155240 # include <netinet/ip_var.h>
77*ab25eeb5Syz155240 #endif
78*ab25eeb5Syz155240 #ifdef	NOT_KERNEL
79*ab25eeb5Syz155240 # undef	_KERNEL
80*ab25eeb5Syz155240 # undef	KERNEL
81*ab25eeb5Syz155240 #endif
82*ab25eeb5Syz155240 #include <netinet/tcp.h>
83*ab25eeb5Syz155240 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */
84*ab25eeb5Syz155240 extern struct ifqueue   ipintrq;		/* ip packet input queue */
85*ab25eeb5Syz155240 #else
86*ab25eeb5Syz155240 # if !defined(__hpux) && !defined(linux)
87*ab25eeb5Syz155240 #  if __FreeBSD_version >= 300000
88*ab25eeb5Syz155240 #   include <net/if_var.h>
89*ab25eeb5Syz155240 #   if __FreeBSD_version >= 500042
90*ab25eeb5Syz155240 #    define IF_QFULL _IF_QFULL
91*ab25eeb5Syz155240 #    define IF_DROP _IF_DROP
92*ab25eeb5Syz155240 #   endif /* __FreeBSD_version >= 500042 */
93*ab25eeb5Syz155240 #  endif
94*ab25eeb5Syz155240 #  include <netinet/in_var.h>
95*ab25eeb5Syz155240 #  include <netinet/tcp_fsm.h>
96*ab25eeb5Syz155240 # endif
97*ab25eeb5Syz155240 #endif
98*ab25eeb5Syz155240 #include <netinet/udp.h>
99*ab25eeb5Syz155240 #include <netinet/ip_icmp.h>
100*ab25eeb5Syz155240 #include "netinet/ip_compat.h"
101*ab25eeb5Syz155240 #include <netinet/tcpip.h>
102*ab25eeb5Syz155240 #include "netinet/ip_fil.h"
103*ab25eeb5Syz155240 #include "netinet/ip_auth.h"
104*ab25eeb5Syz155240 #if !defined(MENTAT) && !defined(linux)
105*ab25eeb5Syz155240 # include <net/netisr.h>
106*ab25eeb5Syz155240 # ifdef __FreeBSD__
107*ab25eeb5Syz155240 #  include <machine/cpufunc.h>
108*ab25eeb5Syz155240 # endif
109*ab25eeb5Syz155240 #endif
110*ab25eeb5Syz155240 #if (__FreeBSD_version >= 300000)
111*ab25eeb5Syz155240 # include <sys/malloc.h>
112*ab25eeb5Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
113*ab25eeb5Syz155240 #  include <sys/libkern.h>
114*ab25eeb5Syz155240 #  include <sys/systm.h>
115*ab25eeb5Syz155240 # endif
116*ab25eeb5Syz155240 #endif
117*ab25eeb5Syz155240 /* END OF INCLUDES */
118*ab25eeb5Syz155240 
119*ab25eeb5Syz155240 #if !defined(lint)
120*ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $";
121*ab25eeb5Syz155240 #endif
122*ab25eeb5Syz155240 
123*ab25eeb5Syz155240 
124*ab25eeb5Syz155240 #if SOLARIS
125*ab25eeb5Syz155240 extern kcondvar_t ipfauthwait;
126*ab25eeb5Syz155240 #endif /* SOLARIS */
127*ab25eeb5Syz155240 #if defined(linux) && defined(_KERNEL)
128*ab25eeb5Syz155240 wait_queue_head_t     fr_authnext_linux;
129*ab25eeb5Syz155240 #endif
130*ab25eeb5Syz155240 
131*ab25eeb5Syz155240 int	fr_authsize = FR_NUMAUTH;
132*ab25eeb5Syz155240 int	fr_authused = 0;
133*ab25eeb5Syz155240 int	fr_defaultauthage = 600;
134*ab25eeb5Syz155240 int	fr_auth_lock = 0;
135*ab25eeb5Syz155240 int	fr_auth_init = 0;
136*ab25eeb5Syz155240 fr_authstat_t	fr_authstats;
137*ab25eeb5Syz155240 static frauth_t *fr_auth = NULL;
138*ab25eeb5Syz155240 mb_t	**fr_authpkts = NULL;
139*ab25eeb5Syz155240 int	fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
140*ab25eeb5Syz155240 frauthent_t	*fae_list = NULL;
141*ab25eeb5Syz155240 frentry_t	*ipauth = NULL,
142*ab25eeb5Syz155240 		*fr_authlist = NULL;
143*ab25eeb5Syz155240 
144*ab25eeb5Syz155240 
145*ab25eeb5Syz155240 int fr_authinit()
146*ab25eeb5Syz155240 {
147*ab25eeb5Syz155240 	KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth));
148*ab25eeb5Syz155240 	if (fr_auth != NULL)
149*ab25eeb5Syz155240 		bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth));
150*ab25eeb5Syz155240 	else
151*ab25eeb5Syz155240 		return -1;
152*ab25eeb5Syz155240 
153*ab25eeb5Syz155240 	KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts));
154*ab25eeb5Syz155240 	if (fr_authpkts != NULL)
155*ab25eeb5Syz155240 		bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
156*ab25eeb5Syz155240 	else
157*ab25eeb5Syz155240 		return -2;
158*ab25eeb5Syz155240 
159*ab25eeb5Syz155240 	MUTEX_INIT(&ipf_authmx, "ipf auth log mutex");
160*ab25eeb5Syz155240 	RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock");
161*ab25eeb5Syz155240 #if SOLARIS && defined(_KERNEL)
162*ab25eeb5Syz155240 	cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL);
163*ab25eeb5Syz155240 #endif
164*ab25eeb5Syz155240 #if defined(linux) && defined(_KERNEL)
165*ab25eeb5Syz155240 	init_waitqueue_head(&fr_authnext_linux);
166*ab25eeb5Syz155240 #endif
167*ab25eeb5Syz155240 
168*ab25eeb5Syz155240 	fr_auth_init = 1;
169*ab25eeb5Syz155240 
170*ab25eeb5Syz155240 	return 0;
171*ab25eeb5Syz155240 }
172*ab25eeb5Syz155240 
173*ab25eeb5Syz155240 
174*ab25eeb5Syz155240 /*
175*ab25eeb5Syz155240  * Check if a packet has authorization.  If the packet is found to match an
176*ab25eeb5Syz155240  * authorization result and that would result in a feedback loop (i.e. it
177*ab25eeb5Syz155240  * will end up returning FR_AUTH) then return FR_BLOCK instead.
178*ab25eeb5Syz155240  */
179*ab25eeb5Syz155240 frentry_t *fr_checkauth(fin, passp)
180*ab25eeb5Syz155240 fr_info_t *fin;
181*ab25eeb5Syz155240 u_32_t *passp;
182*ab25eeb5Syz155240 {
183*ab25eeb5Syz155240 	frentry_t *fr;
184*ab25eeb5Syz155240 	frauth_t *fra;
185*ab25eeb5Syz155240 	u_32_t pass;
186*ab25eeb5Syz155240 	u_short id;
187*ab25eeb5Syz155240 	ip_t *ip;
188*ab25eeb5Syz155240 	int i;
189*ab25eeb5Syz155240 
190*ab25eeb5Syz155240 	if (fr_auth_lock || !fr_authused)
191*ab25eeb5Syz155240 		return NULL;
192*ab25eeb5Syz155240 
193*ab25eeb5Syz155240 	ip = fin->fin_ip;
194*ab25eeb5Syz155240 	id = ip->ip_id;
195*ab25eeb5Syz155240 
196*ab25eeb5Syz155240 	READ_ENTER(&ipf_auth);
197*ab25eeb5Syz155240 	for (i = fr_authstart; i != fr_authend; ) {
198*ab25eeb5Syz155240 		/*
199*ab25eeb5Syz155240 		 * index becomes -2 only after an SIOCAUTHW.  Check this in
200*ab25eeb5Syz155240 		 * case the same packet gets sent again and it hasn't yet been
201*ab25eeb5Syz155240 		 * auth'd.
202*ab25eeb5Syz155240 		 */
203*ab25eeb5Syz155240 		fra = fr_auth + i;
204*ab25eeb5Syz155240 		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
205*ab25eeb5Syz155240 		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
206*ab25eeb5Syz155240 			/*
207*ab25eeb5Syz155240 			 * Avoid feedback loop.
208*ab25eeb5Syz155240 			 */
209*ab25eeb5Syz155240 			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass)))
210*ab25eeb5Syz155240 				pass = FR_BLOCK;
211*ab25eeb5Syz155240 			/*
212*ab25eeb5Syz155240 			 * Create a dummy rule for the stateful checking to
213*ab25eeb5Syz155240 			 * use and return.  Zero out any values we don't
214*ab25eeb5Syz155240 			 * trust from userland!
215*ab25eeb5Syz155240 			 */
216*ab25eeb5Syz155240 			if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
217*ab25eeb5Syz155240 			     (fin->fin_flx & FI_FRAG))) {
218*ab25eeb5Syz155240 				KMALLOC(fr, frentry_t *);
219*ab25eeb5Syz155240 				if (fr) {
220*ab25eeb5Syz155240 					bcopy((char *)fra->fra_info.fin_fr,
221*ab25eeb5Syz155240 					      (char *)fr, sizeof(*fr));
222*ab25eeb5Syz155240 					fr->fr_grp = NULL;
223*ab25eeb5Syz155240 					fr->fr_ifa = fin->fin_ifp;
224*ab25eeb5Syz155240 					fr->fr_func = NULL;
225*ab25eeb5Syz155240 					fr->fr_ref = 1;
226*ab25eeb5Syz155240 					fr->fr_flags = pass;
227*ab25eeb5Syz155240 					fr->fr_ifas[1] = NULL;
228*ab25eeb5Syz155240 					fr->fr_ifas[2] = NULL;
229*ab25eeb5Syz155240 					fr->fr_ifas[3] = NULL;
230*ab25eeb5Syz155240 				}
231*ab25eeb5Syz155240 			} else
232*ab25eeb5Syz155240 				fr = fra->fra_info.fin_fr;
233*ab25eeb5Syz155240 			fin->fin_fr = fr;
234*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
235*ab25eeb5Syz155240 			WRITE_ENTER(&ipf_auth);
236*ab25eeb5Syz155240 			if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
237*ab25eeb5Syz155240 				fr->fr_next = fr_authlist;
238*ab25eeb5Syz155240 				fr_authlist = fr;
239*ab25eeb5Syz155240 			}
240*ab25eeb5Syz155240 			fr_authstats.fas_hits++;
241*ab25eeb5Syz155240 			fra->fra_index = -1;
242*ab25eeb5Syz155240 			fr_authused--;
243*ab25eeb5Syz155240 			if (i == fr_authstart) {
244*ab25eeb5Syz155240 				while (fra->fra_index == -1) {
245*ab25eeb5Syz155240 					i++;
246*ab25eeb5Syz155240 					fra++;
247*ab25eeb5Syz155240 					if (i == fr_authsize) {
248*ab25eeb5Syz155240 						i = 0;
249*ab25eeb5Syz155240 						fra = fr_auth;
250*ab25eeb5Syz155240 					}
251*ab25eeb5Syz155240 					fr_authstart = i;
252*ab25eeb5Syz155240 					if (i == fr_authend)
253*ab25eeb5Syz155240 						break;
254*ab25eeb5Syz155240 				}
255*ab25eeb5Syz155240 				if (fr_authstart == fr_authend) {
256*ab25eeb5Syz155240 					fr_authnext = 0;
257*ab25eeb5Syz155240 					fr_authstart = fr_authend = 0;
258*ab25eeb5Syz155240 				}
259*ab25eeb5Syz155240 			}
260*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
261*ab25eeb5Syz155240 			if (passp != NULL)
262*ab25eeb5Syz155240 				*passp = pass;
263*ab25eeb5Syz155240 			ATOMIC_INC64(fr_authstats.fas_hits);
264*ab25eeb5Syz155240 			return fr;
265*ab25eeb5Syz155240 		}
266*ab25eeb5Syz155240 		i++;
267*ab25eeb5Syz155240 		if (i == fr_authsize)
268*ab25eeb5Syz155240 			i = 0;
269*ab25eeb5Syz155240 	}
270*ab25eeb5Syz155240 	fr_authstats.fas_miss++;
271*ab25eeb5Syz155240 	RWLOCK_EXIT(&ipf_auth);
272*ab25eeb5Syz155240 	ATOMIC_INC64(fr_authstats.fas_miss);
273*ab25eeb5Syz155240 	return NULL;
274*ab25eeb5Syz155240 }
275*ab25eeb5Syz155240 
276*ab25eeb5Syz155240 
277*ab25eeb5Syz155240 /*
278*ab25eeb5Syz155240  * Check if we have room in the auth array to hold details for another packet.
279*ab25eeb5Syz155240  * If we do, store it and wake up any user programs which are waiting to
280*ab25eeb5Syz155240  * hear about these events.
281*ab25eeb5Syz155240  */
282*ab25eeb5Syz155240 int fr_newauth(m, fin)
283*ab25eeb5Syz155240 mb_t *m;
284*ab25eeb5Syz155240 fr_info_t *fin;
285*ab25eeb5Syz155240 {
286*ab25eeb5Syz155240 #if defined(_KERNEL) && defined(MENTAT)
287*ab25eeb5Syz155240 	qpktinfo_t *qpi = fin->fin_qpi;
288*ab25eeb5Syz155240 #endif
289*ab25eeb5Syz155240 	frauth_t *fra;
290*ab25eeb5Syz155240 #if !defined(sparc) && !defined(m68k)
291*ab25eeb5Syz155240 	ip_t *ip;
292*ab25eeb5Syz155240 #endif
293*ab25eeb5Syz155240 	int i;
294*ab25eeb5Syz155240 
295*ab25eeb5Syz155240 	if (fr_auth_lock)
296*ab25eeb5Syz155240 		return 0;
297*ab25eeb5Syz155240 
298*ab25eeb5Syz155240 	WRITE_ENTER(&ipf_auth);
299*ab25eeb5Syz155240 	if (fr_authstart > fr_authend) {
300*ab25eeb5Syz155240 		fr_authstats.fas_nospace++;
301*ab25eeb5Syz155240 		RWLOCK_EXIT(&ipf_auth);
302*ab25eeb5Syz155240 		return 0;
303*ab25eeb5Syz155240 	} else {
304*ab25eeb5Syz155240 		if (fr_authused == fr_authsize) {
305*ab25eeb5Syz155240 			fr_authstats.fas_nospace++;
306*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
307*ab25eeb5Syz155240 			return 0;
308*ab25eeb5Syz155240 		}
309*ab25eeb5Syz155240 	}
310*ab25eeb5Syz155240 
311*ab25eeb5Syz155240 	fr_authstats.fas_added++;
312*ab25eeb5Syz155240 	fr_authused++;
313*ab25eeb5Syz155240 	i = fr_authend++;
314*ab25eeb5Syz155240 	if (fr_authend == fr_authsize)
315*ab25eeb5Syz155240 		fr_authend = 0;
316*ab25eeb5Syz155240 	RWLOCK_EXIT(&ipf_auth);
317*ab25eeb5Syz155240 
318*ab25eeb5Syz155240 	fra = fr_auth + i;
319*ab25eeb5Syz155240 	fra->fra_index = i;
320*ab25eeb5Syz155240 	fra->fra_pass = 0;
321*ab25eeb5Syz155240 	fra->fra_age = fr_defaultauthage;
322*ab25eeb5Syz155240 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
323*ab25eeb5Syz155240 #if !defined(sparc) && !defined(m68k)
324*ab25eeb5Syz155240 	/*
325*ab25eeb5Syz155240 	 * No need to copyback here as we want to undo the changes, not keep
326*ab25eeb5Syz155240 	 * them.
327*ab25eeb5Syz155240 	 */
328*ab25eeb5Syz155240 	ip = fin->fin_ip;
329*ab25eeb5Syz155240 # if defined(MENTAT) && defined(_KERNEL)
330*ab25eeb5Syz155240 	if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4))
331*ab25eeb5Syz155240 # endif
332*ab25eeb5Syz155240 	{
333*ab25eeb5Syz155240 		register u_short bo;
334*ab25eeb5Syz155240 
335*ab25eeb5Syz155240 		bo = ip->ip_len;
336*ab25eeb5Syz155240 		ip->ip_len = htons(bo);
337*ab25eeb5Syz155240 		bo = ip->ip_off;
338*ab25eeb5Syz155240 		ip->ip_off = htons(bo);
339*ab25eeb5Syz155240 	}
340*ab25eeb5Syz155240 #endif
341*ab25eeb5Syz155240 #if SOLARIS && defined(_KERNEL)
342*ab25eeb5Syz155240 	m->b_rptr -= qpi->qpi_off;
343*ab25eeb5Syz155240 	fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
344*ab25eeb5Syz155240 	fra->fra_q = qpi->qpi_q;	/* The queue can disappear! */
345*ab25eeb5Syz155240 	cv_signal(&ipfauthwait);
346*ab25eeb5Syz155240 #else
347*ab25eeb5Syz155240 # if defined(BSD) && !defined(sparc) && (BSD >= 199306)
348*ab25eeb5Syz155240 	if (!fin->fin_out) {
349*ab25eeb5Syz155240 		ip->ip_len = htons(ip->ip_len);
350*ab25eeb5Syz155240 		ip->ip_off = htons(ip->ip_off);
351*ab25eeb5Syz155240 	}
352*ab25eeb5Syz155240 # endif
353*ab25eeb5Syz155240 	fr_authpkts[i] = m;
354*ab25eeb5Syz155240 	WAKEUP(&fr_authnext,0);
355*ab25eeb5Syz155240 #endif
356*ab25eeb5Syz155240 	return 1;
357*ab25eeb5Syz155240 }
358*ab25eeb5Syz155240 
359*ab25eeb5Syz155240 
360*ab25eeb5Syz155240 int fr_auth_ioctl(data, cmd, mode)
361*ab25eeb5Syz155240 caddr_t data;
362*ab25eeb5Syz155240 ioctlcmd_t cmd;
363*ab25eeb5Syz155240 int mode;
364*ab25eeb5Syz155240 {
365*ab25eeb5Syz155240 	mb_t *m;
366*ab25eeb5Syz155240 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \
367*ab25eeb5Syz155240     (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000))
368*ab25eeb5Syz155240 	struct ifqueue *ifq;
369*ab25eeb5Syz155240 	SPL_INT(s);
370*ab25eeb5Syz155240 #endif
371*ab25eeb5Syz155240 	frauth_t auth, *au = &auth, *fra;
372*ab25eeb5Syz155240 	int i, error = 0, len;
373*ab25eeb5Syz155240 	char *t;
374*ab25eeb5Syz155240 
375*ab25eeb5Syz155240 	switch (cmd)
376*ab25eeb5Syz155240 	{
377*ab25eeb5Syz155240 	case SIOCSTLCK :
378*ab25eeb5Syz155240 		if (!(mode & FWRITE)) {
379*ab25eeb5Syz155240 			error = EPERM;
380*ab25eeb5Syz155240 			break;
381*ab25eeb5Syz155240 		}
382*ab25eeb5Syz155240 		fr_lock(data, &fr_auth_lock);
383*ab25eeb5Syz155240 		break;
384*ab25eeb5Syz155240 
385*ab25eeb5Syz155240 	case SIOCATHST:
386*ab25eeb5Syz155240 		fr_authstats.fas_faelist = fae_list;
387*ab25eeb5Syz155240 		error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT);
388*ab25eeb5Syz155240 		break;
389*ab25eeb5Syz155240 
390*ab25eeb5Syz155240 	case SIOCIPFFL:
391*ab25eeb5Syz155240 		SPL_NET(s);
392*ab25eeb5Syz155240 		WRITE_ENTER(&ipf_auth);
393*ab25eeb5Syz155240 		i = fr_authflush();
394*ab25eeb5Syz155240 		RWLOCK_EXIT(&ipf_auth);
395*ab25eeb5Syz155240 		SPL_X(s);
396*ab25eeb5Syz155240 		error = copyoutptr((char *)&i, data, sizeof(i));
397*ab25eeb5Syz155240 		break;
398*ab25eeb5Syz155240 
399*ab25eeb5Syz155240 	case SIOCAUTHW:
400*ab25eeb5Syz155240 fr_authioctlloop:
401*ab25eeb5Syz155240 		error = fr_inobj(data, au, IPFOBJ_FRAUTH);
402*ab25eeb5Syz155240 		READ_ENTER(&ipf_auth);
403*ab25eeb5Syz155240 		if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) {
404*ab25eeb5Syz155240 			error = fr_outobj(data, &fr_auth[fr_authnext],
405*ab25eeb5Syz155240 					  IPFOBJ_FRAUTH);
406*ab25eeb5Syz155240 			if (auth.fra_len != 0 && auth.fra_buf != NULL) {
407*ab25eeb5Syz155240 				/*
408*ab25eeb5Syz155240 				 * Copy packet contents out to user space if
409*ab25eeb5Syz155240 				 * requested.  Bail on an error.
410*ab25eeb5Syz155240 				 */
411*ab25eeb5Syz155240 				m = fr_authpkts[fr_authnext];
412*ab25eeb5Syz155240 				len = MSGDSIZE(m);
413*ab25eeb5Syz155240 				if (len > auth.fra_len)
414*ab25eeb5Syz155240 					len = auth.fra_len;
415*ab25eeb5Syz155240 				auth.fra_len = len;
416*ab25eeb5Syz155240 				for (t = auth.fra_buf; m && (len > 0); ) {
417*ab25eeb5Syz155240 					i = MIN(M_LEN(m), len);
418*ab25eeb5Syz155240 					error = copyoutptr(MTOD(m, char *),
419*ab25eeb5Syz155240 							  t, i);
420*ab25eeb5Syz155240 					len -= i;
421*ab25eeb5Syz155240 					t += i;
422*ab25eeb5Syz155240 					if (error != 0)
423*ab25eeb5Syz155240 						break;
424*ab25eeb5Syz155240 				}
425*ab25eeb5Syz155240 			}
426*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
427*ab25eeb5Syz155240 			if (error != 0)
428*ab25eeb5Syz155240 				break;
429*ab25eeb5Syz155240 			SPL_NET(s);
430*ab25eeb5Syz155240 			WRITE_ENTER(&ipf_auth);
431*ab25eeb5Syz155240 			fr_authnext++;
432*ab25eeb5Syz155240 			if (fr_authnext == fr_authsize)
433*ab25eeb5Syz155240 				fr_authnext = 0;
434*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
435*ab25eeb5Syz155240 			SPL_X(s);
436*ab25eeb5Syz155240 			return 0;
437*ab25eeb5Syz155240 		}
438*ab25eeb5Syz155240 		RWLOCK_EXIT(&ipf_auth);
439*ab25eeb5Syz155240 		/*
440*ab25eeb5Syz155240 		 * We exit ipf_global here because a program that enters in
441*ab25eeb5Syz155240 		 * here will have a lock on it and goto sleep having this lock.
442*ab25eeb5Syz155240 		 * If someone were to do an 'ipf -D' the system would then
443*ab25eeb5Syz155240 		 * deadlock.  The catch with releasing it here is that the
444*ab25eeb5Syz155240 		 * caller of this function expects it to be held when we
445*ab25eeb5Syz155240 		 * return so we have to reacquire it in here.
446*ab25eeb5Syz155240 		 */
447*ab25eeb5Syz155240 		RWLOCK_EXIT(&ipf_global);
448*ab25eeb5Syz155240 
449*ab25eeb5Syz155240 		MUTEX_ENTER(&ipf_authmx);
450*ab25eeb5Syz155240 #ifdef	_KERNEL
451*ab25eeb5Syz155240 # if	SOLARIS
452*ab25eeb5Syz155240 		error = 0;
453*ab25eeb5Syz155240 		if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk))
454*ab25eeb5Syz155240 			error = EINTR;
455*ab25eeb5Syz155240 # else /* SOLARIS */
456*ab25eeb5Syz155240 #  ifdef __hpux
457*ab25eeb5Syz155240 		{
458*ab25eeb5Syz155240 		lock_t *l;
459*ab25eeb5Syz155240 
460*ab25eeb5Syz155240 		l = get_sleep_lock(&fr_authnext);
461*ab25eeb5Syz155240 		error = sleep(&fr_authnext, PZERO+1);
462*ab25eeb5Syz155240 		spinunlock(l);
463*ab25eeb5Syz155240 		}
464*ab25eeb5Syz155240 #  else
465*ab25eeb5Syz155240 #   ifdef __osf__
466*ab25eeb5Syz155240 		error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0,
467*ab25eeb5Syz155240 				&ipf_authmx, MS_LOCK_SIMPLE);
468*ab25eeb5Syz155240 #   else
469*ab25eeb5Syz155240 		error = SLEEP(&fr_authnext, "fr_authnext");
470*ab25eeb5Syz155240 #   endif /* __osf__ */
471*ab25eeb5Syz155240 #  endif /* __hpux */
472*ab25eeb5Syz155240 # endif /* SOLARIS */
473*ab25eeb5Syz155240 #endif
474*ab25eeb5Syz155240 		MUTEX_EXIT(&ipf_authmx);
475*ab25eeb5Syz155240 		READ_ENTER(&ipf_global);
476*ab25eeb5Syz155240 		if (error == 0) {
477*ab25eeb5Syz155240 			READ_ENTER(&ipf_auth);
478*ab25eeb5Syz155240 			goto fr_authioctlloop;
479*ab25eeb5Syz155240 		}
480*ab25eeb5Syz155240 		break;
481*ab25eeb5Syz155240 
482*ab25eeb5Syz155240 	case SIOCAUTHR:
483*ab25eeb5Syz155240 		error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
484*ab25eeb5Syz155240 		if (error != 0)
485*ab25eeb5Syz155240 			return error;
486*ab25eeb5Syz155240 		SPL_NET(s);
487*ab25eeb5Syz155240 		WRITE_ENTER(&ipf_auth);
488*ab25eeb5Syz155240 		i = au->fra_index;
489*ab25eeb5Syz155240 		fra = fr_auth + i;
490*ab25eeb5Syz155240 		if ((i < 0) || (i >= fr_authsize) ||
491*ab25eeb5Syz155240 		    (fra->fra_info.fin_id != au->fra_info.fin_id)) {
492*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
493*ab25eeb5Syz155240 			SPL_X(s);
494*ab25eeb5Syz155240 			return ESRCH;
495*ab25eeb5Syz155240 		}
496*ab25eeb5Syz155240 		m = fr_authpkts[i];
497*ab25eeb5Syz155240 		fra->fra_index = -2;
498*ab25eeb5Syz155240 		fra->fra_pass = au->fra_pass;
499*ab25eeb5Syz155240 		fr_authpkts[i] = NULL;
500*ab25eeb5Syz155240 		RWLOCK_EXIT(&ipf_auth);
501*ab25eeb5Syz155240 #ifdef	_KERNEL
502*ab25eeb5Syz155240 		if ((m != NULL) && (au->fra_info.fin_out != 0)) {
503*ab25eeb5Syz155240 # ifdef MENTAT
504*ab25eeb5Syz155240 			error = !putq(fra->fra_q, m);
505*ab25eeb5Syz155240 # else /* MENTAT */
506*ab25eeb5Syz155240 #  if defined(linux) || defined(AIX)
507*ab25eeb5Syz155240 #  else
508*ab25eeb5Syz155240 #   if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \
509*ab25eeb5Syz155240        (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \
510*ab25eeb5Syz155240        (defined(__FreeBSD__) && (__FreeBSD_version >= 470102)))
511*ab25eeb5Syz155240 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL,
512*ab25eeb5Syz155240 					  NULL);
513*ab25eeb5Syz155240 #   else
514*ab25eeb5Syz155240 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
515*ab25eeb5Syz155240 #   endif
516*ab25eeb5Syz155240 #  endif /* Linux */
517*ab25eeb5Syz155240 # endif /* MENTAT */
518*ab25eeb5Syz155240 			if (error != 0)
519*ab25eeb5Syz155240 				fr_authstats.fas_sendfail++;
520*ab25eeb5Syz155240 			else
521*ab25eeb5Syz155240 				fr_authstats.fas_sendok++;
522*ab25eeb5Syz155240 		} else if (m) {
523*ab25eeb5Syz155240 # ifdef MENTAT
524*ab25eeb5Syz155240 			error = !putq(fra->fra_q, m);
525*ab25eeb5Syz155240 # else /* MENTAT */
526*ab25eeb5Syz155240 #  if defined(linux) || defined(AIX)
527*ab25eeb5Syz155240 #  else
528*ab25eeb5Syz155240 #   if (__FreeBSD_version >= 501000)
529*ab25eeb5Syz155240 			netisr_dispatch(NETISR_IP, m);
530*ab25eeb5Syz155240 #   else
531*ab25eeb5Syz155240 #    if (IRIX >= 60516)
532*ab25eeb5Syz155240 			ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd;
533*ab25eeb5Syz155240 #    else
534*ab25eeb5Syz155240 			ifq = &ipintrq;
535*ab25eeb5Syz155240 #    endif
536*ab25eeb5Syz155240 			if (IF_QFULL(ifq)) {
537*ab25eeb5Syz155240 				IF_DROP(ifq);
538*ab25eeb5Syz155240 				FREE_MB_T(m);
539*ab25eeb5Syz155240 				error = ENOBUFS;
540*ab25eeb5Syz155240 			} else {
541*ab25eeb5Syz155240 				IF_ENQUEUE(ifq, m);
542*ab25eeb5Syz155240 #    if IRIX < 60500
543*ab25eeb5Syz155240 				schednetisr(NETISR_IP);
544*ab25eeb5Syz155240 #    endif
545*ab25eeb5Syz155240 			}
546*ab25eeb5Syz155240 #   endif
547*ab25eeb5Syz155240 #  endif /* Linux */
548*ab25eeb5Syz155240 # endif /* MENTAT */
549*ab25eeb5Syz155240 			if (error != 0)
550*ab25eeb5Syz155240 				fr_authstats.fas_quefail++;
551*ab25eeb5Syz155240 			else
552*ab25eeb5Syz155240 				fr_authstats.fas_queok++;
553*ab25eeb5Syz155240 		} else
554*ab25eeb5Syz155240 			error = EINVAL;
555*ab25eeb5Syz155240 # ifdef MENTAT
556*ab25eeb5Syz155240 		if (error != 0)
557*ab25eeb5Syz155240 			error = EINVAL;
558*ab25eeb5Syz155240 # else /* MENTAT */
559*ab25eeb5Syz155240 		/*
560*ab25eeb5Syz155240 		 * If we experience an error which will result in the packet
561*ab25eeb5Syz155240 		 * not being processed, make sure we advance to the next one.
562*ab25eeb5Syz155240 		 */
563*ab25eeb5Syz155240 		if (error == ENOBUFS) {
564*ab25eeb5Syz155240 			fr_authused--;
565*ab25eeb5Syz155240 			fra->fra_index = -1;
566*ab25eeb5Syz155240 			fra->fra_pass = 0;
567*ab25eeb5Syz155240 			if (i == fr_authstart) {
568*ab25eeb5Syz155240 				while (fra->fra_index == -1) {
569*ab25eeb5Syz155240 					i++;
570*ab25eeb5Syz155240 					if (i == fr_authsize)
571*ab25eeb5Syz155240 						i = 0;
572*ab25eeb5Syz155240 					fr_authstart = i;
573*ab25eeb5Syz155240 					if (i == fr_authend)
574*ab25eeb5Syz155240 						break;
575*ab25eeb5Syz155240 				}
576*ab25eeb5Syz155240 				if (fr_authstart == fr_authend) {
577*ab25eeb5Syz155240 					fr_authnext = 0;
578*ab25eeb5Syz155240 					fr_authstart = fr_authend = 0;
579*ab25eeb5Syz155240 				}
580*ab25eeb5Syz155240 			}
581*ab25eeb5Syz155240 		}
582*ab25eeb5Syz155240 # endif /* MENTAT */
583*ab25eeb5Syz155240 #endif /* _KERNEL */
584*ab25eeb5Syz155240 		SPL_X(s);
585*ab25eeb5Syz155240 		break;
586*ab25eeb5Syz155240 
587*ab25eeb5Syz155240 	default :
588*ab25eeb5Syz155240 		error = EINVAL;
589*ab25eeb5Syz155240 		break;
590*ab25eeb5Syz155240 	}
591*ab25eeb5Syz155240 	return error;
592*ab25eeb5Syz155240 }
593*ab25eeb5Syz155240 
594*ab25eeb5Syz155240 
595*ab25eeb5Syz155240 /*
596*ab25eeb5Syz155240  * Free all network buffer memory used to keep saved packets.
597*ab25eeb5Syz155240  */
598*ab25eeb5Syz155240 void fr_authunload()
599*ab25eeb5Syz155240 {
600*ab25eeb5Syz155240 	register int i;
601*ab25eeb5Syz155240 	register frauthent_t *fae, **faep;
602*ab25eeb5Syz155240 	frentry_t *fr, **frp;
603*ab25eeb5Syz155240 	mb_t *m;
604*ab25eeb5Syz155240 
605*ab25eeb5Syz155240 	if (fr_auth != NULL) {
606*ab25eeb5Syz155240 		KFREES(fr_auth, fr_authsize * sizeof(*fr_auth));
607*ab25eeb5Syz155240 		fr_auth = NULL;
608*ab25eeb5Syz155240 	}
609*ab25eeb5Syz155240 
610*ab25eeb5Syz155240 	if (fr_authpkts != NULL) {
611*ab25eeb5Syz155240 		for (i = 0; i < fr_authsize; i++) {
612*ab25eeb5Syz155240 			m = fr_authpkts[i];
613*ab25eeb5Syz155240 			if (m != NULL) {
614*ab25eeb5Syz155240 				FREE_MB_T(m);
615*ab25eeb5Syz155240 				fr_authpkts[i] = NULL;
616*ab25eeb5Syz155240 			}
617*ab25eeb5Syz155240 		}
618*ab25eeb5Syz155240 		KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
619*ab25eeb5Syz155240 		fr_authpkts = NULL;
620*ab25eeb5Syz155240 	}
621*ab25eeb5Syz155240 
622*ab25eeb5Syz155240 	faep = &fae_list;
623*ab25eeb5Syz155240 	while ((fae = *faep) != NULL) {
624*ab25eeb5Syz155240 		*faep = fae->fae_next;
625*ab25eeb5Syz155240 		KFREE(fae);
626*ab25eeb5Syz155240 	}
627*ab25eeb5Syz155240 	ipauth = NULL;
628*ab25eeb5Syz155240 
629*ab25eeb5Syz155240 	if (fr_authlist != NULL) {
630*ab25eeb5Syz155240 		for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
631*ab25eeb5Syz155240 			if (fr->fr_ref == 1) {
632*ab25eeb5Syz155240 				*frp = fr->fr_next;
633*ab25eeb5Syz155240 				KFREE(fr);
634*ab25eeb5Syz155240 			} else
635*ab25eeb5Syz155240 				frp = &fr->fr_next;
636*ab25eeb5Syz155240 		}
637*ab25eeb5Syz155240 	}
638*ab25eeb5Syz155240 
639*ab25eeb5Syz155240 	if (fr_auth_init == 1) {
640*ab25eeb5Syz155240 # if SOLARIS && defined(_KERNEL)
641*ab25eeb5Syz155240 		cv_destroy(&ipfauthwait);
642*ab25eeb5Syz155240 # endif
643*ab25eeb5Syz155240 		MUTEX_DESTROY(&ipf_authmx);
644*ab25eeb5Syz155240 		RW_DESTROY(&ipf_auth);
645*ab25eeb5Syz155240 
646*ab25eeb5Syz155240 		fr_auth_init = 0;
647*ab25eeb5Syz155240 	}
648*ab25eeb5Syz155240 }
649*ab25eeb5Syz155240 
650*ab25eeb5Syz155240 
651*ab25eeb5Syz155240 /*
652*ab25eeb5Syz155240  * Slowly expire held auth records.  Timeouts are set
653*ab25eeb5Syz155240  * in expectation of this being called twice per second.
654*ab25eeb5Syz155240  */
655*ab25eeb5Syz155240 void fr_authexpire()
656*ab25eeb5Syz155240 {
657*ab25eeb5Syz155240 	register int i;
658*ab25eeb5Syz155240 	register frauth_t *fra;
659*ab25eeb5Syz155240 	register frauthent_t *fae, **faep;
660*ab25eeb5Syz155240 	register frentry_t *fr, **frp;
661*ab25eeb5Syz155240 	mb_t *m;
662*ab25eeb5Syz155240 	SPL_INT(s);
663*ab25eeb5Syz155240 
664*ab25eeb5Syz155240 	if (fr_auth_lock)
665*ab25eeb5Syz155240 		return;
666*ab25eeb5Syz155240 
667*ab25eeb5Syz155240 	SPL_NET(s);
668*ab25eeb5Syz155240 	WRITE_ENTER(&ipf_auth);
669*ab25eeb5Syz155240 	for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) {
670*ab25eeb5Syz155240 		fra->fra_age--;
671*ab25eeb5Syz155240 		if ((fra->fra_age == 0) && (m = fr_authpkts[i])) {
672*ab25eeb5Syz155240 			FREE_MB_T(m);
673*ab25eeb5Syz155240 			fr_authpkts[i] = NULL;
674*ab25eeb5Syz155240 			fr_auth[i].fra_index = -1;
675*ab25eeb5Syz155240 			fr_authstats.fas_expire++;
676*ab25eeb5Syz155240 			fr_authused--;
677*ab25eeb5Syz155240 		}
678*ab25eeb5Syz155240 	}
679*ab25eeb5Syz155240 
680*ab25eeb5Syz155240 	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
681*ab25eeb5Syz155240 		fae->fae_age--;
682*ab25eeb5Syz155240 		if (fae->fae_age == 0) {
683*ab25eeb5Syz155240 			*faep = fae->fae_next;
684*ab25eeb5Syz155240 			KFREE(fae);
685*ab25eeb5Syz155240 			fr_authstats.fas_expire++;
686*ab25eeb5Syz155240 		} else
687*ab25eeb5Syz155240 			faep = &fae->fae_next;
688*ab25eeb5Syz155240 	}
689*ab25eeb5Syz155240 	if (fae_list != NULL)
690*ab25eeb5Syz155240 		ipauth = &fae_list->fae_fr;
691*ab25eeb5Syz155240 	else
692*ab25eeb5Syz155240 		ipauth = NULL;
693*ab25eeb5Syz155240 
694*ab25eeb5Syz155240 	for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
695*ab25eeb5Syz155240 		if (fr->fr_ref == 1) {
696*ab25eeb5Syz155240 			*frp = fr->fr_next;
697*ab25eeb5Syz155240 			KFREE(fr);
698*ab25eeb5Syz155240 		} else
699*ab25eeb5Syz155240 			frp = &fr->fr_next;
700*ab25eeb5Syz155240 	}
701*ab25eeb5Syz155240 	RWLOCK_EXIT(&ipf_auth);
702*ab25eeb5Syz155240 	SPL_X(s);
703*ab25eeb5Syz155240 }
704*ab25eeb5Syz155240 
705*ab25eeb5Syz155240 int fr_preauthcmd(cmd, fr, frptr)
706*ab25eeb5Syz155240 ioctlcmd_t cmd;
707*ab25eeb5Syz155240 frentry_t *fr, **frptr;
708*ab25eeb5Syz155240 {
709*ab25eeb5Syz155240 	frauthent_t *fae, **faep;
710*ab25eeb5Syz155240 	int error = 0;
711*ab25eeb5Syz155240 	SPL_INT(s);
712*ab25eeb5Syz155240 
713*ab25eeb5Syz155240 	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
714*ab25eeb5Syz155240 		return EIO;
715*ab25eeb5Syz155240 
716*ab25eeb5Syz155240 	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
717*ab25eeb5Syz155240 		if (&fae->fae_fr == fr)
718*ab25eeb5Syz155240 			break;
719*ab25eeb5Syz155240 		else
720*ab25eeb5Syz155240 			faep = &fae->fae_next;
721*ab25eeb5Syz155240 	}
722*ab25eeb5Syz155240 
723*ab25eeb5Syz155240 	if (cmd == (ioctlcmd_t)SIOCRMAFR) {
724*ab25eeb5Syz155240 		if (fr == NULL || frptr == NULL)
725*ab25eeb5Syz155240 			error = EINVAL;
726*ab25eeb5Syz155240 		else if (fae == NULL)
727*ab25eeb5Syz155240 			error = ESRCH;
728*ab25eeb5Syz155240 		else {
729*ab25eeb5Syz155240 			SPL_NET(s);
730*ab25eeb5Syz155240 			WRITE_ENTER(&ipf_auth);
731*ab25eeb5Syz155240 			*faep = fae->fae_next;
732*ab25eeb5Syz155240 			if (ipauth == &fae->fae_fr)
733*ab25eeb5Syz155240 				ipauth = fae_list ? &fae_list->fae_fr : NULL;
734*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
735*ab25eeb5Syz155240 			SPL_X(s);
736*ab25eeb5Syz155240 
737*ab25eeb5Syz155240 			KFREE(fae);
738*ab25eeb5Syz155240 		}
739*ab25eeb5Syz155240 	} else if (fr != NULL && frptr != NULL) {
740*ab25eeb5Syz155240 		KMALLOC(fae, frauthent_t *);
741*ab25eeb5Syz155240 		if (fae != NULL) {
742*ab25eeb5Syz155240 			bcopy((char *)fr, (char *)&fae->fae_fr,
743*ab25eeb5Syz155240 			      sizeof(*fr));
744*ab25eeb5Syz155240 			SPL_NET(s);
745*ab25eeb5Syz155240 			WRITE_ENTER(&ipf_auth);
746*ab25eeb5Syz155240 			fae->fae_age = fr_defaultauthage;
747*ab25eeb5Syz155240 			fae->fae_fr.fr_hits = 0;
748*ab25eeb5Syz155240 			fae->fae_fr.fr_next = *frptr;
749*ab25eeb5Syz155240 			*frptr = &fae->fae_fr;
750*ab25eeb5Syz155240 			fae->fae_next = *faep;
751*ab25eeb5Syz155240 			*faep = fae;
752*ab25eeb5Syz155240 			ipauth = &fae_list->fae_fr;
753*ab25eeb5Syz155240 			RWLOCK_EXIT(&ipf_auth);
754*ab25eeb5Syz155240 			SPL_X(s);
755*ab25eeb5Syz155240 		} else
756*ab25eeb5Syz155240 			error = ENOMEM;
757*ab25eeb5Syz155240 	} else
758*ab25eeb5Syz155240 		error = EINVAL;
759*ab25eeb5Syz155240 	return error;
760*ab25eeb5Syz155240 }
761*ab25eeb5Syz155240 
762*ab25eeb5Syz155240 
763*ab25eeb5Syz155240 /*
764*ab25eeb5Syz155240  * Flush held packets.
765*ab25eeb5Syz155240  * Must already be properly SPL'ed and Locked on &ipf_auth.
766*ab25eeb5Syz155240  *
767*ab25eeb5Syz155240  */
768*ab25eeb5Syz155240 int fr_authflush()
769*ab25eeb5Syz155240 {
770*ab25eeb5Syz155240 	register int i, num_flushed;
771*ab25eeb5Syz155240 	mb_t *m;
772*ab25eeb5Syz155240 
773*ab25eeb5Syz155240 	if (fr_auth_lock)
774*ab25eeb5Syz155240 		return -1;
775*ab25eeb5Syz155240 
776*ab25eeb5Syz155240 	num_flushed = 0;
777*ab25eeb5Syz155240 
778*ab25eeb5Syz155240 	for (i = 0 ; i < fr_authsize; i++) {
779*ab25eeb5Syz155240 		m = fr_authpkts[i];
780*ab25eeb5Syz155240 		if (m != NULL) {
781*ab25eeb5Syz155240 			FREE_MB_T(m);
782*ab25eeb5Syz155240 			fr_authpkts[i] = NULL;
783*ab25eeb5Syz155240 			fr_auth[i].fra_index = -1;
784*ab25eeb5Syz155240 			/* perhaps add & use a flush counter inst.*/
785*ab25eeb5Syz155240 			fr_authstats.fas_expire++;
786*ab25eeb5Syz155240 			fr_authused--;
787*ab25eeb5Syz155240 			num_flushed++;
788*ab25eeb5Syz155240 		}
789*ab25eeb5Syz155240 	}
790*ab25eeb5Syz155240 
791*ab25eeb5Syz155240 	fr_authstart = 0;
792*ab25eeb5Syz155240 	fr_authend = 0;
793*ab25eeb5Syz155240 	fr_authnext = 0;
794*ab25eeb5Syz155240 
795*ab25eeb5Syz155240 	return num_flushed;
796*ab25eeb5Syz155240 }
797