1
2/*
3 * Copyright (C) 2012 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 * Id: ip_log.c,v 2.75.2.19 2007/09/09 11:32:06 darrenr Exp $
7 */
8#include <sys/param.h>
9#if defined(KERNEL) || defined(_KERNEL)
10# undef KERNEL
11# undef _KERNEL
12# define        KERNEL	1
13# define        _KERNEL	1
14#endif
15#if defined(__FreeBSD__) && !defined(_KERNEL)
16# include <osreldate.h>
17#endif
18#ifndef SOLARIS
19# if defined(sun) && defined(__SVR4)
20#  define	SOLARIS		1
21# else
22#  define	SOLARIS		0
23# endif
24#endif
25#include <sys/errno.h>
26#include <sys/types.h>
27#include <sys/file.h>
28#ifndef _KERNEL
29# include <stdio.h>
30# include <string.h>
31# include <stdlib.h>
32# include <ctype.h>
33# define _KERNEL
34# define KERNEL
35# include <sys/uio.h>
36# undef _KERNEL
37# undef KERNEL
38#endif
39#if defined(__FreeBSD__) && defined(_KERNEL)
40# include <sys/fcntl.h>
41# include <sys/filio.h>
42#else
43# include <sys/ioctl.h>
44#endif
45#include <sys/time.h>
46#if defined(_KERNEL)
47# include <sys/systm.h>
48# if (defined(NetBSD) && (__NetBSD_Version__ >= 104000000))
49#  include <sys/proc.h>
50# endif
51#endif /* _KERNEL */
52# if defined(NetBSD) || defined(__FreeBSD__)
53#  include <sys/dirent.h>
54# include <sys/mbuf.h>
55# include <sys/select.h>
56# endif
57# if defined(__FreeBSD__)
58#  include <sys/selinfo.h>
59# endif
60#if SOLARIS && defined(_KERNEL)
61#  include <sys/filio.h>
62#  include <sys/cred.h>
63#  include <sys/ddi.h>
64#  include <sys/sunddi.h>
65#  include <sys/ksynch.h>
66#  include <sys/kmem.h>
67#  include <sys/mkdev.h>
68#  include <sys/dditypes.h>
69#  include <sys/cmn_err.h>
70#endif /* SOLARIS && _KERNEL */
71# include <sys/protosw.h>
72#include <sys/socket.h>
73
74#include <net/if.h>
75#ifdef sun
76# include <net/af.h>
77#endif
78#if defined(__FreeBSD__)
79# include <net/if_var.h>
80# include <net/if_private.h>
81#endif
82#include <netinet/in.h>
83# include <netinet/in_var.h>
84#include <netinet/in_systm.h>
85#include <netinet/ip.h>
86#include <netinet/tcp.h>
87#include <netinet/udp.h>
88#include <netinet/ip_icmp.h>
89#ifdef USE_INET6
90# include <netinet/icmp6.h>
91#endif
92# include <netinet/ip_var.h>
93#ifndef _KERNEL
94# include <syslog.h>
95#endif
96#include "netinet/ip_compat.h"
97#include <netinet/tcpip.h>
98#include "netinet/ip_fil.h"
99#include "netinet/ip_nat.h"
100#include "netinet/ip_frag.h"
101#include "netinet/ip_state.h"
102#include "netinet/ip_auth.h"
103#if defined(__FreeBSD__) || defined(__NetBSD__)
104# include <sys/malloc.h>
105#endif
106/* END OF INCLUDES */
107
108#ifdef	IPFILTER_LOG
109
110typedef struct ipf_log_softc_s {
111	ipfmutex_t	ipl_mutex[IPL_LOGSIZE];
112# if SOLARIS && defined(_KERNEL)
113	kcondvar_t	ipl_wait[IPL_LOGSIZE];
114# endif
115	iplog_t		**iplh[IPL_LOGSIZE];
116	iplog_t		*iplt[IPL_LOGSIZE];
117	iplog_t		*ipll[IPL_LOGSIZE];
118	u_long		ipl_logfail[IPL_LOGSIZE];
119	u_long		ipl_logok[IPL_LOGSIZE];
120	fr_info_t	ipl_crc[IPL_LOGSIZE];
121	u_32_t		ipl_counter[IPL_LOGSIZE];
122	int		ipl_suppress;
123	int		ipl_logall;
124	int		ipl_log_init;
125	int		ipl_logsize;
126	int		ipl_used[IPL_LOGSIZE];
127	int		ipl_magic[IPL_LOGSIZE];
128	ipftuneable_t	*ipf_log_tune;
129	int		ipl_readers[IPL_LOGSIZE];
130} ipf_log_softc_t;
131
132static int magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE,
133				  IPL_MAGIC, IPL_MAGIC, IPL_MAGIC,
134				  IPL_MAGIC, IPL_MAGIC };
135
136static ipftuneable_t ipf_log_tuneables[] = {
137	/* log */
138	{ { (void *)offsetof(ipf_log_softc_t, ipl_suppress) },
139		"log_suppress",		0,	1,
140		stsizeof(ipf_log_softc_t, ipl_suppress),
141		0,			NULL,	NULL },
142	{ { (void *)offsetof(ipf_log_softc_t, ipl_logall) },
143		"log_all",		0,	1,
144		stsizeof(ipf_log_softc_t, ipl_logall),
145		0,			NULL,	NULL },
146	{ { (void *)offsetof(ipf_log_softc_t, ipl_logsize) },
147		"log_size",		0,	0x80000,
148		stsizeof(ipf_log_softc_t, ipl_logsize),
149		0,			NULL,	NULL },
150	{ { NULL },		NULL,			0,	0,
151		0,
152		0,			NULL,	NULL }
153};
154
155
156int
157ipf_log_main_load(void)
158{
159	return (0);
160}
161
162
163int
164ipf_log_main_unload(void)
165{
166	return (0);
167}
168
169/* ------------------------------------------------------------------------ */
170/* Function:    ipf_log_soft_create                                         */
171/* Returns:     void * - NULL = failure, else pointer to log context data   */
172/* Parameters:  softc(I) - pointer to soft context main structure           */
173/*                                                                          */
174/* Initialise log buffers & pointers.  Also iniialised the CRC to a local   */
175/* secret for use in calculating the "last log checksum".                   */
176/* ------------------------------------------------------------------------ */
177void *
178ipf_log_soft_create(ipf_main_softc_t *softc)
179{
180	ipf_log_softc_t *softl;
181	int i;
182
183	KMALLOC(softl, ipf_log_softc_t *);
184	if (softl == NULL)
185		return (NULL);
186
187	bzero((char *)softl, sizeof(*softl));
188	bcopy((char *)magic, (char *)softl->ipl_magic, sizeof(magic));
189
190	softl->ipf_log_tune = ipf_tune_array_copy(softl,
191						  sizeof(ipf_log_tuneables),
192						  ipf_log_tuneables);
193	if (softl->ipf_log_tune == NULL) {
194		ipf_log_soft_destroy(softc, softl);
195		return (NULL);
196	}
197	if (ipf_tune_array_link(softc, softl->ipf_log_tune) == -1) {
198		ipf_log_soft_destroy(softc, softl);
199		return (NULL);
200	}
201
202	for (i = IPL_LOGMAX; i >= 0; i--) {
203		MUTEX_INIT(&softl->ipl_mutex[i], "ipf log mutex");
204	}
205
206	softl->ipl_suppress = 1;
207	softl->ipl_logall = 0;
208	softl->ipl_log_init = 0;
209	softl->ipl_logsize = IPFILTER_LOGSIZE;
210
211	return (softl);
212}
213
214/* ------------------------------------------------------------------------ */
215/* Function:    ipf_log_soft_init                                           */
216/* Returns:     int - 0 == success (always returned)                        */
217/* Parameters:  softc(I) - pointer to soft context main structure           */
218/*                                                                          */
219/* Initialise log buffers & pointers.  Also iniialised the CRC to a local   */
220/* secret for use in calculating the "last log checksum".                   */
221/* ------------------------------------------------------------------------ */
222int
223ipf_log_soft_init(ipf_main_softc_t *softc, void *arg)
224{
225	ipf_log_softc_t *softl = arg;
226	int i;
227
228	for (i = IPL_LOGMAX; i >= 0; i--) {
229		softl->iplt[i] = NULL;
230		softl->ipll[i] = NULL;
231		softl->iplh[i] = &softl->iplt[i];
232		bzero((char *)&softl->ipl_crc[i], sizeof(softl->ipl_crc[i]));
233	}
234
235
236	softl->ipl_log_init = 1;
237
238	return (0);
239}
240
241
242/* ------------------------------------------------------------------------ */
243/* Function:    ipf_log_soft_fini                                           */
244/* Parameters:  softc(I) - pointer to soft context main structure           */
245/*              arg(I)   - pointer to log context structure                 */
246/*                                                                          */
247/* Clean up any log data that has accumulated without being read.           */
248/* ------------------------------------------------------------------------ */
249int
250ipf_log_soft_fini(ipf_main_softc_t *softc, void *arg)
251{
252	ipf_log_softc_t *softl = arg;
253	int i;
254
255	if (softl->ipl_log_init == 0)
256		return (0);
257
258	softl->ipl_log_init = 0;
259
260	for (i = IPL_LOGMAX; i >= 0; i--) {
261		(void) ipf_log_clear(softc, i);
262
263		/*
264		 * This is a busy-wait loop so as to avoid yet another lock
265		 * to wait on.
266		 */
267		MUTEX_ENTER(&softl->ipl_mutex[i]);
268		while (softl->ipl_readers[i] > 0) {
269# if SOLARIS && defined(_KERNEL)
270			cv_broadcast(&softl->ipl_wait[i]);
271			MUTEX_EXIT(&softl->ipl_mutex[i]);
272			delay(100);
273			pollwakeup(&softc->ipf_poll_head[i], POLLRDNORM);
274# else
275			MUTEX_EXIT(&softl->ipl_mutex[i]);
276			WAKEUP(softl->iplh, i);
277			POLLWAKEUP(i);
278# endif
279			MUTEX_ENTER(&softl->ipl_mutex[i]);
280		}
281		MUTEX_EXIT(&softl->ipl_mutex[i]);
282	}
283
284	return (0);
285}
286
287
288/* ------------------------------------------------------------------------ */
289/* Function:    ipf_log_soft_destroy                                        */
290/* Parameters:  softc(I) - pointer to soft context main structure           */
291/*              arg(I)   - pointer to log context structure                 */
292/*                                                                          */
293/* When this function is called, it is expected that there are no longer    */
294/* any threads active in the reading code path or the logging code path.    */
295/* ------------------------------------------------------------------------ */
296void
297ipf_log_soft_destroy(ipf_main_softc_t *softc, void *arg)
298{
299	ipf_log_softc_t *softl = arg;
300	int i;
301
302	for (i = IPL_LOGMAX; i >= 0; i--) {
303# if SOLARIS && defined(_KERNEL)
304		cv_destroy(&softl->ipl_wait[i]);
305# endif
306		MUTEX_DESTROY(&softl->ipl_mutex[i]);
307	}
308
309	if (softl->ipf_log_tune != NULL) {
310		ipf_tune_array_unlink(softc, softl->ipf_log_tune);
311		KFREES(softl->ipf_log_tune, sizeof(ipf_log_tuneables));
312		softl->ipf_log_tune = NULL;
313	}
314
315	KFREE(softl);
316}
317
318
319/* ------------------------------------------------------------------------ */
320/* Function:    ipf_log_pkt                                                 */
321/* Returns:     int      - 0 == success, -1 == failure                      */
322/* Parameters:  fin(I)   - pointer to packet information                    */
323/*              flags(I) - flags from filter rules                          */
324/*                                                                          */
325/* Create a log record for a packet given that it has been triggered by a   */
326/* rule (or the default setting).  Calculate the transport protocol header  */
327/* size using predetermined size of a couple of popular protocols and thus  */
328/* how much data to copy into the log, including part of the data body if   */
329/* requested.                                                               */
330/* ------------------------------------------------------------------------ */
331int
332ipf_log_pkt(fr_info_t *fin, u_int flags)
333{
334	ipf_main_softc_t *softc = fin->fin_main_soft;
335	ipf_log_softc_t *softl = softc->ipf_log_soft;
336	register size_t hlen;
337	int types[2], mlen;
338	size_t sizes[2];
339	void *ptrs[2];
340	ipflog_t ipfl;
341	u_char p;
342	mb_t *m;
343# if SOLARIS && defined(_KERNEL) && !defined(FW_HOOKS)
344	qif_t *ifp;
345# else
346	struct ifnet *ifp;
347# endif /* SOLARIS */
348
349	m = fin->fin_m;
350	if (m == NULL)
351		return (-1);
352
353	ipfl.fl_nattag.ipt_num[0] = 0;
354	ifp = fin->fin_ifp;
355	hlen = (char *)fin->fin_dp - (char *)fin->fin_ip;
356
357	/*
358	 * calculate header size.
359	 */
360	if (fin->fin_off == 0) {
361		p = fin->fin_fi.fi_p;
362		if (p == IPPROTO_TCP)
363			hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
364		else if (p == IPPROTO_UDP)
365			hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
366		else if (p == IPPROTO_ICMP) {
367			struct icmp *icmp;
368
369			icmp = (struct icmp *)fin->fin_dp;
370
371			/*
372			 * For ICMP, if the packet is an error packet, also
373			 * include the information about the packet which
374			 * caused the error.
375			 */
376			switch (icmp->icmp_type)
377			{
378			case ICMP_UNREACH :
379			case ICMP_SOURCEQUENCH :
380			case ICMP_REDIRECT :
381			case ICMP_TIMXCEED :
382			case ICMP_PARAMPROB :
383				hlen += MIN(sizeof(struct icmp) + 8,
384					    fin->fin_dlen);
385				break;
386			default :
387				hlen += MIN(sizeof(struct icmp),
388					    fin->fin_dlen);
389				break;
390			}
391		}
392# ifdef USE_INET6
393		else if (p == IPPROTO_ICMPV6) {
394			struct icmp6_hdr *icmp;
395
396			icmp = (struct icmp6_hdr *)fin->fin_dp;
397
398			/*
399			 * For ICMPV6, if the packet is an error packet, also
400			 * include the information about the packet which
401			 * caused the error.
402			 */
403			if (icmp->icmp6_type < 128) {
404				hlen += MIN(sizeof(struct icmp6_hdr) + 8,
405					    fin->fin_dlen);
406			} else {
407				hlen += MIN(sizeof(struct icmp6_hdr),
408					    fin->fin_dlen);
409			}
410		}
411# endif
412	}
413	/*
414	 * Get the interface number and name to which this packet is
415	 * currently associated.
416	 */
417# if SOLARIS && defined(_KERNEL)
418#  if !defined(FW_HOOKS)
419	ipfl.fl_unit = (u_int)ifp->qf_ppa;
420#  endif
421	COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
422# else
423#  if (defined(NetBSD) && (NetBSD  <= 1991011) && (NetBSD >= 199603)) || \
424      defined(__FreeBSD__)
425	COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
426#  else
427	ipfl.fl_unit = (u_int)ifp->if_unit;
428#   if defined(_KERNEL)
429	if ((ipfl.fl_ifname[0] = ifp->if_name[0]))
430		if ((ipfl.fl_ifname[1] = ifp->if_name[1]))
431			if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
432				ipfl.fl_ifname[3] = ifp->if_name[3];
433#   else
434	(void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
435	ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0';
436#   endif
437#  endif
438# endif /* __hpux || SOLARIS */
439	mlen = fin->fin_plen - hlen;
440	if (!softl->ipl_logall) {
441		mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0;
442	} else if ((flags & FR_LOGBODY) == 0) {
443		mlen = 0;
444	}
445	if (mlen < 0)
446		mlen = 0;
447	ipfl.fl_plen = (u_char)mlen;
448	ipfl.fl_hlen = (u_char)hlen;
449	ipfl.fl_rule = fin->fin_rule;
450	(void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN);
451	if (fin->fin_fr != NULL) {
452		ipfl.fl_loglevel = fin->fin_fr->fr_loglevel;
453		ipfl.fl_logtag = fin->fin_fr->fr_logtag;
454	} else {
455		ipfl.fl_loglevel = 0xffff;
456		ipfl.fl_logtag = FR_NOLOGTAG;
457	}
458	if (fin->fin_nattag != NULL)
459		bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag,
460		      sizeof(ipfl.fl_nattag));
461	ipfl.fl_flags = flags;
462	ipfl.fl_breason = (fin->fin_reason & 0xff);
463	ipfl.fl_dir = fin->fin_out;
464	ipfl.fl_lflags = fin->fin_flx;
465	ipfl.fl_family = fin->fin_family;
466	ptrs[0] = (void *)&ipfl;
467	sizes[0] = sizeof(ipfl);
468	types[0] = 0;
469# if SOLARIS && defined(_KERNEL)
470	/*
471	 * Are we copied from the mblk or an aligned array ?
472	 */
473	if (fin->fin_ip == (ip_t *)m->b_rptr) {
474		ptrs[1] = m;
475		sizes[1] = hlen + mlen;
476		types[1] = 1;
477	} else {
478		ptrs[1] = fin->fin_ip;
479		sizes[1] = hlen + mlen;
480		types[1] = 0;
481	}
482# else
483	ptrs[1] = m;
484	sizes[1] = hlen + mlen;
485	types[1] = 1;
486# endif /* SOLARIS */
487	return (ipf_log_items(softc, IPL_LOGIPF, fin, ptrs, sizes, types, 2));
488}
489
490
491/* ------------------------------------------------------------------------ */
492/* Function:    ipf_log_items                                               */
493/* Returns:     int       - 0 == success, -1 == failure                     */
494/* Parameters:  softc(I)  - pointer to main soft context                    */
495/*              unit(I)   - device we are reading from                      */
496/*              fin(I)    - pointer to packet information                   */
497/*              items(I)  - array of pointers to log data                   */
498/*              itemsz(I) - array of size of valid memory pointed to        */
499/*              types(I)  - type of data pointed to by items pointers       */
500/*              cnt(I)    - number of elements in arrays items/itemsz/types */
501/*                                                                          */
502/* Takes an array of parameters and constructs one record to include the    */
503/* miscellaneous packet information, as well as packet data, for reading    */
504/* from the log device.                                                     */
505/* ------------------------------------------------------------------------ */
506int
507ipf_log_items(ipf_main_softc_t *softc, int unit, fr_info_t *fin, void **items,
508	size_t *itemsz, int *types, int cnt)
509{
510	ipf_log_softc_t *softl = softc->ipf_log_soft;
511	caddr_t buf, ptr;
512	iplog_t *ipl;
513	size_t len;
514	int i;
515	SPL_INT(s);
516
517	/*
518	 * Get the total amount of data to be logged.
519	 */
520	for (i = 0, len = sizeof(iplog_t); i < cnt; i++)
521		len += itemsz[i];
522
523	SPL_NET(s);
524	MUTEX_ENTER(&softl->ipl_mutex[unit]);
525	softl->ipl_counter[unit]++;
526	/*
527	 * check that we have space to record this information and can
528	 * allocate that much.
529	 */
530	if ((softl->ipl_used[unit] + len) > softl->ipl_logsize) {
531		softl->ipl_logfail[unit]++;
532		MUTEX_EXIT(&softl->ipl_mutex[unit]);
533		return (-1);
534	}
535
536	KMALLOCS(buf, caddr_t, len);
537	if (buf == NULL) {
538		softl->ipl_logfail[unit]++;
539		MUTEX_EXIT(&softl->ipl_mutex[unit]);
540		return (-1);
541	}
542	ipl = (iplog_t *)buf;
543	ipl->ipl_magic = softl->ipl_magic[unit];
544	ipl->ipl_count = 1;
545	ipl->ipl_seqnum = softl->ipl_counter[unit];
546	ipl->ipl_next = NULL;
547	ipl->ipl_dsize = len;
548#ifdef _KERNEL
549	GETKTIME(&ipl->ipl_sec);
550#else
551	ipl->ipl_sec = 0;
552	ipl->ipl_usec = 0;
553#endif
554
555	/*
556	 * Loop through all the items to be logged, copying each one to the
557	 * buffer.  Use bcopy for normal data or the mb_t copyout routine.
558	 */
559	for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) {
560		if (types[i] == 0) {
561			bcopy(items[i], ptr, itemsz[i]);
562		} else if (types[i] == 1) {
563			COPYDATA(items[i], 0, itemsz[i], ptr);
564		}
565		ptr += itemsz[i];
566	}
567	/*
568	 * Check to see if this log record has a CRC which matches the last
569	 * record logged.  If it does, just up the count on the previous one
570	 * rather than create a new one.
571	 */
572	if (softl->ipl_suppress) {
573		if ((fin != NULL) && (fin->fin_off == 0)) {
574			if ((softl->ipll[unit] != NULL) &&
575			    (fin->fin_crc == softl->ipl_crc[unit].fin_crc) &&
576			    bcmp((char *)fin, (char *)&softl->ipl_crc[unit],
577				 FI_LCSIZE) == 0) {
578				softl->ipll[unit]->ipl_count++;
579				MUTEX_EXIT(&softl->ipl_mutex[unit]);
580				SPL_X(s);
581				KFREES(buf, len);
582				return (0);
583			}
584			bcopy((char *)fin, (char *)&softl->ipl_crc[unit],
585			      FI_LCSIZE);
586			softl->ipl_crc[unit].fin_crc = fin->fin_crc;
587		} else
588			bzero((char *)&softl->ipl_crc[unit], FI_CSIZE);
589	}
590
591	/*
592	 * advance the log pointer to the next empty record and deduct the
593	 * amount of space we're going to use.
594	 */
595	softl->ipl_logok[unit]++;
596	softl->ipll[unit] = ipl;
597	*softl->iplh[unit] = ipl;
598	softl->iplh[unit] = &ipl->ipl_next;
599	softl->ipl_used[unit] += len;
600
601	/*
602	 * Now that the log record has been completed and added to the queue,
603	 * wake up any listeners who may want to read it.
604	 */
605# if SOLARIS && defined(_KERNEL)
606	cv_signal(&softl->ipl_wait[unit]);
607	MUTEX_EXIT(&softl->ipl_mutex[unit]);
608	pollwakeup(&softc->ipf_poll_head[unit], POLLRDNORM);
609# else
610	MUTEX_EXIT(&softl->ipl_mutex[unit]);
611	WAKEUP(softl->iplh, unit);
612	POLLWAKEUP(unit);
613# endif
614	SPL_X(s);
615	return (0);
616}
617
618
619/* ------------------------------------------------------------------------ */
620/* Function:    ipf_log_read                                                */
621/* Returns:     int      - 0 == success, else error value.                  */
622/* Parameters:  softc(I) - pointer to main soft context                     */
623/*              unit(I)  - device we are reading from                       */
624/*              uio(O)   - pointer to information about where to store data */
625/*                                                                          */
626/* Called to handle a read on an IPFilter device.  Returns only complete    */
627/* log messages - will not partially copy a log record out to userland.     */
628/*                                                                          */
629/* NOTE: This function will block and wait for a signal to return data if   */
630/* there is none present.  Asynchronous I/O is not implemented.             */
631/* ------------------------------------------------------------------------ */
632int
633ipf_log_read(ipf_main_softc_t *softc, minor_t unit, struct uio *uio)
634{
635	ipf_log_softc_t *softl = softc->ipf_log_soft;
636	size_t dlen;
637	int error = 0;
638	iplog_t *ipl;
639	SPL_INT(s);
640
641	if (softl->ipl_log_init == 0) {
642		IPFERROR(40007);
643		return (0);
644	}
645
646	/*
647	 * Sanity checks.  Make sure the minor # is valid and we're copying
648	 * a valid chunk of data.
649	 */
650	if (IPL_LOGMAX < unit) {
651		IPFERROR(40001);
652		return (ENXIO);
653	}
654	if (uio->uio_resid == 0)
655		return (0);
656
657	if (uio->uio_resid < sizeof(iplog_t)) {
658		IPFERROR(40002);
659		return (EINVAL);
660	}
661	if (uio->uio_resid > softl->ipl_logsize) {
662		IPFERROR(40005);
663		return (EINVAL);
664	}
665
666	/*
667	 * Lock the log so we can snapshot the variables.  Wait for a signal
668	 * if the log is empty.
669	 */
670	SPL_NET(s);
671	MUTEX_ENTER(&softl->ipl_mutex[unit]);
672	softl->ipl_readers[unit]++;
673
674	while (softl->ipl_log_init == 1 && softl->iplt[unit] == NULL) {
675# if SOLARIS && defined(_KERNEL)
676		if (!cv_wait_sig(&softl->ipl_wait[unit],
677				 &softl->ipl_mutex[unit].ipf_lk)) {
678			softl->ipl_readers[unit]--;
679			MUTEX_EXIT(&softl->ipl_mutex[unit]);
680			IPFERROR(40003);
681			return (EINTR);
682		}
683# else
684		MUTEX_EXIT(&softl->ipl_mutex[unit]);
685		SPL_X(s);
686		error = SLEEP(unit + softl->iplh, "ipl sleep");
687		SPL_NET(s);
688		MUTEX_ENTER(&softl->ipl_mutex[unit]);
689		if (error) {
690			softl->ipl_readers[unit]--;
691			MUTEX_EXIT(&softl->ipl_mutex[unit]);
692			IPFERROR(40004);
693			return (error);
694		}
695# endif /* SOLARIS */
696	}
697	if (softl->ipl_log_init != 1) {
698		softl->ipl_readers[unit]--;
699		MUTEX_EXIT(&softl->ipl_mutex[unit]);
700		IPFERROR(40008);
701		return (EIO);
702	}
703
704# if defined(BSD)
705	uio->uio_rw = UIO_READ;
706# endif
707
708	for (; (ipl = softl->iplt[unit]) != NULL;) {
709		dlen = ipl->ipl_dsize;
710		if (dlen > uio->uio_resid)
711			break;
712		/*
713		 * Don't hold the mutex over the uiomove call.
714		 */
715		softl->iplt[unit] = ipl->ipl_next;
716		softl->ipl_used[unit] -= dlen;
717		MUTEX_EXIT(&softl->ipl_mutex[unit]);
718		SPL_X(s);
719		error = UIOMOVE(ipl, dlen, UIO_READ, uio);
720		if (error) {
721			SPL_NET(s);
722			MUTEX_ENTER(&softl->ipl_mutex[unit]);
723			IPFERROR(40006);
724			ipl->ipl_next = softl->iplt[unit];
725			softl->iplt[unit] = ipl;
726			softl->ipl_used[unit] += dlen;
727			break;
728		}
729		MUTEX_ENTER(&softl->ipl_mutex[unit]);
730		KFREES((caddr_t)ipl, dlen);
731		SPL_NET(s);
732	}
733	if (!softl->iplt[unit]) {
734		softl->ipl_used[unit] = 0;
735		softl->iplh[unit] = &softl->iplt[unit];
736		softl->ipll[unit] = NULL;
737	}
738
739	softl->ipl_readers[unit]--;
740	MUTEX_EXIT(&softl->ipl_mutex[unit]);
741	SPL_X(s);
742	return (error);
743}
744
745
746/* ------------------------------------------------------------------------ */
747/* Function:    ipf_log_clear                                               */
748/* Returns:     int      - number of log bytes cleared.                     */
749/* Parameters:  softc(I) - pointer to main soft context                     */
750/*              unit(I)  - device we are reading from                       */
751/*                                                                          */
752/* Deletes all queued up log records for a given output device.             */
753/* ------------------------------------------------------------------------ */
754int
755ipf_log_clear(ipf_main_softc_t *softc, minor_t unit)
756{
757	ipf_log_softc_t *softl = softc->ipf_log_soft;
758	iplog_t *ipl;
759	int used;
760	SPL_INT(s);
761
762	SPL_NET(s);
763	MUTEX_ENTER(&softl->ipl_mutex[unit]);
764	while ((ipl = softl->iplt[unit]) != NULL) {
765		softl->iplt[unit] = ipl->ipl_next;
766		KFREES((caddr_t)ipl, ipl->ipl_dsize);
767	}
768	softl->iplh[unit] = &softl->iplt[unit];
769	softl->ipll[unit] = NULL;
770	used = softl->ipl_used[unit];
771	softl->ipl_used[unit] = 0;
772	bzero((char *)&softl->ipl_crc[unit], FI_CSIZE);
773	MUTEX_EXIT(&softl->ipl_mutex[unit]);
774	SPL_X(s);
775	return (used);
776}
777
778
779/* ------------------------------------------------------------------------ */
780/* Function:    ipf_log_canread                                             */
781/* Returns:     int      - 0 == no data to read, 1 = data present           */
782/* Parameters:  softc(I) - pointer to main soft context                     */
783/*              unit(I)  - device we are reading from                       */
784/*                                                                          */
785/* Returns an indication of whether or not there is data present in the     */
786/* current buffer for the selected ipf device.                              */
787/* ------------------------------------------------------------------------ */
788int
789ipf_log_canread(ipf_main_softc_t *softc, int unit)
790{
791	ipf_log_softc_t *softl = softc->ipf_log_soft;
792
793	return (softl->iplt[unit] != NULL);
794}
795
796
797/* ------------------------------------------------------------------------ */
798/* Function:    ipf_log_canread                                             */
799/* Returns:     int      - 0 == no data to read, 1 = data present           */
800/* Parameters:  softc(I) - pointer to main soft context                     */
801/*              unit(I)  - device we are reading from                       */
802/*                                                                          */
803/* Returns how many bytes are currently held in log buffers for the         */
804/* selected ipf device.                                                     */
805/* ------------------------------------------------------------------------ */
806int
807ipf_log_bytesused(ipf_main_softc_t *softc, int unit)
808{
809	ipf_log_softc_t *softl = softc->ipf_log_soft;
810
811	if (softl == NULL)
812		return (0);
813
814	return (softl->ipl_used[unit]);
815}
816
817
818/* ------------------------------------------------------------------------ */
819/* Function:    ipf_log_failures                                            */
820/* Returns:     U_QUAD_T - number of log failures                           */
821/* Parameters:  softc(I) - pointer to main soft context                     */
822/*              unit(I)  - device we are reading from                       */
823/*                                                                          */
824/* Returns how many times we've tried to log a packet but failed to do so   */
825/* for the selected ipf device.                                             */
826/* ------------------------------------------------------------------------ */
827u_long
828ipf_log_failures(ipf_main_softc_t *softc, int unit)
829{
830	ipf_log_softc_t *softl = softc->ipf_log_soft;
831
832	if (softl == NULL)
833		return (0);
834
835	return (softl->ipl_logfail[unit]);
836}
837
838
839/* ------------------------------------------------------------------------ */
840/* Function:    ipf_log_logok                                               */
841/* Returns:     U_QUAD_T - number of packets logged                         */
842/* Parameters:  softc(I) - pointer to main soft context                     */
843/*              unit(I)  - device we are reading from                       */
844/*                                                                          */
845/* Returns how many times we've successfully logged a packet for the        */
846/* selected ipf device.                                                     */
847/* ------------------------------------------------------------------------ */
848u_long
849ipf_log_logok(ipf_main_softc_t *softc, int unit)
850{
851	ipf_log_softc_t *softl = softc->ipf_log_soft;
852
853	if (softl == NULL)
854		return (0);
855
856	return (softl->ipl_logok[unit]);
857}
858#endif /* IPFILTER_LOG */
859