1145516Sdarrenr/* $FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_sync.c 319633 2017-06-06 19:21:35Z cy $ */ 2145516Sdarrenr 3145516Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145516Sdarrenr * 6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145516Sdarrenr */ 8145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 9145516Sdarrenr# undef KERNEL 10145516Sdarrenr# undef _KERNEL 11145516Sdarrenr# define KERNEL 1 12145516Sdarrenr# define _KERNEL 1 13145516Sdarrenr#endif 14145516Sdarrenr#include <sys/errno.h> 15145516Sdarrenr#include <sys/types.h> 16145516Sdarrenr#include <sys/param.h> 17145516Sdarrenr#include <sys/file.h> 18145516Sdarrenr#if !defined(_KERNEL) && !defined(__KERNEL__) 19145516Sdarrenr# include <stdio.h> 20145516Sdarrenr# include <stdlib.h> 21145516Sdarrenr# include <string.h> 22145516Sdarrenr# define _KERNEL 23145516Sdarrenr# define KERNEL 24145516Sdarrenr# ifdef __OpenBSD__ 25145516Sdarrenrstruct file; 26145516Sdarrenr# endif 27145516Sdarrenr# include <sys/uio.h> 28145516Sdarrenr# undef _KERNEL 29145516Sdarrenr# undef KERNEL 30145516Sdarrenr#else 31145516Sdarrenr# include <sys/systm.h> 32145516Sdarrenr# if !defined(__SVR4) && !defined(__svr4__) 33145516Sdarrenr# include <sys/mbuf.h> 34145516Sdarrenr# endif 35255332Scy# include <sys/select.h> 36255332Scy# if __FreeBSD_version >= 500000 37255332Scy# include <sys/selinfo.h> 38255332Scy# endif 39145516Sdarrenr#endif 40145516Sdarrenr#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 41145516Sdarrenr# include <sys/proc.h> 42145516Sdarrenr#endif 43145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 220000) 44145516Sdarrenr# include <sys/filio.h> 45145516Sdarrenr# include <sys/fcntl.h> 46145516Sdarrenr#else 47145516Sdarrenr# include <sys/ioctl.h> 48145516Sdarrenr#endif 49145516Sdarrenr#include <sys/time.h> 50145516Sdarrenr#if !defined(linux) 51145516Sdarrenr# include <sys/protosw.h> 52145516Sdarrenr#endif 53145516Sdarrenr#include <sys/socket.h> 54145516Sdarrenr#if defined(__SVR4) || defined(__svr4__) 55145516Sdarrenr# include <sys/filio.h> 56145516Sdarrenr# include <sys/byteorder.h> 57145516Sdarrenr# ifdef _KERNEL 58145516Sdarrenr# include <sys/dditypes.h> 59145516Sdarrenr# endif 60145516Sdarrenr# include <sys/stream.h> 61145516Sdarrenr# include <sys/kmem.h> 62145516Sdarrenr#endif 63145516Sdarrenr 64145516Sdarrenr#include <net/if.h> 65145516Sdarrenr#ifdef sun 66145516Sdarrenr# include <net/af.h> 67145516Sdarrenr#endif 68145516Sdarrenr#include <netinet/in.h> 69145516Sdarrenr#include <netinet/in_systm.h> 70145516Sdarrenr#include <netinet/ip.h> 71145516Sdarrenr#include <netinet/tcp.h> 72145516Sdarrenr#if !defined(linux) 73145516Sdarrenr# include <netinet/ip_var.h> 74145516Sdarrenr#endif 75145516Sdarrenr#if !defined(__hpux) && !defined(linux) 76145516Sdarrenr# include <netinet/tcp_fsm.h> 77145516Sdarrenr#endif 78145516Sdarrenr#include <netinet/udp.h> 79145516Sdarrenr#include <netinet/ip_icmp.h> 80145516Sdarrenr#include "netinet/ip_compat.h" 81145516Sdarrenr#include <netinet/tcpip.h> 82145516Sdarrenr#include "netinet/ip_fil.h" 83145516Sdarrenr#include "netinet/ip_nat.h" 84145516Sdarrenr#include "netinet/ip_frag.h" 85145516Sdarrenr#include "netinet/ip_state.h" 86145516Sdarrenr#include "netinet/ip_proxy.h" 87145516Sdarrenr#include "netinet/ip_sync.h" 88145516Sdarrenr#ifdef USE_INET6 89145516Sdarrenr#include <netinet/icmp6.h> 90145516Sdarrenr#endif 91145516Sdarrenr#if (__FreeBSD_version >= 300000) 92145516Sdarrenr# include <sys/malloc.h> 93145516Sdarrenr# if defined(_KERNEL) && !defined(IPFILTER_LKM) 94145516Sdarrenr# include <sys/libkern.h> 95145516Sdarrenr# include <sys/systm.h> 96145516Sdarrenr# endif 97145516Sdarrenr#endif 98145516Sdarrenr/* END OF INCLUDES */ 99145516Sdarrenr 100145516Sdarrenr#if !defined(lint) 101255332Scystatic const char rcsid[] = "@(#)$Id$"; 102145516Sdarrenr#endif 103145516Sdarrenr 104145516Sdarrenr#define SYNC_STATETABSZ 256 105145516Sdarrenr#define SYNC_NATTABSZ 256 106145516Sdarrenr 107255332Scytypedef struct ipf_sync_softc_s { 108255332Scy ipfmutex_t ipf_syncadd; 109255332Scy ipfmutex_t ipsl_mutex; 110255332Scy ipfrwlock_t ipf_syncstate; 111255332Scy ipfrwlock_t ipf_syncnat; 112145516Sdarrenr#if SOLARIS && defined(_KERNEL) 113255332Scy kcondvar_t ipslwait; 114145516Sdarrenr#endif 115255332Scy#if defined(linux) && defined(_KERNEL) 116255332Scy wait_queue_head_t sl_tail_linux; 117255332Scy#endif 118255332Scy synclist_t **syncstatetab; 119255332Scy synclist_t **syncnattab; 120255332Scy synclogent_t *synclog; 121255332Scy syncupdent_t *syncupd; 122255332Scy u_int ipf_sync_num; 123255332Scy u_int ipf_sync_wrap; 124255332Scy u_int sl_idx; /* next available sync log entry */ 125255332Scy u_int su_idx; /* next available sync update entry */ 126255332Scy u_int sl_tail; /* next sync log entry to read */ 127255332Scy u_int su_tail; /* next sync update entry to read */ 128255332Scy int ipf_sync_log_sz; 129255332Scy int ipf_sync_nat_tab_sz; 130255332Scy int ipf_sync_state_tab_sz; 131255332Scy int ipf_sync_debug; 132255332Scy int ipf_sync_events; 133255332Scy u_32_t ipf_sync_lastwakeup; 134255332Scy int ipf_sync_wake_interval; 135255332Scy int ipf_sync_event_high_wm; 136255332Scy int ipf_sync_queue_high_wm; 137255332Scy int ipf_sync_inited; 138255332Scy} ipf_sync_softc_t; 139145516Sdarrenr 140255332Scystatic int ipf_sync_flush_table __P((ipf_sync_softc_t *, int, synclist_t **)); 141255332Scystatic void ipf_sync_wakeup __P((ipf_main_softc_t *)); 142255332Scystatic void ipf_sync_del __P((ipf_sync_softc_t *, synclist_t *)); 143255332Scystatic void ipf_sync_poll_wakeup __P((ipf_main_softc_t *)); 144255332Scystatic int ipf_sync_nat __P((ipf_main_softc_t *, synchdr_t *, void *)); 145255332Scystatic int ipf_sync_state __P((ipf_main_softc_t *, synchdr_t *, void *)); 146145516Sdarrenr 147145516Sdarrenr# if !defined(sparc) && !defined(__hppa) 148255332Scyvoid ipf_sync_tcporder __P((int, struct tcpdata *)); 149255332Scyvoid ipf_sync_natorder __P((int, struct nat *)); 150255332Scyvoid ipf_sync_storder __P((int, struct ipstate *)); 151145516Sdarrenr# endif 152145516Sdarrenr 153145516Sdarrenr 154255332Scyvoid * 155255332Scyipf_sync_soft_create(softc) 156255332Scy ipf_main_softc_t *softc; 157255332Scy{ 158255332Scy ipf_sync_softc_t *softs; 159255332Scy 160255332Scy KMALLOC(softs, ipf_sync_softc_t *); 161255332Scy if (softs == NULL) { 162255332Scy IPFERROR(110024); 163255332Scy return NULL; 164255332Scy } 165255332Scy 166255332Scy bzero((char *)softs, sizeof(*softs)); 167255332Scy 168255332Scy softs->ipf_sync_log_sz = SYNCLOG_SZ; 169255332Scy softs->ipf_sync_nat_tab_sz = SYNC_STATETABSZ; 170255332Scy softs->ipf_sync_state_tab_sz = SYNC_STATETABSZ; 171255332Scy softs->ipf_sync_event_high_wm = SYNCLOG_SZ * 100 / 90; /* 90% */ 172255332Scy softs->ipf_sync_queue_high_wm = SYNCLOG_SZ * 100 / 90; /* 90% */ 173255332Scy 174255332Scy return softs; 175255332Scy} 176255332Scy 177255332Scy 178145516Sdarrenr/* ------------------------------------------------------------------------ */ 179255332Scy/* Function: ipf_sync_init */ 180145516Sdarrenr/* Returns: int - 0 == success, -1 == failure */ 181145516Sdarrenr/* Parameters: Nil */ 182145516Sdarrenr/* */ 183145516Sdarrenr/* Initialise all of the locks required for the sync code and initialise */ 184145516Sdarrenr/* any data structures, as required. */ 185145516Sdarrenr/* ------------------------------------------------------------------------ */ 186255332Scyint 187255332Scyipf_sync_soft_init(softc, arg) 188255332Scy ipf_main_softc_t *softc; 189255332Scy void *arg; 190145516Sdarrenr{ 191255332Scy ipf_sync_softc_t *softs = arg; 192255332Scy 193255332Scy KMALLOCS(softs->synclog, synclogent_t *, 194255332Scy softs->ipf_sync_log_sz * sizeof(*softs->synclog)); 195255332Scy if (softs->synclog == NULL) 196255332Scy return -1; 197255332Scy bzero((char *)softs->synclog, 198255332Scy softs->ipf_sync_log_sz * sizeof(*softs->synclog)); 199255332Scy 200255332Scy KMALLOCS(softs->syncupd, syncupdent_t *, 201255332Scy softs->ipf_sync_log_sz * sizeof(*softs->syncupd)); 202255332Scy if (softs->syncupd == NULL) 203255332Scy return -2; 204255332Scy bzero((char *)softs->syncupd, 205255332Scy softs->ipf_sync_log_sz * sizeof(*softs->syncupd)); 206255332Scy 207255332Scy KMALLOCS(softs->syncstatetab, synclist_t **, 208255332Scy softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab)); 209255332Scy if (softs->syncstatetab == NULL) 210255332Scy return -3; 211255332Scy bzero((char *)softs->syncstatetab, 212255332Scy softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab)); 213255332Scy 214255332Scy KMALLOCS(softs->syncnattab, synclist_t **, 215255332Scy softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab)); 216255332Scy if (softs->syncnattab == NULL) 217255332Scy return -3; 218255332Scy bzero((char *)softs->syncnattab, 219255332Scy softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab)); 220255332Scy 221255332Scy softs->ipf_sync_num = 1; 222255332Scy softs->ipf_sync_wrap = 0; 223255332Scy softs->sl_idx = 0; 224255332Scy softs->su_idx = 0; 225255332Scy softs->sl_tail = 0; 226255332Scy softs->su_tail = 0; 227255332Scy softs->ipf_sync_events = 0; 228255332Scy softs->ipf_sync_lastwakeup = 0; 229255332Scy 230255332Scy 231145516Sdarrenr# if SOLARIS && defined(_KERNEL) 232255332Scy cv_init(&softs->ipslwait, "ipsl condvar", CV_DRIVER, NULL); 233145516Sdarrenr# endif 234255332Scy RWLOCK_INIT(&softs->ipf_syncstate, "add things to state sync table"); 235255332Scy RWLOCK_INIT(&softs->ipf_syncnat, "add things to nat sync table"); 236255332Scy MUTEX_INIT(&softs->ipf_syncadd, "add things to sync table"); 237255332Scy MUTEX_INIT(&softs->ipsl_mutex, "read ring lock"); 238145516Sdarrenr 239255332Scy softs->ipf_sync_inited = 1; 240145516Sdarrenr 241145516Sdarrenr return 0; 242145516Sdarrenr} 243145516Sdarrenr 244145516Sdarrenr 245255332Scy/* ------------------------------------------------------------------------ */ 246255332Scy/* Function: ipf_sync_unload */ 247255332Scy/* Returns: int - 0 == success, -1 == failure */ 248255332Scy/* Parameters: Nil */ 249255332Scy/* */ 250255332Scy/* Destroy the locks created when initialising and free any memory in use */ 251255332Scy/* with the synchronisation tables. */ 252255332Scy/* ------------------------------------------------------------------------ */ 253255332Scyint 254255332Scyipf_sync_soft_fini(softc, arg) 255255332Scy ipf_main_softc_t *softc; 256255332Scy void *arg; 257255332Scy{ 258255332Scy ipf_sync_softc_t *softs = arg; 259255332Scy 260255332Scy if (softs->syncnattab != NULL) { 261255332Scy ipf_sync_flush_table(softs, softs->ipf_sync_nat_tab_sz, 262255332Scy softs->syncnattab); 263255332Scy KFREES(softs->syncnattab, 264255332Scy softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab)); 265255332Scy softs->syncnattab = NULL; 266255332Scy } 267255332Scy 268255332Scy if (softs->syncstatetab != NULL) { 269255332Scy ipf_sync_flush_table(softs, softs->ipf_sync_state_tab_sz, 270255332Scy softs->syncstatetab); 271255332Scy KFREES(softs->syncstatetab, 272255332Scy softs->ipf_sync_state_tab_sz * 273255332Scy sizeof(*softs->syncstatetab)); 274255332Scy softs->syncstatetab = NULL; 275255332Scy } 276255332Scy 277255332Scy if (softs->syncupd != NULL) { 278255332Scy KFREES(softs->syncupd, 279255332Scy softs->ipf_sync_log_sz * sizeof(*softs->syncupd)); 280255332Scy softs->syncupd = NULL; 281255332Scy } 282255332Scy 283255332Scy if (softs->synclog != NULL) { 284255332Scy KFREES(softs->synclog, 285255332Scy softs->ipf_sync_log_sz * sizeof(*softs->synclog)); 286255332Scy softs->synclog = NULL; 287255332Scy } 288255332Scy 289255332Scy if (softs->ipf_sync_inited == 1) { 290255332Scy MUTEX_DESTROY(&softs->ipsl_mutex); 291255332Scy MUTEX_DESTROY(&softs->ipf_syncadd); 292255332Scy RW_DESTROY(&softs->ipf_syncnat); 293255332Scy RW_DESTROY(&softs->ipf_syncstate); 294255332Scy softs->ipf_sync_inited = 0; 295255332Scy } 296255332Scy 297255332Scy return 0; 298255332Scy} 299255332Scy 300255332Scyvoid 301255332Scyipf_sync_soft_destroy(softc, arg) 302255332Scy ipf_main_softc_t *softc; 303255332Scy void *arg; 304255332Scy{ 305255332Scy ipf_sync_softc_t *softs = arg; 306255332Scy 307255332Scy KFREE(softs); 308255332Scy} 309255332Scy 310255332Scy 311145516Sdarrenr# if !defined(sparc) && !defined(__hppa) 312145516Sdarrenr/* ------------------------------------------------------------------------ */ 313255332Scy/* Function: ipf_sync_tcporder */ 314145516Sdarrenr/* Returns: Nil */ 315145516Sdarrenr/* Parameters: way(I) - direction of byte order conversion. */ 316145516Sdarrenr/* td(IO) - pointer to data to be converted. */ 317145516Sdarrenr/* */ 318145516Sdarrenr/* Do byte swapping on values in the TCP state information structure that */ 319145516Sdarrenr/* need to be used at both ends by the host in their native byte order. */ 320145516Sdarrenr/* ------------------------------------------------------------------------ */ 321255332Scyvoid 322255332Scyipf_sync_tcporder(way, td) 323255332Scy int way; 324255332Scy tcpdata_t *td; 325145516Sdarrenr{ 326145516Sdarrenr if (way) { 327145516Sdarrenr td->td_maxwin = htons(td->td_maxwin); 328145516Sdarrenr td->td_end = htonl(td->td_end); 329145516Sdarrenr td->td_maxend = htonl(td->td_maxend); 330145516Sdarrenr } else { 331145516Sdarrenr td->td_maxwin = ntohs(td->td_maxwin); 332145516Sdarrenr td->td_end = ntohl(td->td_end); 333145516Sdarrenr td->td_maxend = ntohl(td->td_maxend); 334145516Sdarrenr } 335145516Sdarrenr} 336145516Sdarrenr 337145516Sdarrenr 338145516Sdarrenr/* ------------------------------------------------------------------------ */ 339255332Scy/* Function: ipf_sync_natorder */ 340145516Sdarrenr/* Returns: Nil */ 341145516Sdarrenr/* Parameters: way(I) - direction of byte order conversion. */ 342145516Sdarrenr/* nat(IO) - pointer to data to be converted. */ 343145516Sdarrenr/* */ 344145516Sdarrenr/* Do byte swapping on values in the NAT data structure that need to be */ 345145516Sdarrenr/* used at both ends by the host in their native byte order. */ 346145516Sdarrenr/* ------------------------------------------------------------------------ */ 347255332Scyvoid 348255332Scyipf_sync_natorder(way, n) 349255332Scy int way; 350255332Scy nat_t *n; 351145516Sdarrenr{ 352145516Sdarrenr if (way) { 353145516Sdarrenr n->nat_age = htonl(n->nat_age); 354145516Sdarrenr n->nat_flags = htonl(n->nat_flags); 355145516Sdarrenr n->nat_ipsumd = htonl(n->nat_ipsumd); 356145516Sdarrenr n->nat_use = htonl(n->nat_use); 357145516Sdarrenr n->nat_dir = htonl(n->nat_dir); 358145516Sdarrenr } else { 359145516Sdarrenr n->nat_age = ntohl(n->nat_age); 360145516Sdarrenr n->nat_flags = ntohl(n->nat_flags); 361145516Sdarrenr n->nat_ipsumd = ntohl(n->nat_ipsumd); 362145516Sdarrenr n->nat_use = ntohl(n->nat_use); 363145516Sdarrenr n->nat_dir = ntohl(n->nat_dir); 364145516Sdarrenr } 365145516Sdarrenr} 366145516Sdarrenr 367145516Sdarrenr 368145516Sdarrenr/* ------------------------------------------------------------------------ */ 369255332Scy/* Function: ipf_sync_storder */ 370145516Sdarrenr/* Returns: Nil */ 371145516Sdarrenr/* Parameters: way(I) - direction of byte order conversion. */ 372145516Sdarrenr/* ips(IO) - pointer to data to be converted. */ 373145516Sdarrenr/* */ 374145516Sdarrenr/* Do byte swapping on values in the IP state data structure that need to */ 375145516Sdarrenr/* be used at both ends by the host in their native byte order. */ 376145516Sdarrenr/* ------------------------------------------------------------------------ */ 377255332Scyvoid 378255332Scyipf_sync_storder(way, ips) 379255332Scy int way; 380255332Scy ipstate_t *ips; 381145516Sdarrenr{ 382255332Scy ipf_sync_tcporder(way, &ips->is_tcp.ts_data[0]); 383255332Scy ipf_sync_tcporder(way, &ips->is_tcp.ts_data[1]); 384145516Sdarrenr 385145516Sdarrenr if (way) { 386145516Sdarrenr ips->is_hv = htonl(ips->is_hv); 387145516Sdarrenr ips->is_die = htonl(ips->is_die); 388145516Sdarrenr ips->is_pass = htonl(ips->is_pass); 389145516Sdarrenr ips->is_flags = htonl(ips->is_flags); 390153876Sguido ips->is_opt[0] = htonl(ips->is_opt[0]); 391153876Sguido ips->is_opt[1] = htonl(ips->is_opt[1]); 392153876Sguido ips->is_optmsk[0] = htonl(ips->is_optmsk[0]); 393153876Sguido ips->is_optmsk[1] = htonl(ips->is_optmsk[1]); 394145516Sdarrenr ips->is_sec = htons(ips->is_sec); 395145516Sdarrenr ips->is_secmsk = htons(ips->is_secmsk); 396145516Sdarrenr ips->is_auth = htons(ips->is_auth); 397145516Sdarrenr ips->is_authmsk = htons(ips->is_authmsk); 398145516Sdarrenr ips->is_s0[0] = htonl(ips->is_s0[0]); 399145516Sdarrenr ips->is_s0[1] = htonl(ips->is_s0[1]); 400145516Sdarrenr ips->is_smsk[0] = htons(ips->is_smsk[0]); 401145516Sdarrenr ips->is_smsk[1] = htons(ips->is_smsk[1]); 402145516Sdarrenr } else { 403145516Sdarrenr ips->is_hv = ntohl(ips->is_hv); 404145516Sdarrenr ips->is_die = ntohl(ips->is_die); 405145516Sdarrenr ips->is_pass = ntohl(ips->is_pass); 406145516Sdarrenr ips->is_flags = ntohl(ips->is_flags); 407153876Sguido ips->is_opt[0] = ntohl(ips->is_opt[0]); 408153876Sguido ips->is_opt[1] = ntohl(ips->is_opt[1]); 409153876Sguido ips->is_optmsk[0] = ntohl(ips->is_optmsk[0]); 410153876Sguido ips->is_optmsk[1] = ntohl(ips->is_optmsk[1]); 411145516Sdarrenr ips->is_sec = ntohs(ips->is_sec); 412145516Sdarrenr ips->is_secmsk = ntohs(ips->is_secmsk); 413145516Sdarrenr ips->is_auth = ntohs(ips->is_auth); 414145516Sdarrenr ips->is_authmsk = ntohs(ips->is_authmsk); 415145516Sdarrenr ips->is_s0[0] = ntohl(ips->is_s0[0]); 416145516Sdarrenr ips->is_s0[1] = ntohl(ips->is_s0[1]); 417145516Sdarrenr ips->is_smsk[0] = ntohl(ips->is_smsk[0]); 418145516Sdarrenr ips->is_smsk[1] = ntohl(ips->is_smsk[1]); 419145516Sdarrenr } 420145516Sdarrenr} 421145516Sdarrenr# else /* !defined(sparc) && !defined(__hppa) */ 422255332Scy# define ipf_sync_tcporder(x,y) 423255332Scy# define ipf_sync_natorder(x,y) 424255332Scy# define ipf_sync_storder(x,y) 425145516Sdarrenr# endif /* !defined(sparc) && !defined(__hppa) */ 426145516Sdarrenr 427145516Sdarrenr 428145516Sdarrenr/* ------------------------------------------------------------------------ */ 429255332Scy/* Function: ipf_sync_write */ 430145516Sdarrenr/* Returns: int - 0 == success, else error value. */ 431145516Sdarrenr/* Parameters: uio(I) - pointer to information about data to write */ 432145516Sdarrenr/* */ 433145516Sdarrenr/* Moves data from user space into the kernel and uses it for updating data */ 434145516Sdarrenr/* structures in the state/NAT tables. */ 435145516Sdarrenr/* ------------------------------------------------------------------------ */ 436255332Scyint 437255332Scyipf_sync_write(softc, uio) 438255332Scy ipf_main_softc_t *softc; 439255332Scy struct uio *uio; 440145516Sdarrenr{ 441255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 442145516Sdarrenr synchdr_t sh; 443145516Sdarrenr 444255332Scy /* 445145516Sdarrenr * THIS MUST BE SUFFICIENT LARGE TO STORE 446255332Scy * ANY POSSIBLE DATA TYPE 447145516Sdarrenr */ 448255332Scy char data[2048]; 449145516Sdarrenr 450145516Sdarrenr int err = 0; 451145516Sdarrenr 452255332Scy# if BSD_GE_YEAR(199306) || defined(__FreeBSD__) || defined(__osf__) 453145516Sdarrenr uio->uio_rw = UIO_WRITE; 454145516Sdarrenr# endif 455145516Sdarrenr 456145516Sdarrenr /* Try to get bytes */ 457145516Sdarrenr while (uio->uio_resid > 0) { 458145516Sdarrenr 459145516Sdarrenr if (uio->uio_resid >= sizeof(sh)) { 460145516Sdarrenr 461172776Sdarrenr err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio); 462145516Sdarrenr 463145516Sdarrenr if (err) { 464255332Scy if (softs->ipf_sync_debug > 2) 465145516Sdarrenr printf("uiomove(header) failed: %d\n", 466145516Sdarrenr err); 467145516Sdarrenr return err; 468145516Sdarrenr } 469145516Sdarrenr 470145516Sdarrenr /* convert to host order */ 471145516Sdarrenr sh.sm_magic = ntohl(sh.sm_magic); 472145516Sdarrenr sh.sm_len = ntohl(sh.sm_len); 473145516Sdarrenr sh.sm_num = ntohl(sh.sm_num); 474145516Sdarrenr 475255332Scy if (softs->ipf_sync_debug > 8) 476145516Sdarrenr printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n", 477145516Sdarrenr sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd, 478145516Sdarrenr sh.sm_table, sh.sm_rev, sh.sm_len, 479145516Sdarrenr sh.sm_magic); 480145516Sdarrenr 481145516Sdarrenr if (sh.sm_magic != SYNHDRMAGIC) { 482255332Scy if (softs->ipf_sync_debug > 2) 483255332Scy printf("uiomove(header) invalid %s\n", 484145516Sdarrenr "magic"); 485255332Scy IPFERROR(110001); 486145516Sdarrenr return EINVAL; 487145516Sdarrenr } 488145516Sdarrenr 489145516Sdarrenr if (sh.sm_v != 4 && sh.sm_v != 6) { 490255332Scy if (softs->ipf_sync_debug > 2) 491145516Sdarrenr printf("uiomove(header) invalid %s\n", 492145516Sdarrenr "protocol"); 493255332Scy IPFERROR(110002); 494145516Sdarrenr return EINVAL; 495145516Sdarrenr } 496145516Sdarrenr 497145516Sdarrenr if (sh.sm_cmd > SMC_MAXCMD) { 498255332Scy if (softs->ipf_sync_debug > 2) 499145516Sdarrenr printf("uiomove(header) invalid %s\n", 500145516Sdarrenr "command"); 501255332Scy IPFERROR(110003); 502145516Sdarrenr return EINVAL; 503145516Sdarrenr } 504145516Sdarrenr 505145516Sdarrenr 506145516Sdarrenr if (sh.sm_table > SMC_MAXTBL) { 507255332Scy if (softs->ipf_sync_debug > 2) 508145516Sdarrenr printf("uiomove(header) invalid %s\n", 509145516Sdarrenr "table"); 510255332Scy IPFERROR(110004); 511145516Sdarrenr return EINVAL; 512145516Sdarrenr } 513145516Sdarrenr 514145516Sdarrenr } else { 515145516Sdarrenr /* unsufficient data, wait until next call */ 516255332Scy if (softs->ipf_sync_debug > 2) 517145516Sdarrenr printf("uiomove(header) insufficient data"); 518255332Scy IPFERROR(110005); 519145516Sdarrenr return EAGAIN; 520145516Sdarrenr } 521145516Sdarrenr 522145516Sdarrenr 523145516Sdarrenr /* 524255332Scy * We have a header, so try to read the amount of data 525145516Sdarrenr * needed for the request 526145516Sdarrenr */ 527145516Sdarrenr 528145516Sdarrenr /* not supported */ 529145516Sdarrenr if (sh.sm_len == 0) { 530255332Scy if (softs->ipf_sync_debug > 2) 531145516Sdarrenr printf("uiomove(data zero length %s\n", 532145516Sdarrenr "not supported"); 533255332Scy IPFERROR(110006); 534145516Sdarrenr return EINVAL; 535145516Sdarrenr } 536145516Sdarrenr 537145516Sdarrenr if (uio->uio_resid >= sh.sm_len) { 538145516Sdarrenr 539172776Sdarrenr err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio); 540145516Sdarrenr 541145516Sdarrenr if (err) { 542255332Scy if (softs->ipf_sync_debug > 2) 543145516Sdarrenr printf("uiomove(data) failed: %d\n", 544145516Sdarrenr err); 545145516Sdarrenr return err; 546145516Sdarrenr } 547145516Sdarrenr 548255332Scy if (softs->ipf_sync_debug > 7) 549145516Sdarrenr printf("uiomove(data) %d bytes read\n", 550145516Sdarrenr sh.sm_len); 551145516Sdarrenr 552145516Sdarrenr if (sh.sm_table == SMC_STATE) 553255332Scy err = ipf_sync_state(softc, &sh, data); 554145516Sdarrenr else if (sh.sm_table == SMC_NAT) 555255332Scy err = ipf_sync_nat(softc, &sh, data); 556255332Scy if (softs->ipf_sync_debug > 7) 557145516Sdarrenr printf("[%d] Finished with error %d\n", 558145516Sdarrenr sh.sm_num, err); 559145516Sdarrenr 560145516Sdarrenr } else { 561145516Sdarrenr /* insufficient data, wait until next call */ 562255332Scy if (softs->ipf_sync_debug > 2) 563145516Sdarrenr printf("uiomove(data) %s %d bytes, got %d\n", 564145516Sdarrenr "insufficient data, need", 565255332Scy sh.sm_len, (int)uio->uio_resid); 566255332Scy IPFERROR(110007); 567145516Sdarrenr return EAGAIN; 568145516Sdarrenr } 569255332Scy } 570145516Sdarrenr 571145516Sdarrenr /* no more data */ 572145516Sdarrenr return 0; 573145516Sdarrenr} 574145516Sdarrenr 575145516Sdarrenr 576145516Sdarrenr/* ------------------------------------------------------------------------ */ 577255332Scy/* Function: ipf_sync_read */ 578145516Sdarrenr/* Returns: int - 0 == success, else error value. */ 579145516Sdarrenr/* Parameters: uio(O) - pointer to information about where to store data */ 580145516Sdarrenr/* */ 581145516Sdarrenr/* This function is called when a user program wants to read some data */ 582145516Sdarrenr/* for pending state/NAT updates. If no data is available, the caller is */ 583145516Sdarrenr/* put to sleep, pending a wakeup from the "lower half" of this code. */ 584145516Sdarrenr/* ------------------------------------------------------------------------ */ 585255332Scyint 586255332Scyipf_sync_read(softc, uio) 587255332Scy ipf_main_softc_t *softc; 588255332Scy struct uio *uio; 589145516Sdarrenr{ 590255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 591145516Sdarrenr syncupdent_t *su; 592145516Sdarrenr synclogent_t *sl; 593145516Sdarrenr int err = 0; 594145516Sdarrenr 595255332Scy if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) { 596255332Scy IPFERROR(110008); 597145516Sdarrenr return EINVAL; 598255332Scy } 599145516Sdarrenr 600255332Scy# if BSD_GE_YEAR(199306) || defined(__FreeBSD__) || defined(__osf__) 601145516Sdarrenr uio->uio_rw = UIO_READ; 602145516Sdarrenr# endif 603145516Sdarrenr 604255332Scy MUTEX_ENTER(&softs->ipsl_mutex); 605255332Scy while ((softs->sl_tail == softs->sl_idx) && 606255332Scy (softs->su_tail == softs->su_idx)) { 607255332Scy# if defined(_KERNEL) 608255332Scy# if SOLARIS 609255332Scy if (!cv_wait_sig(&softs->ipslwait, &softs->ipsl_mutex.ipf_lk)) { 610255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 611255332Scy IPFERROR(110009); 612145516Sdarrenr return EINTR; 613145516Sdarrenr } 614255332Scy# else 615255332Scy# ifdef __hpux 616145516Sdarrenr { 617145516Sdarrenr lock_t *l; 618145516Sdarrenr 619255332Scy l = get_sleep_lock(&softs->sl_tail); 620255332Scy err = sleep(&softs->sl_tail, PZERO+1); 621147367Sdarrenr if (err) { 622255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 623255332Scy IPFERROR(110010); 624147367Sdarrenr return EINTR; 625147367Sdarrenr } 626145516Sdarrenr spinunlock(l); 627145516Sdarrenr } 628255332Scy# else /* __hpux */ 629255332Scy# ifdef __osf__ 630255332Scy err = mpsleep(&softs->sl_tail, PSUSP|PCATCH, "ipl sleep", 0, 631255332Scy &softs->ipsl_mutex, MS_LOCK_SIMPLE); 632255332Scy if (err) { 633255332Scy IPFERROR(110011); 634147367Sdarrenr return EINTR; 635255332Scy } 636255332Scy# else 637255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 638255332Scy err = SLEEP(&softs->sl_tail, "ipl sleep"); 639255332Scy if (err) { 640255332Scy IPFERROR(110012); 641147367Sdarrenr return EINTR; 642255332Scy } 643255332Scy MUTEX_ENTER(&softs->ipsl_mutex); 644255332Scy# endif /* __osf__ */ 645255332Scy# endif /* __hpux */ 646255332Scy# endif /* SOLARIS */ 647255332Scy# endif /* _KERNEL */ 648145516Sdarrenr } 649145516Sdarrenr 650255332Scy while ((softs->sl_tail < softs->sl_idx) && 651255332Scy (uio->uio_resid > sizeof(*sl))) { 652255332Scy sl = softs->synclog + softs->sl_tail++; 653255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 654172776Sdarrenr err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio); 655145516Sdarrenr if (err != 0) 656255332Scy goto goterror; 657255332Scy MUTEX_ENTER(&softs->ipsl_mutex); 658145516Sdarrenr } 659145516Sdarrenr 660255332Scy while ((softs->su_tail < softs->su_idx) && 661255332Scy (uio->uio_resid > sizeof(*su))) { 662255332Scy su = softs->syncupd + softs->su_tail; 663255332Scy softs->su_tail++; 664255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 665172776Sdarrenr err = UIOMOVE(su, sizeof(*su), UIO_READ, uio); 666145516Sdarrenr if (err != 0) 667255332Scy goto goterror; 668255332Scy MUTEX_ENTER(&softs->ipsl_mutex); 669145516Sdarrenr if (su->sup_hdr.sm_sl != NULL) 670145516Sdarrenr su->sup_hdr.sm_sl->sl_idx = -1; 671145516Sdarrenr } 672255332Scy if (softs->sl_tail == softs->sl_idx) 673255332Scy softs->sl_tail = softs->sl_idx = 0; 674255332Scy if (softs->su_tail == softs->su_idx) 675255332Scy softs->su_tail = softs->su_idx = 0; 676255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 677255332Scygoterror: 678145516Sdarrenr return err; 679145516Sdarrenr} 680145516Sdarrenr 681145516Sdarrenr 682145516Sdarrenr/* ------------------------------------------------------------------------ */ 683255332Scy/* Function: ipf_sync_state */ 684145516Sdarrenr/* Returns: int - 0 == success, else error value. */ 685145516Sdarrenr/* Parameters: sp(I) - pointer to sync packet data header */ 686145516Sdarrenr/* uio(I) - pointer to user data for further information */ 687145516Sdarrenr/* */ 688145516Sdarrenr/* Updates the state table according to information passed in the sync */ 689145516Sdarrenr/* header. As required, more data is fetched from the uio structure but */ 690145516Sdarrenr/* varies depending on the contents of the sync header. This function can */ 691145516Sdarrenr/* create a new state entry or update one. Deletion is left to the state */ 692145516Sdarrenr/* structures being timed out correctly. */ 693145516Sdarrenr/* ------------------------------------------------------------------------ */ 694255332Scystatic int 695255332Scyipf_sync_state(softc, sp, data) 696255332Scy ipf_main_softc_t *softc; 697255332Scy synchdr_t *sp; 698255332Scy void *data; 699145516Sdarrenr{ 700255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 701145516Sdarrenr synctcp_update_t su; 702145516Sdarrenr ipstate_t *is, sn; 703145516Sdarrenr synclist_t *sl; 704145516Sdarrenr frentry_t *fr; 705145516Sdarrenr u_int hv; 706145516Sdarrenr int err = 0; 707145516Sdarrenr 708255332Scy hv = sp->sm_num & (softs->ipf_sync_state_tab_sz - 1); 709145516Sdarrenr 710145516Sdarrenr switch (sp->sm_cmd) 711145516Sdarrenr { 712145516Sdarrenr case SMC_CREATE : 713145516Sdarrenr 714145516Sdarrenr bcopy(data, &sn, sizeof(sn)); 715145516Sdarrenr KMALLOC(is, ipstate_t *); 716145516Sdarrenr if (is == NULL) { 717255332Scy IPFERROR(110013); 718145516Sdarrenr err = ENOMEM; 719145516Sdarrenr break; 720145516Sdarrenr } 721145516Sdarrenr 722145516Sdarrenr KMALLOC(sl, synclist_t *); 723145516Sdarrenr if (sl == NULL) { 724255332Scy IPFERROR(110014); 725145516Sdarrenr err = ENOMEM; 726145516Sdarrenr KFREE(is); 727145516Sdarrenr break; 728145516Sdarrenr } 729145516Sdarrenr 730145516Sdarrenr bzero((char *)is, offsetof(ipstate_t, is_die)); 731145516Sdarrenr bcopy((char *)&sn.is_die, (char *)&is->is_die, 732145516Sdarrenr sizeof(*is) - offsetof(ipstate_t, is_die)); 733255332Scy ipf_sync_storder(0, is); 734145516Sdarrenr 735145516Sdarrenr /* 736145516Sdarrenr * We need to find the same rule on the slave as was used on 737145516Sdarrenr * the master to create this state entry. 738145516Sdarrenr */ 739255332Scy READ_ENTER(&softc->ipf_mutex); 740255332Scy fr = ipf_getrulen(softc, IPL_LOGIPF, sn.is_group, sn.is_rulen); 741145516Sdarrenr if (fr != NULL) { 742145516Sdarrenr MUTEX_ENTER(&fr->fr_lock); 743145516Sdarrenr fr->fr_ref++; 744145516Sdarrenr fr->fr_statecnt++; 745145516Sdarrenr MUTEX_EXIT(&fr->fr_lock); 746145516Sdarrenr } 747255332Scy RWLOCK_EXIT(&softc->ipf_mutex); 748145516Sdarrenr 749255332Scy if (softs->ipf_sync_debug > 4) 750145516Sdarrenr printf("[%d] Filter rules = %p\n", sp->sm_num, fr); 751145516Sdarrenr 752145516Sdarrenr is->is_rule = fr; 753145516Sdarrenr is->is_sync = sl; 754145516Sdarrenr 755145516Sdarrenr sl->sl_idx = -1; 756145516Sdarrenr sl->sl_ips = is; 757145516Sdarrenr bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr)); 758145516Sdarrenr 759255332Scy WRITE_ENTER(&softs->ipf_syncstate); 760255332Scy WRITE_ENTER(&softc->ipf_state); 761145516Sdarrenr 762255332Scy sl->sl_pnext = softs->syncstatetab + hv; 763255332Scy sl->sl_next = softs->syncstatetab[hv]; 764255332Scy if (softs->syncstatetab[hv] != NULL) 765255332Scy softs->syncstatetab[hv]->sl_pnext = &sl->sl_next; 766255332Scy softs->syncstatetab[hv] = sl; 767255332Scy MUTEX_DOWNGRADE(&softs->ipf_syncstate); 768255332Scy ipf_state_insert(softc, is, sp->sm_rev); 769145516Sdarrenr /* 770145516Sdarrenr * Do not initialise the interface pointers for the state 771145516Sdarrenr * entry as the full complement of interface names may not 772145516Sdarrenr * be present. 773145516Sdarrenr * 774145516Sdarrenr * Put this state entry on its timeout queue. 775145516Sdarrenr */ 776145516Sdarrenr /*fr_setstatequeue(is, sp->sm_rev);*/ 777145516Sdarrenr break; 778145516Sdarrenr 779145516Sdarrenr case SMC_UPDATE : 780145516Sdarrenr bcopy(data, &su, sizeof(su)); 781145516Sdarrenr 782255332Scy if (softs->ipf_sync_debug > 4) 783145516Sdarrenr printf("[%d] Update age %lu state %d/%d \n", 784145516Sdarrenr sp->sm_num, su.stu_age, su.stu_state[0], 785145516Sdarrenr su.stu_state[1]); 786145516Sdarrenr 787255332Scy READ_ENTER(&softs->ipf_syncstate); 788255332Scy for (sl = softs->syncstatetab[hv]; (sl != NULL); 789255332Scy sl = sl->sl_next) 790145516Sdarrenr if (sl->sl_hdr.sm_num == sp->sm_num) 791145516Sdarrenr break; 792145516Sdarrenr if (sl == NULL) { 793255332Scy if (softs->ipf_sync_debug > 1) 794145516Sdarrenr printf("[%d] State not found - can't update\n", 795145516Sdarrenr sp->sm_num); 796255332Scy RWLOCK_EXIT(&softs->ipf_syncstate); 797255332Scy IPFERROR(110015); 798145516Sdarrenr err = ENOENT; 799145516Sdarrenr break; 800145516Sdarrenr } 801145516Sdarrenr 802255332Scy READ_ENTER(&softc->ipf_state); 803145516Sdarrenr 804255332Scy if (softs->ipf_sync_debug > 6) 805255332Scy printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n", 806255332Scy sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p, 807145516Sdarrenr sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table, 808145516Sdarrenr sl->sl_hdr.sm_rev); 809145516Sdarrenr 810145516Sdarrenr is = sl->sl_ips; 811145516Sdarrenr 812145516Sdarrenr MUTEX_ENTER(&is->is_lock); 813145516Sdarrenr switch (sp->sm_p) 814145516Sdarrenr { 815145516Sdarrenr case IPPROTO_TCP : 816145516Sdarrenr /* XXX FV --- shouldn't we do ntohl/htonl???? XXX */ 817145516Sdarrenr is->is_send = su.stu_data[0].td_end; 818145516Sdarrenr is->is_maxsend = su.stu_data[0].td_maxend; 819145516Sdarrenr is->is_maxswin = su.stu_data[0].td_maxwin; 820145516Sdarrenr is->is_state[0] = su.stu_state[0]; 821145516Sdarrenr is->is_dend = su.stu_data[1].td_end; 822145516Sdarrenr is->is_maxdend = su.stu_data[1].td_maxend; 823145516Sdarrenr is->is_maxdwin = su.stu_data[1].td_maxwin; 824145516Sdarrenr is->is_state[1] = su.stu_state[1]; 825145516Sdarrenr break; 826145516Sdarrenr default : 827145516Sdarrenr break; 828145516Sdarrenr } 829145516Sdarrenr 830255332Scy if (softs->ipf_sync_debug > 6) 831145516Sdarrenr printf("[%d] Setting timers for state\n", sp->sm_num); 832145516Sdarrenr 833255332Scy ipf_state_setqueue(softc, is, sp->sm_rev); 834145516Sdarrenr 835145516Sdarrenr MUTEX_EXIT(&is->is_lock); 836145516Sdarrenr break; 837145516Sdarrenr 838145516Sdarrenr default : 839255332Scy IPFERROR(110016); 840145516Sdarrenr err = EINVAL; 841145516Sdarrenr break; 842145516Sdarrenr } 843145516Sdarrenr 844145516Sdarrenr if (err == 0) { 845255332Scy RWLOCK_EXIT(&softc->ipf_state); 846255332Scy RWLOCK_EXIT(&softs->ipf_syncstate); 847145516Sdarrenr } 848145516Sdarrenr 849255332Scy if (softs->ipf_sync_debug > 6) 850145516Sdarrenr printf("[%d] Update completed with error %d\n", 851145516Sdarrenr sp->sm_num, err); 852145516Sdarrenr 853145516Sdarrenr return err; 854145516Sdarrenr} 855145516Sdarrenr 856145516Sdarrenr 857145516Sdarrenr/* ------------------------------------------------------------------------ */ 858255332Scy/* Function: ipf_sync_del */ 859145516Sdarrenr/* Returns: Nil */ 860145516Sdarrenr/* Parameters: sl(I) - pointer to synclist object to delete */ 861145516Sdarrenr/* */ 862255332Scy/* Deletes an object from the synclist. */ 863145516Sdarrenr/* ------------------------------------------------------------------------ */ 864255332Scystatic void 865255332Scyipf_sync_del(softs, sl) 866255332Scy ipf_sync_softc_t *softs; 867255332Scy synclist_t *sl; 868145516Sdarrenr{ 869145516Sdarrenr *sl->sl_pnext = sl->sl_next; 870145516Sdarrenr if (sl->sl_next != NULL) 871145516Sdarrenr sl->sl_next->sl_pnext = sl->sl_pnext; 872145516Sdarrenr if (sl->sl_idx != -1) 873255332Scy softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL; 874255332Scy} 875255332Scy 876255332Scy 877255332Scy/* ------------------------------------------------------------------------ */ 878255332Scy/* Function: ipf_sync_del_state */ 879255332Scy/* Returns: Nil */ 880255332Scy/* Parameters: sl(I) - pointer to synclist object to delete */ 881255332Scy/* */ 882255332Scy/* Deletes an object from the synclist state table and free's its memory. */ 883255332Scy/* ------------------------------------------------------------------------ */ 884255332Scyvoid 885255332Scyipf_sync_del_state(arg, sl) 886255332Scy void *arg; 887255332Scy synclist_t *sl; 888255332Scy{ 889255332Scy ipf_sync_softc_t *softs = arg; 890255332Scy 891255332Scy WRITE_ENTER(&softs->ipf_syncstate); 892255332Scy ipf_sync_del(softs, sl); 893255332Scy RWLOCK_EXIT(&softs->ipf_syncstate); 894145516Sdarrenr KFREE(sl); 895145516Sdarrenr} 896145516Sdarrenr 897145516Sdarrenr 898145516Sdarrenr/* ------------------------------------------------------------------------ */ 899255332Scy/* Function: ipf_sync_del_nat */ 900255332Scy/* Returns: Nil */ 901255332Scy/* Parameters: sl(I) - pointer to synclist object to delete */ 902255332Scy/* */ 903255332Scy/* Deletes an object from the synclist nat table and free's its memory. */ 904255332Scy/* ------------------------------------------------------------------------ */ 905255332Scyvoid 906255332Scyipf_sync_del_nat(arg, sl) 907255332Scy void *arg; 908255332Scy synclist_t *sl; 909255332Scy{ 910255332Scy ipf_sync_softc_t *softs = arg; 911255332Scy 912255332Scy WRITE_ENTER(&softs->ipf_syncnat); 913255332Scy ipf_sync_del(softs, sl); 914255332Scy RWLOCK_EXIT(&softs->ipf_syncnat); 915255332Scy KFREE(sl); 916255332Scy} 917255332Scy 918255332Scy 919255332Scy/* ------------------------------------------------------------------------ */ 920255332Scy/* Function: ipf_sync_nat */ 921145516Sdarrenr/* Returns: int - 0 == success, else error value. */ 922145516Sdarrenr/* Parameters: sp(I) - pointer to sync packet data header */ 923145516Sdarrenr/* uio(I) - pointer to user data for further information */ 924145516Sdarrenr/* */ 925145516Sdarrenr/* Updates the NAT table according to information passed in the sync */ 926145516Sdarrenr/* header. As required, more data is fetched from the uio structure but */ 927145516Sdarrenr/* varies depending on the contents of the sync header. This function can */ 928145516Sdarrenr/* create a new NAT entry or update one. Deletion is left to the NAT */ 929145516Sdarrenr/* structures being timed out correctly. */ 930145516Sdarrenr/* ------------------------------------------------------------------------ */ 931255332Scystatic int 932255332Scyipf_sync_nat(softc, sp, data) 933255332Scy ipf_main_softc_t *softc; 934255332Scy synchdr_t *sp; 935255332Scy void *data; 936145516Sdarrenr{ 937255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 938145516Sdarrenr syncupdent_t su; 939145516Sdarrenr nat_t *n, *nat; 940145516Sdarrenr synclist_t *sl; 941145516Sdarrenr u_int hv = 0; 942319633Scy int err = 0; 943145516Sdarrenr 944255332Scy READ_ENTER(&softs->ipf_syncnat); 945145516Sdarrenr 946145516Sdarrenr switch (sp->sm_cmd) 947145516Sdarrenr { 948145516Sdarrenr case SMC_CREATE : 949145516Sdarrenr KMALLOC(n, nat_t *); 950145516Sdarrenr if (n == NULL) { 951255332Scy IPFERROR(110017); 952145516Sdarrenr err = ENOMEM; 953145516Sdarrenr break; 954145516Sdarrenr } 955145516Sdarrenr 956145516Sdarrenr KMALLOC(sl, synclist_t *); 957145516Sdarrenr if (sl == NULL) { 958255332Scy IPFERROR(110018); 959145516Sdarrenr err = ENOMEM; 960145516Sdarrenr KFREE(n); 961145516Sdarrenr break; 962145516Sdarrenr } 963145516Sdarrenr 964161356Sguido nat = (nat_t *)data; 965145516Sdarrenr bzero((char *)n, offsetof(nat_t, nat_age)); 966145516Sdarrenr bcopy((char *)&nat->nat_age, (char *)&n->nat_age, 967145516Sdarrenr sizeof(*n) - offsetof(nat_t, nat_age)); 968255332Scy ipf_sync_natorder(0, n); 969145516Sdarrenr n->nat_sync = sl; 970255332Scy n->nat_rev = sl->sl_rev; 971145516Sdarrenr 972145516Sdarrenr sl->sl_idx = -1; 973145516Sdarrenr sl->sl_ipn = n; 974145516Sdarrenr sl->sl_num = ntohl(sp->sm_num); 975161356Sguido 976255332Scy WRITE_ENTER(&softc->ipf_nat); 977255332Scy sl->sl_pnext = softs->syncnattab + hv; 978255332Scy sl->sl_next = softs->syncnattab[hv]; 979255332Scy if (softs->syncnattab[hv] != NULL) 980255332Scy softs->syncnattab[hv]->sl_pnext = &sl->sl_next; 981255332Scy softs->syncnattab[hv] = sl; 982255332Scy (void) ipf_nat_insert(softc, softc->ipf_nat_soft, n); 983255332Scy RWLOCK_EXIT(&softc->ipf_nat); 984145516Sdarrenr break; 985145516Sdarrenr 986145516Sdarrenr case SMC_UPDATE : 987145516Sdarrenr bcopy(data, &su, sizeof(su)); 988145516Sdarrenr 989255332Scy for (sl = softs->syncnattab[hv]; (sl != NULL); 990255332Scy sl = sl->sl_next) 991145516Sdarrenr if (sl->sl_hdr.sm_num == sp->sm_num) 992145516Sdarrenr break; 993145516Sdarrenr if (sl == NULL) { 994255332Scy IPFERROR(110019); 995145516Sdarrenr err = ENOENT; 996145516Sdarrenr break; 997145516Sdarrenr } 998145516Sdarrenr 999255332Scy READ_ENTER(&softc->ipf_nat); 1000145516Sdarrenr 1001145516Sdarrenr nat = sl->sl_ipn; 1002255332Scy nat->nat_rev = sl->sl_rev; 1003145516Sdarrenr 1004145516Sdarrenr MUTEX_ENTER(&nat->nat_lock); 1005255332Scy ipf_nat_setqueue(softc, softc->ipf_nat_soft, nat); 1006145516Sdarrenr MUTEX_EXIT(&nat->nat_lock); 1007145516Sdarrenr 1008255332Scy RWLOCK_EXIT(&softc->ipf_nat); 1009145516Sdarrenr 1010145516Sdarrenr break; 1011145516Sdarrenr 1012145516Sdarrenr default : 1013255332Scy IPFERROR(110020); 1014145516Sdarrenr err = EINVAL; 1015145516Sdarrenr break; 1016145516Sdarrenr } 1017145516Sdarrenr 1018255332Scy RWLOCK_EXIT(&softs->ipf_syncnat); 1019319633Scy return err; 1020145516Sdarrenr} 1021145516Sdarrenr 1022145516Sdarrenr 1023145516Sdarrenr/* ------------------------------------------------------------------------ */ 1024255332Scy/* Function: ipf_sync_new */ 1025145516Sdarrenr/* Returns: synclist_t* - NULL == failure, else pointer to new synclist */ 1026145516Sdarrenr/* data structure. */ 1027145516Sdarrenr/* Parameters: tab(I) - type of synclist_t to create */ 1028145516Sdarrenr/* fin(I) - pointer to packet information */ 1029145516Sdarrenr/* ptr(I) - pointer to owning object */ 1030145516Sdarrenr/* */ 1031145516Sdarrenr/* Creates a new sync table entry and notifies any sleepers that it's there */ 1032145516Sdarrenr/* waiting to be processed. */ 1033145516Sdarrenr/* ------------------------------------------------------------------------ */ 1034255332Scysynclist_t * 1035255332Scyipf_sync_new(softc, tab, fin, ptr) 1036255332Scy ipf_main_softc_t *softc; 1037255332Scy int tab; 1038255332Scy fr_info_t *fin; 1039255332Scy void *ptr; 1040145516Sdarrenr{ 1041255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1042145516Sdarrenr synclist_t *sl, *ss; 1043145516Sdarrenr synclogent_t *sle; 1044145516Sdarrenr u_int hv, sz; 1045145516Sdarrenr 1046255332Scy if (softs->sl_idx == softs->ipf_sync_log_sz) 1047145516Sdarrenr return NULL; 1048145516Sdarrenr KMALLOC(sl, synclist_t *); 1049145516Sdarrenr if (sl == NULL) 1050145516Sdarrenr return NULL; 1051145516Sdarrenr 1052255332Scy MUTEX_ENTER(&softs->ipf_syncadd); 1053145516Sdarrenr /* 1054145516Sdarrenr * Get a unique number for this synclist_t. The number is only meant 1055145516Sdarrenr * to be unique for the lifetime of the structure and may be reused 1056145516Sdarrenr * later. 1057145516Sdarrenr */ 1058255332Scy softs->ipf_sync_num++; 1059255332Scy if (softs->ipf_sync_num == 0) { 1060255332Scy softs->ipf_sync_num = 1; 1061255332Scy softs->ipf_sync_wrap++; 1062145516Sdarrenr } 1063145516Sdarrenr 1064145516Sdarrenr /* 1065145516Sdarrenr * Use the synch number of the object as the hash key. Should end up 1066145516Sdarrenr * with relatively even distribution over time. 1067145516Sdarrenr * XXX - an attacker could lunch an DoS attack, of sorts, if they are 1068145516Sdarrenr * the only one causing new table entries by only keeping open every 1069145516Sdarrenr * nth connection they make, where n is a value in the interval 1070145516Sdarrenr * [0, SYNC_STATETABSZ-1]. 1071145516Sdarrenr */ 1072255332Scy switch (tab) 1073255332Scy { 1074255332Scy case SMC_STATE : 1075255332Scy hv = softs->ipf_sync_num & (softs->ipf_sync_state_tab_sz - 1); 1076255332Scy while (softs->ipf_sync_wrap != 0) { 1077255332Scy for (ss = softs->syncstatetab[hv]; ss; ss = ss->sl_next) 1078255332Scy if (ss->sl_hdr.sm_num == softs->ipf_sync_num) 1079255332Scy break; 1080255332Scy if (ss == NULL) 1081255332Scy break; 1082255332Scy softs->ipf_sync_num++; 1083255332Scy hv = softs->ipf_sync_num & 1084255332Scy (softs->ipf_sync_state_tab_sz - 1); 1085255332Scy } 1086255332Scy sl->sl_pnext = softs->syncstatetab + hv; 1087255332Scy sl->sl_next = softs->syncstatetab[hv]; 1088255332Scy softs->syncstatetab[hv] = sl; 1089255332Scy break; 1090145516Sdarrenr 1091255332Scy case SMC_NAT : 1092255332Scy hv = softs->ipf_sync_num & (softs->ipf_sync_nat_tab_sz - 1); 1093255332Scy while (softs->ipf_sync_wrap != 0) { 1094255332Scy for (ss = softs->syncnattab[hv]; ss; ss = ss->sl_next) 1095255332Scy if (ss->sl_hdr.sm_num == softs->ipf_sync_num) 1096255332Scy break; 1097255332Scy if (ss == NULL) 1098255332Scy break; 1099255332Scy softs->ipf_sync_num++; 1100255332Scy hv = softs->ipf_sync_num & 1101255332Scy (softs->ipf_sync_nat_tab_sz - 1); 1102255332Scy } 1103255332Scy sl->sl_pnext = softs->syncnattab + hv; 1104255332Scy sl->sl_next = softs->syncnattab[hv]; 1105255332Scy softs->syncnattab[hv] = sl; 1106255332Scy break; 1107255332Scy 1108255332Scy default : 1109255332Scy break; 1110255332Scy } 1111255332Scy 1112255332Scy sl->sl_num = softs->ipf_sync_num; 1113255332Scy MUTEX_EXIT(&softs->ipf_syncadd); 1114255332Scy 1115145516Sdarrenr sl->sl_magic = htonl(SYNHDRMAGIC); 1116145516Sdarrenr sl->sl_v = fin->fin_v; 1117145516Sdarrenr sl->sl_p = fin->fin_p; 1118145516Sdarrenr sl->sl_cmd = SMC_CREATE; 1119145516Sdarrenr sl->sl_idx = -1; 1120145516Sdarrenr sl->sl_table = tab; 1121145516Sdarrenr sl->sl_rev = fin->fin_rev; 1122145516Sdarrenr if (tab == SMC_STATE) { 1123145516Sdarrenr sl->sl_ips = ptr; 1124145516Sdarrenr sz = sizeof(*sl->sl_ips); 1125145516Sdarrenr } else if (tab == SMC_NAT) { 1126145516Sdarrenr sl->sl_ipn = ptr; 1127145516Sdarrenr sz = sizeof(*sl->sl_ipn); 1128145516Sdarrenr } else { 1129145516Sdarrenr ptr = NULL; 1130145516Sdarrenr sz = 0; 1131145516Sdarrenr } 1132145516Sdarrenr sl->sl_len = sz; 1133145516Sdarrenr 1134145516Sdarrenr /* 1135145516Sdarrenr * Create the log entry to be read by a user daemon. When it has been 1136145516Sdarrenr * finished and put on the queue, send a signal to wakeup any waiters. 1137145516Sdarrenr */ 1138255332Scy MUTEX_ENTER(&softs->ipf_syncadd); 1139255332Scy sle = softs->synclog + softs->sl_idx++; 1140145516Sdarrenr bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr, 1141145516Sdarrenr sizeof(sle->sle_hdr)); 1142145516Sdarrenr sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num); 1143145516Sdarrenr sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len); 1144145516Sdarrenr if (ptr != NULL) { 1145145516Sdarrenr bcopy((char *)ptr, (char *)&sle->sle_un, sz); 1146145516Sdarrenr if (tab == SMC_STATE) { 1147255332Scy ipf_sync_storder(1, &sle->sle_un.sleu_ips); 1148145516Sdarrenr } else if (tab == SMC_NAT) { 1149255332Scy ipf_sync_natorder(1, &sle->sle_un.sleu_ipn); 1150145516Sdarrenr } 1151145516Sdarrenr } 1152255332Scy MUTEX_EXIT(&softs->ipf_syncadd); 1153145516Sdarrenr 1154255332Scy ipf_sync_wakeup(softc); 1155145516Sdarrenr return sl; 1156145516Sdarrenr} 1157145516Sdarrenr 1158145516Sdarrenr 1159145516Sdarrenr/* ------------------------------------------------------------------------ */ 1160255332Scy/* Function: ipf_sync_update */ 1161145516Sdarrenr/* Returns: Nil */ 1162145516Sdarrenr/* Parameters: tab(I) - type of synclist_t to create */ 1163145516Sdarrenr/* fin(I) - pointer to packet information */ 1164145516Sdarrenr/* sl(I) - pointer to synchronisation object */ 1165145516Sdarrenr/* */ 1166145516Sdarrenr/* For outbound packets, only, create an sync update record for the user */ 1167145516Sdarrenr/* process to read. */ 1168145516Sdarrenr/* ------------------------------------------------------------------------ */ 1169255332Scyvoid 1170255332Scyipf_sync_update(softc, tab, fin, sl) 1171255332Scy ipf_main_softc_t *softc; 1172255332Scy int tab; 1173255332Scy fr_info_t *fin; 1174255332Scy synclist_t *sl; 1175145516Sdarrenr{ 1176255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1177145516Sdarrenr synctcp_update_t *st; 1178145516Sdarrenr syncupdent_t *slu; 1179145516Sdarrenr ipstate_t *ips; 1180145516Sdarrenr nat_t *nat; 1181255332Scy ipfrwlock_t *lock; 1182145516Sdarrenr 1183145516Sdarrenr if (fin->fin_out == 0 || sl == NULL) 1184145516Sdarrenr return; 1185145516Sdarrenr 1186255332Scy if (tab == SMC_STATE) { 1187255332Scy lock = &softs->ipf_syncstate; 1188255332Scy } else { 1189255332Scy lock = &softs->ipf_syncnat; 1190255332Scy } 1191255332Scy 1192255332Scy READ_ENTER(lock); 1193145516Sdarrenr if (sl->sl_idx == -1) { 1194255332Scy MUTEX_ENTER(&softs->ipf_syncadd); 1195255332Scy slu = softs->syncupd + softs->su_idx; 1196255332Scy sl->sl_idx = softs->su_idx++; 1197255332Scy MUTEX_EXIT(&softs->ipf_syncadd); 1198255332Scy 1199145516Sdarrenr bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr, 1200145516Sdarrenr sizeof(slu->sup_hdr)); 1201145516Sdarrenr slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC); 1202145516Sdarrenr slu->sup_hdr.sm_sl = sl; 1203145516Sdarrenr slu->sup_hdr.sm_cmd = SMC_UPDATE; 1204145516Sdarrenr slu->sup_hdr.sm_table = tab; 1205145516Sdarrenr slu->sup_hdr.sm_num = htonl(sl->sl_num); 1206145516Sdarrenr slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update)); 1207145516Sdarrenr slu->sup_hdr.sm_rev = fin->fin_rev; 1208145516Sdarrenr# if 0 1209145516Sdarrenr if (fin->fin_p == IPPROTO_TCP) { 1210145516Sdarrenr st->stu_len[0] = 0; 1211145516Sdarrenr st->stu_len[1] = 0; 1212145516Sdarrenr } 1213145516Sdarrenr# endif 1214145516Sdarrenr } else 1215255332Scy slu = softs->syncupd + sl->sl_idx; 1216145516Sdarrenr 1217145516Sdarrenr /* 1218145516Sdarrenr * Only TCP has complex timeouts, others just use default timeouts. 1219145516Sdarrenr * For TCP, we only need to track the connection state and window. 1220145516Sdarrenr */ 1221145516Sdarrenr if (fin->fin_p == IPPROTO_TCP) { 1222145516Sdarrenr st = &slu->sup_tcp; 1223145516Sdarrenr if (tab == SMC_STATE) { 1224145516Sdarrenr ips = sl->sl_ips; 1225145516Sdarrenr st->stu_age = htonl(ips->is_die); 1226145516Sdarrenr st->stu_data[0].td_end = ips->is_send; 1227145516Sdarrenr st->stu_data[0].td_maxend = ips->is_maxsend; 1228145516Sdarrenr st->stu_data[0].td_maxwin = ips->is_maxswin; 1229145516Sdarrenr st->stu_state[0] = ips->is_state[0]; 1230145516Sdarrenr st->stu_data[1].td_end = ips->is_dend; 1231145516Sdarrenr st->stu_data[1].td_maxend = ips->is_maxdend; 1232145516Sdarrenr st->stu_data[1].td_maxwin = ips->is_maxdwin; 1233145516Sdarrenr st->stu_state[1] = ips->is_state[1]; 1234145516Sdarrenr } else if (tab == SMC_NAT) { 1235145516Sdarrenr nat = sl->sl_ipn; 1236145516Sdarrenr st->stu_age = htonl(nat->nat_age); 1237145516Sdarrenr } 1238145516Sdarrenr } 1239255332Scy RWLOCK_EXIT(lock); 1240145516Sdarrenr 1241255332Scy ipf_sync_wakeup(softc); 1242145516Sdarrenr} 1243145516Sdarrenr 1244145516Sdarrenr 1245145516Sdarrenr/* ------------------------------------------------------------------------ */ 1246255332Scy/* Function: ipf_sync_flush_table */ 1247255332Scy/* Returns: int - number of entries freed by flushing table */ 1248255332Scy/* Parameters: tabsize(I) - size of the array pointed to by table */ 1249255332Scy/* table(I) - pointer to sync table to empty */ 1250255332Scy/* */ 1251255332Scy/* Walk through a table of sync entries and free each one. It is assumed */ 1252255332Scy/* that some lock is held so that nobody else tries to access the table */ 1253255332Scy/* during this cleanup. */ 1254255332Scy/* ------------------------------------------------------------------------ */ 1255255332Scystatic int 1256255332Scyipf_sync_flush_table(softs, tabsize, table) 1257255332Scy ipf_sync_softc_t *softs; 1258255332Scy int tabsize; 1259255332Scy synclist_t **table; 1260255332Scy{ 1261255332Scy synclist_t *sl; 1262255332Scy int i, items; 1263255332Scy 1264255332Scy items = 0; 1265255332Scy 1266255332Scy for (i = 0; i < tabsize; i++) { 1267255332Scy while ((sl = table[i]) != NULL) { 1268255332Scy switch (sl->sl_table) { 1269255332Scy case SMC_STATE : 1270255332Scy if (sl->sl_ips != NULL) 1271255332Scy sl->sl_ips->is_sync = NULL; 1272255332Scy break; 1273255332Scy case SMC_NAT : 1274255332Scy if (sl->sl_ipn != NULL) 1275255332Scy sl->sl_ipn->nat_sync = NULL; 1276255332Scy break; 1277255332Scy } 1278255332Scy if (sl->sl_next != NULL) 1279255332Scy sl->sl_next->sl_pnext = sl->sl_pnext; 1280255332Scy table[i] = sl->sl_next; 1281255332Scy if (sl->sl_idx != -1) 1282255332Scy softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL; 1283255332Scy KFREE(sl); 1284255332Scy items++; 1285255332Scy } 1286255332Scy } 1287255332Scy 1288255332Scy return items; 1289255332Scy} 1290255332Scy 1291255332Scy 1292255332Scy/* ------------------------------------------------------------------------ */ 1293255332Scy/* Function: ipf_sync_ioctl */ 1294145516Sdarrenr/* Returns: int - 0 == success, != 0 == failure */ 1295145516Sdarrenr/* Parameters: data(I) - pointer to ioctl data */ 1296145516Sdarrenr/* cmd(I) - ioctl command integer */ 1297145516Sdarrenr/* mode(I) - file mode bits used with open */ 1298145516Sdarrenr/* */ 1299145516Sdarrenr/* This function currently does not handle any ioctls and so just returns */ 1300145516Sdarrenr/* EINVAL on all occasions. */ 1301145516Sdarrenr/* ------------------------------------------------------------------------ */ 1302255332Scyint 1303255332Scyipf_sync_ioctl(softc, data, cmd, mode, uid, ctx) 1304255332Scy ipf_main_softc_t *softc; 1305255332Scy caddr_t data; 1306255332Scy ioctlcmd_t cmd; 1307255332Scy int mode, uid; 1308255332Scy void *ctx; 1309145516Sdarrenr{ 1310255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1311255332Scy int error, i; 1312255332Scy SPL_INT(s); 1313255332Scy 1314255332Scy switch (cmd) 1315255332Scy { 1316255332Scy case SIOCIPFFL: 1317255332Scy error = BCOPYIN(data, &i, sizeof(i)); 1318255332Scy if (error != 0) { 1319255332Scy IPFERROR(110023); 1320255332Scy error = EFAULT; 1321255332Scy break; 1322255332Scy } 1323255332Scy 1324255332Scy switch (i) 1325255332Scy { 1326255332Scy case SMC_RLOG : 1327255332Scy SPL_NET(s); 1328255332Scy MUTEX_ENTER(&softs->ipsl_mutex); 1329255332Scy i = (softs->sl_tail - softs->sl_idx) + 1330255332Scy (softs->su_tail - softs->su_idx); 1331255332Scy softs->sl_idx = 0; 1332255332Scy softs->su_idx = 0; 1333255332Scy softs->sl_tail = 0; 1334255332Scy softs->su_tail = 0; 1335255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 1336255332Scy SPL_X(s); 1337255332Scy break; 1338255332Scy 1339255332Scy case SMC_NAT : 1340255332Scy SPL_NET(s); 1341255332Scy WRITE_ENTER(&softs->ipf_syncnat); 1342255332Scy i = ipf_sync_flush_table(softs, SYNC_NATTABSZ, 1343255332Scy softs->syncnattab); 1344255332Scy RWLOCK_EXIT(&softs->ipf_syncnat); 1345255332Scy SPL_X(s); 1346255332Scy break; 1347255332Scy 1348255332Scy case SMC_STATE : 1349255332Scy SPL_NET(s); 1350255332Scy WRITE_ENTER(&softs->ipf_syncstate); 1351255332Scy i = ipf_sync_flush_table(softs, SYNC_STATETABSZ, 1352255332Scy softs->syncstatetab); 1353255332Scy RWLOCK_EXIT(&softs->ipf_syncstate); 1354255332Scy SPL_X(s); 1355255332Scy break; 1356255332Scy } 1357255332Scy 1358255332Scy error = BCOPYOUT(&i, data, sizeof(i)); 1359255332Scy if (error != 0) { 1360255332Scy IPFERROR(110022); 1361255332Scy error = EFAULT; 1362255332Scy } 1363255332Scy break; 1364255332Scy 1365255332Scy default : 1366255332Scy IPFERROR(110021); 1367255332Scy error = EINVAL; 1368255332Scy break; 1369255332Scy } 1370255332Scy 1371255332Scy return error; 1372145516Sdarrenr} 1373161356Sguido 1374161356Sguido 1375255332Scy/* ------------------------------------------------------------------------ */ 1376255332Scy/* Function: ipf_sync_canread */ 1377255332Scy/* Returns: int - 0 == success, != 0 == failure */ 1378255332Scy/* Parameters: Nil */ 1379255332Scy/* */ 1380255332Scy/* This function provides input to the poll handler about whether or not */ 1381255332Scy/* there is data waiting to be read from the /dev/ipsync device. */ 1382255332Scy/* ------------------------------------------------------------------------ */ 1383255332Scyint 1384255332Scyipf_sync_canread(arg) 1385255332Scy void *arg; 1386161356Sguido{ 1387255332Scy ipf_sync_softc_t *softs = arg; 1388255332Scy return !((softs->sl_tail == softs->sl_idx) && 1389255332Scy (softs->su_tail == softs->su_idx)); 1390161356Sguido} 1391161356Sguido 1392161356Sguido 1393255332Scy/* ------------------------------------------------------------------------ */ 1394255332Scy/* Function: ipf_sync_canwrite */ 1395255332Scy/* Returns: int - 1 == can always write */ 1396255332Scy/* Parameters: Nil */ 1397255332Scy/* */ 1398255332Scy/* This function lets the poll handler know that it is always ready willing */ 1399255332Scy/* to accept write events. */ 1400255332Scy/* XXX Maybe this should return false if the sync table is full? */ 1401255332Scy/* ------------------------------------------------------------------------ */ 1402255332Scyint 1403255332Scyipf_sync_canwrite(arg) 1404255332Scy void *arg; 1405161356Sguido{ 1406161356Sguido return 1; 1407161356Sguido} 1408255332Scy 1409255332Scy 1410255332Scy/* ------------------------------------------------------------------------ */ 1411255332Scy/* Function: ipf_sync_wakeup */ 1412255332Scy/* Parameters: Nil */ 1413255332Scy/* Returns: Nil */ 1414255332Scy/* */ 1415255332Scy/* This function implements the heuristics that decide how often to */ 1416255332Scy/* generate a poll wakeup for programs that are waiting for information */ 1417255332Scy/* about when they can do a read on /dev/ipsync. */ 1418255332Scy/* */ 1419255332Scy/* There are three different considerations here: */ 1420255332Scy/* - do not keep a program waiting too long: ipf_sync_wake_interval is the */ 1421255332Scy/* maximum number of ipf ticks to let pass by; */ 1422255332Scy/* - do not let the queue of ouststanding things to generate notifies for */ 1423255332Scy/* get too full (ipf_sync_queue_high_wm is the high water mark); */ 1424255332Scy/* - do not let too many events get collapsed in before deciding that the */ 1425255332Scy/* other host(s) need an update (ipf_sync_event_high_wm is the high water */ 1426255332Scy/* mark for this counter.) */ 1427255332Scy/* ------------------------------------------------------------------------ */ 1428255332Scystatic void 1429255332Scyipf_sync_wakeup(softc) 1430255332Scy ipf_main_softc_t *softc; 1431255332Scy{ 1432255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1433255332Scy 1434255332Scy softs->ipf_sync_events++; 1435255332Scy if ((softc->ipf_ticks > 1436255332Scy softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval) || 1437255332Scy (softs->ipf_sync_events > softs->ipf_sync_event_high_wm) || 1438255332Scy ((softs->sl_tail - softs->sl_idx) > 1439255332Scy softs->ipf_sync_queue_high_wm) || 1440255332Scy ((softs->su_tail - softs->su_idx) > 1441255332Scy softs->ipf_sync_queue_high_wm)) { 1442255332Scy 1443255332Scy ipf_sync_poll_wakeup(softc); 1444255332Scy } 1445255332Scy} 1446255332Scy 1447255332Scy 1448255332Scy/* ------------------------------------------------------------------------ */ 1449255332Scy/* Function: ipf_sync_poll_wakeup */ 1450255332Scy/* Parameters: Nil */ 1451255332Scy/* Returns: Nil */ 1452255332Scy/* */ 1453255332Scy/* Deliver a poll wakeup and reset counters for two of the three heuristics */ 1454255332Scy/* ------------------------------------------------------------------------ */ 1455255332Scystatic void 1456255332Scyipf_sync_poll_wakeup(softc) 1457255332Scy ipf_main_softc_t *softc; 1458255332Scy{ 1459255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1460255332Scy 1461255332Scy softs->ipf_sync_events = 0; 1462255332Scy softs->ipf_sync_lastwakeup = softc->ipf_ticks; 1463255332Scy 1464255332Scy# ifdef _KERNEL 1465255332Scy# if SOLARIS 1466255332Scy MUTEX_ENTER(&softs->ipsl_mutex); 1467255332Scy cv_signal(&softs->ipslwait); 1468255332Scy MUTEX_EXIT(&softs->ipsl_mutex); 1469255332Scy pollwakeup(&softc->ipf_poll_head[IPL_LOGSYNC], POLLIN|POLLRDNORM); 1470255332Scy# else 1471255332Scy WAKEUP(&softs->sl_tail, 0); 1472255332Scy POLLWAKEUP(IPL_LOGSYNC); 1473255332Scy# endif 1474255332Scy# endif 1475255332Scy} 1476255332Scy 1477255332Scy 1478255332Scy/* ------------------------------------------------------------------------ */ 1479255332Scy/* Function: ipf_sync_expire */ 1480255332Scy/* Parameters: Nil */ 1481255332Scy/* Returns: Nil */ 1482255332Scy/* */ 1483255332Scy/* This is the function called even ipf_tick. It implements one of the */ 1484255332Scy/* three heuristics above *IF* there are events waiting. */ 1485255332Scy/* ------------------------------------------------------------------------ */ 1486255332Scyvoid 1487255332Scyipf_sync_expire(softc) 1488255332Scy ipf_main_softc_t *softc; 1489255332Scy{ 1490255332Scy ipf_sync_softc_t *softs = softc->ipf_sync_soft; 1491255332Scy 1492255332Scy if ((softs->ipf_sync_events > 0) && 1493255332Scy (softc->ipf_ticks > 1494255332Scy softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval)) { 1495255332Scy ipf_sync_poll_wakeup(softc); 1496255332Scy } 1497255332Scy} 1498