xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_log.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1 /*
2  * Copyright (C) 1997-2003 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * $Id: ip_log.c,v 2.54 2003/06/28 17:01:57 darrenr Exp $
7  *
8  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
9  * Use is subject to license terms.
10  */
11 
12 #pragma ident	"%Z%%M%	%I%	%E% SMI"
13 
14 #include <sys/param.h>
15 #if defined(KERNEL) || defined(_KERNEL)
16 # undef KERNEL
17 # undef _KERNEL
18 # define        KERNEL	1
19 # define        _KERNEL	1
20 #endif
21 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
22     defined(_KERNEL)
23 # include "opt_ipfilter_log.h"
24 #endif
25 #ifdef  __FreeBSD__
26 # if !defined(IPFILTER_LKM)
27 #  if defined(_KERNEL)
28 #   if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
29 #    include "opt_ipfilter.h"
30 #   endif
31 #  else
32 #   include <osreldate.h>
33 #  endif
34 # endif
35 #endif
36 #ifdef	IPFILTER_LOG
37 # ifndef SOLARIS
38 #  define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
39 # endif
40 # include <sys/errno.h>
41 # include <sys/types.h>
42 # include <sys/file.h>
43 # ifndef _KERNEL
44 #  include <stdio.h>
45 #  include <string.h>
46 #  include <stdlib.h>
47 #  include <ctype.h>
48 #  define _KERNEL
49 # ifdef __OpenBSD__
50 struct file;
51 # endif
52 #  include <sys/uio.h>
53 #  undef _KERNEL
54 # endif
55 # if __FreeBSD_version >= 220000 && defined(_KERNEL)
56 #  include <sys/fcntl.h>
57 #  include <sys/filio.h>
58 # else
59 #  include <sys/ioctl.h>
60 # endif
61 # include <sys/time.h>
62 # if defined(_KERNEL)
63 #  include <sys/systm.h>
64 #  if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
65 #   include <sys/proc.h>
66 #  endif
67 # endif /* _KERNEL */
68 # if !SOLARIS && !defined(__hpux)
69 #  if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
70 #   include <sys/dirent.h>
71 #  else
72 #   include <sys/dir.h>
73 #  endif
74 #  include <sys/mbuf.h>
75 # else
76 #  if !defined(__hpux) && defined(_KERNEL)
77 #   include <sys/filio.h>
78 #   include <sys/cred.h>
79 #   include <sys/ddi.h>
80 #   include <sys/sunddi.h>
81 #   include <sys/ksynch.h>
82 #   include <sys/kmem.h>
83 #   include <sys/mkdev.h>
84 #   include <sys/dditypes.h>
85 #   include <sys/cmn_err.h>
86 #  endif /* !__hpux */
87 # endif /* !SOLARIS && !__hpux */
88 # include <sys/protosw.h>
89 # include <sys/socket.h>
90 
91 # include <net/if.h>
92 # ifdef sun
93 #  include <net/af.h>
94 # endif
95 # if __FreeBSD_version >= 300000
96 #  include <net/if_var.h>
97 # endif
98 # include <net/route.h>
99 # include <netinet/in.h>
100 # ifdef __sgi
101 #  include <sys/ddi.h>
102 #  ifdef IFF_DRVRLOCK /* IRIX6 */
103 #   include <sys/hashing.h>
104 #  endif
105 # endif
106 # if !defined(__hpux) && !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/
107 #  include <netinet/in_var.h>
108 # endif
109 # include <netinet/in_systm.h>
110 # include <netinet/ip.h>
111 # include <netinet/tcp.h>
112 # include <netinet/udp.h>
113 # include <netinet/ip_icmp.h>
114 # ifdef USE_INET6
115 #  include <netinet/icmp6.h>
116 # endif
117 # include <netinet/ip_var.h>
118 # ifndef _KERNEL
119 #  include <syslog.h>
120 # endif
121 # include <netinet/tcpip.h>
122 #if SOLARIS2 >= 10
123 # include "ip_compat.h"
124 # include "ip_fil.h"
125 # include "ip_nat.h"
126 # include "ip_frag.h"
127 # include "ip_state.h"
128 # include "ip_auth.h"
129 #else
130 # include "netinet/ip_compat.h"
131 # include "netinet/ip_fil.h"
132 # include "netinet/ip_nat.h"
133 # include "netinet/ip_frag.h"
134 # include "netinet/ip_state.h"
135 # include "netinet/ip_auth.h"
136 #endif
137 # if (__FreeBSD_version >= 300000) || defined(__NetBSD__)
138 #  include <sys/malloc.h>
139 # endif
140 
141 # if defined(__hpux) && defined(_KERNEL) && (HPUXREV >= 1111)
142 #  define	IPL_SELECT
143 # endif
144 
145 # if defined(IPL_SELECT)
146 #   include	<machine/sys/user.h>
147 #   include	<sys/kthread_iface.h>
148 #   define	READ_COLLISION	0x001
149 
150 struct {
151 	kthread	*read_waiter;
152 	int	state;
153 } iplog_ss[IPL_LOGMAX+1];
154 
155 extern int selwait;
156 # endif /* IPL_SELECT */
157 
158 # ifdef USE_MUTEXES
159 extern	ipfmutex_t	ipl_mutex;
160 #  if SOLARIS
161 extern	kcondvar_t	iplwait;
162 #  endif
163 # endif
164 
165 iplog_t	**iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE];
166 int	iplused[IPL_LOGSIZE];
167 static fr_info_t	iplcrc[IPL_LOGSIZE];
168 int	ipl_suppress = 1;
169 int	ipl_buffer_sz;
170 int	ipl_logmax = IPL_LOGMAX;
171 int	ipl_logall = 0;
172 int	ipl_log_init = 0;
173 
174 
175 /* ------------------------------------------------------------------------ */
176 /* Function:    fr_loginit                                                  */
177 /* Returns:     int - 0 == success (always returned)                        */
178 /* Parameters:  Nil                                                         */
179 /*                                                                          */
180 /* Initialise log buffers & pointers.  Also iniialised the CRC to a local   */
181 /* secret for use in calculating the "last log checksum".                   */
182 /* ------------------------------------------------------------------------ */
183 int fr_loginit()
184 {
185 	int	i;
186 
187 	for (i = IPL_LOGMAX; i >= 0; i--) {
188 		iplt[i] = NULL;
189 		ipll[i] = NULL;
190 		iplh[i] = &iplt[i];
191 		iplused[i] = 0;
192 		bzero((char *)&iplcrc[i], sizeof(iplcrc[i]));
193 # ifdef	IPL_SELECT
194 		iplog_ss[i].read_waiter = 0;
195 		iplog_ss[i].state = 0;
196 # endif
197 	}
198 
199 # if SOLARIS && defined(_KERNEL)
200 	cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL);
201 # endif
202 	MUTEX_INIT(&ipl_mutex, "ipf log mutex");
203 
204 	ipl_log_init = 1;
205 
206 	return 0;
207 }
208 
209 
210 /* ------------------------------------------------------------------------ */
211 /* Function:    fr_logunload                                                */
212 /* Returns:     Nil                                                         */
213 /* Parameters:  Nil                                                         */
214 /*                                                                          */
215 /* Clean up any log data that has accumulated without being read.           */
216 /* ------------------------------------------------------------------------ */
217 void fr_logunload()
218 {
219 	int i;
220 
221 	if (ipl_log_init == 0)
222 		return;
223 
224 	for (i = IPL_LOGMAX; i >= 0; i--)
225 		(void) ipflog_clear(i);
226 
227 # if SOLARIS && defined(_KERNEL)
228 	cv_destroy(&iplwait);
229 # endif
230 	MUTEX_DESTROY(&ipl_mutex);
231 
232 	ipl_log_init = 0;
233 }
234 
235 
236 /* ------------------------------------------------------------------------ */
237 /* Function:    ipflog                                                      */
238 /* Returns:     int - 0 == success, -1 == failure                           */
239 /* Parameters:  fin(I)   - pointer to packet information                    */
240 /*              flags(I) - flags from filter rules                          */
241 /*                                                                          */
242 /* Create a log record for a packet given that it has been triggered by a   */
243 /* rule (or the default setting).  Calculate the transport protocol header  */
244 /* size using predetermined size of a couple of popular protocols and thus  */
245 /* how much data to copy into the log, including part of the data body if   */
246 /* requested.                                                               */
247 /* ------------------------------------------------------------------------ */
248 int ipflog(fin, flags)
249 fr_info_t *fin;
250 u_int flags;
251 {
252 	register size_t hlen;
253 	int types[2], mlen;
254 	size_t sizes[2];
255 	void *ptrs[2];
256 	ipflog_t ipfl;
257 	u_char p;
258 	mb_t *m;
259 # if SOLARIS && defined(_KERNEL)
260 #  ifndef IRE_ILL_CN
261 	ill_t *ifp;
262 #  else
263 	s_ill_t *ifp;
264 #  endif /* IRE_ILL_CN */
265 # else
266 #  if defined(__hpux) && defined(_KERNEL)
267 	ifinfo_t *ifp;
268 #  else
269 	struct ifnet *ifp;
270 #  endif
271 # endif /* SOLARIS */
272 
273 	m = fin->fin_m;
274 	ifp = fin->fin_ifp;
275 	hlen = fin->fin_hlen;
276 	/*
277 	 * calculate header size.
278 	 */
279 	if (fin->fin_off == 0) {
280 		p = fin->fin_fi.fi_p;
281 		if (p == IPPROTO_TCP)
282 			hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
283 		else if (p == IPPROTO_UDP)
284 			hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
285 		else if (p == IPPROTO_ICMP) {
286 			struct icmp *icmp;
287 
288 			icmp = (struct icmp *)fin->fin_dp;
289 
290 			/*
291 			 * For ICMP, if the packet is an error packet, also
292 			 * include the information about the packet which
293 			 * caused the error.
294 			 */
295 			switch (icmp->icmp_type)
296 			{
297 			case ICMP_UNREACH :
298 			case ICMP_SOURCEQUENCH :
299 			case ICMP_REDIRECT :
300 			case ICMP_TIMXCEED :
301 			case ICMP_PARAMPROB :
302 				hlen += MIN(sizeof(struct icmp) + 8,
303 					    fin->fin_dlen);
304 				break;
305 			default :
306 				hlen += MIN(sizeof(struct icmp),
307 					    fin->fin_dlen);
308 				break;
309 			}
310 		}
311 # ifdef USE_INET6
312 		else if (p == IPPROTO_ICMPV6) {
313 			struct icmp6_hdr *icmp;
314 
315 			icmp = (struct icmp6_hdr *)fin->fin_dp;
316 
317 			/*
318 			 * For ICMPV6, if the packet is an error packet, also
319 			 * include the information about the packet which
320 			 * caused the error.
321 			 */
322 			if (icmp->icmp6_type < 128) {
323 				hlen += MIN(sizeof(struct icmp6_hdr) + 8,
324 					    fin->fin_dlen);
325 			} else {
326 				hlen += MIN(sizeof(struct icmp6_hdr),
327 					    fin->fin_dlen);
328 			}
329 		}
330 # endif
331 	}
332 	/*
333 	 * Get the interface number and name to which this packet is
334 	 * currently associated.
335 	 */
336 # if SOLARIS && defined(_KERNEL)
337 	ipfl.fl_unit = (u_char)0;
338 	(void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
339 # else
340 #  if defined(__hpux) && defined(_KERNEL)
341 	ipfl.fl_unit = (u_char)ifp->ifi_ppa;
342 	bcopy(IFNAME(ifp), ipfl.fl_ifname,
343 	      MIN(ifp->ifi_name_length, sizeof(ipfl.fl_ifname)));
344 #  else
345 #   if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
346 	(defined(OpenBSD) && (OpenBSD >= 199603))
347 	(void) strncpy(ipfl.fl_ifname, ifp->if_xname, sizeof(ipfl.fl_ifname));
348 #   else
349 	ipfl.fl_unit = (u_char)ifp->if_unit;
350 #    if defined(_KERNEL)
351 	if ((ipfl.fl_ifname[0] = ifp->if_name[0]))
352 		if ((ipfl.fl_ifname[1] = ifp->if_name[1]))
353 			if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
354 				ipfl.fl_ifname[3] = ifp->if_name[3];
355 #    else
356 	(void) strncpy(ipfl.fl_ifname, ifp->if_name, LIFNAMSIZ);
357 	ipfl.fl_ifname[LIFNAMSIZ - 1] = '\0';
358 #    endif
359 #   endif
360 #  endif /* __hpux */
361 # endif /* SOLARIS */
362 	mlen = fin->fin_plen - hlen;
363 	if (!ipl_logall) {
364 		mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0;
365 	} else if ((flags & FR_LOGBODY) == 0) {
366 		mlen = 0;
367 	}
368 	if (mlen < 0)
369 		mlen = 0;
370 	ipfl.fl_plen = (u_char)mlen;
371 	ipfl.fl_hlen = (u_char)hlen;
372 	ipfl.fl_rule = fin->fin_rule;
373 	(void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN);
374 	if (fin->fin_fr != NULL) {
375 		ipfl.fl_loglevel = fin->fin_fr->fr_loglevel;
376 		ipfl.fl_tag = fin->fin_fr->fr_logtag;
377 	} else {
378 		ipfl.fl_loglevel = 0xffff;
379 		ipfl.fl_tag = FR_NOLOGTAG;
380 	}
381 	ipfl.fl_flags = flags;
382 	ipfl.fl_dir = fin->fin_out;
383 	ipfl.fl_lflags = fin->fin_flx;
384 	ptrs[0] = (void *)&ipfl;
385 	sizes[0] = sizeof(ipfl);
386 	types[0] = 0;
387 # if defined(MENTAT) && defined(_KERNEL)
388 	/*
389 	 * Are we copied from the mblk or an aligned array ?
390 	 */
391 	if (fin->fin_ip == (ip_t *)m->b_rptr) {
392 		ptrs[1] = m;
393 		sizes[1] = hlen + mlen;
394 		types[1] = 1;
395 	} else {
396 		ptrs[1] = fin->fin_ip;
397 		sizes[1] = hlen + mlen;
398 		types[1] = 0;
399 	}
400 # else
401 	ptrs[1] = m;
402 	sizes[1] = hlen + mlen;
403 	types[1] = 1;
404 # endif /* MENTAT */
405 	return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2);
406 }
407 
408 
409 /* ------------------------------------------------------------------------ */
410 /* Function:    ipllog                                                      */
411 /* Returns:     int - 0 == success, -1 == failure                           */
412 /* Parameters:  dev(I)    - device that owns this log record                */
413 /*              fin(I)    - pointer to packet information                   */
414 /*              items(I)  - array of pointers to log data                   */
415 /*              itemsz(I) - array of size of valid memory pointed to        */
416 /*              types(I)  - type of data pointed to by items pointers       */
417 /*              cnt(I)    - number of elements in arrays items/itemsz/types */
418 /*                                                                          */
419 /* Takes an array of parameters and constructs one record to include the    */
420 /* miscellaneous packet information, as well as packet data, for reading    */
421 /* from the log device.                                                     */
422 /* ------------------------------------------------------------------------ */
423 int ipllog(dev, fin, items, itemsz, types, cnt)
424 int dev;
425 fr_info_t *fin;
426 void **items;
427 size_t *itemsz;
428 int *types, cnt;
429 {
430 	caddr_t buf, s;
431 	iplog_t *ipl;
432 	size_t len;
433 	int i;
434 
435 	/*
436 	 * Check to see if this log record has a CRC which matches the last
437 	 * record logged.  If it does, just up the count on the previous one
438 	 * rather than create a new one.
439 	 */
440 	if (ipl_suppress) {
441 		MUTEX_ENTER(&ipl_mutex);
442 		if (fin != NULL) {
443 			if ((ipll[dev] != NULL) &&
444 			    bcmp((char *)fin, (char *)&iplcrc[dev],
445 				 FI_LCSIZE) == 0) {
446 				ipll[dev]->ipl_count++;
447 				MUTEX_EXIT(&ipl_mutex);
448 				return 0;
449 			}
450 			bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE);
451 		} else
452 			bzero((char *)&iplcrc[dev], FI_CSIZE);
453 		MUTEX_EXIT(&ipl_mutex);
454 	}
455 
456 	/*
457 	 * Get the total amount of data to be logged.
458 	 */
459 	for (i = 0, len = sizeof(iplog_t); i < cnt; i++)
460 		len += itemsz[i];
461 
462 	/*
463 	 * check that we have space to record this information and can
464 	 * allocate that much.
465 	 */
466 	MUTEX_ENTER(&ipl_mutex);
467 	if ((iplused[dev] + len) > IPFILTER_LOGSIZE) {
468 		MUTEX_EXIT(&ipl_mutex);
469 		return 0;
470 	}
471 	iplused[dev] += len;
472 	MUTEX_EXIT(&ipl_mutex);
473 
474 	KMALLOCS(buf, caddr_t, len);
475 	if (!buf)
476 		return 0;
477 
478 	/*
479 	 * advance the log pointer to the next empty record and deduct the
480 	 * amount of space we're going to use.
481 	 */
482 	ipl = (iplog_t *)buf;
483 	ipl->ipl_magic = IPL_MAGIC;
484 	ipl->ipl_count = 1;
485 	ipl->ipl_next = NULL;
486 	ipl->ipl_dsize = len;
487 #ifdef _KERNEL
488 	GETKTIME(&ipl->ipl_sec);
489 #else
490 	ipl->ipl_sec = 0;
491 	ipl->ipl_usec = 0;
492 #endif
493 
494 	/*
495 	 * Loop through all the items to be logged, copying each one to the
496 	 * buffer.  Use bcopy for normal data or the mb_t copyout routine.
497 	 */
498 	for (i = 0, s = buf + sizeof(*ipl); i < cnt; i++) {
499 		if (types[i] == 0) {
500 			bcopy(items[i], s, itemsz[i]);
501 		} else if (types[i] == 1) {
502 			COPYDATA(items[i], 0, itemsz[i], s);
503 		}
504 		s += itemsz[i];
505 	}
506 	MUTEX_ENTER(&ipl_mutex);
507 	ipll[dev] = ipl;
508 	*iplh[dev] = ipl;
509 	iplh[dev] = &ipl->ipl_next;
510 
511 	/*
512 	 * Now that the log record has been completed and added to the queue,
513 	 * wake up any listeners who may want to read it.
514 	 */
515 # if SOLARIS && defined(_KERNEL)
516 	cv_signal(&iplwait);
517 	MUTEX_EXIT(&ipl_mutex);
518 # else
519 	MUTEX_EXIT(&ipl_mutex);
520 	WAKEUP(&iplh[dev]);
521 # endif
522 # ifdef	IPL_SELECT
523 	iplog_input_ready(dev);
524 # endif
525 	return 1;
526 }
527 
528 
529 /* ------------------------------------------------------------------------ */
530 /* Function:    ipflog_read                                                 */
531 /* Returns:     int    - 0 == success, else error value.                    */
532 /* Parameters:  unit(I) - device we are reading from                        */
533 /*              uio(O)  - pointer to information about where to store data  */
534 /*                                                                          */
535 /* Called to handle a read on an IPFilter device.  Returns only complete    */
536 /* log messages - will not partially copy a log record out to userland.     */
537 /*                                                                          */
538 /* NOTE: This function will block and wait for a signal to return data if   */
539 /* there is none present.  Asynchronous I/O is not implemented.             */
540 /* ------------------------------------------------------------------------ */
541 int ipflog_read(unit, uio)
542 minor_t unit;
543 struct uio *uio;
544 {
545 	size_t dlen, copied;
546 	int error = 0;
547 	iplog_t *ipl;
548 # if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
549 	int s;
550 # endif
551 
552 	/*
553 	 * Sanity checks.  Make sure the minor # is valid and we're copying
554 	 * a valid chunk of data.
555 	 */
556 	if (IPL_LOGMAX < unit)
557 		return ENXIO;
558 	if (uio->uio_resid == 0)
559 		return 0;
560 	if ((uio->uio_resid < sizeof(iplog_t)) ||
561 	    (uio->uio_resid > IPFILTER_LOGSIZE))
562 		return EINVAL;
563 
564 	/*
565 	 * Lock the log so we can snapshot the variables.  Wait for a signal
566 	 * if the log is empty.
567 	 */
568 	SPL_NET(s);
569 	MUTEX_ENTER(&ipl_mutex);
570 
571 	while (iplt[unit] == NULL) {
572 # if SOLARIS && defined(_KERNEL)
573 		if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) {
574 			MUTEX_EXIT(&ipl_mutex);
575 			return EINTR;
576 		}
577 # else
578 #  if defined(__hpux) && defined(_KERNEL)
579 		lock_t *l;
580 
581 #   ifdef IPL_SELECT
582 		if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) {
583 			/* this is no blocking system call */
584 			MUTEX_EXIT(&ipl_mutex);
585 			return 0;
586 		}
587 #   endif
588 
589 		MUTEX_EXIT(&ipl_mutex);
590 		l = get_sleep_lock(&iplh[unit]);
591 		error = sleep(&iplh[unit], PZERO+1);
592 		spinunlock(l);
593 #  else
594 #   if defined(__osf__) && defined(_KERNEL)
595 		error = mpsleep(&iplh[unit], PSUSP|PCATCH,  "iplread", 0,
596 				&ipl_mutex, MS_LOCK_SIMPLE);
597 #   else
598 		MUTEX_EXIT(&ipl_mutex);
599 		SPL_X(s);
600 		error = SLEEP(&iplh[unit], "ipl sleep");
601 #   endif /* __osf__ */
602 #  endif /* __hpux */
603 		if (error)
604 			return error;
605 		SPL_NET(s);
606 		MUTEX_ENTER(&ipl_mutex);
607 # endif /* SOLARIS */
608 	}
609 
610 # if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__)
611 	uio->uio_rw = UIO_READ;
612 # endif
613 
614 	for (copied = 0; ((ipl = iplt[unit]) != NULL); copied += dlen) {
615 		dlen = ipl->ipl_dsize;
616 		if (dlen > uio->uio_resid)
617 			break;
618 		/*
619 		 * Don't hold the mutex over the uiomove call.
620 		 */
621 		iplt[unit] = ipl->ipl_next;
622 		iplused[unit] -= dlen;
623 		if (iplt[unit] == NULL) {
624 			iplh[unit] = &iplt[unit];
625 			ipll[unit] = NULL;
626 		}
627 		MUTEX_EXIT(&ipl_mutex);
628 		SPL_X(s);
629 		error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio);
630 		if (error) {
631 			SPL_NET(s);
632 			MUTEX_ENTER(&ipl_mutex);
633 			iplused[unit] += dlen;
634 			ipl->ipl_next = iplt[unit];
635 			iplt[unit] = ipl;
636 			ipll[unit] = ipl;
637 			if (iplh[unit] == &iplt[unit]) {
638 				*iplh[unit] = ipl;
639 				iplh[unit] = &ipl->ipl_next;
640 			}
641 			break;
642 		}
643 		KFREES((caddr_t)ipl, dlen);
644 		SPL_NET(s);
645 		MUTEX_ENTER(&ipl_mutex);
646 	}
647 	MUTEX_EXIT(&ipl_mutex);
648 	SPL_X(s);
649 	return error;
650 }
651 
652 
653 /* ------------------------------------------------------------------------ */
654 /* Function:    ipflog_clear                                                */
655 /* Returns:     int    - number of log bytes cleared.                       */
656 /* Parameters:  unit(I) - device we are reading from                        */
657 /*                                                                          */
658 /* Deletes all queued up log records for a given output device.             */
659 /* ------------------------------------------------------------------------ */
660 int ipflog_clear(unit)
661 minor_t unit;
662 {
663 	iplog_t *ipl;
664 	int used;
665 
666 	MUTEX_ENTER(&ipl_mutex);
667 	while ((ipl = iplt[unit]) != NULL) {
668 		iplt[unit] = ipl->ipl_next;
669 		KFREES((caddr_t)ipl, ipl->ipl_dsize);
670 	}
671 	iplh[unit] = &iplt[unit];
672 	ipll[unit] = NULL;
673 	used = iplused[unit];
674 	iplused[unit] = 0;
675 	bzero((char *)&iplcrc[unit], FI_CSIZE);
676 	MUTEX_EXIT(&ipl_mutex);
677 	return used;
678 }
679 #endif /* IPFILTER_LOG */
680