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