1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 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/file.h> 18 #if !defined(_KERNEL) && !defined(__KERNEL__) 19 # include <stdio.h> 20 # include <stdlib.h> 21 # include <string.h> 22 # define _KERNEL 23 # define KERNEL 24 # include <sys/uio.h> 25 # undef _KERNEL 26 # undef KERNEL 27 #else 28 # include <sys/systm.h> 29 # if !defined(__SVR4) 30 # include <sys/mbuf.h> 31 # endif 32 # include <sys/select.h> 33 # ifdef __FreeBSD__ 34 # include <sys/selinfo.h> 35 # endif 36 #endif 37 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 38 # include <sys/proc.h> 39 #endif 40 #if defined(_KERNEL) && defined(__FreeBSD__) 41 # include <sys/filio.h> 42 # include <sys/fcntl.h> 43 #else 44 # include <sys/ioctl.h> 45 #endif 46 #include <sys/time.h> 47 # include <sys/protosw.h> 48 #include <sys/socket.h> 49 #if defined(__SVR4) 50 # include <sys/filio.h> 51 # include <sys/byteorder.h> 52 # ifdef _KERNEL 53 # include <sys/dditypes.h> 54 # endif 55 # include <sys/stream.h> 56 # include <sys/kmem.h> 57 #endif 58 59 #include <net/if.h> 60 #ifdef sun 61 # include <net/af.h> 62 #endif 63 #include <netinet/in.h> 64 #include <netinet/in_systm.h> 65 #include <netinet/ip.h> 66 #include <netinet/tcp.h> 67 # include <netinet/ip_var.h> 68 # include <netinet/tcp_fsm.h> 69 #include <netinet/udp.h> 70 #include <netinet/ip_icmp.h> 71 #include "netinet/ip_compat.h" 72 #include <netinet/tcpip.h> 73 #include "netinet/ip_fil.h" 74 #include "netinet/ip_nat.h" 75 #include "netinet/ip_frag.h" 76 #include "netinet/ip_state.h" 77 #include "netinet/ip_proxy.h" 78 #include "netinet/ip_sync.h" 79 #ifdef USE_INET6 80 #include <netinet/icmp6.h> 81 #endif 82 #if defined(__FreeBSD__) 83 # include <sys/malloc.h> 84 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 85 # include <sys/libkern.h> 86 # include <sys/systm.h> 87 # endif 88 #endif 89 /* END OF INCLUDES */ 90 91 #if !defined(lint) 92 static const char rcsid[] = "@(#)$Id$"; 93 #endif 94 95 #define SYNC_STATETABSZ 256 96 #define SYNC_NATTABSZ 256 97 98 typedef struct ipf_sync_softc_s { 99 ipfmutex_t ipf_syncadd; 100 ipfmutex_t ipsl_mutex; 101 ipfrwlock_t ipf_syncstate; 102 ipfrwlock_t ipf_syncnat; 103 #if SOLARIS && defined(_KERNEL) 104 kcondvar_t ipslwait; 105 #endif 106 synclist_t **syncstatetab; 107 synclist_t **syncnattab; 108 synclogent_t *synclog; 109 syncupdent_t *syncupd; 110 u_int ipf_sync_num; 111 u_int ipf_sync_wrap; 112 u_int sl_idx; /* next available sync log entry */ 113 u_int su_idx; /* next available sync update entry */ 114 u_int sl_tail; /* next sync log entry to read */ 115 u_int su_tail; /* next sync update entry to read */ 116 int ipf_sync_log_sz; 117 int ipf_sync_nat_tab_sz; 118 int ipf_sync_state_tab_sz; 119 int ipf_sync_debug; 120 int ipf_sync_events; 121 u_32_t ipf_sync_lastwakeup; 122 int ipf_sync_wake_interval; 123 int ipf_sync_event_high_wm; 124 int ipf_sync_queue_high_wm; 125 int ipf_sync_inited; 126 } ipf_sync_softc_t; 127 128 static int ipf_sync_flush_table(ipf_sync_softc_t *, int, synclist_t **); 129 static void ipf_sync_wakeup(ipf_main_softc_t *); 130 static void ipf_sync_del(ipf_sync_softc_t *, synclist_t *); 131 static void ipf_sync_poll_wakeup(ipf_main_softc_t *); 132 static int ipf_sync_nat(ipf_main_softc_t *, synchdr_t *, void *); 133 static int ipf_sync_state(ipf_main_softc_t *, synchdr_t *, void *); 134 135 # if !defined(sparc) && !defined(__hppa) 136 void ipf_sync_tcporder(int, struct tcpdata *); 137 void ipf_sync_natorder(int, struct nat *); 138 void ipf_sync_storder(int, struct ipstate *); 139 # endif 140 141 142 void * 143 ipf_sync_soft_create(ipf_main_softc_t *softc) 144 { 145 ipf_sync_softc_t *softs; 146 147 KMALLOC(softs, ipf_sync_softc_t *); 148 if (softs == NULL) { 149 IPFERROR(110024); 150 return (NULL); 151 } 152 153 bzero((char *)softs, sizeof(*softs)); 154 155 softs->ipf_sync_log_sz = SYNCLOG_SZ; 156 softs->ipf_sync_nat_tab_sz = SYNC_STATETABSZ; 157 softs->ipf_sync_state_tab_sz = SYNC_STATETABSZ; 158 softs->ipf_sync_event_high_wm = SYNCLOG_SZ * 100 / 90; /* 90% */ 159 softs->ipf_sync_queue_high_wm = SYNCLOG_SZ * 100 / 90; /* 90% */ 160 161 return (softs); 162 } 163 164 165 /* ------------------------------------------------------------------------ */ 166 /* Function: ipf_sync_init */ 167 /* Returns: int - 0 == success, -1 == failure */ 168 /* Parameters: Nil */ 169 /* */ 170 /* Initialise all of the locks required for the sync code and initialise */ 171 /* any data structures, as required. */ 172 /* ------------------------------------------------------------------------ */ 173 int 174 ipf_sync_soft_init(ipf_main_softc_t *softc, void *arg) 175 { 176 ipf_sync_softc_t *softs = arg; 177 178 KMALLOCS(softs->synclog, synclogent_t *, 179 softs->ipf_sync_log_sz * sizeof(*softs->synclog)); 180 if (softs->synclog == NULL) 181 return (-1); 182 bzero((char *)softs->synclog, 183 softs->ipf_sync_log_sz * sizeof(*softs->synclog)); 184 185 KMALLOCS(softs->syncupd, syncupdent_t *, 186 softs->ipf_sync_log_sz * sizeof(*softs->syncupd)); 187 if (softs->syncupd == NULL) 188 return (-2); 189 bzero((char *)softs->syncupd, 190 softs->ipf_sync_log_sz * sizeof(*softs->syncupd)); 191 192 KMALLOCS(softs->syncstatetab, synclist_t **, 193 softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab)); 194 if (softs->syncstatetab == NULL) 195 return (-3); 196 bzero((char *)softs->syncstatetab, 197 softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab)); 198 199 KMALLOCS(softs->syncnattab, synclist_t **, 200 softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab)); 201 if (softs->syncnattab == NULL) 202 return (-3); 203 bzero((char *)softs->syncnattab, 204 softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab)); 205 206 softs->ipf_sync_num = 1; 207 softs->ipf_sync_wrap = 0; 208 softs->sl_idx = 0; 209 softs->su_idx = 0; 210 softs->sl_tail = 0; 211 softs->su_tail = 0; 212 softs->ipf_sync_events = 0; 213 softs->ipf_sync_lastwakeup = 0; 214 215 216 # if SOLARIS && defined(_KERNEL) 217 cv_init(&softs->ipslwait, "ipsl condvar", CV_DRIVER, NULL); 218 # endif 219 RWLOCK_INIT(&softs->ipf_syncstate, "add things to state sync table"); 220 RWLOCK_INIT(&softs->ipf_syncnat, "add things to nat sync table"); 221 MUTEX_INIT(&softs->ipf_syncadd, "add things to sync table"); 222 MUTEX_INIT(&softs->ipsl_mutex, "read ring lock"); 223 224 softs->ipf_sync_inited = 1; 225 226 return (0); 227 } 228 229 230 /* ------------------------------------------------------------------------ */ 231 /* Function: ipf_sync_unload */ 232 /* Returns: int - 0 == success, -1 == failure */ 233 /* Parameters: Nil */ 234 /* */ 235 /* Destroy the locks created when initialising and free any memory in use */ 236 /* with the synchronisation tables. */ 237 /* ------------------------------------------------------------------------ */ 238 int 239 ipf_sync_soft_fini(ipf_main_softc_t *softc, void *arg) 240 { 241 ipf_sync_softc_t *softs = arg; 242 243 if (softs->syncnattab != NULL) { 244 ipf_sync_flush_table(softs, softs->ipf_sync_nat_tab_sz, 245 softs->syncnattab); 246 KFREES(softs->syncnattab, 247 softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab)); 248 softs->syncnattab = NULL; 249 } 250 251 if (softs->syncstatetab != NULL) { 252 ipf_sync_flush_table(softs, softs->ipf_sync_state_tab_sz, 253 softs->syncstatetab); 254 KFREES(softs->syncstatetab, 255 softs->ipf_sync_state_tab_sz * 256 sizeof(*softs->syncstatetab)); 257 softs->syncstatetab = NULL; 258 } 259 260 if (softs->syncupd != NULL) { 261 KFREES(softs->syncupd, 262 softs->ipf_sync_log_sz * sizeof(*softs->syncupd)); 263 softs->syncupd = NULL; 264 } 265 266 if (softs->synclog != NULL) { 267 KFREES(softs->synclog, 268 softs->ipf_sync_log_sz * sizeof(*softs->synclog)); 269 softs->synclog = NULL; 270 } 271 272 if (softs->ipf_sync_inited == 1) { 273 MUTEX_DESTROY(&softs->ipsl_mutex); 274 MUTEX_DESTROY(&softs->ipf_syncadd); 275 RW_DESTROY(&softs->ipf_syncnat); 276 RW_DESTROY(&softs->ipf_syncstate); 277 softs->ipf_sync_inited = 0; 278 } 279 280 return (0); 281 } 282 283 void 284 ipf_sync_soft_destroy(ipf_main_softc_t *softc, void *arg) 285 { 286 ipf_sync_softc_t *softs = arg; 287 288 KFREE(softs); 289 } 290 291 292 # if !defined(sparc) 293 /* ------------------------------------------------------------------------ */ 294 /* Function: ipf_sync_tcporder */ 295 /* Returns: Nil */ 296 /* Parameters: way(I) - direction of byte order conversion. */ 297 /* td(IO) - pointer to data to be converted. */ 298 /* */ 299 /* Do byte swapping on values in the TCP state information structure that */ 300 /* need to be used at both ends by the host in their native byte order. */ 301 /* ------------------------------------------------------------------------ */ 302 void 303 ipf_sync_tcporder(int way, tcpdata_t *td) 304 { 305 if (way) { 306 td->td_maxwin = htons(td->td_maxwin); 307 td->td_end = htonl(td->td_end); 308 td->td_maxend = htonl(td->td_maxend); 309 } else { 310 td->td_maxwin = ntohs(td->td_maxwin); 311 td->td_end = ntohl(td->td_end); 312 td->td_maxend = ntohl(td->td_maxend); 313 } 314 } 315 316 317 /* ------------------------------------------------------------------------ */ 318 /* Function: ipf_sync_natorder */ 319 /* Returns: Nil */ 320 /* Parameters: way(I) - direction of byte order conversion. */ 321 /* nat(IO) - pointer to data to be converted. */ 322 /* */ 323 /* Do byte swapping on values in the NAT data structure that need to be */ 324 /* used at both ends by the host in their native byte order. */ 325 /* ------------------------------------------------------------------------ */ 326 void 327 ipf_sync_natorder(int way, nat_t *n) 328 { 329 if (way) { 330 n->nat_age = htonl(n->nat_age); 331 n->nat_flags = htonl(n->nat_flags); 332 n->nat_ipsumd = htonl(n->nat_ipsumd); 333 n->nat_use = htonl(n->nat_use); 334 n->nat_dir = htonl(n->nat_dir); 335 } else { 336 n->nat_age = ntohl(n->nat_age); 337 n->nat_flags = ntohl(n->nat_flags); 338 n->nat_ipsumd = ntohl(n->nat_ipsumd); 339 n->nat_use = ntohl(n->nat_use); 340 n->nat_dir = ntohl(n->nat_dir); 341 } 342 } 343 344 345 /* ------------------------------------------------------------------------ */ 346 /* Function: ipf_sync_storder */ 347 /* Returns: Nil */ 348 /* Parameters: way(I) - direction of byte order conversion. */ 349 /* ips(IO) - pointer to data to be converted. */ 350 /* */ 351 /* Do byte swapping on values in the IP state data structure that need to */ 352 /* be used at both ends by the host in their native byte order. */ 353 /* ------------------------------------------------------------------------ */ 354 void 355 ipf_sync_storder(int way, ipstate_t *ips) 356 { 357 ipf_sync_tcporder(way, &ips->is_tcp.ts_data[0]); 358 ipf_sync_tcporder(way, &ips->is_tcp.ts_data[1]); 359 360 if (way) { 361 ips->is_hv = htonl(ips->is_hv); 362 ips->is_die = htonl(ips->is_die); 363 ips->is_pass = htonl(ips->is_pass); 364 ips->is_flags = htonl(ips->is_flags); 365 ips->is_opt[0] = htonl(ips->is_opt[0]); 366 ips->is_opt[1] = htonl(ips->is_opt[1]); 367 ips->is_optmsk[0] = htonl(ips->is_optmsk[0]); 368 ips->is_optmsk[1] = htonl(ips->is_optmsk[1]); 369 ips->is_sec = htons(ips->is_sec); 370 ips->is_secmsk = htons(ips->is_secmsk); 371 ips->is_auth = htons(ips->is_auth); 372 ips->is_authmsk = htons(ips->is_authmsk); 373 ips->is_s0[0] = htonl(ips->is_s0[0]); 374 ips->is_s0[1] = htonl(ips->is_s0[1]); 375 ips->is_smsk[0] = htons(ips->is_smsk[0]); 376 ips->is_smsk[1] = htons(ips->is_smsk[1]); 377 } else { 378 ips->is_hv = ntohl(ips->is_hv); 379 ips->is_die = ntohl(ips->is_die); 380 ips->is_pass = ntohl(ips->is_pass); 381 ips->is_flags = ntohl(ips->is_flags); 382 ips->is_opt[0] = ntohl(ips->is_opt[0]); 383 ips->is_opt[1] = ntohl(ips->is_opt[1]); 384 ips->is_optmsk[0] = ntohl(ips->is_optmsk[0]); 385 ips->is_optmsk[1] = ntohl(ips->is_optmsk[1]); 386 ips->is_sec = ntohs(ips->is_sec); 387 ips->is_secmsk = ntohs(ips->is_secmsk); 388 ips->is_auth = ntohs(ips->is_auth); 389 ips->is_authmsk = ntohs(ips->is_authmsk); 390 ips->is_s0[0] = ntohl(ips->is_s0[0]); 391 ips->is_s0[1] = ntohl(ips->is_s0[1]); 392 ips->is_smsk[0] = ntohl(ips->is_smsk[0]); 393 ips->is_smsk[1] = ntohl(ips->is_smsk[1]); 394 } 395 } 396 # else /* !defined(sparc) */ 397 # define ipf_sync_tcporder(x,y) 398 # define ipf_sync_natorder(x,y) 399 # define ipf_sync_storder(x,y) 400 # endif /* !defined(sparc) */ 401 402 403 /* ------------------------------------------------------------------------ */ 404 /* Function: ipf_sync_write */ 405 /* Returns: int - 0 == success, else error value. */ 406 /* Parameters: uio(I) - pointer to information about data to write */ 407 /* */ 408 /* Moves data from user space into the kernel and uses it for updating data */ 409 /* structures in the state/NAT tables. */ 410 /* ------------------------------------------------------------------------ */ 411 int 412 ipf_sync_write(ipf_main_softc_t *softc, struct uio *uio) 413 { 414 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 415 synchdr_t sh; 416 417 /* 418 * THIS MUST BE SUFFICIENT LARGE TO STORE 419 * ANY POSSIBLE DATA TYPE 420 */ 421 char data[2048]; 422 423 int err = 0; 424 425 # if defined(__NetBSD__) || defined(__FreeBSD__) 426 uio->uio_rw = UIO_WRITE; 427 # endif 428 429 /* Try to get bytes */ 430 while (uio->uio_resid > 0) { 431 432 if (uio->uio_resid >= sizeof(sh)) { 433 434 err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio); 435 436 if (err) { 437 if (softs->ipf_sync_debug > 2) 438 printf("uiomove(header) failed: %d\n", 439 err); 440 return (err); 441 } 442 443 /* convert to host order */ 444 sh.sm_magic = ntohl(sh.sm_magic); 445 sh.sm_len = ntohl(sh.sm_len); 446 sh.sm_num = ntohl(sh.sm_num); 447 448 if (softs->ipf_sync_debug > 8) 449 printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n", 450 sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd, 451 sh.sm_table, sh.sm_rev, sh.sm_len, 452 sh.sm_magic); 453 454 if (sh.sm_magic != SYNHDRMAGIC) { 455 if (softs->ipf_sync_debug > 2) 456 printf("uiomove(header) invalid %s\n", 457 "magic"); 458 IPFERROR(110001); 459 return (EINVAL); 460 } 461 462 if (sh.sm_v != 4 && sh.sm_v != 6) { 463 if (softs->ipf_sync_debug > 2) 464 printf("uiomove(header) invalid %s\n", 465 "protocol"); 466 IPFERROR(110002); 467 return (EINVAL); 468 } 469 470 if (sh.sm_cmd > SMC_MAXCMD) { 471 if (softs->ipf_sync_debug > 2) 472 printf("uiomove(header) invalid %s\n", 473 "command"); 474 IPFERROR(110003); 475 return (EINVAL); 476 } 477 478 479 if (sh.sm_table > SMC_MAXTBL) { 480 if (softs->ipf_sync_debug > 2) 481 printf("uiomove(header) invalid %s\n", 482 "table"); 483 IPFERROR(110004); 484 return (EINVAL); 485 } 486 487 } else { 488 /* unsufficient data, wait until next call */ 489 if (softs->ipf_sync_debug > 2) 490 printf("uiomove(header) insufficient data"); 491 IPFERROR(110005); 492 return (EAGAIN); 493 } 494 495 496 /* 497 * We have a header, so try to read the amount of data 498 * needed for the request 499 */ 500 501 /* not supported */ 502 if (sh.sm_len == 0) { 503 if (softs->ipf_sync_debug > 2) 504 printf("uiomove(data zero length %s\n", 505 "not supported"); 506 IPFERROR(110006); 507 return (EINVAL); 508 } 509 510 if (uio->uio_resid >= sh.sm_len) { 511 512 err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio); 513 514 if (err) { 515 if (softs->ipf_sync_debug > 2) 516 printf("uiomove(data) failed: %d\n", 517 err); 518 return (err); 519 } 520 521 if (softs->ipf_sync_debug > 7) 522 printf("uiomove(data) %d bytes read\n", 523 sh.sm_len); 524 525 if (sh.sm_table == SMC_STATE) 526 err = ipf_sync_state(softc, &sh, data); 527 else if (sh.sm_table == SMC_NAT) 528 err = ipf_sync_nat(softc, &sh, data); 529 if (softs->ipf_sync_debug > 7) 530 printf("[%d] Finished with error %d\n", 531 sh.sm_num, err); 532 533 } else { 534 /* insufficient data, wait until next call */ 535 if (softs->ipf_sync_debug > 2) 536 printf("uiomove(data) %s %d bytes, got %d\n", 537 "insufficient data, need", 538 sh.sm_len, (int)uio->uio_resid); 539 IPFERROR(110007); 540 return (EAGAIN); 541 } 542 } 543 544 /* no more data */ 545 return (0); 546 } 547 548 549 /* ------------------------------------------------------------------------ */ 550 /* Function: ipf_sync_read */ 551 /* Returns: int - 0 == success, else error value. */ 552 /* Parameters: uio(O) - pointer to information about where to store data */ 553 /* */ 554 /* This function is called when a user program wants to read some data */ 555 /* for pending state/NAT updates. If no data is available, the caller is */ 556 /* put to sleep, pending a wakeup from the "lower half" of this code. */ 557 /* ------------------------------------------------------------------------ */ 558 int 559 ipf_sync_read(ipf_main_softc_t *softc, struct uio *uio) 560 { 561 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 562 syncupdent_t *su; 563 synclogent_t *sl; 564 int err = 0; 565 566 if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) { 567 IPFERROR(110008); 568 return (EINVAL); 569 } 570 571 # if defined(__NetBSD__) || defined(__FreeBSD__) 572 uio->uio_rw = UIO_READ; 573 # endif 574 575 MUTEX_ENTER(&softs->ipsl_mutex); 576 while ((softs->sl_tail == softs->sl_idx) && 577 (softs->su_tail == softs->su_idx)) { 578 # if defined(_KERNEL) 579 # if SOLARIS 580 if (!cv_wait_sig(&softs->ipslwait, &softs->ipsl_mutex.ipf_lk)) { 581 MUTEX_EXIT(&softs->ipsl_mutex); 582 IPFERROR(110009); 583 return (EINTR); 584 } 585 # else 586 MUTEX_EXIT(&softs->ipsl_mutex); 587 err = SLEEP(&softs->sl_tail, "ipl sleep"); 588 if (err) { 589 IPFERROR(110012); 590 return (EINTR); 591 } 592 MUTEX_ENTER(&softs->ipsl_mutex); 593 # endif /* SOLARIS */ 594 # endif /* _KERNEL */ 595 } 596 597 while ((softs->sl_tail < softs->sl_idx) && 598 (uio->uio_resid > sizeof(*sl))) { 599 sl = softs->synclog + softs->sl_tail++; 600 MUTEX_EXIT(&softs->ipsl_mutex); 601 err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio); 602 if (err != 0) 603 goto goterror; 604 MUTEX_ENTER(&softs->ipsl_mutex); 605 } 606 607 while ((softs->su_tail < softs->su_idx) && 608 (uio->uio_resid > sizeof(*su))) { 609 su = softs->syncupd + softs->su_tail; 610 softs->su_tail++; 611 MUTEX_EXIT(&softs->ipsl_mutex); 612 err = UIOMOVE(su, sizeof(*su), UIO_READ, uio); 613 if (err != 0) 614 goto goterror; 615 MUTEX_ENTER(&softs->ipsl_mutex); 616 if (su->sup_hdr.sm_sl != NULL) 617 su->sup_hdr.sm_sl->sl_idx = -1; 618 } 619 if (softs->sl_tail == softs->sl_idx) 620 softs->sl_tail = softs->sl_idx = 0; 621 if (softs->su_tail == softs->su_idx) 622 softs->su_tail = softs->su_idx = 0; 623 MUTEX_EXIT(&softs->ipsl_mutex); 624 goterror: 625 return (err); 626 } 627 628 629 /* ------------------------------------------------------------------------ */ 630 /* Function: ipf_sync_state */ 631 /* Returns: int - 0 == success, else error value. */ 632 /* Parameters: sp(I) - pointer to sync packet data header */ 633 /* uio(I) - pointer to user data for further information */ 634 /* */ 635 /* Updates the state table according to information passed in the sync */ 636 /* header. As required, more data is fetched from the uio structure but */ 637 /* varies depending on the contents of the sync header. This function can */ 638 /* create a new state entry or update one. Deletion is left to the state */ 639 /* structures being timed out correctly. */ 640 /* ------------------------------------------------------------------------ */ 641 static int 642 ipf_sync_state(ipf_main_softc_t *softc, synchdr_t *sp, void *data) 643 { 644 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 645 synctcp_update_t su; 646 ipstate_t *is, sn; 647 synclist_t *sl; 648 frentry_t *fr; 649 u_int hv; 650 int err = 0; 651 652 hv = sp->sm_num & (softs->ipf_sync_state_tab_sz - 1); 653 654 switch (sp->sm_cmd) 655 { 656 case SMC_CREATE : 657 658 bcopy(data, &sn, sizeof(sn)); 659 KMALLOC(is, ipstate_t *); 660 if (is == NULL) { 661 IPFERROR(110013); 662 err = ENOMEM; 663 break; 664 } 665 666 KMALLOC(sl, synclist_t *); 667 if (sl == NULL) { 668 IPFERROR(110014); 669 err = ENOMEM; 670 KFREE(is); 671 break; 672 } 673 674 bzero((char *)is, offsetof(ipstate_t, is_die)); 675 bcopy((char *)&sn.is_die, (char *)&is->is_die, 676 sizeof(*is) - offsetof(ipstate_t, is_die)); 677 ipf_sync_storder(0, is); 678 679 /* 680 * We need to find the same rule on the slave as was used on 681 * the master to create this state entry. 682 */ 683 READ_ENTER(&softc->ipf_mutex); 684 fr = ipf_getrulen(softc, IPL_LOGIPF, sn.is_group, sn.is_rulen); 685 if (fr != NULL) { 686 MUTEX_ENTER(&fr->fr_lock); 687 fr->fr_ref++; 688 fr->fr_statecnt++; 689 MUTEX_EXIT(&fr->fr_lock); 690 } 691 RWLOCK_EXIT(&softc->ipf_mutex); 692 693 if (softs->ipf_sync_debug > 4) 694 printf("[%d] Filter rules = %p\n", sp->sm_num, fr); 695 696 is->is_rule = fr; 697 is->is_sync = sl; 698 699 sl->sl_idx = -1; 700 sl->sl_ips = is; 701 bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr)); 702 703 WRITE_ENTER(&softs->ipf_syncstate); 704 WRITE_ENTER(&softc->ipf_state); 705 706 sl->sl_pnext = softs->syncstatetab + hv; 707 sl->sl_next = softs->syncstatetab[hv]; 708 if (softs->syncstatetab[hv] != NULL) 709 softs->syncstatetab[hv]->sl_pnext = &sl->sl_next; 710 softs->syncstatetab[hv] = sl; 711 MUTEX_DOWNGRADE(&softs->ipf_syncstate); 712 ipf_state_insert(softc, is, sp->sm_rev); 713 /* 714 * Do not initialise the interface pointers for the state 715 * entry as the full complement of interface names may not 716 * be present. 717 * 718 * Put this state entry on its timeout queue. 719 */ 720 /*fr_setstatequeue(is, sp->sm_rev);*/ 721 break; 722 723 case SMC_UPDATE : 724 bcopy(data, &su, sizeof(su)); 725 726 if (softs->ipf_sync_debug > 4) 727 printf("[%d] Update age %lu state %d/%d \n", 728 sp->sm_num, su.stu_age, su.stu_state[0], 729 su.stu_state[1]); 730 731 READ_ENTER(&softs->ipf_syncstate); 732 for (sl = softs->syncstatetab[hv]; (sl != NULL); 733 sl = sl->sl_next) 734 if (sl->sl_hdr.sm_num == sp->sm_num) 735 break; 736 if (sl == NULL) { 737 if (softs->ipf_sync_debug > 1) 738 printf("[%d] State not found - can't update\n", 739 sp->sm_num); 740 RWLOCK_EXIT(&softs->ipf_syncstate); 741 IPFERROR(110015); 742 err = ENOENT; 743 break; 744 } 745 746 READ_ENTER(&softc->ipf_state); 747 748 if (softs->ipf_sync_debug > 6) 749 printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n", 750 sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p, 751 sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table, 752 sl->sl_hdr.sm_rev); 753 754 is = sl->sl_ips; 755 756 MUTEX_ENTER(&is->is_lock); 757 switch (sp->sm_p) 758 { 759 case IPPROTO_TCP : 760 /* XXX FV --- shouldn't we do ntohl/htonl???? XXX */ 761 is->is_send = su.stu_data[0].td_end; 762 is->is_maxsend = su.stu_data[0].td_maxend; 763 is->is_maxswin = su.stu_data[0].td_maxwin; 764 is->is_state[0] = su.stu_state[0]; 765 is->is_dend = su.stu_data[1].td_end; 766 is->is_maxdend = su.stu_data[1].td_maxend; 767 is->is_maxdwin = su.stu_data[1].td_maxwin; 768 is->is_state[1] = su.stu_state[1]; 769 break; 770 default : 771 break; 772 } 773 774 if (softs->ipf_sync_debug > 6) 775 printf("[%d] Setting timers for state\n", sp->sm_num); 776 777 ipf_state_setqueue(softc, is, sp->sm_rev); 778 779 MUTEX_EXIT(&is->is_lock); 780 break; 781 782 default : 783 IPFERROR(110016); 784 err = EINVAL; 785 break; 786 } 787 788 if (err == 0) { 789 RWLOCK_EXIT(&softc->ipf_state); 790 RWLOCK_EXIT(&softs->ipf_syncstate); 791 } 792 793 if (softs->ipf_sync_debug > 6) 794 printf("[%d] Update completed with error %d\n", 795 sp->sm_num, err); 796 797 return (err); 798 } 799 800 801 /* ------------------------------------------------------------------------ */ 802 /* Function: ipf_sync_del */ 803 /* Returns: Nil */ 804 /* Parameters: sl(I) - pointer to synclist object to delete */ 805 /* */ 806 /* Deletes an object from the synclist. */ 807 /* ------------------------------------------------------------------------ */ 808 static void 809 ipf_sync_del(ipf_sync_softc_t *softs, synclist_t *sl) 810 { 811 *sl->sl_pnext = sl->sl_next; 812 if (sl->sl_next != NULL) 813 sl->sl_next->sl_pnext = sl->sl_pnext; 814 if (sl->sl_idx != -1) 815 softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL; 816 } 817 818 819 /* ------------------------------------------------------------------------ */ 820 /* Function: ipf_sync_del_state */ 821 /* Returns: Nil */ 822 /* Parameters: sl(I) - pointer to synclist object to delete */ 823 /* */ 824 /* Deletes an object from the synclist state table and free's its memory. */ 825 /* ------------------------------------------------------------------------ */ 826 void 827 ipf_sync_del_state(void *arg, synclist_t *sl) 828 { 829 ipf_sync_softc_t *softs = arg; 830 831 WRITE_ENTER(&softs->ipf_syncstate); 832 ipf_sync_del(softs, sl); 833 RWLOCK_EXIT(&softs->ipf_syncstate); 834 KFREE(sl); 835 } 836 837 838 /* ------------------------------------------------------------------------ */ 839 /* Function: ipf_sync_del_nat */ 840 /* Returns: Nil */ 841 /* Parameters: sl(I) - pointer to synclist object to delete */ 842 /* */ 843 /* Deletes an object from the synclist nat table and free's its memory. */ 844 /* ------------------------------------------------------------------------ */ 845 void 846 ipf_sync_del_nat(void *arg, synclist_t *sl) 847 { 848 ipf_sync_softc_t *softs = arg; 849 850 WRITE_ENTER(&softs->ipf_syncnat); 851 ipf_sync_del(softs, sl); 852 RWLOCK_EXIT(&softs->ipf_syncnat); 853 KFREE(sl); 854 } 855 856 857 /* ------------------------------------------------------------------------ */ 858 /* Function: ipf_sync_nat */ 859 /* Returns: int - 0 == success, else error value. */ 860 /* Parameters: sp(I) - pointer to sync packet data header */ 861 /* uio(I) - pointer to user data for further information */ 862 /* */ 863 /* Updates the NAT table according to information passed in the sync */ 864 /* header. As required, more data is fetched from the uio structure but */ 865 /* varies depending on the contents of the sync header. This function can */ 866 /* create a new NAT entry or update one. Deletion is left to the NAT */ 867 /* structures being timed out correctly. */ 868 /* ------------------------------------------------------------------------ */ 869 static int 870 ipf_sync_nat(ipf_main_softc_t *softc, synchdr_t *sp, void *data) 871 { 872 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 873 syncupdent_t su; 874 nat_t *n, *nat; 875 synclist_t *sl; 876 u_int hv = 0; 877 int err = 0; 878 879 READ_ENTER(&softs->ipf_syncnat); 880 881 switch (sp->sm_cmd) 882 { 883 case SMC_CREATE : 884 KMALLOC(n, nat_t *); 885 if (n == NULL) { 886 IPFERROR(110017); 887 err = ENOMEM; 888 break; 889 } 890 891 KMALLOC(sl, synclist_t *); 892 if (sl == NULL) { 893 IPFERROR(110018); 894 err = ENOMEM; 895 KFREE(n); 896 break; 897 } 898 899 nat = (nat_t *)data; 900 bzero((char *)n, offsetof(nat_t, nat_age)); 901 bcopy((char *)&nat->nat_age, (char *)&n->nat_age, 902 sizeof(*n) - offsetof(nat_t, nat_age)); 903 ipf_sync_natorder(0, n); 904 n->nat_sync = sl; 905 n->nat_rev = sl->sl_rev; 906 907 sl->sl_idx = -1; 908 sl->sl_ipn = n; 909 sl->sl_num = ntohl(sp->sm_num); 910 911 WRITE_ENTER(&softc->ipf_nat); 912 sl->sl_pnext = softs->syncnattab + hv; 913 sl->sl_next = softs->syncnattab[hv]; 914 if (softs->syncnattab[hv] != NULL) 915 softs->syncnattab[hv]->sl_pnext = &sl->sl_next; 916 softs->syncnattab[hv] = sl; 917 (void) ipf_nat_insert(softc, softc->ipf_nat_soft, n); 918 RWLOCK_EXIT(&softc->ipf_nat); 919 break; 920 921 case SMC_UPDATE : 922 bcopy(data, &su, sizeof(su)); 923 924 for (sl = softs->syncnattab[hv]; (sl != NULL); 925 sl = sl->sl_next) 926 if (sl->sl_hdr.sm_num == sp->sm_num) 927 break; 928 if (sl == NULL) { 929 IPFERROR(110019); 930 err = ENOENT; 931 break; 932 } 933 934 READ_ENTER(&softc->ipf_nat); 935 936 nat = sl->sl_ipn; 937 nat->nat_rev = sl->sl_rev; 938 939 MUTEX_ENTER(&nat->nat_lock); 940 ipf_nat_setqueue(softc, softc->ipf_nat_soft, nat); 941 MUTEX_EXIT(&nat->nat_lock); 942 943 RWLOCK_EXIT(&softc->ipf_nat); 944 945 break; 946 947 default : 948 IPFERROR(110020); 949 err = EINVAL; 950 break; 951 } 952 953 RWLOCK_EXIT(&softs->ipf_syncnat); 954 return (err); 955 } 956 957 958 /* ------------------------------------------------------------------------ */ 959 /* Function: ipf_sync_new */ 960 /* Returns: synclist_t* - NULL == failure, else pointer to new synclist */ 961 /* data structure. */ 962 /* Parameters: tab(I) - type of synclist_t to create */ 963 /* fin(I) - pointer to packet information */ 964 /* ptr(I) - pointer to owning object */ 965 /* */ 966 /* Creates a new sync table entry and notifies any sleepers that it's there */ 967 /* waiting to be processed. */ 968 /* ------------------------------------------------------------------------ */ 969 synclist_t * 970 ipf_sync_new(ipf_main_softc_t *softc, int tab, fr_info_t *fin, void *ptr) 971 { 972 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 973 synclist_t *sl, *ss; 974 synclogent_t *sle; 975 u_int hv, sz; 976 977 if (softs->sl_idx == softs->ipf_sync_log_sz) 978 return (NULL); 979 KMALLOC(sl, synclist_t *); 980 if (sl == NULL) 981 return (NULL); 982 983 MUTEX_ENTER(&softs->ipf_syncadd); 984 /* 985 * Get a unique number for this synclist_t. The number is only meant 986 * to be unique for the lifetime of the structure and may be reused 987 * later. 988 */ 989 softs->ipf_sync_num++; 990 if (softs->ipf_sync_num == 0) { 991 softs->ipf_sync_num = 1; 992 softs->ipf_sync_wrap++; 993 } 994 995 /* 996 * Use the synch number of the object as the hash key. Should end up 997 * with relatively even distribution over time. 998 * XXX - an attacker could lunch an DoS attack, of sorts, if they are 999 * the only one causing new table entries by only keeping open every 1000 * nth connection they make, where n is a value in the interval 1001 * [0, SYNC_STATETABSZ-1]. 1002 */ 1003 switch (tab) 1004 { 1005 case SMC_STATE : 1006 hv = softs->ipf_sync_num & (softs->ipf_sync_state_tab_sz - 1); 1007 while (softs->ipf_sync_wrap != 0) { 1008 for (ss = softs->syncstatetab[hv]; ss; ss = ss->sl_next) 1009 if (ss->sl_hdr.sm_num == softs->ipf_sync_num) 1010 break; 1011 if (ss == NULL) 1012 break; 1013 softs->ipf_sync_num++; 1014 hv = softs->ipf_sync_num & 1015 (softs->ipf_sync_state_tab_sz - 1); 1016 } 1017 sl->sl_pnext = softs->syncstatetab + hv; 1018 sl->sl_next = softs->syncstatetab[hv]; 1019 softs->syncstatetab[hv] = sl; 1020 break; 1021 1022 case SMC_NAT : 1023 hv = softs->ipf_sync_num & (softs->ipf_sync_nat_tab_sz - 1); 1024 while (softs->ipf_sync_wrap != 0) { 1025 for (ss = softs->syncnattab[hv]; ss; ss = ss->sl_next) 1026 if (ss->sl_hdr.sm_num == softs->ipf_sync_num) 1027 break; 1028 if (ss == NULL) 1029 break; 1030 softs->ipf_sync_num++; 1031 hv = softs->ipf_sync_num & 1032 (softs->ipf_sync_nat_tab_sz - 1); 1033 } 1034 sl->sl_pnext = softs->syncnattab + hv; 1035 sl->sl_next = softs->syncnattab[hv]; 1036 softs->syncnattab[hv] = sl; 1037 break; 1038 1039 default : 1040 break; 1041 } 1042 1043 sl->sl_num = softs->ipf_sync_num; 1044 MUTEX_EXIT(&softs->ipf_syncadd); 1045 1046 sl->sl_magic = htonl(SYNHDRMAGIC); 1047 sl->sl_v = fin->fin_v; 1048 sl->sl_p = fin->fin_p; 1049 sl->sl_cmd = SMC_CREATE; 1050 sl->sl_idx = -1; 1051 sl->sl_table = tab; 1052 sl->sl_rev = fin->fin_rev; 1053 if (tab == SMC_STATE) { 1054 sl->sl_ips = ptr; 1055 sz = sizeof(*sl->sl_ips); 1056 } else if (tab == SMC_NAT) { 1057 sl->sl_ipn = ptr; 1058 sz = sizeof(*sl->sl_ipn); 1059 } else { 1060 ptr = NULL; 1061 sz = 0; 1062 } 1063 sl->sl_len = sz; 1064 1065 /* 1066 * Create the log entry to be read by a user daemon. When it has been 1067 * finished and put on the queue, send a signal to wakeup any waiters. 1068 */ 1069 MUTEX_ENTER(&softs->ipf_syncadd); 1070 sle = softs->synclog + softs->sl_idx++; 1071 bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr, 1072 sizeof(sle->sle_hdr)); 1073 sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num); 1074 sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len); 1075 if (ptr != NULL) { 1076 bcopy((char *)ptr, (char *)&sle->sle_un, sz); 1077 if (tab == SMC_STATE) { 1078 ipf_sync_storder(1, &sle->sle_un.sleu_ips); 1079 } else if (tab == SMC_NAT) { 1080 ipf_sync_natorder(1, &sle->sle_un.sleu_ipn); 1081 } 1082 } 1083 MUTEX_EXIT(&softs->ipf_syncadd); 1084 1085 ipf_sync_wakeup(softc); 1086 return (sl); 1087 } 1088 1089 1090 /* ------------------------------------------------------------------------ */ 1091 /* Function: ipf_sync_update */ 1092 /* Returns: Nil */ 1093 /* Parameters: tab(I) - type of synclist_t to create */ 1094 /* fin(I) - pointer to packet information */ 1095 /* sl(I) - pointer to synchronisation object */ 1096 /* */ 1097 /* For outbound packets, only, create an sync update record for the user */ 1098 /* process to read. */ 1099 /* ------------------------------------------------------------------------ */ 1100 void 1101 ipf_sync_update(ipf_main_softc_t *softc, int tab, fr_info_t *fin, 1102 synclist_t *sl) 1103 { 1104 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1105 synctcp_update_t *st; 1106 syncupdent_t *slu; 1107 ipstate_t *ips; 1108 nat_t *nat; 1109 ipfrwlock_t *lock; 1110 1111 if (fin->fin_out == 0 || sl == NULL) 1112 return; 1113 1114 if (tab == SMC_STATE) { 1115 lock = &softs->ipf_syncstate; 1116 } else { 1117 lock = &softs->ipf_syncnat; 1118 } 1119 1120 READ_ENTER(lock); 1121 if (sl->sl_idx == -1) { 1122 MUTEX_ENTER(&softs->ipf_syncadd); 1123 slu = softs->syncupd + softs->su_idx; 1124 sl->sl_idx = softs->su_idx++; 1125 MUTEX_EXIT(&softs->ipf_syncadd); 1126 1127 bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr, 1128 sizeof(slu->sup_hdr)); 1129 slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC); 1130 slu->sup_hdr.sm_sl = sl; 1131 slu->sup_hdr.sm_cmd = SMC_UPDATE; 1132 slu->sup_hdr.sm_table = tab; 1133 slu->sup_hdr.sm_num = htonl(sl->sl_num); 1134 slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update)); 1135 slu->sup_hdr.sm_rev = fin->fin_rev; 1136 # if 0 1137 if (fin->fin_p == IPPROTO_TCP) { 1138 st->stu_len[0] = 0; 1139 st->stu_len[1] = 0; 1140 } 1141 # endif 1142 } else 1143 slu = softs->syncupd + sl->sl_idx; 1144 1145 /* 1146 * Only TCP has complex timeouts, others just use default timeouts. 1147 * For TCP, we only need to track the connection state and window. 1148 */ 1149 if (fin->fin_p == IPPROTO_TCP) { 1150 st = &slu->sup_tcp; 1151 if (tab == SMC_STATE) { 1152 ips = sl->sl_ips; 1153 st->stu_age = htonl(ips->is_die); 1154 st->stu_data[0].td_end = ips->is_send; 1155 st->stu_data[0].td_maxend = ips->is_maxsend; 1156 st->stu_data[0].td_maxwin = ips->is_maxswin; 1157 st->stu_state[0] = ips->is_state[0]; 1158 st->stu_data[1].td_end = ips->is_dend; 1159 st->stu_data[1].td_maxend = ips->is_maxdend; 1160 st->stu_data[1].td_maxwin = ips->is_maxdwin; 1161 st->stu_state[1] = ips->is_state[1]; 1162 } else if (tab == SMC_NAT) { 1163 nat = sl->sl_ipn; 1164 st->stu_age = htonl(nat->nat_age); 1165 } 1166 } 1167 RWLOCK_EXIT(lock); 1168 1169 ipf_sync_wakeup(softc); 1170 } 1171 1172 1173 /* ------------------------------------------------------------------------ */ 1174 /* Function: ipf_sync_flush_table */ 1175 /* Returns: int - number of entries freed by flushing table */ 1176 /* Parameters: tabsize(I) - size of the array pointed to by table */ 1177 /* table(I) - pointer to sync table to empty */ 1178 /* */ 1179 /* Walk through a table of sync entries and free each one. It is assumed */ 1180 /* that some lock is held so that nobody else tries to access the table */ 1181 /* during this cleanup. */ 1182 /* ------------------------------------------------------------------------ */ 1183 static int 1184 ipf_sync_flush_table(ipf_sync_softc_t *softs, int tabsize, synclist_t **table) 1185 { 1186 synclist_t *sl; 1187 int i, items; 1188 1189 items = 0; 1190 1191 for (i = 0; i < tabsize; i++) { 1192 while ((sl = table[i]) != NULL) { 1193 switch (sl->sl_table) { 1194 case SMC_STATE : 1195 if (sl->sl_ips != NULL) 1196 sl->sl_ips->is_sync = NULL; 1197 break; 1198 case SMC_NAT : 1199 if (sl->sl_ipn != NULL) 1200 sl->sl_ipn->nat_sync = NULL; 1201 break; 1202 } 1203 if (sl->sl_next != NULL) 1204 sl->sl_next->sl_pnext = sl->sl_pnext; 1205 table[i] = sl->sl_next; 1206 if (sl->sl_idx != -1) 1207 softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL; 1208 KFREE(sl); 1209 items++; 1210 } 1211 } 1212 1213 return (items); 1214 } 1215 1216 1217 /* ------------------------------------------------------------------------ */ 1218 /* Function: ipf_sync_ioctl */ 1219 /* Returns: int - 0 == success, != 0 == failure */ 1220 /* Parameters: data(I) - pointer to ioctl data */ 1221 /* cmd(I) - ioctl command integer */ 1222 /* mode(I) - file mode bits used with open */ 1223 /* */ 1224 /* This function currently does not handle any ioctls and so just returns */ 1225 /* EINVAL on all occasions. */ 1226 /* ------------------------------------------------------------------------ */ 1227 int 1228 ipf_sync_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, 1229 int mode, int uid, void *ctx) 1230 { 1231 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1232 int error, i; 1233 SPL_INT(s); 1234 1235 switch (cmd) 1236 { 1237 case SIOCIPFFL: 1238 error = BCOPYIN(data, &i, sizeof(i)); 1239 if (error != 0) { 1240 IPFERROR(110023); 1241 error = EFAULT; 1242 break; 1243 } 1244 1245 switch (i) 1246 { 1247 case SMC_RLOG : 1248 SPL_NET(s); 1249 MUTEX_ENTER(&softs->ipsl_mutex); 1250 i = (softs->sl_tail - softs->sl_idx) + 1251 (softs->su_tail - softs->su_idx); 1252 softs->sl_idx = 0; 1253 softs->su_idx = 0; 1254 softs->sl_tail = 0; 1255 softs->su_tail = 0; 1256 MUTEX_EXIT(&softs->ipsl_mutex); 1257 SPL_X(s); 1258 break; 1259 1260 case SMC_NAT : 1261 SPL_NET(s); 1262 WRITE_ENTER(&softs->ipf_syncnat); 1263 i = ipf_sync_flush_table(softs, SYNC_NATTABSZ, 1264 softs->syncnattab); 1265 RWLOCK_EXIT(&softs->ipf_syncnat); 1266 SPL_X(s); 1267 break; 1268 1269 case SMC_STATE : 1270 SPL_NET(s); 1271 WRITE_ENTER(&softs->ipf_syncstate); 1272 i = ipf_sync_flush_table(softs, SYNC_STATETABSZ, 1273 softs->syncstatetab); 1274 RWLOCK_EXIT(&softs->ipf_syncstate); 1275 SPL_X(s); 1276 break; 1277 } 1278 1279 error = BCOPYOUT(&i, data, sizeof(i)); 1280 if (error != 0) { 1281 IPFERROR(110022); 1282 error = EFAULT; 1283 } 1284 break; 1285 1286 default : 1287 IPFERROR(110021); 1288 error = EINVAL; 1289 break; 1290 } 1291 1292 return (error); 1293 } 1294 1295 1296 /* ------------------------------------------------------------------------ */ 1297 /* Function: ipf_sync_canread */ 1298 /* Returns: int - 0 == success, != 0 == failure */ 1299 /* Parameters: Nil */ 1300 /* */ 1301 /* This function provides input to the poll handler about whether or not */ 1302 /* there is data waiting to be read from the /dev/ipsync device. */ 1303 /* ------------------------------------------------------------------------ */ 1304 int 1305 ipf_sync_canread(void *arg) 1306 { 1307 ipf_sync_softc_t *softs = arg; 1308 return (!((softs->sl_tail == softs->sl_idx) && 1309 (softs->su_tail == softs->su_idx))); 1310 } 1311 1312 1313 /* ------------------------------------------------------------------------ */ 1314 /* Function: ipf_sync_canwrite */ 1315 /* Returns: int - 1 == can always write */ 1316 /* Parameters: Nil */ 1317 /* */ 1318 /* This function lets the poll handler know that it is always ready willing */ 1319 /* to accept write events. */ 1320 /* XXX Maybe this should return false if the sync table is full? */ 1321 /* ------------------------------------------------------------------------ */ 1322 int 1323 ipf_sync_canwrite(void *arg) 1324 { 1325 return (1); 1326 } 1327 1328 1329 /* ------------------------------------------------------------------------ */ 1330 /* Function: ipf_sync_wakeup */ 1331 /* Parameters: Nil */ 1332 /* Returns: Nil */ 1333 /* */ 1334 /* This function implements the heuristics that decide how often to */ 1335 /* generate a poll wakeup for programs that are waiting for information */ 1336 /* about when they can do a read on /dev/ipsync. */ 1337 /* */ 1338 /* There are three different considerations here: */ 1339 /* - do not keep a program waiting too long: ipf_sync_wake_interval is the */ 1340 /* maximum number of ipf ticks to let pass by; */ 1341 /* - do not let the queue of ouststanding things to generate notifies for */ 1342 /* get too full (ipf_sync_queue_high_wm is the high water mark); */ 1343 /* - do not let too many events get collapsed in before deciding that the */ 1344 /* other host(s) need an update (ipf_sync_event_high_wm is the high water */ 1345 /* mark for this counter.) */ 1346 /* ------------------------------------------------------------------------ */ 1347 static void 1348 ipf_sync_wakeup(ipf_main_softc_t *softc) 1349 { 1350 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1351 1352 softs->ipf_sync_events++; 1353 if ((softc->ipf_ticks > 1354 softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval) || 1355 (softs->ipf_sync_events > softs->ipf_sync_event_high_wm) || 1356 ((softs->sl_tail - softs->sl_idx) > 1357 softs->ipf_sync_queue_high_wm) || 1358 ((softs->su_tail - softs->su_idx) > 1359 softs->ipf_sync_queue_high_wm)) { 1360 1361 ipf_sync_poll_wakeup(softc); 1362 } 1363 } 1364 1365 1366 /* ------------------------------------------------------------------------ */ 1367 /* Function: ipf_sync_poll_wakeup */ 1368 /* Parameters: Nil */ 1369 /* Returns: Nil */ 1370 /* */ 1371 /* Deliver a poll wakeup and reset counters for two of the three heuristics */ 1372 /* ------------------------------------------------------------------------ */ 1373 static void 1374 ipf_sync_poll_wakeup(ipf_main_softc_t *softc) 1375 { 1376 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1377 1378 softs->ipf_sync_events = 0; 1379 softs->ipf_sync_lastwakeup = softc->ipf_ticks; 1380 1381 # ifdef _KERNEL 1382 # if SOLARIS 1383 MUTEX_ENTER(&softs->ipsl_mutex); 1384 cv_signal(&softs->ipslwait); 1385 MUTEX_EXIT(&softs->ipsl_mutex); 1386 pollwakeup(&softc->ipf_poll_head[IPL_LOGSYNC], POLLIN|POLLRDNORM); 1387 # else 1388 WAKEUP(&softs->sl_tail, 0); 1389 POLLWAKEUP(IPL_LOGSYNC); 1390 # endif 1391 # endif 1392 } 1393 1394 1395 /* ------------------------------------------------------------------------ */ 1396 /* Function: ipf_sync_expire */ 1397 /* Parameters: Nil */ 1398 /* Returns: Nil */ 1399 /* */ 1400 /* This is the function called even ipf_tick. It implements one of the */ 1401 /* three heuristics above *IF* there are events waiting. */ 1402 /* ------------------------------------------------------------------------ */ 1403 void 1404 ipf_sync_expire(ipf_main_softc_t *softc) 1405 { 1406 ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1407 1408 if ((softs->ipf_sync_events > 0) && 1409 (softc->ipf_ticks > 1410 softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval)) { 1411 ipf_sync_poll_wakeup(softc); 1412 } 1413 } 1414