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