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