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