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