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