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