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