ip_auth.c revision 161356
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_auth.c 161356 2006-08-16 12:06:35Z guido $ */ 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 161356 2006-08-16 12:06:35Z guido $"; 124/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.13 2006/03/29 11:19:55 darrenr Exp $"; */ 125#endif 126 127 128#if SOLARIS && defined(_KERNEL) 129extern kcondvar_t ipfauthwait; 130extern struct pollhead iplpollhead[IPL_LOGSIZE]; 131#endif /* SOLARIS */ 132#if defined(linux) && defined(_KERNEL) 133wait_queue_head_t fr_authnext_linux; 134#endif 135 136int fr_authsize = FR_NUMAUTH; 137int fr_authused = 0; 138int fr_defaultauthage = 600; 139int fr_auth_lock = 0; 140int fr_auth_init = 0; 141fr_authstat_t fr_authstats; 142static frauth_t *fr_auth = NULL; 143mb_t **fr_authpkts = NULL; 144int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; 145frauthent_t *fae_list = NULL; 146frentry_t *ipauth = NULL, 147 *fr_authlist = NULL; 148 149 150int fr_authinit() 151{ 152 KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); 153 if (fr_auth != NULL) 154 bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); 155 else 156 return -1; 157 158 KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); 159 if (fr_authpkts != NULL) 160 bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 161 else 162 return -2; 163 164 MUTEX_INIT(&ipf_authmx, "ipf auth log mutex"); 165 RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock"); 166#if SOLARIS && defined(_KERNEL) 167 cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 168#endif 169#if defined(linux) && defined(_KERNEL) 170 init_waitqueue_head(&fr_authnext_linux); 171#endif 172 173 fr_auth_init = 1; 174 175 return 0; 176} 177 178 179/* 180 * Check if a packet has authorization. If the packet is found to match an 181 * authorization result and that would result in a feedback loop (i.e. it 182 * will end up returning FR_AUTH) then return FR_BLOCK instead. 183 */ 184frentry_t *fr_checkauth(fin, passp) 185fr_info_t *fin; 186u_32_t *passp; 187{ 188 frentry_t *fr; 189 frauth_t *fra; 190 u_32_t pass; 191 u_short id; 192 ip_t *ip; 193 int i; 194 195 if (fr_auth_lock || !fr_authused) 196 return NULL; 197 198 ip = fin->fin_ip; 199 id = ip->ip_id; 200 201 READ_ENTER(&ipf_auth); 202 for (i = fr_authstart; i != fr_authend; ) { 203 /* 204 * index becomes -2 only after an SIOCAUTHW. Check this in 205 * case the same packet gets sent again and it hasn't yet been 206 * auth'd. 207 */ 208 fra = fr_auth + i; 209 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 210 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 211 /* 212 * Avoid feedback loop. 213 */ 214 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 215 pass = FR_BLOCK; 216 /* 217 * Create a dummy rule for the stateful checking to 218 * use and return. Zero out any values we don't 219 * trust from userland! 220 */ 221 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 222 (fin->fin_flx & FI_FRAG))) { 223 KMALLOC(fr, frentry_t *); 224 if (fr) { 225 bcopy((char *)fra->fra_info.fin_fr, 226 (char *)fr, sizeof(*fr)); 227 fr->fr_grp = NULL; 228 fr->fr_ifa = fin->fin_ifp; 229 fr->fr_func = NULL; 230 fr->fr_ref = 1; 231 fr->fr_flags = pass; 232 fr->fr_ifas[1] = NULL; 233 fr->fr_ifas[2] = NULL; 234 fr->fr_ifas[3] = NULL; 235 } 236 } else 237 fr = fra->fra_info.fin_fr; 238 fin->fin_fr = fr; 239 RWLOCK_EXIT(&ipf_auth); 240 WRITE_ENTER(&ipf_auth); 241 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 242 fr->fr_next = fr_authlist; 243 fr_authlist = fr; 244 } 245 fr_authstats.fas_hits++; 246 fra->fra_index = -1; 247 fr_authused--; 248 if (i == fr_authstart) { 249 while (fra->fra_index == -1) { 250 i++; 251 fra++; 252 if (i == fr_authsize) { 253 i = 0; 254 fra = fr_auth; 255 } 256 fr_authstart = i; 257 if (i == fr_authend) 258 break; 259 } 260 if (fr_authstart == fr_authend) { 261 fr_authnext = 0; 262 fr_authstart = fr_authend = 0; 263 } 264 } 265 RWLOCK_EXIT(&ipf_auth); 266 if (passp != NULL) 267 *passp = pass; 268 ATOMIC_INC64(fr_authstats.fas_hits); 269 return fr; 270 } 271 i++; 272 if (i == fr_authsize) 273 i = 0; 274 } 275 fr_authstats.fas_miss++; 276 RWLOCK_EXIT(&ipf_auth); 277 ATOMIC_INC64(fr_authstats.fas_miss); 278 return NULL; 279} 280 281 282/* 283 * Check if we have room in the auth array to hold details for another packet. 284 * If we do, store it and wake up any user programs which are waiting to 285 * hear about these events. 286 */ 287int fr_newauth(m, fin) 288mb_t *m; 289fr_info_t *fin; 290{ 291#if defined(_KERNEL) && defined(MENTAT) 292 qpktinfo_t *qpi = fin->fin_qpi; 293#endif 294 frauth_t *fra; 295#if !defined(sparc) && !defined(m68k) 296 ip_t *ip; 297#endif 298 int i; 299 300 if (fr_auth_lock) 301 return 0; 302 303 WRITE_ENTER(&ipf_auth); 304 if (fr_authstart > fr_authend) { 305 fr_authstats.fas_nospace++; 306 RWLOCK_EXIT(&ipf_auth); 307 return 0; 308 } else { 309 if (fr_authused == fr_authsize) { 310 fr_authstats.fas_nospace++; 311 RWLOCK_EXIT(&ipf_auth); 312 return 0; 313 } 314 } 315 316 fr_authstats.fas_added++; 317 fr_authused++; 318 i = fr_authend++; 319 if (fr_authend == fr_authsize) 320 fr_authend = 0; 321 RWLOCK_EXIT(&ipf_auth); 322 323 fra = fr_auth + i; 324 fra->fra_index = i; 325 fra->fra_pass = fin->fin_fr->fr_flags; 326 fra->fra_age = fr_defaultauthage; 327 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 328#if !defined(sparc) && !defined(m68k) 329 /* 330 * No need to copyback here as we want to undo the changes, not keep 331 * them. 332 */ 333 ip = fin->fin_ip; 334# if defined(MENTAT) && defined(_KERNEL) 335 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 336# endif 337 { 338 register u_short bo; 339 340 bo = ip->ip_len; 341 ip->ip_len = htons(bo); 342 bo = ip->ip_off; 343 ip->ip_off = htons(bo); 344 } 345#endif 346#if SOLARIS && defined(_KERNEL) 347 COPYIFNAME(fin->fin_ifp, fra->fra_info.fin_ifname); 348 m->b_rptr -= qpi->qpi_off; 349 fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 350 fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ 351 fra->fra_m = *fin->fin_mp; 352 fra->fra_info.fin_mp = &fra->fra_m; 353 cv_signal(&ipfauthwait); 354 pollwakeup(&iplpollhead[IPL_LOGAUTH], POLLIN|POLLRDNORM); 355#else 356 fr_authpkts[i] = m; 357 WAKEUP(&fr_authnext,0); 358#endif 359 return 1; 360} 361 362 363int fr_auth_ioctl(data, cmd, mode) 364caddr_t data; 365ioctlcmd_t cmd; 366int mode; 367{ 368 frauth_t auth, *au = &auth, *fra; 369 int i, error = 0, len; 370 char *t; 371 mb_t *m; 372#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 373 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 374 struct ifqueue *ifq; 375 SPL_INT(s); 376#endif 377 378 switch (cmd) 379 { 380 case SIOCSTLCK : 381 if (!(mode & FWRITE)) { 382 error = EPERM; 383 break; 384 } 385 fr_lock(data, &fr_auth_lock); 386 break; 387 388 case SIOCATHST: 389 fr_authstats.fas_faelist = fae_list; 390 error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); 391 break; 392 393 case SIOCIPFFL: 394 SPL_NET(s); 395 WRITE_ENTER(&ipf_auth); 396 i = fr_authflush(); 397 RWLOCK_EXIT(&ipf_auth); 398 SPL_X(s); 399 error = copyoutptr((char *)&i, data, sizeof(i)); 400 break; 401 402 case SIOCAUTHW: 403fr_authioctlloop: 404 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 405 if (error != 0) 406 break; 407 READ_ENTER(&ipf_auth); 408 if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { 409 error = fr_outobj(data, &fr_auth[fr_authnext], 410 IPFOBJ_FRAUTH); 411 if (error != 0) 412 break; 413 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 414 /* 415 * Copy packet contents out to user space if 416 * requested. Bail on an error. 417 */ 418 m = fr_authpkts[fr_authnext]; 419 len = MSGDSIZE(m); 420 if (len > auth.fra_len) 421 len = auth.fra_len; 422 auth.fra_len = len; 423 for (t = auth.fra_buf; m && (len > 0); ) { 424 i = MIN(M_LEN(m), len); 425 error = copyoutptr(MTOD(m, char *), 426 &t, i); 427 len -= i; 428 t += i; 429 if (error != 0) 430 break; 431 m = m->m_next; 432 } 433 } 434 RWLOCK_EXIT(&ipf_auth); 435 if (error != 0) 436 break; 437 SPL_NET(s); 438 WRITE_ENTER(&ipf_auth); 439 fr_authnext++; 440 if (fr_authnext == fr_authsize) 441 fr_authnext = 0; 442 RWLOCK_EXIT(&ipf_auth); 443 SPL_X(s); 444 return 0; 445 } 446 RWLOCK_EXIT(&ipf_auth); 447 /* 448 * We exit ipf_global here because a program that enters in 449 * here will have a lock on it and goto sleep having this lock. 450 * If someone were to do an 'ipf -D' the system would then 451 * deadlock. The catch with releasing it here is that the 452 * caller of this function expects it to be held when we 453 * return so we have to reacquire it in here. 454 */ 455 RWLOCK_EXIT(&ipf_global); 456 457 MUTEX_ENTER(&ipf_authmx); 458#ifdef _KERNEL 459# if SOLARIS 460 error = 0; 461 if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) 462 error = EINTR; 463# else /* SOLARIS */ 464# ifdef __hpux 465 { 466 lock_t *l; 467 468 l = get_sleep_lock(&fr_authnext); 469 error = sleep(&fr_authnext, PZERO+1); 470 spinunlock(l); 471 } 472# else 473# ifdef __osf__ 474 error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, 475 &ipf_authmx, MS_LOCK_SIMPLE); 476# else 477 error = SLEEP(&fr_authnext, "fr_authnext"); 478# endif /* __osf__ */ 479# endif /* __hpux */ 480# endif /* SOLARIS */ 481#endif 482 MUTEX_EXIT(&ipf_authmx); 483 READ_ENTER(&ipf_global); 484 if (error == 0) 485 goto fr_authioctlloop; 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 error = 0; 497 if ((i < 0) || (i >= fr_authsize) || 498 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 499 RWLOCK_EXIT(&ipf_auth); 500 SPL_X(s); 501 return ESRCH; 502 } 503 m = fr_authpkts[i]; 504 fra->fra_index = -2; 505 fra->fra_pass = au->fra_pass; 506 fr_authpkts[i] = NULL; 507 RWLOCK_EXIT(&ipf_auth); 508#ifdef _KERNEL 509 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 510# ifdef MENTAT 511 error = ipf_inject(&fra->fra_info); 512 if (error != 0) { 513 FREE_MB_T(m); 514 error = ENOBUFS; 515 } 516# else /* MENTAT */ 517# if defined(linux) || defined(AIX) 518# else 519# if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199802) || \ 520 (defined(__OpenBSD__)) || \ 521 (defined(__sgi) && (IRIX >= 60500) || \ 522 (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) 523 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, 524 NULL); 525# else 526 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 527# endif 528# endif /* Linux */ 529# endif /* MENTAT */ 530 if (error != 0) 531 fr_authstats.fas_sendfail++; 532 else 533 fr_authstats.fas_sendok++; 534 } else if (m) { 535# ifdef MENTAT 536 error = ipf_inject(&fra->fra_info); 537 if (error != 0) { 538 FREE_MB_T(m); 539 error = ENOBUFS; 540 } 541# else /* MENTAT */ 542# if defined(linux) || defined(AIX) 543# else 544# if (__FreeBSD_version >= 501000) 545 netisr_dispatch(NETISR_IP, m); 546# else 547# if (IRIX >= 60516) 548 ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; 549# else 550 ifq = &ipintrq; 551# endif 552 if (IF_QFULL(ifq)) { 553 IF_DROP(ifq); 554 FREE_MB_T(m); 555 error = ENOBUFS; 556 } else { 557 IF_ENQUEUE(ifq, m); 558# if IRIX < 60500 559 schednetisr(NETISR_IP); 560# endif 561 } 562# endif 563# endif /* Linux */ 564# endif /* MENTAT */ 565 if (error != 0) 566 fr_authstats.fas_quefail++; 567 else 568 fr_authstats.fas_queok++; 569 } else 570 error = EINVAL; 571 /* 572 * If we experience an error which will result in the packet 573 * not being processed, make sure we advance to the next one. 574 */ 575 if (error == ENOBUFS) { 576 fr_authused--; 577 fra->fra_index = -1; 578 fra->fra_pass = 0; 579 if (i == fr_authstart) { 580 while (fra->fra_index == -1) { 581 i++; 582 if (i == fr_authsize) 583 i = 0; 584 fr_authstart = i; 585 if (i == fr_authend) 586 break; 587 } 588 if (fr_authstart == fr_authend) { 589 fr_authnext = 0; 590 fr_authstart = fr_authend = 0; 591 } 592 } 593 } 594#endif /* _KERNEL */ 595 SPL_X(s); 596 break; 597 598 default : 599 error = EINVAL; 600 break; 601 } 602 return error; 603} 604 605 606/* 607 * Free all network buffer memory used to keep saved packets. 608 */ 609void fr_authunload() 610{ 611 register int i; 612 register frauthent_t *fae, **faep; 613 frentry_t *fr, **frp; 614 mb_t *m; 615 616 if (fr_auth != NULL) { 617 KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); 618 fr_auth = NULL; 619 } 620 621 if (fr_authpkts != NULL) { 622 for (i = 0; i < fr_authsize; i++) { 623 m = fr_authpkts[i]; 624 if (m != NULL) { 625 FREE_MB_T(m); 626 fr_authpkts[i] = NULL; 627 } 628 } 629 KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 630 fr_authpkts = NULL; 631 } 632 633 faep = &fae_list; 634 while ((fae = *faep) != NULL) { 635 *faep = fae->fae_next; 636 KFREE(fae); 637 } 638 ipauth = NULL; 639 640 if (fr_authlist != NULL) { 641 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 642 if (fr->fr_ref == 1) { 643 *frp = fr->fr_next; 644 KFREE(fr); 645 } else 646 frp = &fr->fr_next; 647 } 648 } 649 650 if (fr_auth_init == 1) { 651# if SOLARIS && defined(_KERNEL) 652 cv_destroy(&ipfauthwait); 653# endif 654 MUTEX_DESTROY(&ipf_authmx); 655 RW_DESTROY(&ipf_auth); 656 657 fr_auth_init = 0; 658 } 659} 660 661 662/* 663 * Slowly expire held auth records. Timeouts are set 664 * in expectation of this being called twice per second. 665 */ 666void fr_authexpire() 667{ 668 register int i; 669 register frauth_t *fra; 670 register frauthent_t *fae, **faep; 671 register frentry_t *fr, **frp; 672 mb_t *m; 673 SPL_INT(s); 674 675 if (fr_auth_lock) 676 return; 677 678 SPL_NET(s); 679 WRITE_ENTER(&ipf_auth); 680 for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { 681 fra->fra_age--; 682 if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { 683 FREE_MB_T(m); 684 fr_authpkts[i] = NULL; 685 fr_auth[i].fra_index = -1; 686 fr_authstats.fas_expire++; 687 fr_authused--; 688 } 689 } 690 691 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 692 fae->fae_age--; 693 if (fae->fae_age == 0) { 694 *faep = fae->fae_next; 695 KFREE(fae); 696 fr_authstats.fas_expire++; 697 } else 698 faep = &fae->fae_next; 699 } 700 if (fae_list != NULL) 701 ipauth = &fae_list->fae_fr; 702 else 703 ipauth = NULL; 704 705 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 706 if (fr->fr_ref == 1) { 707 *frp = fr->fr_next; 708 KFREE(fr); 709 } else 710 frp = &fr->fr_next; 711 } 712 RWLOCK_EXIT(&ipf_auth); 713 SPL_X(s); 714} 715 716int fr_preauthcmd(cmd, fr, frptr) 717ioctlcmd_t cmd; 718frentry_t *fr, **frptr; 719{ 720 frauthent_t *fae, **faep; 721 int error = 0; 722 SPL_INT(s); 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 809 810int fr_auth_waiting() 811{ 812 return (fr_authnext != fr_authend) && fr_authpkts[fr_authnext]; 813} 814