ip_log.c revision 3448:aaf16568054b
1298770Sdelphij/*
2275970Scy * Copyright (C) 1997-2003 by Darren Reed.
3275970Scy *
4275970Scy * See the IPFILTER.LICENCE file for details on licencing.
5275970Scy *
6298770Sdelphij * $Id: ip_log.c,v 2.75.2.7 2005/06/11 07:47:44 darrenr Exp $
7275970Scy *
8275970Scy * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
9275970Scy * Use is subject to license terms.
10275970Scy */
11275970Scy
12275970Scy#pragma ident	"%Z%%M%	%I%	%E% SMI"
13275970Scy
14275970Scy#include <sys/param.h>
15275970Scy#if defined(KERNEL) || defined(_KERNEL)
16275970Scy# undef KERNEL
17275970Scy# undef _KERNEL
18275970Scy# define        KERNEL	1
19275970Scy# define        _KERNEL	1
20275970Scy#endif
21275970Scy#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
22275970Scy    defined(_KERNEL)
23275970Scy# include "opt_ipfilter_log.h"
24275970Scy#endif
25275970Scy#if defined(__FreeBSD__) && !defined(IPFILTER_LKM)
26275970Scy# if defined(_KERNEL)
27275970Scy#  if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
28275970Scy#   include "opt_ipfilter.h"
29275970Scy#  endif
30275970Scy# else
31275970Scy#  include <osreldate.h>
32275970Scy# endif
33275970Scy#endif
34275970Scy#ifndef SOLARIS
35275970Scy# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
36275970Scy#endif
37275970Scy#include <sys/errno.h>
38275970Scy#include <sys/types.h>
39275970Scy#include <sys/file.h>
40275970Scy#ifndef _KERNEL
41275970Scy# include <stdio.h>
42275970Scy# include <string.h>
43275970Scy# include <stdlib.h>
44275970Scy# include <ctype.h>
45275970Scy# define _KERNEL
46275970Scy# define KERNEL
47275970Scy# ifdef __OpenBSD__
48275970Scystruct file;
49275970Scy# endif
50275970Scy# include <sys/uio.h>
51275970Scy# undef _KERNEL
52275970Scy# undef KERNEL
53275970Scy#endif
54275970Scy#if __FreeBSD_version >= 220000 && defined(_KERNEL)
55275970Scy# include <sys/fcntl.h>
56275970Scy# include <sys/filio.h>
57275970Scy#else
58275970Scy# include <sys/ioctl.h>
59275970Scy#endif
60275970Scy#include <sys/time.h>
61275970Scy#if defined(_KERNEL)
62275970Scy# include <sys/systm.h>
63275970Scy# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
64275970Scy#  include <sys/proc.h>
65275970Scy# endif
66275970Scy#endif /* _KERNEL */
67275970Scy#if !SOLARIS && !defined(__hpux) && !defined(linux)
68275970Scy# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
69275970Scy#  include <sys/dirent.h>
70275970Scy# else
71275970Scy#  include <sys/dir.h>
72275970Scy# endif
73275970Scy# include <sys/mbuf.h>
74275970Scy#else
75275970Scy# if !defined(__hpux) && defined(_KERNEL)
76275970Scy#  include <sys/filio.h>
77275970Scy#  include <sys/cred.h>
78275970Scy#  include <sys/ddi.h>
79275970Scy#  include <sys/sunddi.h>
80275970Scy#  include <sys/ksynch.h>
81275970Scy#  include <sys/kmem.h>
82275970Scy#  include <sys/mkdev.h>
83275970Scy#  include <sys/dditypes.h>
84275970Scy#  include <sys/cmn_err.h>
85275970Scy# endif /* !__hpux */
86275970Scy#endif /* !SOLARIS && !__hpux */
87275970Scy#if !defined(linux)
88275970Scy# include <sys/protosw.h>
89275970Scy#endif
90275970Scy#include <sys/socket.h>
91275970Scy
92275970Scy#include <net/if.h>
93275970Scy#ifdef sun
94275970Scy# include <net/af.h>
95275970Scy#endif
96275970Scy#if __FreeBSD_version >= 300000
97275970Scy# include <net/if_var.h>
98275970Scy#endif
99275970Scy#include <net/route.h>
100275970Scy#include <netinet/in.h>
101275970Scy#ifdef __sgi
102275970Scy# include <sys/ddi.h>
103275970Scy# ifdef IFF_DRVRLOCK /* IRIX6 */
104275970Scy#  include <sys/hashing.h>
105275970Scy# endif
106275970Scy#endif
107275970Scy#if !defined(__hpux) && !defined(linux) && \
108275970Scy    !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/
109275970Scy# include <netinet/in_var.h>
110275970Scy#endif
111275970Scy#include <netinet/in_systm.h>
112275970Scy#include <netinet/ip.h>
113275970Scy#include <netinet/tcp.h>
114298770Sdelphij#include <netinet/udp.h>
115298770Sdelphij#include <netinet/ip_icmp.h>
116298770Sdelphij#ifdef USE_INET6
117298770Sdelphij# include <netinet/icmp6.h>
118298770Sdelphij#endif
119298770Sdelphij#if !defined(linux)
120298770Sdelphij# include <netinet/ip_var.h>
121298770Sdelphij#endif
122275970Scy#ifndef _KERNEL
123275970Scy# include <syslog.h>
124275970Scy#endif
125275970Scy#include "netinet/ip_compat.h"
126275970Scy#include <netinet/tcpip.h>
127275970Scy#include "netinet/ip_fil.h"
128275970Scy#include "netinet/ip_nat.h"
129275970Scy#include "netinet/ip_frag.h"
130275970Scy#include "netinet/ip_state.h"
131275970Scy#include "netinet/ip_auth.h"
132275970Scy#include "netinet/ipf_stack.h"
133275970Scy#if (__FreeBSD_version >= 300000) || defined(__NetBSD__)
134275970Scy# include <sys/malloc.h>
135275970Scy#endif
136275970Scy/* END OF INCLUDES */
137275970Scy
138275970Scy#ifdef	IPFILTER_LOG
139275970Scy
140275970Scy# if defined(IPL_SELECT)
141275970Scy#  include	<machine/sys/user.h>
142275970Scy#  include	<sys/kthread_iface.h>
143275970Scy#  define	READ_COLLISION	0x001
144275970Scy
145275970Scyiplog_select_t	iplog_ss[IPL_LOGMAX+1];
146275970Scy
147275970Scyextern int selwait;
148275970Scy# endif /* IPL_SELECT */
149275970Scy
150275970Scy/* ipl_magic never changes */
151275970Scyint	ipl_magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE,
152275970Scy				   IPL_MAGIC, IPL_MAGIC, IPL_MAGIC,
153275970Scy				   IPL_MAGIC, IPL_MAGIC };
154275970Scy
155275970Scy/* ------------------------------------------------------------------------ */
156298770Sdelphij/* Function:    fr_loginit                                                  */
157275970Scy/* Returns:     int - 0 == success (always returned)                        */
158275970Scy/* Parameters:  Nil                                                         */
159275970Scy/*                                                                          */
160275970Scy/* Initialise log buffers & pointers.  Also iniialised the CRC to a local   */
161275970Scy/* secret for use in calculating the "last log checksum".                   */
162275970Scy/* ------------------------------------------------------------------------ */
163275970Scyint fr_loginit(ifs)
164298770Sdelphijipf_stack_t *ifs;
165298770Sdelphij{
166275970Scy	int	i;
167275970Scy
168275970Scy	ifs->ifs_ipl_suppress = 1;
169275970Scy	ifs->ifs_ipl_logmax = IPL_LOGMAX;
170275970Scy	ifs->ifs_ipl_logsize = IPFILTER_LOGSIZE;
171275970Scy	for (i = IPL_LOGMAX; i >= 0; i--) {
172275970Scy		ifs->ifs_iplt[i] = NULL;
173298770Sdelphij		ifs->ifs_ipll[i] = NULL;
174275970Scy		ifs->ifs_iplh[i] = &ifs->ifs_iplt[i];
175275970Scy		ifs->ifs_iplused[i] = 0;
176275970Scy		bzero((char *)&ifs->ifs_iplcrc[i], sizeof(ifs->ifs_iplcrc[i]));
177275970Scy# ifdef	IPL_SELECT
178275970Scy		iplog_ss[i].read_waiter = 0;
179275970Scy		iplog_ss[i].state = 0;
180275970Scy# endif
181275970Scy# if defined(linux) && defined(_KERNEL)
182275970Scy		init_waitqueue_head(iplh_linux + i);
183275970Scy# endif
184275970Scy	}
185275970Scy
186275970Scy# if SOLARIS && defined(_KERNEL)
187275970Scy	cv_init(&ifs->ifs_iplwait, "ipl condvar", CV_DRIVER, NULL);
188275970Scy# endif
189275970Scy	MUTEX_INIT(&ifs->ifs_ipl_mutex, "ipf log mutex");
190275970Scy
191275970Scy	ifs->ifs_ipl_log_init = 1;
192275970Scy
193275970Scy	return 0;
194275970Scy}
195275970Scy
196275970Scy
197275970Scy/* ------------------------------------------------------------------------ */
198275970Scy/* Function:    fr_logunload                                                */
199275970Scy/* Returns:     Nil                                                         */
200275970Scy/* Parameters:  Nil                                                         */
201275970Scy/*                                                                          */
202275970Scy/* Clean up any log data that has accumulated without being read.           */
203275970Scy/* ------------------------------------------------------------------------ */
204275970Scyvoid fr_logunload(ifs)
205275970Scyipf_stack_t *ifs;
206275970Scy{
207275970Scy	int i;
208275970Scy
209275970Scy	if (ifs->ifs_ipl_log_init == 0)
210275970Scy		return;
211275970Scy
212275970Scy	for (i = IPL_LOGMAX; i >= 0; i--)
213275970Scy		(void) ipflog_clear(i, ifs);
214275970Scy
215275970Scy# if SOLARIS && defined(_KERNEL)
216275970Scy	cv_destroy(&ifs->ifs_iplwait);
217275970Scy# endif
218275970Scy	MUTEX_DESTROY(&ifs->ifs_ipl_mutex);
219275970Scy
220275970Scy	ifs->ifs_ipl_log_init = 0;
221275970Scy}
222275970Scy
223275970Scy
224275970Scy/* ------------------------------------------------------------------------ */
225275970Scy/* Function:    ipflog                                                      */
226275970Scy/* Returns:     int - 0 == success, -1 == failure                           */
227275970Scy/* Parameters:  fin(I)   - pointer to packet information                    */
228275970Scy/*              flags(I) - flags from filter rules                          */
229275970Scy/*                                                                          */
230275970Scy/* Create a log record for a packet given that it has been triggered by a   */
231275970Scy/* rule (or the default setting).  Calculate the transport protocol header  */
232275970Scy/* size using predetermined size of a couple of popular protocols and thus  */
233275970Scy/* how much data to copy into the log, including part of the data body if   */
234275970Scy/* requested.                                                               */
235275970Scy/* ------------------------------------------------------------------------ */
236275970Scyint ipflog(fin, flags)
237275970Scyfr_info_t *fin;
238275970Scyu_int flags;
239275970Scy{
240275970Scy	register size_t hlen;
241275970Scy	int types[2], mlen;
242275970Scy	size_t sizes[2];
243275970Scy	void *ptrs[2];
244275970Scy	ipflog_t ipfl;
245275970Scy	u_char p;
246275970Scy	mb_t *m;
247275970Scy# if SOLARIS && defined(_KERNEL)
248275970Scy	net_data_t nif;
249275970Scy	void *ifp;
250275970Scy# else
251275970Scy#  if defined(__hpux) && defined(_KERNEL)
252275970Scy	qif_t *ifp;
253275970Scy#  else
254275970Scy	struct ifnet *ifp;
255275970Scy#  endif
256275970Scy# endif /* SOLARIS */
257275970Scy	ipf_stack_t *ifs = fin->fin_ifs;
258275970Scy
259275970Scy	ipfl.fl_nattag.ipt_num[0] = 0;
260275970Scy	m = fin->fin_m;
261275970Scy	ifp = fin->fin_ifp;
262275970Scy	hlen = fin->fin_hlen;
263275970Scy	/*
264275970Scy	 * calculate header size.
265275970Scy	 */
266275970Scy	if (fin->fin_off == 0) {
267275970Scy		p = fin->fin_fi.fi_p;
268275970Scy		if (p == IPPROTO_TCP)
269275970Scy			hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
270275970Scy		else if (p == IPPROTO_UDP)
271275970Scy			hlen += MIN(sizeof(udphdr_t), fin->fin_dlen);
272275970Scy		else if (p == IPPROTO_ICMP) {
273275970Scy			struct icmp *icmp;
274275970Scy
275275970Scy			icmp = (struct icmp *)fin->fin_dp;
276275970Scy
277275970Scy			/*
278275970Scy			 * For ICMP, if the packet is an error packet, also
279275970Scy			 * include the information about the packet which
280275970Scy			 * caused the error.
281275970Scy			 */
282275970Scy			switch (icmp->icmp_type)
283275970Scy			{
284275970Scy			case ICMP_UNREACH :
285275970Scy			case ICMP_SOURCEQUENCH :
286275970Scy			case ICMP_REDIRECT :
287275970Scy			case ICMP_TIMXCEED :
288275970Scy			case ICMP_PARAMPROB :
289275970Scy				hlen += MIN(sizeof(struct icmp) + 8,
290275970Scy					    fin->fin_dlen);
291275970Scy				break;
292275970Scy			default :
293275970Scy				hlen += MIN(sizeof(struct icmp),
294275970Scy					    fin->fin_dlen);
295275970Scy				break;
296275970Scy			}
297275970Scy		}
298275970Scy# ifdef USE_INET6
299298770Sdelphij		else if (p == IPPROTO_ICMPV6) {
300298770Sdelphij			struct icmp6_hdr *icmp;
301298770Sdelphij
302275970Scy			icmp = (struct icmp6_hdr *)fin->fin_dp;
303275970Scy
304275970Scy			/*
305275970Scy			 * For ICMPV6, if the packet is an error packet, also
306275970Scy			 * include the information about the packet which
307275970Scy			 * caused the error.
308275970Scy			 */
309275970Scy			if (icmp->icmp6_type < 128) {
310275970Scy				hlen += MIN(sizeof(struct icmp6_hdr) + 8,
311275970Scy					    fin->fin_dlen);
312298770Sdelphij			} else {
313298770Sdelphij				hlen += MIN(sizeof(struct icmp6_hdr),
314298770Sdelphij					    fin->fin_dlen);
315275970Scy			}
316275970Scy		}
317275970Scy# endif
318275970Scy	}
319275970Scy	/*
320275970Scy	 * Get the interface number and name to which this packet is
321275970Scy	 * currently associated.
322275970Scy	 */
323275970Scy# if SOLARIS && defined(_KERNEL)
324275970Scy	ipfl.fl_unit = (u_int)0;
325275970Scy	nif = NULL;
326275970Scy	if (fin->fin_fi.fi_v == 4)
327275970Scy		nif = ifs->ifs_ipf_ipv4;
328275970Scy	else if (fin->fin_fi.fi_v == 6)
329275970Scy		nif = ifs->ifs_ipf_ipv6;
330275970Scy	if (nif != NULL) {
331275970Scy		if (net_getifname(nif, (phy_if_t)ifp,
332275970Scy		    ipfl.fl_ifname, sizeof(ipfl.fl_ifname)) != 0)
333275970Scy			return (-1);
334275970Scy	}
335275970Scy
336275970Scy# else
337275970Scy#  if defined(__hpux) && defined(_KERNEL)
338275970Scy	ipfl.fl_unit = (u_int)0;
339275970Scy	(void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
340275970Scy#  else
341275970Scy#   if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
342275970Scy       (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
343275970Scy       (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
344275970Scy	COPYIFNAME(ifp, ipfl.fl_ifname);
345275970Scy#   else
346275970Scy	ipfl.fl_unit = (u_int)ifp->if_unit;
347298770Sdelphij#    if defined(_KERNEL)
348298770Sdelphij	if ((ipfl.fl_ifname[0] = ifp->if_name[0]))
349298770Sdelphij		if ((ipfl.fl_ifname[1] = ifp->if_name[1]))
350298770Sdelphij			if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
351298770Sdelphij				ipfl.fl_ifname[3] = ifp->if_name[3];
352275970Scy#    else
353275970Scy	(void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
354275970Scy	ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0';
355275970Scy#    endif
356275970Scy#   endif
357275970Scy#  endif /* __hpux */
358275970Scy# endif /* SOLARIS */
359275970Scy	mlen = fin->fin_plen - hlen;
360275970Scy	if (!ifs->ifs_ipl_logall) {
361275970Scy		mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0;
362275970Scy	} else if ((flags & FR_LOGBODY) == 0) {
363275970Scy		mlen = 0;
364298770Sdelphij	}
365298770Sdelphij	if (mlen < 0)
366298770Sdelphij		mlen = 0;
367298770Sdelphij	ipfl.fl_plen = (u_char)mlen;
368298770Sdelphij	ipfl.fl_hlen = (u_char)hlen;
369275970Scy	ipfl.fl_rule = fin->fin_rule;
370275970Scy	(void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN);
371275970Scy	if (fin->fin_fr != NULL) {
372275970Scy		ipfl.fl_loglevel = fin->fin_fr->fr_loglevel;
373275970Scy		ipfl.fl_logtag = fin->fin_fr->fr_logtag;
374275970Scy	} else {
375275970Scy		ipfl.fl_loglevel = 0xffff;
376275970Scy		ipfl.fl_logtag = FR_NOLOGTAG;
377275970Scy	}
378275970Scy	if (fin->fin_nattag != NULL)
379275970Scy		bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag,
380275970Scy		      sizeof(ipfl.fl_nattag));
381275970Scy	ipfl.fl_flags = flags;
382275970Scy	ipfl.fl_dir = fin->fin_out;
383275970Scy	ipfl.fl_lflags = fin->fin_flx;
384275970Scy	ptrs[0] = (void *)&ipfl;
385275970Scy	sizes[0] = sizeof(ipfl);
386275970Scy	types[0] = 0;
387298770Sdelphij# if defined(MENTAT) && defined(_KERNEL)
388298770Sdelphij	/*
389298770Sdelphij	 * Are we copied from the mblk or an aligned array ?
390298770Sdelphij	 */
391298770Sdelphij	if (fin->fin_ip == (ip_t *)m->b_rptr) {
392298770Sdelphij		ptrs[1] = m;
393275970Scy		sizes[1] = hlen + mlen;
394275970Scy		types[1] = 1;
395275970Scy	} else {
396275970Scy		ptrs[1] = fin->fin_ip;
397275970Scy		sizes[1] = hlen + mlen;
398275970Scy		types[1] = 0;
399275970Scy	}
400275970Scy# else
401275970Scy	ptrs[1] = m;
402275970Scy	sizes[1] = hlen + mlen;
403275970Scy	types[1] = 1;
404275970Scy# endif /* MENTAT */
405275970Scy	return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2, fin->fin_ifs);
406275970Scy}
407275970Scy
408275970Scy
409275970Scy/* ------------------------------------------------------------------------ */
410275970Scy/* Function:    ipllog                                                      */
411275970Scy/* Returns:     int - 0 == success, -1 == failure                           */
412275970Scy/* Parameters:  dev(I)    - device that owns this log record                */
413275970Scy/*              fin(I)    - pointer to packet information                   */
414275970Scy/*              items(I)  - array of pointers to log data                   */
415275970Scy/*              itemsz(I) - array of size of valid memory pointed to        */
416275970Scy/*              types(I)  - type of data pointed to by items pointers       */
417275970Scy/*              cnt(I)    - number of elements in arrays items/itemsz/types */
418275970Scy/*                                                                          */
419275970Scy/* Takes an array of parameters and constructs one record to include the    */
420275970Scy/* miscellaneous packet information, as well as packet data, for reading    */
421275970Scy/* from the log device.                                                     */
422275970Scy/* ------------------------------------------------------------------------ */
423275970Scyint ipllog(dev, fin, items, itemsz, types, cnt, ifs)
424275970Scyint dev;
425275970Scyfr_info_t *fin;
426275970Scyvoid **items;
427275970Scysize_t *itemsz;
428275970Scyint *types, cnt;
429275970Scyipf_stack_t *ifs;
430275970Scy{
431275970Scy	caddr_t buf, ptr;
432275970Scy	iplog_t *ipl;
433275970Scy	size_t len;
434275970Scy	int i;
435280849Scy	SPL_INT(s);
436280849Scy
437280849Scy	/*
438280849Scy	 * Check to see if this log record has a CRC which matches the last
439280849Scy	 * record logged.  If it does, just up the count on the previous one
440280849Scy	 * rather than create a new one.
441280849Scy	 */
442280849Scy	if (ifs->ifs_ipl_suppress) {
443280849Scy		MUTEX_ENTER(&ifs->ifs_ipl_mutex);
444280849Scy		if ((fin != NULL) && (fin->fin_off == 0)) {
445280849Scy			if ((ifs->ifs_ipll[dev] != NULL) &&
446280849Scy			    bcmp((char *)fin, (char *)&ifs->ifs_iplcrc[dev],
447280849Scy				 FI_LCSIZE) == 0) {
448280849Scy				ifs->ifs_ipll[dev]->ipl_count++;
449275970Scy				MUTEX_EXIT(&ifs->ifs_ipl_mutex);
450275970Scy				return 0;
451275970Scy			}
452275970Scy			bcopy((char *)fin, (char *)&ifs->ifs_iplcrc[dev],
453275970Scy			      FI_LCSIZE);
454275970Scy		} else
455275970Scy			bzero((char *)&ifs->ifs_iplcrc[dev], FI_CSIZE);
456275970Scy		MUTEX_EXIT(&ifs->ifs_ipl_mutex);
457275970Scy	}
458275970Scy
459275970Scy	/*
460275970Scy	 * Get the total amount of data to be logged.
461275970Scy	 */
462275970Scy	for (i = 0, len = sizeof(iplog_t); i < cnt; i++)
463275970Scy		len += itemsz[i];
464275970Scy
465275970Scy	/*
466275970Scy	 * check that we have space to record this information and can
467275970Scy	 * allocate that much.
468275970Scy	 */
469275970Scy	KMALLOCS(buf, caddr_t, len);
470275970Scy	if (buf == NULL)
471275970Scy		return -1;
472275970Scy	SPL_NET(s);
473275970Scy	MUTEX_ENTER(&ifs->ifs_ipl_mutex);
474275970Scy	if ((ifs->ifs_iplused[dev] + len) > IPFILTER_LOGSIZE) {
475275970Scy		MUTEX_EXIT(&ifs->ifs_ipl_mutex);
476275970Scy		SPL_X(s);
477275970Scy		KFREES(buf, len);
478275970Scy		return -1;
479275970Scy	}
480275970Scy	ifs->ifs_iplused[dev] += len;
481275970Scy	MUTEX_EXIT(&ifs->ifs_ipl_mutex);
482275970Scy	SPL_X(s);
483275970Scy
484275970Scy	/*
485275970Scy	 * advance the log pointer to the next empty record and deduct the
486275970Scy	 * amount of space we're going to use.
487275970Scy	 */
488275970Scy	ipl = (iplog_t *)buf;
489275970Scy	ipl->ipl_magic = ipl_magic[dev];
490275970Scy	ipl->ipl_count = 1;
491275970Scy	ipl->ipl_next = NULL;
492275970Scy	ipl->ipl_dsize = len;
493275970Scy#ifdef _KERNEL
494275970Scy	GETKTIME(&ipl->ipl_sec);
495275970Scy#else
496275970Scy	ipl->ipl_sec = 0;
497275970Scy	ipl->ipl_usec = 0;
498275970Scy#endif
499275970Scy
500275970Scy	/*
501275970Scy	 * Loop through all the items to be logged, copying each one to the
502275970Scy	 * buffer.  Use bcopy for normal data or the mb_t copyout routine.
503275970Scy	 */
504275970Scy	for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) {
505275970Scy		if (types[i] == 0) {
506275970Scy			bcopy(items[i], ptr, itemsz[i]);
507275970Scy		} else if (types[i] == 1) {
508275970Scy			COPYDATA(items[i], 0, itemsz[i], ptr);
509275970Scy		}
510275970Scy		ptr += itemsz[i];
511275970Scy	}
512275970Scy	SPL_NET(s);
513275970Scy	MUTEX_ENTER(&ifs->ifs_ipl_mutex);
514275970Scy	ifs->ifs_ipll[dev] = ipl;
515275970Scy	*ifs->ifs_iplh[dev] = ipl;
516275970Scy	ifs->ifs_iplh[dev] = &ipl->ipl_next;
517275970Scy
518275970Scy	/*
519275970Scy	 * Now that the log record has been completed and added to the queue,
520275970Scy	 * wake up any listeners who may want to read it.
521275970Scy	 */
522275970Scy# if SOLARIS && defined(_KERNEL)
523275970Scy	cv_signal(&ifs->ifs_iplwait);
524275970Scy	MUTEX_EXIT(&ifs->ifs_ipl_mutex);
525275970Scy# else
526275970Scy	MUTEX_EXIT(&ifs->ifs_ipl_mutex);
527275970Scy	WAKEUP(&ifs->ifs_iplh, dev);
528275970Scy# endif
529275970Scy	SPL_X(s);
530275970Scy# ifdef	IPL_SELECT
531275970Scy	iplog_input_ready(dev);
532275970Scy# endif
533275970Scy	return 0;
534275970Scy}
535275970Scy
536275970Scy
537275970Scy/* ------------------------------------------------------------------------ */
538298770Sdelphij/* Function:    ipflog_read                                                 */
539275970Scy/* Returns:     int    - 0 == success, else error value.                    */
540275970Scy/* Parameters:  unit(I) - device we are reading from                        */
541275970Scy/*              uio(O)  - pointer to information about where to store data  */
542275970Scy/*                                                                          */
543275970Scy/* Called to handle a read on an IPFilter device.  Returns only complete    */
544275970Scy/* log messages - will not partially copy a log record out to userland.     */
545275970Scy/*                                                                          */
546275970Scy/* NOTE: This function will block and wait for a signal to return data if   */
547275970Scy/* there is none present.  Asynchronous I/O is not implemented.             */
548275970Scy/* ------------------------------------------------------------------------ */
549275970Scyint ipflog_read(unit, uio, ifs)
550275970Scyminor_t unit;
551275970Scystruct uio *uio;
552275970Scyipf_stack_t *ifs;
553275970Scy{
554275970Scy	size_t dlen, copied;
555275970Scy	int error = 0;
556275970Scy	iplog_t *ipl;
557275970Scy	SPL_INT(s);
558275970Scy
559275970Scy	/*
560275970Scy	 * Sanity checks.  Make sure the minor # is valid and we're copying
561275970Scy	 * a valid chunk of data.
562275970Scy	 */
563275970Scy	if (IPL_LOGMAX < unit)
564275970Scy		return ENXIO;
565275970Scy	if (uio->uio_resid == 0)
566275970Scy		return 0;
567275970Scy	if ((uio->uio_resid < sizeof(iplog_t)) ||
568275970Scy	    (uio->uio_resid > ifs->ifs_ipl_logsize))
569275970Scy		return EINVAL;
570275970Scy
571275970Scy	/*
572275970Scy	 * Lock the log so we can snapshot the variables.  Wait for a signal
573275970Scy	 * if the log is empty.
574275970Scy	 */
575275970Scy	SPL_NET(s);
576275970Scy	MUTEX_ENTER(&ifs->ifs_ipl_mutex);
577275970Scy
578275970Scy	while (ifs->ifs_iplt[unit] == NULL) {
579275970Scy# if SOLARIS && defined(_KERNEL)
580275970Scy		if (!cv_wait_sig(&ifs->ifs_iplwait, &ifs->ifs_ipl_mutex.ipf_lk)) {
581275970Scy			MUTEX_EXIT(&ifs->ifs_ipl_mutex);
582275970Scy			return EINTR;
583275970Scy		}
584275970Scy# else
585275970Scy#  if defined(__hpux) && defined(_KERNEL)
586275970Scy		lock_t *l;
587275970Scy
588275970Scy#   ifdef IPL_SELECT
589275970Scy		if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) {
590275970Scy			/* this is no blocking system call */
591275970Scy			MUTEX_EXIT(&ifs->ifs_ipl_mutex);
592275970Scy			return 0;
593275970Scy		}
594275970Scy#   endif
595275970Scy
596275970Scy		MUTEX_EXIT(&ifs->ifs_ipl_mutex);
597275970Scy		l = get_sleep_lock(&ifs->ifs_iplh[unit]);
598275970Scy		error = sleep(&ifs->ifs_iplh[unit], PZERO+1);
599275970Scy		spinunlock(l);
600275970Scy#  else
601275970Scy#   if defined(__osf__) && defined(_KERNEL)
602275970Scy		error = mpsleep(&ifs->ifs_iplh[unit], PSUSP|PCATCH,  "iplread", 0,
603275970Scy				&ifs->ifs_ipl_mutex, MS_LOCK_SIMPLE);
604275970Scy#   else
605275970Scy		MUTEX_EXIT(&ifs->ifs_ipl_mutex);
606275970Scy		SPL_X(s);
607275970Scy		error = SLEEP(&ifs->ifs_iplh[unit], "ipl sleep");
608275970Scy#   endif /* __osf__ */
609275970Scy#  endif /* __hpux */
610275970Scy		if (error)
611275970Scy			return error;
612275970Scy		SPL_NET(s);
613275970Scy		MUTEX_ENTER(&ifs->ifs_ipl_mutex);
614275970Scy# endif /* SOLARIS */
615275970Scy	}
616275970Scy
617275970Scy# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__)
618275970Scy	uio->uio_rw = UIO_READ;
619275970Scy# endif
620275970Scy
621275970Scy	for (copied = 0; ((ipl = ifs->ifs_iplt[unit]) != NULL); copied += dlen) {
622275970Scy		dlen = ipl->ipl_dsize;
623275970Scy		if (dlen > uio->uio_resid)
624275970Scy			break;
625275970Scy		/*
626275970Scy		 * Don't hold the mutex over the uiomove call.
627275970Scy		 */
628275970Scy		ifs->ifs_iplt[unit] = ipl->ipl_next;
629275970Scy		ifs->ifs_iplused[unit] -= dlen;
630275970Scy		if (ifs->ifs_iplt[unit] == NULL) {
631275970Scy			ifs->ifs_iplh[unit] = &ifs->ifs_iplt[unit];
632275970Scy			ifs->ifs_ipll[unit] = NULL;
633275970Scy		}
634275970Scy		MUTEX_EXIT(&ifs->ifs_ipl_mutex);
635275970Scy		SPL_X(s);
636275970Scy		error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio);
637275970Scy		if (error) {
638275970Scy			SPL_NET(s);
639275970Scy			MUTEX_ENTER(&ifs->ifs_ipl_mutex);
640275970Scy			ifs->ifs_iplused[unit] += dlen;
641275970Scy			ipl->ipl_next = ifs->ifs_iplt[unit];
642275970Scy			ifs->ifs_iplt[unit] = ipl;
643275970Scy			ifs->ifs_ipll[unit] = ipl;
644275970Scy			if (ifs->ifs_iplh[unit] == &ifs->ifs_iplt[unit]) {
645275970Scy				*ifs->ifs_iplh[unit] = ipl;
646275970Scy				ifs->ifs_iplh[unit] = &ipl->ipl_next;
647275970Scy			}
648275970Scy			break;
649275970Scy		}
650275970Scy		MUTEX_ENTER(&ifs->ifs_ipl_mutex);
651275970Scy		KFREES((caddr_t)ipl, dlen);
652275970Scy		SPL_NET(s);
653275970Scy	}
654275970Scy
655275970Scy	MUTEX_EXIT(&ifs->ifs_ipl_mutex);
656275970Scy	SPL_X(s);
657275970Scy	return error;
658275970Scy}
659275970Scy
660275970Scy
661275970Scy/* ------------------------------------------------------------------------ */
662275970Scy/* Function:    ipflog_clear                                                */
663275970Scy/* Returns:     int    - number of log bytes cleared.                       */
664275970Scy/* Parameters:  unit(I) - device we are reading from                        */
665275970Scy/*                                                                          */
666275970Scy/* Deletes all queued up log records for a given output device.             */
667275970Scy/* ------------------------------------------------------------------------ */
668275970Scyint ipflog_clear(unit, ifs)
669275970Scyminor_t unit;
670275970Scyipf_stack_t *ifs;
671275970Scy{
672275970Scy	iplog_t *ipl;
673275970Scy	int used;
674275970Scy	SPL_INT(s);
675275970Scy
676275970Scy	SPL_NET(s);
677275970Scy	MUTEX_ENTER(&ifs->ifs_ipl_mutex);
678275970Scy	while ((ipl = ifs->ifs_iplt[unit]) != NULL) {
679275970Scy		ifs->ifs_iplt[unit] = ipl->ipl_next;
680275970Scy		KFREES((caddr_t)ipl, ipl->ipl_dsize);
681275970Scy	}
682275970Scy	ifs->ifs_iplh[unit] = &ifs->ifs_iplt[unit];
683275970Scy	ifs->ifs_ipll[unit] = NULL;
684275970Scy	used = ifs->ifs_iplused[unit];
685275970Scy	ifs->ifs_iplused[unit] = 0;
686275970Scy	bzero((char *)&ifs->ifs_iplcrc[unit], FI_CSIZE);
687275970Scy	MUTEX_EXIT(&ifs->ifs_ipl_mutex);
688275970Scy	SPL_X(s);
689275970Scy	return used;
690275970Scy}
691275970Scy#endif /* IPFILTER_LOG */
692275970Scy