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