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