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