1 /* 2 * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 */ 6 #if defined(KERNEL) || defined(_KERNEL) 7 # undef KERNEL 8 # undef _KERNEL 9 # define KERNEL 1 10 # define _KERNEL 1 11 #endif 12 #include <sys/errno.h> 13 #include <sys/types.h> 14 #include <sys/param.h> 15 #include <sys/time.h> 16 #include <sys/file.h> 17 #if !defined(_KERNEL) 18 # include <stdio.h> 19 # include <stdlib.h> 20 # include <string.h> 21 # define _KERNEL 22 # ifdef __OpenBSD__ 23 struct file; 24 # endif 25 # include <sys/uio.h> 26 # undef _KERNEL 27 #endif 28 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 29 # include <sys/filio.h> 30 # include <sys/fcntl.h> 31 #else 32 # include <sys/ioctl.h> 33 #endif 34 #if !defined(linux) 35 # include <sys/protosw.h> 36 #endif 37 #include <sys/socket.h> 38 #if defined(_KERNEL) 39 # include <sys/systm.h> 40 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 41 # include <sys/mbuf.h> 42 # endif 43 #endif 44 #if defined(__SVR4) || defined(__svr4__) 45 # include <sys/filio.h> 46 # include <sys/byteorder.h> 47 # ifdef _KERNEL 48 # include <sys/dditypes.h> 49 # endif 50 # include <sys/stream.h> 51 # include <sys/kmem.h> 52 #endif 53 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) 54 # include <sys/queue.h> 55 #endif 56 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 57 # include <machine/cpu.h> 58 #endif 59 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 60 # include <sys/proc.h> 61 #endif 62 #include <net/if.h> 63 #ifdef sun 64 # include <net/af.h> 65 #endif 66 #include <net/route.h> 67 #include <netinet/in.h> 68 #include <netinet/in_systm.h> 69 #include <netinet/ip.h> 70 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 71 # define KERNEL 72 # define _KERNEL 73 # define NOT_KERNEL 74 #endif 75 #if !defined(linux) 76 # include <netinet/ip_var.h> 77 #endif 78 #ifdef NOT_KERNEL 79 # undef _KERNEL 80 # undef KERNEL 81 #endif 82 #include <netinet/tcp.h> 83 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 84 extern struct ifqueue ipintrq; /* ip packet input queue */ 85 #else 86 # if !defined(__hpux) && !defined(linux) 87 # if __FreeBSD_version >= 300000 88 # include <net/if_var.h> 89 # if __FreeBSD_version >= 500042 90 # define IF_QFULL _IF_QFULL 91 # define IF_DROP _IF_DROP 92 # endif /* __FreeBSD_version >= 500042 */ 93 # endif 94 # include <netinet/in_var.h> 95 # include <netinet/tcp_fsm.h> 96 # endif 97 #endif 98 #include <netinet/udp.h> 99 #include <netinet/ip_icmp.h> 100 #include "netinet/ip_compat.h" 101 #include <netinet/tcpip.h> 102 #include "netinet/ip_fil.h" 103 #include "netinet/ip_auth.h" 104 #if !defined(MENTAT) && !defined(linux) 105 # include <net/netisr.h> 106 # ifdef __FreeBSD__ 107 # include <machine/cpufunc.h> 108 # endif 109 #endif 110 #if (__FreeBSD_version >= 300000) 111 # include <sys/malloc.h> 112 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 113 # include <sys/libkern.h> 114 # include <sys/systm.h> 115 # endif 116 #endif 117 /* END OF INCLUDES */ 118 119 #if !defined(lint) 120 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $"; 121 #endif 122 123 124 #if SOLARIS 125 extern kcondvar_t ipfauthwait; 126 #endif /* SOLARIS */ 127 #if defined(linux) && defined(_KERNEL) 128 wait_queue_head_t fr_authnext_linux; 129 #endif 130 131 int fr_authsize = FR_NUMAUTH; 132 int fr_authused = 0; 133 int fr_defaultauthage = 600; 134 int fr_auth_lock = 0; 135 int fr_auth_init = 0; 136 fr_authstat_t fr_authstats; 137 static frauth_t *fr_auth = NULL; 138 mb_t **fr_authpkts = NULL; 139 int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; 140 frauthent_t *fae_list = NULL; 141 frentry_t *ipauth = NULL, 142 *fr_authlist = NULL; 143 144 145 int fr_authinit() 146 { 147 KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); 148 if (fr_auth != NULL) 149 bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); 150 else 151 return -1; 152 153 KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); 154 if (fr_authpkts != NULL) 155 bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 156 else 157 return -2; 158 159 MUTEX_INIT(&ipf_authmx, "ipf auth log mutex"); 160 RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock"); 161 #if SOLARIS && defined(_KERNEL) 162 cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 163 #endif 164 #if defined(linux) && defined(_KERNEL) 165 init_waitqueue_head(&fr_authnext_linux); 166 #endif 167 168 fr_auth_init = 1; 169 170 return 0; 171 } 172 173 174 /* 175 * Check if a packet has authorization. If the packet is found to match an 176 * authorization result and that would result in a feedback loop (i.e. it 177 * will end up returning FR_AUTH) then return FR_BLOCK instead. 178 */ 179 frentry_t *fr_checkauth(fin, passp) 180 fr_info_t *fin; 181 u_32_t *passp; 182 { 183 frentry_t *fr; 184 frauth_t *fra; 185 u_32_t pass; 186 u_short id; 187 ip_t *ip; 188 int i; 189 190 if (fr_auth_lock || !fr_authused) 191 return NULL; 192 193 ip = fin->fin_ip; 194 id = ip->ip_id; 195 196 READ_ENTER(&ipf_auth); 197 for (i = fr_authstart; i != fr_authend; ) { 198 /* 199 * index becomes -2 only after an SIOCAUTHW. Check this in 200 * case the same packet gets sent again and it hasn't yet been 201 * auth'd. 202 */ 203 fra = fr_auth + i; 204 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 205 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 206 /* 207 * Avoid feedback loop. 208 */ 209 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 210 pass = FR_BLOCK; 211 /* 212 * Create a dummy rule for the stateful checking to 213 * use and return. Zero out any values we don't 214 * trust from userland! 215 */ 216 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 217 (fin->fin_flx & FI_FRAG))) { 218 KMALLOC(fr, frentry_t *); 219 if (fr) { 220 bcopy((char *)fra->fra_info.fin_fr, 221 (char *)fr, sizeof(*fr)); 222 fr->fr_grp = NULL; 223 fr->fr_ifa = fin->fin_ifp; 224 fr->fr_func = NULL; 225 fr->fr_ref = 1; 226 fr->fr_flags = pass; 227 fr->fr_ifas[1] = NULL; 228 fr->fr_ifas[2] = NULL; 229 fr->fr_ifas[3] = NULL; 230 } 231 } else 232 fr = fra->fra_info.fin_fr; 233 fin->fin_fr = fr; 234 RWLOCK_EXIT(&ipf_auth); 235 WRITE_ENTER(&ipf_auth); 236 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 237 fr->fr_next = fr_authlist; 238 fr_authlist = fr; 239 } 240 fr_authstats.fas_hits++; 241 fra->fra_index = -1; 242 fr_authused--; 243 if (i == fr_authstart) { 244 while (fra->fra_index == -1) { 245 i++; 246 fra++; 247 if (i == fr_authsize) { 248 i = 0; 249 fra = fr_auth; 250 } 251 fr_authstart = i; 252 if (i == fr_authend) 253 break; 254 } 255 if (fr_authstart == fr_authend) { 256 fr_authnext = 0; 257 fr_authstart = fr_authend = 0; 258 } 259 } 260 RWLOCK_EXIT(&ipf_auth); 261 if (passp != NULL) 262 *passp = pass; 263 ATOMIC_INC64(fr_authstats.fas_hits); 264 return fr; 265 } 266 i++; 267 if (i == fr_authsize) 268 i = 0; 269 } 270 fr_authstats.fas_miss++; 271 RWLOCK_EXIT(&ipf_auth); 272 ATOMIC_INC64(fr_authstats.fas_miss); 273 return NULL; 274 } 275 276 277 /* 278 * Check if we have room in the auth array to hold details for another packet. 279 * If we do, store it and wake up any user programs which are waiting to 280 * hear about these events. 281 */ 282 int fr_newauth(m, fin) 283 mb_t *m; 284 fr_info_t *fin; 285 { 286 #if defined(_KERNEL) && defined(MENTAT) 287 qpktinfo_t *qpi = fin->fin_qpi; 288 #endif 289 frauth_t *fra; 290 #if !defined(sparc) && !defined(m68k) 291 ip_t *ip; 292 #endif 293 int i; 294 295 if (fr_auth_lock) 296 return 0; 297 298 WRITE_ENTER(&ipf_auth); 299 if (fr_authstart > fr_authend) { 300 fr_authstats.fas_nospace++; 301 RWLOCK_EXIT(&ipf_auth); 302 return 0; 303 } else { 304 if (fr_authused == fr_authsize) { 305 fr_authstats.fas_nospace++; 306 RWLOCK_EXIT(&ipf_auth); 307 return 0; 308 } 309 } 310 311 fr_authstats.fas_added++; 312 fr_authused++; 313 i = fr_authend++; 314 if (fr_authend == fr_authsize) 315 fr_authend = 0; 316 RWLOCK_EXIT(&ipf_auth); 317 318 fra = fr_auth + i; 319 fra->fra_index = i; 320 fra->fra_pass = 0; 321 fra->fra_age = fr_defaultauthage; 322 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 323 #if !defined(sparc) && !defined(m68k) 324 /* 325 * No need to copyback here as we want to undo the changes, not keep 326 * them. 327 */ 328 ip = fin->fin_ip; 329 # if defined(MENTAT) && defined(_KERNEL) 330 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 331 # endif 332 { 333 register u_short bo; 334 335 bo = ip->ip_len; 336 ip->ip_len = htons(bo); 337 bo = ip->ip_off; 338 ip->ip_off = htons(bo); 339 } 340 #endif 341 #if SOLARIS && defined(_KERNEL) 342 m->b_rptr -= qpi->qpi_off; 343 fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 344 fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ 345 cv_signal(&ipfauthwait); 346 #else 347 # if defined(BSD) && !defined(sparc) && (BSD >= 199306) 348 if (!fin->fin_out) { 349 ip->ip_len = htons(ip->ip_len); 350 ip->ip_off = htons(ip->ip_off); 351 } 352 # endif 353 fr_authpkts[i] = m; 354 WAKEUP(&fr_authnext,0); 355 #endif 356 return 1; 357 } 358 359 360 int fr_auth_ioctl(data, cmd, mode) 361 caddr_t data; 362 ioctlcmd_t cmd; 363 int mode; 364 { 365 mb_t *m; 366 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 367 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 368 struct ifqueue *ifq; 369 SPL_INT(s); 370 #endif 371 frauth_t auth, *au = &auth, *fra; 372 int i, error = 0, len; 373 char *t; 374 375 switch (cmd) 376 { 377 case SIOCSTLCK : 378 if (!(mode & FWRITE)) { 379 error = EPERM; 380 break; 381 } 382 fr_lock(data, &fr_auth_lock); 383 break; 384 385 case SIOCATHST: 386 fr_authstats.fas_faelist = fae_list; 387 error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); 388 break; 389 390 case SIOCIPFFL: 391 SPL_NET(s); 392 WRITE_ENTER(&ipf_auth); 393 i = fr_authflush(); 394 RWLOCK_EXIT(&ipf_auth); 395 SPL_X(s); 396 error = copyoutptr((char *)&i, data, sizeof(i)); 397 break; 398 399 case SIOCAUTHW: 400 fr_authioctlloop: 401 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 402 READ_ENTER(&ipf_auth); 403 if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { 404 error = fr_outobj(data, &fr_auth[fr_authnext], 405 IPFOBJ_FRAUTH); 406 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 407 /* 408 * Copy packet contents out to user space if 409 * requested. Bail on an error. 410 */ 411 m = fr_authpkts[fr_authnext]; 412 len = MSGDSIZE(m); 413 if (len > auth.fra_len) 414 len = auth.fra_len; 415 auth.fra_len = len; 416 for (t = auth.fra_buf; m && (len > 0); ) { 417 i = MIN(M_LEN(m), len); 418 error = copyoutptr(MTOD(m, char *), 419 t, i); 420 len -= i; 421 t += i; 422 if (error != 0) 423 break; 424 } 425 } 426 RWLOCK_EXIT(&ipf_auth); 427 if (error != 0) 428 break; 429 SPL_NET(s); 430 WRITE_ENTER(&ipf_auth); 431 fr_authnext++; 432 if (fr_authnext == fr_authsize) 433 fr_authnext = 0; 434 RWLOCK_EXIT(&ipf_auth); 435 SPL_X(s); 436 return 0; 437 } 438 RWLOCK_EXIT(&ipf_auth); 439 /* 440 * We exit ipf_global here because a program that enters in 441 * here will have a lock on it and goto sleep having this lock. 442 * If someone were to do an 'ipf -D' the system would then 443 * deadlock. The catch with releasing it here is that the 444 * caller of this function expects it to be held when we 445 * return so we have to reacquire it in here. 446 */ 447 RWLOCK_EXIT(&ipf_global); 448 449 MUTEX_ENTER(&ipf_authmx); 450 #ifdef _KERNEL 451 # if SOLARIS 452 error = 0; 453 if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) 454 error = EINTR; 455 # else /* SOLARIS */ 456 # ifdef __hpux 457 { 458 lock_t *l; 459 460 l = get_sleep_lock(&fr_authnext); 461 error = sleep(&fr_authnext, PZERO+1); 462 spinunlock(l); 463 } 464 # else 465 # ifdef __osf__ 466 error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, 467 &ipf_authmx, MS_LOCK_SIMPLE); 468 # else 469 error = SLEEP(&fr_authnext, "fr_authnext"); 470 # endif /* __osf__ */ 471 # endif /* __hpux */ 472 # endif /* SOLARIS */ 473 #endif 474 MUTEX_EXIT(&ipf_authmx); 475 READ_ENTER(&ipf_global); 476 if (error == 0) { 477 READ_ENTER(&ipf_auth); 478 goto fr_authioctlloop; 479 } 480 break; 481 482 case SIOCAUTHR: 483 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 484 if (error != 0) 485 return error; 486 SPL_NET(s); 487 WRITE_ENTER(&ipf_auth); 488 i = au->fra_index; 489 fra = fr_auth + i; 490 if ((i < 0) || (i >= fr_authsize) || 491 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 492 RWLOCK_EXIT(&ipf_auth); 493 SPL_X(s); 494 return ESRCH; 495 } 496 m = fr_authpkts[i]; 497 fra->fra_index = -2; 498 fra->fra_pass = au->fra_pass; 499 fr_authpkts[i] = NULL; 500 RWLOCK_EXIT(&ipf_auth); 501 #ifdef _KERNEL 502 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 503 # ifdef MENTAT 504 error = !putq(fra->fra_q, m); 505 # else /* MENTAT */ 506 # if defined(linux) || defined(AIX) 507 # else 508 # if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ 509 (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \ 510 (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) 511 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, 512 NULL); 513 # else 514 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 515 # endif 516 # endif /* Linux */ 517 # endif /* MENTAT */ 518 if (error != 0) 519 fr_authstats.fas_sendfail++; 520 else 521 fr_authstats.fas_sendok++; 522 } else if (m) { 523 # ifdef MENTAT 524 error = !putq(fra->fra_q, m); 525 # else /* MENTAT */ 526 # if defined(linux) || defined(AIX) 527 # else 528 # if (__FreeBSD_version >= 501000) 529 netisr_dispatch(NETISR_IP, m); 530 # else 531 # if (IRIX >= 60516) 532 ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; 533 # else 534 ifq = &ipintrq; 535 # endif 536 if (IF_QFULL(ifq)) { 537 IF_DROP(ifq); 538 FREE_MB_T(m); 539 error = ENOBUFS; 540 } else { 541 IF_ENQUEUE(ifq, m); 542 # if IRIX < 60500 543 schednetisr(NETISR_IP); 544 # endif 545 } 546 # endif 547 # endif /* Linux */ 548 # endif /* MENTAT */ 549 if (error != 0) 550 fr_authstats.fas_quefail++; 551 else 552 fr_authstats.fas_queok++; 553 } else 554 error = EINVAL; 555 # ifdef MENTAT 556 if (error != 0) 557 error = EINVAL; 558 # else /* MENTAT */ 559 /* 560 * If we experience an error which will result in the packet 561 * not being processed, make sure we advance to the next one. 562 */ 563 if (error == ENOBUFS) { 564 fr_authused--; 565 fra->fra_index = -1; 566 fra->fra_pass = 0; 567 if (i == fr_authstart) { 568 while (fra->fra_index == -1) { 569 i++; 570 if (i == fr_authsize) 571 i = 0; 572 fr_authstart = i; 573 if (i == fr_authend) 574 break; 575 } 576 if (fr_authstart == fr_authend) { 577 fr_authnext = 0; 578 fr_authstart = fr_authend = 0; 579 } 580 } 581 } 582 # endif /* MENTAT */ 583 #endif /* _KERNEL */ 584 SPL_X(s); 585 break; 586 587 default : 588 error = EINVAL; 589 break; 590 } 591 return error; 592 } 593 594 595 /* 596 * Free all network buffer memory used to keep saved packets. 597 */ 598 void fr_authunload() 599 { 600 register int i; 601 register frauthent_t *fae, **faep; 602 frentry_t *fr, **frp; 603 mb_t *m; 604 605 if (fr_auth != NULL) { 606 KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); 607 fr_auth = NULL; 608 } 609 610 if (fr_authpkts != NULL) { 611 for (i = 0; i < fr_authsize; i++) { 612 m = fr_authpkts[i]; 613 if (m != NULL) { 614 FREE_MB_T(m); 615 fr_authpkts[i] = NULL; 616 } 617 } 618 KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 619 fr_authpkts = NULL; 620 } 621 622 faep = &fae_list; 623 while ((fae = *faep) != NULL) { 624 *faep = fae->fae_next; 625 KFREE(fae); 626 } 627 ipauth = NULL; 628 629 if (fr_authlist != NULL) { 630 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 631 if (fr->fr_ref == 1) { 632 *frp = fr->fr_next; 633 KFREE(fr); 634 } else 635 frp = &fr->fr_next; 636 } 637 } 638 639 if (fr_auth_init == 1) { 640 # if SOLARIS && defined(_KERNEL) 641 cv_destroy(&ipfauthwait); 642 # endif 643 MUTEX_DESTROY(&ipf_authmx); 644 RW_DESTROY(&ipf_auth); 645 646 fr_auth_init = 0; 647 } 648 } 649 650 651 /* 652 * Slowly expire held auth records. Timeouts are set 653 * in expectation of this being called twice per second. 654 */ 655 void fr_authexpire() 656 { 657 register int i; 658 register frauth_t *fra; 659 register frauthent_t *fae, **faep; 660 register frentry_t *fr, **frp; 661 mb_t *m; 662 SPL_INT(s); 663 664 if (fr_auth_lock) 665 return; 666 667 SPL_NET(s); 668 WRITE_ENTER(&ipf_auth); 669 for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { 670 fra->fra_age--; 671 if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { 672 FREE_MB_T(m); 673 fr_authpkts[i] = NULL; 674 fr_auth[i].fra_index = -1; 675 fr_authstats.fas_expire++; 676 fr_authused--; 677 } 678 } 679 680 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 681 fae->fae_age--; 682 if (fae->fae_age == 0) { 683 *faep = fae->fae_next; 684 KFREE(fae); 685 fr_authstats.fas_expire++; 686 } else 687 faep = &fae->fae_next; 688 } 689 if (fae_list != NULL) 690 ipauth = &fae_list->fae_fr; 691 else 692 ipauth = NULL; 693 694 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 695 if (fr->fr_ref == 1) { 696 *frp = fr->fr_next; 697 KFREE(fr); 698 } else 699 frp = &fr->fr_next; 700 } 701 RWLOCK_EXIT(&ipf_auth); 702 SPL_X(s); 703 } 704 705 int fr_preauthcmd(cmd, fr, frptr) 706 ioctlcmd_t cmd; 707 frentry_t *fr, **frptr; 708 { 709 frauthent_t *fae, **faep; 710 int error = 0; 711 SPL_INT(s); 712 713 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 714 return EIO; 715 716 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 717 if (&fae->fae_fr == fr) 718 break; 719 else 720 faep = &fae->fae_next; 721 } 722 723 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 724 if (fr == NULL || frptr == NULL) 725 error = EINVAL; 726 else if (fae == NULL) 727 error = ESRCH; 728 else { 729 SPL_NET(s); 730 WRITE_ENTER(&ipf_auth); 731 *faep = fae->fae_next; 732 if (ipauth == &fae->fae_fr) 733 ipauth = fae_list ? &fae_list->fae_fr : NULL; 734 RWLOCK_EXIT(&ipf_auth); 735 SPL_X(s); 736 737 KFREE(fae); 738 } 739 } else if (fr != NULL && frptr != NULL) { 740 KMALLOC(fae, frauthent_t *); 741 if (fae != NULL) { 742 bcopy((char *)fr, (char *)&fae->fae_fr, 743 sizeof(*fr)); 744 SPL_NET(s); 745 WRITE_ENTER(&ipf_auth); 746 fae->fae_age = fr_defaultauthage; 747 fae->fae_fr.fr_hits = 0; 748 fae->fae_fr.fr_next = *frptr; 749 *frptr = &fae->fae_fr; 750 fae->fae_next = *faep; 751 *faep = fae; 752 ipauth = &fae_list->fae_fr; 753 RWLOCK_EXIT(&ipf_auth); 754 SPL_X(s); 755 } else 756 error = ENOMEM; 757 } else 758 error = EINVAL; 759 return error; 760 } 761 762 763 /* 764 * Flush held packets. 765 * Must already be properly SPL'ed and Locked on &ipf_auth. 766 * 767 */ 768 int fr_authflush() 769 { 770 register int i, num_flushed; 771 mb_t *m; 772 773 if (fr_auth_lock) 774 return -1; 775 776 num_flushed = 0; 777 778 for (i = 0 ; i < fr_authsize; i++) { 779 m = fr_authpkts[i]; 780 if (m != NULL) { 781 FREE_MB_T(m); 782 fr_authpkts[i] = NULL; 783 fr_auth[i].fra_index = -1; 784 /* perhaps add & use a flush counter inst.*/ 785 fr_authstats.fas_expire++; 786 fr_authused--; 787 num_flushed++; 788 } 789 } 790 791 fr_authstart = 0; 792 fr_authend = 0; 793 fr_authnext = 0; 794 795 return num_flushed; 796 } 797