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