ip_log.c revision 145522
1145522Sdarrenr/*	$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_log.c 145522 2005-04-25 18:43:14Z darrenr $	*/
2145522Sdarrenr
353642Sguido/*
4145522Sdarrenr * Copyright (C) 1997-2003 by Darren Reed.
553642Sguido *
680482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
753642Sguido *
857126Sguido * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_log.c 145522 2005-04-25 18:43:14Z darrenr $
9145522Sdarrenr * Id: ip_log.c,v 2.75.2.6 2004/10/16 07:59:27 darrenr Exp
1053642Sguido */
1153642Sguido#include <sys/param.h>
12145522Sdarrenr#if defined(KERNEL) || defined(_KERNEL)
13145522Sdarrenr# undef KERNEL
14145522Sdarrenr# undef _KERNEL
15145522Sdarrenr# define        KERNEL	1
16145522Sdarrenr# define        _KERNEL	1
1753642Sguido#endif
1895563Sdarrenr#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
1995563Sdarrenr    defined(_KERNEL)
2053642Sguido# include "opt_ipfilter_log.h"
2153642Sguido#endif
22145522Sdarrenr#if defined(__FreeBSD__) && !defined(IPFILTER_LKM)
23145522Sdarrenr# if defined(_KERNEL)
24145522Sdarrenr#  if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
25145522Sdarrenr#   include "opt_ipfilter.h"
2653642Sguido#  endif
2760857Sdarrenr# else
28145522Sdarrenr#  include <osreldate.h>
2953642Sguido# endif
3053642Sguido#endif
31145522Sdarrenr#ifndef SOLARIS
32145522Sdarrenr# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
33145522Sdarrenr#endif
34145522Sdarrenr#include <sys/errno.h>
35145522Sdarrenr#include <sys/types.h>
36145522Sdarrenr#include <sys/file.h>
37145522Sdarrenr#ifndef _KERNEL
38145522Sdarrenr# include <stdio.h>
39145522Sdarrenr# include <string.h>
40145522Sdarrenr# include <stdlib.h>
41145522Sdarrenr# include <ctype.h>
42145522Sdarrenr# define _KERNEL
43145522Sdarrenr# define KERNEL
44145522Sdarrenr# ifdef __OpenBSD__
45145522Sdarrenrstruct file;
4653642Sguido# endif
47145522Sdarrenr# include <sys/uio.h>
48145522Sdarrenr# undef _KERNEL
49145522Sdarrenr# undef KERNEL
50145522Sdarrenr#endif
51145522Sdarrenr#if __FreeBSD_version >= 220000 && defined(_KERNEL)
52145522Sdarrenr# include <sys/fcntl.h>
53145522Sdarrenr# include <sys/filio.h>
54145522Sdarrenr#else
55145522Sdarrenr# include <sys/ioctl.h>
56145522Sdarrenr#endif
57145522Sdarrenr#include <sys/time.h>
58145522Sdarrenr#if defined(_KERNEL)
59145522Sdarrenr# include <sys/systm.h>
60145522Sdarrenr# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
61145522Sdarrenr#  include <sys/proc.h>
6253642Sguido# endif
63145522Sdarrenr#endif /* _KERNEL */
64145522Sdarrenr#if !SOLARIS && !defined(__hpux) && !defined(linux)
65145522Sdarrenr# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
66145522Sdarrenr#  include <sys/dirent.h>
6753642Sguido# else
68145522Sdarrenr#  include <sys/dir.h>
6953642Sguido# endif
70145522Sdarrenr# include <sys/mbuf.h>
71145522Sdarrenr#else
72145522Sdarrenr# if !defined(__hpux) && defined(_KERNEL)
7353642Sguido#  include <sys/filio.h>
7453642Sguido#  include <sys/cred.h>
75145522Sdarrenr#  include <sys/ddi.h>
76145522Sdarrenr#  include <sys/sunddi.h>
77145522Sdarrenr#  include <sys/ksynch.h>
7853642Sguido#  include <sys/kmem.h>
79145522Sdarrenr#  include <sys/mkdev.h>
80145522Sdarrenr#  include <sys/dditypes.h>
81145522Sdarrenr#  include <sys/cmn_err.h>
82145522Sdarrenr# endif /* !__hpux */
83145522Sdarrenr#endif /* !SOLARIS && !__hpux */
84145522Sdarrenr#if !defined(linux)
8580482Sdarrenr# include <sys/protosw.h>
86145522Sdarrenr#endif
87145522Sdarrenr#include <sys/socket.h>
8853642Sguido
89145522Sdarrenr#include <net/if.h>
90145522Sdarrenr#ifdef sun
91145522Sdarrenr# include <net/af.h>
92145522Sdarrenr#endif
93145522Sdarrenr#if __FreeBSD_version >= 300000
94145522Sdarrenr# include <net/if_var.h>
95145522Sdarrenr#endif
96145522Sdarrenr#include <net/route.h>
97145522Sdarrenr#include <netinet/in.h>
98145522Sdarrenr#ifdef __sgi
99145522Sdarrenr# include <sys/ddi.h>
100145522Sdarrenr# ifdef IFF_DRVRLOCK /* IRIX6 */
101145522Sdarrenr#  include <sys/hashing.h>
10253642Sguido# endif
103145522Sdarrenr#endif
104145522Sdarrenr#if !defined(__hpux) && !defined(linux) && \
105145522Sdarrenr    !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/
106145522Sdarrenr# include <netinet/in_var.h>
107145522Sdarrenr#endif
108145522Sdarrenr#include <netinet/in_systm.h>
109145522Sdarrenr#include <netinet/ip.h>
110145522Sdarrenr#include <netinet/tcp.h>
111145522Sdarrenr#include <netinet/udp.h>
112145522Sdarrenr#include <netinet/ip_icmp.h>
113145522Sdarrenr#ifdef USE_INET6
114145522Sdarrenr# include <netinet/icmp6.h>
115145522Sdarrenr#endif
116145522Sdarrenr#if !defined(linux)
11780482Sdarrenr# include <netinet/ip_var.h>
118145522Sdarrenr#endif
119145522Sdarrenr#ifndef _KERNEL
120145522Sdarrenr# include <syslog.h>
121145522Sdarrenr#endif
122145522Sdarrenr#include "netinet/ip_compat.h"
123145522Sdarrenr#include <netinet/tcpip.h>
124145522Sdarrenr#include "netinet/ip_fil.h"
125145522Sdarrenr#include "netinet/ip_nat.h"
126145522Sdarrenr#include "netinet/ip_frag.h"
127145522Sdarrenr#include "netinet/ip_state.h"
128145522Sdarrenr#include "netinet/ip_auth.h"
129145522Sdarrenr#if (__FreeBSD_version >= 300000) || defined(__NetBSD__)
130145522Sdarrenr# include <sys/malloc.h>
131145522Sdarrenr#endif
132145522Sdarrenr/* END OF INCLUDES */
13353642Sguido
134145522Sdarrenr#ifdef	IPFILTER_LOG
13553642Sguido
136145522Sdarrenr# if defined(IPL_SELECT)
137145522Sdarrenr#  include	<machine/sys/user.h>
138145522Sdarrenr#  include	<sys/kthread_iface.h>
139145522Sdarrenr#  define	READ_COLLISION	0x001
14053642Sguido
141145522Sdarrenriplog_select_t	iplog_ss[IPL_LOGMAX+1];
142145522Sdarrenr
143145522Sdarrenrextern int selwait;
144145522Sdarrenr# endif /* IPL_SELECT */
145145522Sdarrenr
146145522Sdarrenr# if defined(linux) && defined(_KERNEL)
147145522Sdarrenrwait_queue_head_t	iplh_linux[IPL_LOGSIZE];
148145522Sdarrenr# endif
149145522Sdarrenr# if SOLARIS
15053642Sguidoextern	kcondvar_t	iplwait;
15153642Sguido# endif
15253642Sguido
153145522Sdarrenriplog_t	**iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE];
154145522Sdarrenrint	iplused[IPL_LOGSIZE];
155145522Sdarrenrstatic fr_info_t	iplcrc[IPL_LOGSIZE];
156145522Sdarrenrint	ipl_suppress = 1;
157145522Sdarrenrint	ipl_buffer_sz;
158145522Sdarrenrint	ipl_logmax = IPL_LOGMAX;
159145522Sdarrenrint	ipl_logall = 0;
160145522Sdarrenrint	ipl_log_init = 0;
161145522Sdarrenrint	ipl_logsize = IPFILTER_LOGSIZE;
162145522Sdarrenrint	ipl_magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE,
163145522Sdarrenr				   IPL_MAGIC, IPL_MAGIC, IPL_MAGIC,
164145522Sdarrenr				   IPL_MAGIC, IPL_MAGIC };
16553642Sguido
16653642Sguido
167145522Sdarrenr/* ------------------------------------------------------------------------ */
168145522Sdarrenr/* Function:    fr_loginit                                                  */
169145522Sdarrenr/* Returns:     int - 0 == success (always returned)                        */
170145522Sdarrenr/* Parameters:  Nil                                                         */
171145522Sdarrenr/*                                                                          */
172145522Sdarrenr/* Initialise log buffers & pointers.  Also iniialised the CRC to a local   */
173145522Sdarrenr/* secret for use in calculating the "last log checksum".                   */
174145522Sdarrenr/* ------------------------------------------------------------------------ */
175145522Sdarrenrint fr_loginit()
17653642Sguido{
17753642Sguido	int	i;
17853642Sguido
17953642Sguido	for (i = IPL_LOGMAX; i >= 0; i--) {
18053642Sguido		iplt[i] = NULL;
18153642Sguido		ipll[i] = NULL;
18253642Sguido		iplh[i] = &iplt[i];
18353642Sguido		iplused[i] = 0;
18453642Sguido		bzero((char *)&iplcrc[i], sizeof(iplcrc[i]));
185145522Sdarrenr# ifdef	IPL_SELECT
186145522Sdarrenr		iplog_ss[i].read_waiter = 0;
187145522Sdarrenr		iplog_ss[i].state = 0;
188145522Sdarrenr# endif
189145522Sdarrenr# if defined(linux) && defined(_KERNEL)
190145522Sdarrenr		init_waitqueue_head(iplh_linux + i);
191145522Sdarrenr# endif
19253642Sguido	}
193145522Sdarrenr
194145522Sdarrenr# if SOLARIS && defined(_KERNEL)
195145522Sdarrenr	cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL);
196145522Sdarrenr# endif
197145522Sdarrenr	MUTEX_INIT(&ipl_mutex, "ipf log mutex");
198145522Sdarrenr
199145522Sdarrenr	ipl_log_init = 1;
200145522Sdarrenr
201145522Sdarrenr	return 0;
20253642Sguido}
20353642Sguido
20453642Sguido
205145522Sdarrenr/* ------------------------------------------------------------------------ */
206145522Sdarrenr/* Function:    fr_logunload                                                */
207145522Sdarrenr/* Returns:     Nil                                                         */
208145522Sdarrenr/* Parameters:  Nil                                                         */
209145522Sdarrenr/*                                                                          */
210145522Sdarrenr/* Clean up any log data that has accumulated without being read.           */
211145522Sdarrenr/* ------------------------------------------------------------------------ */
212145522Sdarrenrvoid fr_logunload()
213145522Sdarrenr{
214145522Sdarrenr	int i;
215145522Sdarrenr
216145522Sdarrenr	if (ipl_log_init == 0)
217145522Sdarrenr		return;
218145522Sdarrenr
219145522Sdarrenr	for (i = IPL_LOGMAX; i >= 0; i--)
220145522Sdarrenr		(void) ipflog_clear(i);
221145522Sdarrenr
222145522Sdarrenr# if SOLARIS && defined(_KERNEL)
223145522Sdarrenr	cv_destroy(&iplwait);
224145522Sdarrenr# endif
225145522Sdarrenr	MUTEX_DESTROY(&ipl_mutex);
226145522Sdarrenr
227145522Sdarrenr	ipl_log_init = 0;
228145522Sdarrenr}
229145522Sdarrenr
230145522Sdarrenr
231145522Sdarrenr/* ------------------------------------------------------------------------ */
232145522Sdarrenr/* Function:    ipflog                                                      */
233145522Sdarrenr/* Returns:     int - 0 == success, -1 == failure                           */
234145522Sdarrenr/* Parameters:  fin(I)   - pointer to packet information                    */
235145522Sdarrenr/*              flags(I) - flags from filter rules                          */
236145522Sdarrenr/*                                                                          */
237145522Sdarrenr/* Create a log record for a packet given that it has been triggered by a   */
238145522Sdarrenr/* rule (or the default setting).  Calculate the transport protocol header  */
239145522Sdarrenr/* size using predetermined size of a couple of popular protocols and thus  */
240145522Sdarrenr/* how much data to copy into the log, including part of the data body if   */
241145522Sdarrenr/* requested.                                                               */
242145522Sdarrenr/* ------------------------------------------------------------------------ */
243145522Sdarrenrint ipflog(fin, flags)
244145522Sdarrenrfr_info_t *fin;
24553642Sguidou_int flags;
24653642Sguido{
247145522Sdarrenr	register size_t hlen;
248145522Sdarrenr	int types[2], mlen;
24953642Sguido	size_t sizes[2];
25053642Sguido	void *ptrs[2];
251145522Sdarrenr	ipflog_t ipfl;
25260857Sdarrenr	u_char p;
253145522Sdarrenr	mb_t *m;
254145522Sdarrenr# if (SOLARIS || defined(__hpux)) && defined(_KERNEL)
255145522Sdarrenr	qif_t *ifp;
25653642Sguido# else
257145522Sdarrenr	struct ifnet *ifp;
258145522Sdarrenr# endif /* SOLARIS || __hpux */
25953642Sguido
260145522Sdarrenr	ipfl.fl_nattag.ipt_num[0] = 0;
261145522Sdarrenr	m = fin->fin_m;
262145522Sdarrenr	ifp = fin->fin_ifp;
263145522Sdarrenr	hlen = fin->fin_hlen;
26453642Sguido	/*
26553642Sguido	 * calculate header size.
26653642Sguido	 */
26760857Sdarrenr	if (fin->fin_off == 0) {
26860857Sdarrenr		p = fin->fin_fi.fi_p;
26960857Sdarrenr		if (p == IPPROTO_TCP)
27053642Sguido			hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
27160857Sdarrenr		else if (p == IPPROTO_UDP)
27253642Sguido			hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
27360857Sdarrenr		else if (p == IPPROTO_ICMP) {
27460857Sdarrenr			struct icmp *icmp;
27553642Sguido
27660857Sdarrenr			icmp = (struct icmp *)fin->fin_dp;
277145522Sdarrenr
27853642Sguido			/*
27953642Sguido			 * For ICMP, if the packet is an error packet, also
28053642Sguido			 * include the information about the packet which
28153642Sguido			 * caused the error.
28253642Sguido			 */
28353642Sguido			switch (icmp->icmp_type)
28453642Sguido			{
28553642Sguido			case ICMP_UNREACH :
28653642Sguido			case ICMP_SOURCEQUENCH :
28753642Sguido			case ICMP_REDIRECT :
28853642Sguido			case ICMP_TIMXCEED :
28953642Sguido			case ICMP_PARAMPROB :
29053642Sguido				hlen += MIN(sizeof(struct icmp) + 8,
29153642Sguido					    fin->fin_dlen);
29253642Sguido				break;
29353642Sguido			default :
29453642Sguido				hlen += MIN(sizeof(struct icmp),
29553642Sguido					    fin->fin_dlen);
29653642Sguido				break;
29753642Sguido			}
29853642Sguido		}
299145522Sdarrenr# ifdef USE_INET6
300110916Sdarrenr		else if (p == IPPROTO_ICMPV6) {
301110916Sdarrenr			struct icmp6_hdr *icmp;
302110916Sdarrenr
303110916Sdarrenr			icmp = (struct icmp6_hdr *)fin->fin_dp;
304145522Sdarrenr
305110916Sdarrenr			/*
306110916Sdarrenr			 * For ICMPV6, if the packet is an error packet, also
307110916Sdarrenr			 * include the information about the packet which
308110916Sdarrenr			 * caused the error.
309110916Sdarrenr			 */
310110916Sdarrenr			if (icmp->icmp6_type < 128) {
311110916Sdarrenr				hlen += MIN(sizeof(struct icmp6_hdr) + 8,
312110916Sdarrenr					    fin->fin_dlen);
313110916Sdarrenr			} else {
314110916Sdarrenr				hlen += MIN(sizeof(struct icmp6_hdr),
315110916Sdarrenr					    fin->fin_dlen);
316110916Sdarrenr			}
317110916Sdarrenr		}
318145522Sdarrenr# endif
31953642Sguido	}
32053642Sguido	/*
32153642Sguido	 * Get the interface number and name to which this packet is
32253642Sguido	 * currently associated.
32353642Sguido	 */
324145522Sdarrenr# if (SOLARIS || defined(__hpux)) && defined(_KERNEL)
325145522Sdarrenr	ipfl.fl_unit = (u_int)ifp->qf_ppa;
326145522Sdarrenr	COPYIFNAME(ifp, ipfl.fl_ifname);
32753642Sguido# else
32853642Sguido#  if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
329145522Sdarrenr      (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
330130886Sdarrenr      (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
331145522Sdarrenr	COPYIFNAME(ifp, ipfl.fl_ifname);
33253642Sguido#  else
333130886Sdarrenr	ipfl.fl_unit = (u_int)ifp->if_unit;
334145522Sdarrenr#   if defined(_KERNEL)
335145522Sdarrenr	if ((ipfl.fl_ifname[0] = ifp->if_name[0]))
336145522Sdarrenr		if ((ipfl.fl_ifname[1] = ifp->if_name[1]))
337145522Sdarrenr			if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
338145522Sdarrenr				ipfl.fl_ifname[3] = ifp->if_name[3];
339145522Sdarrenr#   else
340145522Sdarrenr	(void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
341145522Sdarrenr	ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0';
342145522Sdarrenr#   endif
34353642Sguido#  endif
344145522Sdarrenr# endif /* __hpux || SOLARIS */
345145522Sdarrenr	mlen = fin->fin_plen - hlen;
346145522Sdarrenr	if (!ipl_logall) {
347145522Sdarrenr		mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0;
348145522Sdarrenr	} else if ((flags & FR_LOGBODY) == 0) {
349145522Sdarrenr		mlen = 0;
350145522Sdarrenr	}
351145522Sdarrenr	if (mlen < 0)
352145522Sdarrenr		mlen = 0;
35353642Sguido	ipfl.fl_plen = (u_char)mlen;
35453642Sguido	ipfl.fl_hlen = (u_char)hlen;
35553642Sguido	ipfl.fl_rule = fin->fin_rule;
356145522Sdarrenr	(void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN);
357145522Sdarrenr	if (fin->fin_fr != NULL) {
35853642Sguido		ipfl.fl_loglevel = fin->fin_fr->fr_loglevel;
359145522Sdarrenr		ipfl.fl_logtag = fin->fin_fr->fr_logtag;
360145522Sdarrenr	} else {
36153642Sguido		ipfl.fl_loglevel = 0xffff;
362145522Sdarrenr		ipfl.fl_logtag = FR_NOLOGTAG;
363145522Sdarrenr	}
364145522Sdarrenr	if (fin->fin_nattag != NULL)
365145522Sdarrenr		bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag,
366145522Sdarrenr		      sizeof(ipfl.fl_nattag));
36753642Sguido	ipfl.fl_flags = flags;
36892685Sdarrenr	ipfl.fl_dir = fin->fin_out;
369145522Sdarrenr	ipfl.fl_lflags = fin->fin_flx;
37053642Sguido	ptrs[0] = (void *)&ipfl;
37153642Sguido	sizes[0] = sizeof(ipfl);
37253642Sguido	types[0] = 0;
373145522Sdarrenr# if defined(MENTAT) && defined(_KERNEL)
37453642Sguido	/*
37553642Sguido	 * Are we copied from the mblk or an aligned array ?
37653642Sguido	 */
377145522Sdarrenr	if (fin->fin_ip == (ip_t *)m->b_rptr) {
37853642Sguido		ptrs[1] = m;
37953642Sguido		sizes[1] = hlen + mlen;
38053642Sguido		types[1] = 1;
38153642Sguido	} else {
382145522Sdarrenr		ptrs[1] = fin->fin_ip;
38353642Sguido		sizes[1] = hlen + mlen;
38453642Sguido		types[1] = 0;
38553642Sguido	}
38653642Sguido# else
38753642Sguido	ptrs[1] = m;
38853642Sguido	sizes[1] = hlen + mlen;
38953642Sguido	types[1] = 1;
390145522Sdarrenr# endif /* MENTAT */
39153642Sguido	return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2);
39253642Sguido}
39353642Sguido
39453642Sguido
395145522Sdarrenr/* ------------------------------------------------------------------------ */
396145522Sdarrenr/* Function:    ipllog                                                      */
397145522Sdarrenr/* Returns:     int - 0 == success, -1 == failure                           */
398145522Sdarrenr/* Parameters:  dev(I)    - device that owns this log record                */
399145522Sdarrenr/*              fin(I)    - pointer to packet information                   */
400145522Sdarrenr/*              items(I)  - array of pointers to log data                   */
401145522Sdarrenr/*              itemsz(I) - array of size of valid memory pointed to        */
402145522Sdarrenr/*              types(I)  - type of data pointed to by items pointers       */
403145522Sdarrenr/*              cnt(I)    - number of elements in arrays items/itemsz/types */
404145522Sdarrenr/*                                                                          */
405145522Sdarrenr/* Takes an array of parameters and constructs one record to include the    */
406145522Sdarrenr/* miscellaneous packet information, as well as packet data, for reading    */
407145522Sdarrenr/* from the log device.                                                     */
408145522Sdarrenr/* ------------------------------------------------------------------------ */
40953642Sguidoint ipllog(dev, fin, items, itemsz, types, cnt)
41053642Sguidoint dev;
41153642Sguidofr_info_t *fin;
41253642Sguidovoid **items;
41353642Sguidosize_t *itemsz;
41453642Sguidoint *types, cnt;
41553642Sguido{
416145522Sdarrenr	caddr_t buf, ptr;
41753642Sguido	iplog_t *ipl;
41853642Sguido	size_t len;
41953642Sguido	int i;
420145522Sdarrenr# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
421145522Sdarrenr	int s;
422145522Sdarrenr# endif
423145522Sdarrenr
42453642Sguido	/*
42553642Sguido	 * Check to see if this log record has a CRC which matches the last
42653642Sguido	 * record logged.  If it does, just up the count on the previous one
42753642Sguido	 * rather than create a new one.
42853642Sguido	 */
429145522Sdarrenr	if (ipl_suppress) {
430145522Sdarrenr		MUTEX_ENTER(&ipl_mutex);
431145522Sdarrenr		if ((fin != NULL) && (fin->fin_off == 0)) {
432145522Sdarrenr			if ((ipll[dev] != NULL) &&
433145522Sdarrenr			    bcmp((char *)fin, (char *)&iplcrc[dev],
434145522Sdarrenr				 FI_LCSIZE) == 0) {
435145522Sdarrenr				ipll[dev]->ipl_count++;
436145522Sdarrenr				MUTEX_EXIT(&ipl_mutex);
437145522Sdarrenr				return 0;
438145522Sdarrenr			}
439145522Sdarrenr			bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE);
440145522Sdarrenr		} else
441145522Sdarrenr			bzero((char *)&iplcrc[dev], FI_CSIZE);
442145522Sdarrenr		MUTEX_EXIT(&ipl_mutex);
443145522Sdarrenr	}
44453642Sguido
44553642Sguido	/*
44653642Sguido	 * Get the total amount of data to be logged.
44753642Sguido	 */
448145522Sdarrenr	for (i = 0, len = sizeof(iplog_t); i < cnt; i++)
44953642Sguido		len += itemsz[i];
45053642Sguido
45153642Sguido	/*
45253642Sguido	 * check that we have space to record this information and can
45353642Sguido	 * allocate that much.
45453642Sguido	 */
45553642Sguido	KMALLOCS(buf, caddr_t, len);
456145522Sdarrenr	if (buf == NULL)
457145522Sdarrenr		return -1;
458145522Sdarrenr	SPL_NET(s);
45953642Sguido	MUTEX_ENTER(&ipl_mutex);
460145522Sdarrenr	if ((iplused[dev] + len) > ipl_logsize) {
46153642Sguido		MUTEX_EXIT(&ipl_mutex);
462145522Sdarrenr		SPL_X(s);
46353642Sguido		KFREES(buf, len);
464145522Sdarrenr		return -1;
46553642Sguido	}
46653642Sguido	iplused[dev] += len;
46753642Sguido	MUTEX_EXIT(&ipl_mutex);
468145522Sdarrenr	SPL_X(s);
46953642Sguido
47053642Sguido	/*
47153642Sguido	 * advance the log pointer to the next empty record and deduct the
47253642Sguido	 * amount of space we're going to use.
47353642Sguido	 */
47453642Sguido	ipl = (iplog_t *)buf;
475145522Sdarrenr	ipl->ipl_magic = ipl_magic[dev];
47653642Sguido	ipl->ipl_count = 1;
47753642Sguido	ipl->ipl_next = NULL;
47853642Sguido	ipl->ipl_dsize = len;
479145522Sdarrenr#ifdef _KERNEL
480145522Sdarrenr	GETKTIME(&ipl->ipl_sec);
481145522Sdarrenr#else
48292685Sdarrenr	ipl->ipl_sec = 0;
48392685Sdarrenr	ipl->ipl_usec = 0;
484145522Sdarrenr#endif
48553642Sguido
48653642Sguido	/*
48753642Sguido	 * Loop through all the items to be logged, copying each one to the
48853642Sguido	 * buffer.  Use bcopy for normal data or the mb_t copyout routine.
48953642Sguido	 */
490145522Sdarrenr	for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) {
491145522Sdarrenr		if (types[i] == 0) {
492145522Sdarrenr			bcopy(items[i], ptr, itemsz[i]);
493145522Sdarrenr		} else if (types[i] == 1) {
494145522Sdarrenr			COPYDATA(items[i], 0, itemsz[i], ptr);
49553642Sguido		}
496145522Sdarrenr		ptr += itemsz[i];
49753642Sguido	}
498145522Sdarrenr	SPL_NET(s);
49953642Sguido	MUTEX_ENTER(&ipl_mutex);
50053642Sguido	ipll[dev] = ipl;
50153642Sguido	*iplh[dev] = ipl;
50253642Sguido	iplh[dev] = &ipl->ipl_next;
503145522Sdarrenr
504145522Sdarrenr	/*
505145522Sdarrenr	 * Now that the log record has been completed and added to the queue,
506145522Sdarrenr	 * wake up any listeners who may want to read it.
507145522Sdarrenr	 */
50892685Sdarrenr# if SOLARIS && defined(_KERNEL)
50953642Sguido	cv_signal(&iplwait);
510145522Sdarrenr	MUTEX_EXIT(&ipl_mutex);
51153642Sguido# else
51253642Sguido	MUTEX_EXIT(&ipl_mutex);
513145522Sdarrenr	WAKEUP(iplh,dev);
51453642Sguido# endif
515145522Sdarrenr	SPL_X(s);
516145522Sdarrenr# ifdef	IPL_SELECT
517145522Sdarrenr	iplog_input_ready(dev);
518145522Sdarrenr# endif
519145522Sdarrenr	return 0;
52053642Sguido}
52153642Sguido
52253642Sguido
523145522Sdarrenr/* ------------------------------------------------------------------------ */
524145522Sdarrenr/* Function:    ipflog_read                                                 */
525145522Sdarrenr/* Returns:     int    - 0 == success, else error value.                    */
526145522Sdarrenr/* Parameters:  unit(I) - device we are reading from                        */
527145522Sdarrenr/*              uio(O)  - pointer to information about where to store data  */
528145522Sdarrenr/*                                                                          */
529145522Sdarrenr/* Called to handle a read on an IPFilter device.  Returns only complete    */
530145522Sdarrenr/* log messages - will not partially copy a log record out to userland.     */
531145522Sdarrenr/*                                                                          */
532145522Sdarrenr/* NOTE: This function will block and wait for a signal to return data if   */
533145522Sdarrenr/* there is none present.  Asynchronous I/O is not implemented.             */
534145522Sdarrenr/* ------------------------------------------------------------------------ */
53553642Sguidoint ipflog_read(unit, uio)
53653642Sguidominor_t unit;
53753642Sguidostruct uio *uio;
53853642Sguido{
53953642Sguido	size_t dlen, copied;
54053642Sguido	int error = 0;
54153642Sguido	iplog_t *ipl;
542145522Sdarrenr# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
54353642Sguido	int s;
54453642Sguido# endif
54553642Sguido
54653642Sguido	/*
54753642Sguido	 * Sanity checks.  Make sure the minor # is valid and we're copying
54853642Sguido	 * a valid chunk of data.
54953642Sguido	 */
55053642Sguido	if (IPL_LOGMAX < unit)
55153642Sguido		return ENXIO;
552145522Sdarrenr	if (uio->uio_resid == 0)
55353642Sguido		return 0;
554145522Sdarrenr	if ((uio->uio_resid < sizeof(iplog_t)) ||
555145522Sdarrenr	    (uio->uio_resid > ipl_logsize))
55653642Sguido		return EINVAL;
557145522Sdarrenr
55853642Sguido	/*
55953642Sguido	 * Lock the log so we can snapshot the variables.  Wait for a signal
56053642Sguido	 * if the log is empty.
56153642Sguido	 */
56253642Sguido	SPL_NET(s);
56353642Sguido	MUTEX_ENTER(&ipl_mutex);
56453642Sguido
565130886Sdarrenr	while (iplt[unit] == NULL) {
56653642Sguido# if SOLARIS && defined(_KERNEL)
567145522Sdarrenr		if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) {
56853642Sguido			MUTEX_EXIT(&ipl_mutex);
56953642Sguido			return EINTR;
57053642Sguido		}
57153642Sguido# else
572145522Sdarrenr#  if defined(__hpux) && defined(_KERNEL)
573145522Sdarrenr		lock_t *l;
574145522Sdarrenr
575145522Sdarrenr#   ifdef IPL_SELECT
576145522Sdarrenr		if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) {
577145522Sdarrenr			/* this is no blocking system call */
578145522Sdarrenr			MUTEX_EXIT(&ipl_mutex);
579145522Sdarrenr			return 0;
580145522Sdarrenr		}
581145522Sdarrenr#   endif
582145522Sdarrenr
58353642Sguido		MUTEX_EXIT(&ipl_mutex);
584145522Sdarrenr		l = get_sleep_lock(&iplh[unit]);
585145522Sdarrenr		error = sleep(&iplh[unit], PZERO+1);
586145522Sdarrenr		spinunlock(l);
587145522Sdarrenr#  else
588145522Sdarrenr#   if defined(__osf__) && defined(_KERNEL)
589145522Sdarrenr		error = mpsleep(&iplh[unit], PSUSP|PCATCH,  "iplread", 0,
590145522Sdarrenr				&ipl_mutex, MS_LOCK_SIMPLE);
591145522Sdarrenr#   else
592145522Sdarrenr		MUTEX_EXIT(&ipl_mutex);
593145522Sdarrenr		SPL_X(s);
594145522Sdarrenr		error = SLEEP(unit + iplh, "ipl sleep");
595145522Sdarrenr#   endif /* __osf__ */
596145522Sdarrenr#  endif /* __hpux */
597145522Sdarrenr		if (error)
59853642Sguido			return error;
599145522Sdarrenr		SPL_NET(s);
60053642Sguido		MUTEX_ENTER(&ipl_mutex);
60153642Sguido# endif /* SOLARIS */
60253642Sguido	}
60353642Sguido
604145522Sdarrenr# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__)
60553642Sguido	uio->uio_rw = UIO_READ;
60653642Sguido# endif
60753642Sguido
608145522Sdarrenr	for (copied = 0; (ipl = iplt[unit]) != NULL; copied += dlen) {
60953642Sguido		dlen = ipl->ipl_dsize;
61053642Sguido		if (dlen > uio->uio_resid)
61153642Sguido			break;
61253642Sguido		/*
61353642Sguido		 * Don't hold the mutex over the uiomove call.
61453642Sguido		 */
61553642Sguido		iplt[unit] = ipl->ipl_next;
61653642Sguido		iplused[unit] -= dlen;
61753642Sguido		MUTEX_EXIT(&ipl_mutex);
618145522Sdarrenr		SPL_X(s);
61953642Sguido		error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio);
62053642Sguido		if (error) {
621145522Sdarrenr			SPL_NET(s);
622145522Sdarrenr			MUTEX_ENTER(&ipl_mutex);
62353642Sguido			ipl->ipl_next = iplt[unit];
62453642Sguido			iplt[unit] = ipl;
62553642Sguido			iplused[unit] += dlen;
62653642Sguido			break;
62753642Sguido		}
628145522Sdarrenr		MUTEX_ENTER(&ipl_mutex);
62953642Sguido		KFREES((caddr_t)ipl, dlen);
630145522Sdarrenr		SPL_NET(s);
63153642Sguido	}
63253642Sguido	if (!iplt[unit]) {
63353642Sguido		iplused[unit] = 0;
63453642Sguido		iplh[unit] = &iplt[unit];
63553642Sguido		ipll[unit] = NULL;
63653642Sguido	}
63753642Sguido
63853642Sguido	MUTEX_EXIT(&ipl_mutex);
63953642Sguido	SPL_X(s);
64053642Sguido	return error;
64153642Sguido}
64253642Sguido
64353642Sguido
644145522Sdarrenr/* ------------------------------------------------------------------------ */
645145522Sdarrenr/* Function:    ipflog_clear                                                */
646145522Sdarrenr/* Returns:     int    - number of log bytes cleared.                       */
647145522Sdarrenr/* Parameters:  unit(I) - device we are reading from                        */
648145522Sdarrenr/*                                                                          */
649145522Sdarrenr/* Deletes all queued up log records for a given output device.             */
650145522Sdarrenr/* ------------------------------------------------------------------------ */
65153642Sguidoint ipflog_clear(unit)
65253642Sguidominor_t unit;
65353642Sguido{
65453642Sguido	iplog_t *ipl;
65553642Sguido	int used;
656145522Sdarrenr# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
657145522Sdarrenr	int s;
658145522Sdarrenr# endif
65953642Sguido
660145522Sdarrenr	SPL_NET(s);
66153642Sguido	MUTEX_ENTER(&ipl_mutex);
662145522Sdarrenr	while ((ipl = iplt[unit]) != NULL) {
66353642Sguido		iplt[unit] = ipl->ipl_next;
66453642Sguido		KFREES((caddr_t)ipl, ipl->ipl_dsize);
66553642Sguido	}
66653642Sguido	iplh[unit] = &iplt[unit];
66753642Sguido	ipll[unit] = NULL;
66853642Sguido	used = iplused[unit];
66953642Sguido	iplused[unit] = 0;
670145522Sdarrenr	bzero((char *)&iplcrc[unit], FI_CSIZE);
67153642Sguido	MUTEX_EXIT(&ipl_mutex);
672145522Sdarrenr	SPL_X(s);
67353642Sguido	return used;
67453642Sguido}
67553642Sguido#endif /* IPFILTER_LOG */
676