1/* $FreeBSD: releng/10.3/sys/contrib/ipfilter/netinet/ip_log.c 267020 2014-06-03 19:06:47Z cy $ */ 2 3/* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * $FreeBSD: releng/10.3/sys/contrib/ipfilter/netinet/ip_log.c 267020 2014-06-03 19:06:47Z 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 int i; 218 219 KMALLOC(softl, ipf_log_softc_t *); 220 if (softl == NULL) 221 return NULL; 222 223 bzero((char *)softl, sizeof(*softl)); 224 bcopy((char *)magic, (char *)softl->ipl_magic, sizeof(magic)); 225 226 softl->ipf_log_tune = ipf_tune_array_copy(softl, 227 sizeof(ipf_log_tuneables), 228 ipf_log_tuneables); 229 if (softl->ipf_log_tune == NULL) { 230 ipf_log_soft_destroy(softc, softl); 231 return NULL; 232 } 233 if (ipf_tune_array_link(softc, softl->ipf_log_tune) == -1) { 234 ipf_log_soft_destroy(softc, softl); 235 return NULL; 236 } 237 238 for (i = IPL_LOGMAX; i >= 0; i--) { 239 MUTEX_INIT(&softl->ipl_mutex[i], "ipf log mutex"); 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(softc, arg) 260 ipf_main_softc_t *softc; 261 void *arg; 262{ 263 ipf_log_softc_t *softl = arg; 264 int i; 265 266 for (i = IPL_LOGMAX; i >= 0; i--) { 267 softl->iplt[i] = NULL; 268 softl->ipll[i] = NULL; 269 softl->iplh[i] = &softl->iplt[i]; 270 bzero((char *)&softl->ipl_crc[i], sizeof(softl->ipl_crc[i])); 271# ifdef IPL_SELECT 272 softl->iplog_ss[i].read_waiter = 0; 273 softl->iplog_ss[i].state = 0; 274# endif 275 } 276 277 278 softl->ipl_log_init = 1; 279 280 return 0; 281} 282 283 284/* ------------------------------------------------------------------------ */ 285/* Function: ipf_log_soft_fini */ 286/* Parameters: softc(I) - pointer to soft context main structure */ 287/* arg(I) - pointer to log context structure */ 288/* */ 289/* Clean up any log data that has accumulated without being read. */ 290/* ------------------------------------------------------------------------ */ 291int 292ipf_log_soft_fini(softc, arg) 293 ipf_main_softc_t *softc; 294 void *arg; 295{ 296 ipf_log_softc_t *softl = arg; 297 int i; 298 299 if (softl->ipl_log_init == 0) 300 return 0; 301 302 softl->ipl_log_init = 0; 303 304 for (i = IPL_LOGMAX; i >= 0; i--) { 305 (void) ipf_log_clear(softc, i); 306 307 /* 308 * This is a busy-wait loop so as to avoid yet another lock 309 * to wait on. 310 */ 311 MUTEX_ENTER(&softl->ipl_mutex[i]); 312 while (softl->ipl_readers[i] > 0) { 313# if SOLARIS && defined(_KERNEL) 314 cv_broadcast(&softl->ipl_wait[i]); 315 MUTEX_EXIT(&softl->ipl_mutex[i]); 316 delay(100); 317 pollwakeup(&softc->ipf_poll_head[i], POLLRDNORM); 318# else 319 MUTEX_EXIT(&softl->ipl_mutex[i]); 320 WAKEUP(softl->iplh, i); 321 POLLWAKEUP(i); 322# endif 323 MUTEX_ENTER(&softl->ipl_mutex[i]); 324 } 325 MUTEX_EXIT(&softl->ipl_mutex[i]); 326 } 327 328 return 0; 329} 330 331 332/* ------------------------------------------------------------------------ */ 333/* Function: ipf_log_soft_destroy */ 334/* Parameters: softc(I) - pointer to soft context main structure */ 335/* arg(I) - pointer to log context structure */ 336/* */ 337/* When this function is called, it is expected that there are no longer */ 338/* any threads active in the reading code path or the logging code path. */ 339/* ------------------------------------------------------------------------ */ 340void 341ipf_log_soft_destroy(softc, arg) 342 ipf_main_softc_t *softc; 343 void *arg; 344{ 345 ipf_log_softc_t *softl = arg; 346 int i; 347 348 for (i = IPL_LOGMAX; i >= 0; i--) { 349# if SOLARIS && defined(_KERNEL) 350 cv_destroy(&softl->ipl_wait[i]); 351# endif 352 MUTEX_DESTROY(&softl->ipl_mutex[i]); 353 } 354 355 if (softl->ipf_log_tune != NULL) { 356 ipf_tune_array_unlink(softc, softl->ipf_log_tune); 357 KFREES(softl->ipf_log_tune, sizeof(ipf_log_tuneables)); 358 softl->ipf_log_tune = NULL; 359 } 360 361 KFREE(softl); 362} 363 364 365/* ------------------------------------------------------------------------ */ 366/* Function: ipf_log_pkt */ 367/* Returns: int - 0 == success, -1 == failure */ 368/* Parameters: fin(I) - pointer to packet information */ 369/* flags(I) - flags from filter rules */ 370/* */ 371/* Create a log record for a packet given that it has been triggered by a */ 372/* rule (or the default setting). Calculate the transport protocol header */ 373/* size using predetermined size of a couple of popular protocols and thus */ 374/* how much data to copy into the log, including part of the data body if */ 375/* requested. */ 376/* ------------------------------------------------------------------------ */ 377int 378ipf_log_pkt(fin, flags) 379 fr_info_t *fin; 380 u_int flags; 381{ 382 ipf_main_softc_t *softc = fin->fin_main_soft; 383 ipf_log_softc_t *softl = softc->ipf_log_soft; 384 register size_t hlen; 385 int types[2], mlen; 386 size_t sizes[2]; 387 void *ptrs[2]; 388 ipflog_t ipfl; 389 u_char p; 390 mb_t *m; 391# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && !defined(FW_HOOKS) 392 qif_t *ifp; 393# else 394 struct ifnet *ifp; 395# endif /* SOLARIS || __hpux */ 396 397 m = fin->fin_m; 398 if (m == NULL) 399 return -1; 400 401 ipfl.fl_nattag.ipt_num[0] = 0; 402 ifp = fin->fin_ifp; 403 hlen = (char *)fin->fin_dp - (char *)fin->fin_ip; 404 405 /* 406 * calculate header size. 407 */ 408 if (fin->fin_off == 0) { 409 p = fin->fin_fi.fi_p; 410 if (p == IPPROTO_TCP) 411 hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); 412 else if (p == IPPROTO_UDP) 413 hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); 414 else if (p == IPPROTO_ICMP) { 415 struct icmp *icmp; 416 417 icmp = (struct icmp *)fin->fin_dp; 418 419 /* 420 * For ICMP, if the packet is an error packet, also 421 * include the information about the packet which 422 * caused the error. 423 */ 424 switch (icmp->icmp_type) 425 { 426 case ICMP_UNREACH : 427 case ICMP_SOURCEQUENCH : 428 case ICMP_REDIRECT : 429 case ICMP_TIMXCEED : 430 case ICMP_PARAMPROB : 431 hlen += MIN(sizeof(struct icmp) + 8, 432 fin->fin_dlen); 433 break; 434 default : 435 hlen += MIN(sizeof(struct icmp), 436 fin->fin_dlen); 437 break; 438 } 439 } 440# ifdef USE_INET6 441 else if (p == IPPROTO_ICMPV6) { 442 struct icmp6_hdr *icmp; 443 444 icmp = (struct icmp6_hdr *)fin->fin_dp; 445 446 /* 447 * For ICMPV6, if the packet is an error packet, also 448 * include the information about the packet which 449 * caused the error. 450 */ 451 if (icmp->icmp6_type < 128) { 452 hlen += MIN(sizeof(struct icmp6_hdr) + 8, 453 fin->fin_dlen); 454 } else { 455 hlen += MIN(sizeof(struct icmp6_hdr), 456 fin->fin_dlen); 457 } 458 } 459# endif 460 } 461 /* 462 * Get the interface number and name to which this packet is 463 * currently associated. 464 */ 465# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) 466# if !defined(FW_HOOKS) 467 ipfl.fl_unit = (u_int)ifp->qf_ppa; 468# endif 469 COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 470# else 471# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ 472 OPENBSD_GE_REV(199603) || defined(linux) || FREEBSD_GE_REV(501113) 473 COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); 474# else 475 ipfl.fl_unit = (u_int)ifp->if_unit; 476# if defined(_KERNEL) 477 if ((ipfl.fl_ifname[0] = ifp->if_name[0])) 478 if ((ipfl.fl_ifname[1] = ifp->if_name[1])) 479 if ((ipfl.fl_ifname[2] = ifp->if_name[2])) 480 ipfl.fl_ifname[3] = ifp->if_name[3]; 481# else 482 (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); 483 ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; 484# endif 485# endif 486# endif /* __hpux || SOLARIS */ 487 mlen = fin->fin_plen - hlen; 488 if (!softl->ipl_logall) { 489 mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; 490 } else if ((flags & FR_LOGBODY) == 0) { 491 mlen = 0; 492 } 493 if (mlen < 0) 494 mlen = 0; 495 ipfl.fl_plen = (u_char)mlen; 496 ipfl.fl_hlen = (u_char)hlen; 497 ipfl.fl_rule = fin->fin_rule; 498 (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); 499 if (fin->fin_fr != NULL) { 500 ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; 501 ipfl.fl_logtag = fin->fin_fr->fr_logtag; 502 } else { 503 ipfl.fl_loglevel = 0xffff; 504 ipfl.fl_logtag = FR_NOLOGTAG; 505 } 506 if (fin->fin_nattag != NULL) 507 bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, 508 sizeof(ipfl.fl_nattag)); 509 ipfl.fl_flags = flags; 510 ipfl.fl_breason = (fin->fin_reason & 0xff); 511 ipfl.fl_dir = fin->fin_out; 512 ipfl.fl_lflags = fin->fin_flx; 513 ipfl.fl_family = fin->fin_family; 514 ptrs[0] = (void *)&ipfl; 515 sizes[0] = sizeof(ipfl); 516 types[0] = 0; 517# if defined(MENTAT) && defined(_KERNEL) 518 /* 519 * Are we copied from the mblk or an aligned array ? 520 */ 521 if (fin->fin_ip == (ip_t *)m->b_rptr) { 522 ptrs[1] = m; 523 sizes[1] = hlen + mlen; 524 types[1] = 1; 525 } else { 526 ptrs[1] = fin->fin_ip; 527 sizes[1] = hlen + mlen; 528 types[1] = 0; 529 } 530# else 531 ptrs[1] = m; 532 sizes[1] = hlen + mlen; 533 types[1] = 1; 534# endif /* MENTAT */ 535 return ipf_log_items(softc, IPL_LOGIPF, fin, ptrs, sizes, types, 2); 536} 537 538 539/* ------------------------------------------------------------------------ */ 540/* Function: ipf_log_items */ 541/* Returns: int - 0 == success, -1 == failure */ 542/* Parameters: softc(I) - pointer to main soft context */ 543/* unit(I) - device we are reading from */ 544/* fin(I) - pointer to packet information */ 545/* items(I) - array of pointers to log data */ 546/* itemsz(I) - array of size of valid memory pointed to */ 547/* types(I) - type of data pointed to by items pointers */ 548/* cnt(I) - number of elements in arrays items/itemsz/types */ 549/* */ 550/* Takes an array of parameters and constructs one record to include the */ 551/* miscellaneous packet information, as well as packet data, for reading */ 552/* from the log device. */ 553/* ------------------------------------------------------------------------ */ 554int 555ipf_log_items(softc, unit, fin, items, itemsz, types, cnt) 556 ipf_main_softc_t *softc; 557 int unit; 558 fr_info_t *fin; 559 void **items; 560 size_t *itemsz; 561 int *types, cnt; 562{ 563 ipf_log_softc_t *softl = softc->ipf_log_soft; 564 caddr_t buf, ptr; 565 iplog_t *ipl; 566 size_t len; 567 int i; 568 SPL_INT(s); 569 570 /* 571 * Get the total amount of data to be logged. 572 */ 573 for (i = 0, len = sizeof(iplog_t); i < cnt; i++) 574 len += itemsz[i]; 575 576 SPL_NET(s); 577 MUTEX_ENTER(&softl->ipl_mutex[unit]); 578 softl->ipl_counter[unit]++; 579 /* 580 * check that we have space to record this information and can 581 * allocate that much. 582 */ 583 if ((softl->ipl_used[unit] + len) > softl->ipl_logsize) { 584 softl->ipl_logfail[unit]++; 585 MUTEX_EXIT(&softl->ipl_mutex[unit]); 586 return -1; 587 } 588 589 KMALLOCS(buf, caddr_t, len); 590 if (buf == NULL) { 591 softl->ipl_logfail[unit]++; 592 MUTEX_EXIT(&softl->ipl_mutex[unit]); 593 return -1; 594 } 595 ipl = (iplog_t *)buf; 596 ipl->ipl_magic = softl->ipl_magic[unit]; 597 ipl->ipl_count = 1; 598 ipl->ipl_seqnum = softl->ipl_counter[unit]; 599 ipl->ipl_next = NULL; 600 ipl->ipl_dsize = len; 601#ifdef _KERNEL 602 GETKTIME(&ipl->ipl_sec); 603#else 604 ipl->ipl_sec = 0; 605 ipl->ipl_usec = 0; 606#endif 607 608 /* 609 * Loop through all the items to be logged, copying each one to the 610 * buffer. Use bcopy for normal data or the mb_t copyout routine. 611 */ 612 for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { 613 if (types[i] == 0) { 614 bcopy(items[i], ptr, itemsz[i]); 615 } else if (types[i] == 1) { 616 COPYDATA(items[i], 0, itemsz[i], ptr); 617 } 618 ptr += itemsz[i]; 619 } 620 /* 621 * Check to see if this log record has a CRC which matches the last 622 * record logged. If it does, just up the count on the previous one 623 * rather than create a new one. 624 */ 625 if (softl->ipl_suppress) { 626 if ((fin != NULL) && (fin->fin_off == 0)) { 627 if ((softl->ipll[unit] != NULL) && 628 (fin->fin_crc == softl->ipl_crc[unit].fin_crc) && 629 bcmp((char *)fin, (char *)&softl->ipl_crc[unit], 630 FI_LCSIZE) == 0) { 631 softl->ipll[unit]->ipl_count++; 632 MUTEX_EXIT(&softl->ipl_mutex[unit]); 633 SPL_X(s); 634 KFREES(buf, len); 635 return 0; 636 } 637 bcopy((char *)fin, (char *)&softl->ipl_crc[unit], 638 FI_LCSIZE); 639 softl->ipl_crc[unit].fin_crc = fin->fin_crc; 640 } else 641 bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 642 } 643 644 /* 645 * advance the log pointer to the next empty record and deduct the 646 * amount of space we're going to use. 647 */ 648 softl->ipl_logok[unit]++; 649 softl->ipll[unit] = ipl; 650 *softl->iplh[unit] = ipl; 651 softl->iplh[unit] = &ipl->ipl_next; 652 softl->ipl_used[unit] += len; 653 654 /* 655 * Now that the log record has been completed and added to the queue, 656 * wake up any listeners who may want to read it. 657 */ 658# if SOLARIS && defined(_KERNEL) 659 cv_signal(&softl->ipl_wait[unit]); 660 MUTEX_EXIT(&softl->ipl_mutex[unit]); 661 pollwakeup(&softc->ipf_poll_head[unit], POLLRDNORM); 662# else 663 MUTEX_EXIT(&softl->ipl_mutex[unit]); 664 WAKEUP(softl->iplh, unit); 665 POLLWAKEUP(unit); 666# endif 667 SPL_X(s); 668# ifdef IPL_SELECT 669 iplog_input_ready(unit); 670# endif 671 return 0; 672} 673 674 675/* ------------------------------------------------------------------------ */ 676/* Function: ipf_log_read */ 677/* Returns: int - 0 == success, else error value. */ 678/* Parameters: softc(I) - pointer to main soft context */ 679/* unit(I) - device we are reading from */ 680/* uio(O) - pointer to information about where to store data */ 681/* */ 682/* Called to handle a read on an IPFilter device. Returns only complete */ 683/* log messages - will not partially copy a log record out to userland. */ 684/* */ 685/* NOTE: This function will block and wait for a signal to return data if */ 686/* there is none present. Asynchronous I/O is not implemented. */ 687/* ------------------------------------------------------------------------ */ 688int 689ipf_log_read(softc, unit, uio) 690 ipf_main_softc_t *softc; 691 minor_t unit; 692 struct uio *uio; 693{ 694 ipf_log_softc_t *softl = softc->ipf_log_soft; 695 size_t dlen, copied; 696 int error = 0; 697 iplog_t *ipl; 698 SPL_INT(s); 699 700 if (softl->ipl_log_init == 0) { 701 IPFERROR(40007); 702 return 0; 703 } 704 705 /* 706 * Sanity checks. Make sure the minor # is valid and we're copying 707 * a valid chunk of data. 708 */ 709 if (IPL_LOGMAX < unit) { 710 IPFERROR(40001); 711 return ENXIO; 712 } 713 if (uio->uio_resid == 0) 714 return 0; 715 716 if (uio->uio_resid < sizeof(iplog_t)) { 717 IPFERROR(40002); 718 return EINVAL; 719 } 720 if (uio->uio_resid > softl->ipl_logsize) { 721 IPFERROR(40005); 722 return EINVAL; 723 } 724 725 /* 726 * Lock the log so we can snapshot the variables. Wait for a signal 727 * if the log is empty. 728 */ 729 SPL_NET(s); 730 MUTEX_ENTER(&softl->ipl_mutex[unit]); 731 softl->ipl_readers[unit]++; 732 733 while (softl->ipl_log_init == 1 && softl->iplt[unit] == NULL) { 734# if SOLARIS && defined(_KERNEL) 735 if (!cv_wait_sig(&softl->ipl_wait[unit], 736 &softl->ipl_mutex[unit].ipf_lk)) { 737 softl->ipl_readers[unit]--; 738 MUTEX_EXIT(&softl->ipl_mutex[unit]); 739 IPFERROR(40003); 740 return EINTR; 741 } 742# else 743# if defined(__hpux) && defined(_KERNEL) 744 lock_t *l; 745 746# ifdef IPL_SELECT 747 if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { 748 /* this is no blocking system call */ 749 softl->ipl_readers[unit]--; 750 MUTEX_EXIT(&softl->ipl_mutex[unit]); 751 return 0; 752 } 753# endif 754 755 MUTEX_EXIT(&softl->ipl_mutex[unit]); 756 l = get_sleep_lock(&softl->iplh[unit]); 757 error = sleep(&softl->iplh[unit], PZERO+1); 758 spinunlock(l); 759# else 760# if defined(__osf__) && defined(_KERNEL) 761 error = mpsleep(&softl->iplh[unit], PSUSP|PCATCH, "ipfread", 0, 762 &softl->ipl_mutex, MS_LOCK_SIMPLE); 763# else 764 MUTEX_EXIT(&softl->ipl_mutex[unit]); 765 SPL_X(s); 766 error = SLEEP(unit + softl->iplh, "ipl sleep"); 767# endif /* __osf__ */ 768# endif /* __hpux */ 769 SPL_NET(s); 770 MUTEX_ENTER(&softl->ipl_mutex[unit]); 771 if (error) { 772 softl->ipl_readers[unit]--; 773 MUTEX_EXIT(&softl->ipl_mutex[unit]); 774 IPFERROR(40004); 775 return error; 776 } 777# endif /* SOLARIS */ 778 } 779 if (softl->ipl_log_init != 1) { 780 softl->ipl_readers[unit]--; 781 MUTEX_EXIT(&softl->ipl_mutex[unit]); 782 IPFERROR(40008); 783 return EIO; 784 } 785 786# if (defined(BSD) && (BSD >= 199101)) || defined(__FreeBSD__) || \ 787 defined(__osf__) 788 uio->uio_rw = UIO_READ; 789# endif 790 791 for (copied = 0; (ipl = softl->iplt[unit]) != NULL; copied += dlen) { 792 dlen = ipl->ipl_dsize; 793 if (dlen > uio->uio_resid) 794 break; 795 /* 796 * Don't hold the mutex over the uiomove call. 797 */ 798 softl->iplt[unit] = ipl->ipl_next; 799 softl->ipl_used[unit] -= dlen; 800 MUTEX_EXIT(&softl->ipl_mutex[unit]); 801 SPL_X(s); 802 error = UIOMOVE(ipl, dlen, UIO_READ, uio); 803 if (error) { 804 SPL_NET(s); 805 MUTEX_ENTER(&softl->ipl_mutex[unit]); 806 IPFERROR(40006); 807 ipl->ipl_next = softl->iplt[unit]; 808 softl->iplt[unit] = ipl; 809 softl->ipl_used[unit] += dlen; 810 break; 811 } 812 MUTEX_ENTER(&softl->ipl_mutex[unit]); 813 KFREES((caddr_t)ipl, dlen); 814 SPL_NET(s); 815 } 816 if (!softl->iplt[unit]) { 817 softl->ipl_used[unit] = 0; 818 softl->iplh[unit] = &softl->iplt[unit]; 819 softl->ipll[unit] = NULL; 820 } 821 822 softl->ipl_readers[unit]--; 823 MUTEX_EXIT(&softl->ipl_mutex[unit]); 824 SPL_X(s); 825 return error; 826} 827 828 829/* ------------------------------------------------------------------------ */ 830/* Function: ipf_log_clear */ 831/* Returns: int - number of log bytes cleared. */ 832/* Parameters: softc(I) - pointer to main soft context */ 833/* unit(I) - device we are reading from */ 834/* */ 835/* Deletes all queued up log records for a given output device. */ 836/* ------------------------------------------------------------------------ */ 837int 838ipf_log_clear(softc, unit) 839 ipf_main_softc_t *softc; 840 minor_t unit; 841{ 842 ipf_log_softc_t *softl = softc->ipf_log_soft; 843 iplog_t *ipl; 844 int used; 845 SPL_INT(s); 846 847 SPL_NET(s); 848 MUTEX_ENTER(&softl->ipl_mutex[unit]); 849 while ((ipl = softl->iplt[unit]) != NULL) { 850 softl->iplt[unit] = ipl->ipl_next; 851 KFREES((caddr_t)ipl, ipl->ipl_dsize); 852 } 853 softl->iplh[unit] = &softl->iplt[unit]; 854 softl->ipll[unit] = NULL; 855 used = softl->ipl_used[unit]; 856 softl->ipl_used[unit] = 0; 857 bzero((char *)&softl->ipl_crc[unit], FI_CSIZE); 858 MUTEX_EXIT(&softl->ipl_mutex[unit]); 859 SPL_X(s); 860 return used; 861} 862 863 864/* ------------------------------------------------------------------------ */ 865/* Function: ipf_log_canread */ 866/* Returns: int - 0 == no data to read, 1 = data present */ 867/* Parameters: softc(I) - pointer to main soft context */ 868/* unit(I) - device we are reading from */ 869/* */ 870/* Returns an indication of whether or not there is data present in the */ 871/* current buffer for the selected ipf device. */ 872/* ------------------------------------------------------------------------ */ 873int 874ipf_log_canread(softc, unit) 875 ipf_main_softc_t *softc; 876 int unit; 877{ 878 ipf_log_softc_t *softl = softc->ipf_log_soft; 879 880 return softl->iplt[unit] != NULL; 881} 882 883 884/* ------------------------------------------------------------------------ */ 885/* Function: ipf_log_canread */ 886/* Returns: int - 0 == no data to read, 1 = data present */ 887/* Parameters: softc(I) - pointer to main soft context */ 888/* unit(I) - device we are reading from */ 889/* */ 890/* Returns how many bytes are currently held in log buffers for the */ 891/* selected ipf device. */ 892/* ------------------------------------------------------------------------ */ 893int 894ipf_log_bytesused(softc, unit) 895 ipf_main_softc_t *softc; 896 int unit; 897{ 898 ipf_log_softc_t *softl = softc->ipf_log_soft; 899 900 if (softl == NULL) 901 return 0; 902 903 return softl->ipl_used[unit]; 904} 905 906 907/* ------------------------------------------------------------------------ */ 908/* Function: ipf_log_failures */ 909/* Returns: U_QUAD_T - number of log failures */ 910/* Parameters: softc(I) - pointer to main soft context */ 911/* unit(I) - device we are reading from */ 912/* */ 913/* Returns how many times we've tried to log a packet but failed to do so */ 914/* for the selected ipf device. */ 915/* ------------------------------------------------------------------------ */ 916u_long 917ipf_log_failures(softc, unit) 918 ipf_main_softc_t *softc; 919 int unit; 920{ 921 ipf_log_softc_t *softl = softc->ipf_log_soft; 922 923 if (softl == NULL) 924 return 0; 925 926 return softl->ipl_logfail[unit]; 927} 928 929 930/* ------------------------------------------------------------------------ */ 931/* Function: ipf_log_logok */ 932/* Returns: U_QUAD_T - number of packets logged */ 933/* Parameters: softc(I) - pointer to main soft context */ 934/* unit(I) - device we are reading from */ 935/* */ 936/* Returns how many times we've successfully logged a packet for the */ 937/* selected ipf device. */ 938/* ------------------------------------------------------------------------ */ 939u_long 940ipf_log_logok(softc, unit) 941 ipf_main_softc_t *softc; 942 int unit; 943{ 944 ipf_log_softc_t *softl = softc->ipf_log_soft; 945 946 if (softl == NULL) 947 return 0; 948 949 return softl->ipl_logok[unit]; 950} 951#endif /* IPFILTER_LOG */ 952