1145516Sdarrenr/*	$FreeBSD$	*/
2145516Sdarrenr
3145516Sdarrenr/*
4145516Sdarrenr * Copyright (C) 1995-1998 by Darren Reed.
5145516Sdarrenr *
6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145516Sdarrenr */
8145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL)
9145516Sdarrenr# undef KERNEL
10145516Sdarrenr# undef _KERNEL
11145516Sdarrenr# define        KERNEL	1
12145516Sdarrenr# define        _KERNEL	1
13145516Sdarrenr#endif
14145516Sdarrenr#include <sys/errno.h>
15145516Sdarrenr#include <sys/types.h>
16145516Sdarrenr#include <sys/param.h>
17145516Sdarrenr#include <sys/file.h>
18145516Sdarrenr#if !defined(_KERNEL) && !defined(__KERNEL__)
19145516Sdarrenr# include <stdio.h>
20145516Sdarrenr# include <stdlib.h>
21145516Sdarrenr# include <string.h>
22145516Sdarrenr# define _KERNEL
23145516Sdarrenr# define KERNEL
24145516Sdarrenr# ifdef __OpenBSD__
25145516Sdarrenrstruct file;
26145516Sdarrenr# endif
27145516Sdarrenr# include <sys/uio.h>
28145516Sdarrenr# undef _KERNEL
29145516Sdarrenr# undef KERNEL
30145516Sdarrenr#else
31145516Sdarrenr# include <sys/systm.h>
32145516Sdarrenr# if !defined(__SVR4) && !defined(__svr4__)
33145516Sdarrenr#  include <sys/mbuf.h>
34145516Sdarrenr# endif
35145516Sdarrenr#endif
36145516Sdarrenr#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
37145516Sdarrenr# include <sys/proc.h>
38145516Sdarrenr#endif
39145516Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
40145516Sdarrenr# include <sys/filio.h>
41145516Sdarrenr# include <sys/fcntl.h>
42145516Sdarrenr# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
43145516Sdarrenr#  include "opt_ipfilter.h"
44145516Sdarrenr# endif
45145516Sdarrenr#else
46145516Sdarrenr# include <sys/ioctl.h>
47145516Sdarrenr#endif
48145516Sdarrenr#include <sys/time.h>
49145516Sdarrenr#if !defined(linux)
50145516Sdarrenr# include <sys/protosw.h>
51145516Sdarrenr#endif
52145516Sdarrenr#include <sys/socket.h>
53145516Sdarrenr#if defined(__SVR4) || defined(__svr4__)
54145516Sdarrenr# include <sys/filio.h>
55145516Sdarrenr# include <sys/byteorder.h>
56145516Sdarrenr# ifdef _KERNEL
57145516Sdarrenr#  include <sys/dditypes.h>
58145516Sdarrenr# endif
59145516Sdarrenr# include <sys/stream.h>
60145516Sdarrenr# include <sys/kmem.h>
61145516Sdarrenr#endif
62145516Sdarrenr
63145516Sdarrenr#include <net/if.h>
64145516Sdarrenr#ifdef sun
65145516Sdarrenr# include <net/af.h>
66145516Sdarrenr#endif
67145516Sdarrenr#include <net/route.h>
68145516Sdarrenr#include <netinet/in.h>
69145516Sdarrenr#include <netinet/in_systm.h>
70145516Sdarrenr#include <netinet/ip.h>
71145516Sdarrenr#include <netinet/tcp.h>
72145516Sdarrenr#if !defined(linux)
73145516Sdarrenr# include <netinet/ip_var.h>
74145516Sdarrenr#endif
75145516Sdarrenr#if !defined(__hpux) && !defined(linux)
76145516Sdarrenr# include <netinet/tcp_fsm.h>
77145516Sdarrenr#endif
78145516Sdarrenr#include <netinet/udp.h>
79145516Sdarrenr#include <netinet/ip_icmp.h>
80145516Sdarrenr#include "netinet/ip_compat.h"
81145516Sdarrenr#include <netinet/tcpip.h>
82145516Sdarrenr#include "netinet/ip_fil.h"
83145516Sdarrenr#include "netinet/ip_nat.h"
84145516Sdarrenr#include "netinet/ip_frag.h"
85145516Sdarrenr#include "netinet/ip_state.h"
86145516Sdarrenr#include "netinet/ip_proxy.h"
87145516Sdarrenr#include "netinet/ip_sync.h"
88145516Sdarrenr#ifdef  USE_INET6
89145516Sdarrenr#include <netinet/icmp6.h>
90145516Sdarrenr#endif
91145516Sdarrenr#if (__FreeBSD_version >= 300000)
92145516Sdarrenr# include <sys/malloc.h>
93145516Sdarrenr# if defined(_KERNEL) && !defined(IPFILTER_LKM)
94145516Sdarrenr#  include <sys/libkern.h>
95145516Sdarrenr#  include <sys/systm.h>
96145516Sdarrenr# endif
97145516Sdarrenr#endif
98145516Sdarrenr/* END OF INCLUDES */
99145516Sdarrenr
100145516Sdarrenr#if !defined(lint)
101172776Sdarrenrstatic const char rcsid[] = "@(#)$Id: ip_sync.c,v 2.40.2.9 2007/06/02 21:22:28 darrenr Exp $";
102145516Sdarrenr#endif
103145516Sdarrenr
104145516Sdarrenr#define	SYNC_STATETABSZ	256
105145516Sdarrenr#define	SYNC_NATTABSZ	256
106145516Sdarrenr
107145516Sdarrenr#ifdef	IPFILTER_SYNC
108145516Sdarrenripfmutex_t	ipf_syncadd, ipsl_mutex;
109145516Sdarrenripfrwlock_t	ipf_syncstate, ipf_syncnat;
110145516Sdarrenr#if SOLARIS && defined(_KERNEL)
111145516Sdarrenrkcondvar_t	ipslwait;
112145516Sdarrenr#endif
113145516Sdarrenrsynclist_t	*syncstatetab[SYNC_STATETABSZ];
114145516Sdarrenrsynclist_t	*syncnattab[SYNC_NATTABSZ];
115145516Sdarrenrsynclogent_t	synclog[SYNCLOG_SZ];
116145516Sdarrenrsyncupdent_t	syncupd[SYNCLOG_SZ];
117145516Sdarrenru_int		ipf_syncnum = 1;
118145516Sdarrenru_int		ipf_syncwrap = 0;
119145516Sdarrenru_int		sl_idx = 0,	/* next available sync log entry */
120145516Sdarrenr		su_idx = 0,	/* next available sync update entry */
121145516Sdarrenr		sl_tail = 0,	/* next sync log entry to read */
122145516Sdarrenr		su_tail = 0;	/* next sync update entry to read */
123145516Sdarrenrint		ipf_sync_debug = 0;
124145516Sdarrenr
125145516Sdarrenr
126145516Sdarrenr# if !defined(sparc) && !defined(__hppa)
127145516Sdarrenrvoid ipfsync_tcporder __P((int, struct tcpdata *));
128145516Sdarrenrvoid ipfsync_natorder __P((int, struct nat *));
129145516Sdarrenrvoid ipfsync_storder __P((int, struct ipstate *));
130145516Sdarrenr# endif
131145516Sdarrenr
132145516Sdarrenr
133145516Sdarrenr/* ------------------------------------------------------------------------ */
134145516Sdarrenr/* Function:    ipfsync_init                                                */
135145516Sdarrenr/* Returns:     int - 0 == success, -1 == failure                           */
136145516Sdarrenr/* Parameters:  Nil                                                         */
137145516Sdarrenr/*                                                                          */
138145516Sdarrenr/* Initialise all of the locks required for the sync code and initialise    */
139145516Sdarrenr/* any data structures, as required.                                        */
140145516Sdarrenr/* ------------------------------------------------------------------------ */
141145516Sdarrenrint ipfsync_init()
142145516Sdarrenr{
143145516Sdarrenr	RWLOCK_INIT(&ipf_syncstate, "add things to state sync table");
144145516Sdarrenr	RWLOCK_INIT(&ipf_syncnat, "add things to nat sync table");
145145516Sdarrenr	MUTEX_INIT(&ipf_syncadd, "add things to sync table");
146145516Sdarrenr	MUTEX_INIT(&ipsl_mutex, "add things to sync table");
147145516Sdarrenr# if SOLARIS && defined(_KERNEL)
148145516Sdarrenr	cv_init(&ipslwait, "ipsl condvar", CV_DRIVER, NULL);
149145516Sdarrenr# endif
150145516Sdarrenr
151145516Sdarrenr	bzero((char *)syncnattab, sizeof(syncnattab));
152145516Sdarrenr	bzero((char *)syncstatetab, sizeof(syncstatetab));
153145516Sdarrenr
154145516Sdarrenr	return 0;
155145516Sdarrenr}
156145516Sdarrenr
157145516Sdarrenr
158145516Sdarrenr# if !defined(sparc) && !defined(__hppa)
159145516Sdarrenr/* ------------------------------------------------------------------------ */
160145516Sdarrenr/* Function:    ipfsync_tcporder                                            */
161145516Sdarrenr/* Returns:     Nil                                                         */
162145516Sdarrenr/* Parameters:  way(I) - direction of byte order conversion.                */
163145516Sdarrenr/*              td(IO) - pointer to data to be converted.                   */
164145516Sdarrenr/*                                                                          */
165145516Sdarrenr/* Do byte swapping on values in the TCP state information structure that   */
166145516Sdarrenr/* need to be used at both ends by the host in their native byte order.     */
167145516Sdarrenr/* ------------------------------------------------------------------------ */
168145516Sdarrenrvoid ipfsync_tcporder(way, td)
169145516Sdarrenrint way;
170145516Sdarrenrtcpdata_t *td;
171145516Sdarrenr{
172145516Sdarrenr	if (way) {
173145516Sdarrenr		td->td_maxwin = htons(td->td_maxwin);
174145516Sdarrenr		td->td_end = htonl(td->td_end);
175145516Sdarrenr		td->td_maxend = htonl(td->td_maxend);
176145516Sdarrenr	} else {
177145516Sdarrenr		td->td_maxwin = ntohs(td->td_maxwin);
178145516Sdarrenr		td->td_end = ntohl(td->td_end);
179145516Sdarrenr		td->td_maxend = ntohl(td->td_maxend);
180145516Sdarrenr	}
181145516Sdarrenr}
182145516Sdarrenr
183145516Sdarrenr
184145516Sdarrenr/* ------------------------------------------------------------------------ */
185145516Sdarrenr/* Function:    ipfsync_natorder                                            */
186145516Sdarrenr/* Returns:     Nil                                                         */
187145516Sdarrenr/* Parameters:  way(I)  - direction of byte order conversion.               */
188145516Sdarrenr/*              nat(IO) - pointer to data to be converted.                  */
189145516Sdarrenr/*                                                                          */
190145516Sdarrenr/* Do byte swapping on values in the NAT data structure that need to be     */
191145516Sdarrenr/* used at both ends by the host in their native byte order.                */
192145516Sdarrenr/* ------------------------------------------------------------------------ */
193145516Sdarrenrvoid ipfsync_natorder(way, n)
194145516Sdarrenrint way;
195145516Sdarrenrnat_t *n;
196145516Sdarrenr{
197145516Sdarrenr	if (way) {
198145516Sdarrenr		n->nat_age = htonl(n->nat_age);
199145516Sdarrenr		n->nat_flags = htonl(n->nat_flags);
200145516Sdarrenr		n->nat_ipsumd = htonl(n->nat_ipsumd);
201145516Sdarrenr		n->nat_use = htonl(n->nat_use);
202145516Sdarrenr		n->nat_dir = htonl(n->nat_dir);
203145516Sdarrenr	} else {
204145516Sdarrenr		n->nat_age = ntohl(n->nat_age);
205145516Sdarrenr		n->nat_flags = ntohl(n->nat_flags);
206145516Sdarrenr		n->nat_ipsumd = ntohl(n->nat_ipsumd);
207145516Sdarrenr		n->nat_use = ntohl(n->nat_use);
208145516Sdarrenr		n->nat_dir = ntohl(n->nat_dir);
209145516Sdarrenr	}
210145516Sdarrenr}
211145516Sdarrenr
212145516Sdarrenr
213145516Sdarrenr/* ------------------------------------------------------------------------ */
214145516Sdarrenr/* Function:    ipfsync_storder                                             */
215145516Sdarrenr/* Returns:     Nil                                                         */
216145516Sdarrenr/* Parameters:  way(I)  - direction of byte order conversion.               */
217145516Sdarrenr/*              ips(IO) - pointer to data to be converted.                  */
218145516Sdarrenr/*                                                                          */
219145516Sdarrenr/* Do byte swapping on values in the IP state data structure that need to   */
220145516Sdarrenr/* be used at both ends by the host in their native byte order.             */
221145516Sdarrenr/* ------------------------------------------------------------------------ */
222145516Sdarrenrvoid ipfsync_storder(way, ips)
223145516Sdarrenrint way;
224145516Sdarrenripstate_t *ips;
225145516Sdarrenr{
226145516Sdarrenr	ipfsync_tcporder(way, &ips->is_tcp.ts_data[0]);
227145516Sdarrenr	ipfsync_tcporder(way, &ips->is_tcp.ts_data[1]);
228145516Sdarrenr
229145516Sdarrenr	if (way) {
230145516Sdarrenr		ips->is_hv = htonl(ips->is_hv);
231145516Sdarrenr		ips->is_die = htonl(ips->is_die);
232145516Sdarrenr		ips->is_pass = htonl(ips->is_pass);
233145516Sdarrenr		ips->is_flags = htonl(ips->is_flags);
234153876Sguido		ips->is_opt[0] = htonl(ips->is_opt[0]);
235153876Sguido		ips->is_opt[1] = htonl(ips->is_opt[1]);
236153876Sguido		ips->is_optmsk[0] = htonl(ips->is_optmsk[0]);
237153876Sguido		ips->is_optmsk[1] = htonl(ips->is_optmsk[1]);
238145516Sdarrenr		ips->is_sec = htons(ips->is_sec);
239145516Sdarrenr		ips->is_secmsk = htons(ips->is_secmsk);
240145516Sdarrenr		ips->is_auth = htons(ips->is_auth);
241145516Sdarrenr		ips->is_authmsk = htons(ips->is_authmsk);
242145516Sdarrenr		ips->is_s0[0] = htonl(ips->is_s0[0]);
243145516Sdarrenr		ips->is_s0[1] = htonl(ips->is_s0[1]);
244145516Sdarrenr		ips->is_smsk[0] = htons(ips->is_smsk[0]);
245145516Sdarrenr		ips->is_smsk[1] = htons(ips->is_smsk[1]);
246145516Sdarrenr	} else {
247145516Sdarrenr		ips->is_hv = ntohl(ips->is_hv);
248145516Sdarrenr		ips->is_die = ntohl(ips->is_die);
249145516Sdarrenr		ips->is_pass = ntohl(ips->is_pass);
250145516Sdarrenr		ips->is_flags = ntohl(ips->is_flags);
251153876Sguido		ips->is_opt[0] = ntohl(ips->is_opt[0]);
252153876Sguido		ips->is_opt[1] = ntohl(ips->is_opt[1]);
253153876Sguido		ips->is_optmsk[0] = ntohl(ips->is_optmsk[0]);
254153876Sguido		ips->is_optmsk[1] = ntohl(ips->is_optmsk[1]);
255145516Sdarrenr		ips->is_sec = ntohs(ips->is_sec);
256145516Sdarrenr		ips->is_secmsk = ntohs(ips->is_secmsk);
257145516Sdarrenr		ips->is_auth = ntohs(ips->is_auth);
258145516Sdarrenr		ips->is_authmsk = ntohs(ips->is_authmsk);
259145516Sdarrenr		ips->is_s0[0] = ntohl(ips->is_s0[0]);
260145516Sdarrenr		ips->is_s0[1] = ntohl(ips->is_s0[1]);
261145516Sdarrenr		ips->is_smsk[0] = ntohl(ips->is_smsk[0]);
262145516Sdarrenr		ips->is_smsk[1] = ntohl(ips->is_smsk[1]);
263145516Sdarrenr	}
264145516Sdarrenr}
265145516Sdarrenr# else /* !defined(sparc) && !defined(__hppa) */
266145516Sdarrenr#  define	ipfsync_tcporder(x,y)
267145516Sdarrenr#  define	ipfsync_natorder(x,y)
268145516Sdarrenr#  define	ipfsync_storder(x,y)
269145516Sdarrenr# endif /* !defined(sparc) && !defined(__hppa) */
270145516Sdarrenr
271145516Sdarrenr/* enable this for debugging */
272145516Sdarrenr
273145516Sdarrenr# ifdef _KERNEL
274145516Sdarrenr/* ------------------------------------------------------------------------ */
275145516Sdarrenr/* Function:    ipfsync_write                                               */
276145516Sdarrenr/* Returns:     int    - 0 == success, else error value.                    */
277145516Sdarrenr/* Parameters:  uio(I) - pointer to information about data to write         */
278145516Sdarrenr/*                                                                          */
279145516Sdarrenr/* Moves data from user space into the kernel and uses it for updating data */
280145516Sdarrenr/* structures in the state/NAT tables.                                      */
281145516Sdarrenr/* ------------------------------------------------------------------------ */
282145516Sdarrenrint ipfsync_write(uio)
283145516Sdarrenrstruct uio *uio;
284145516Sdarrenr{
285145516Sdarrenr	synchdr_t sh;
286145516Sdarrenr
287145516Sdarrenr	/*
288145516Sdarrenr	 * THIS MUST BE SUFFICIENT LARGE TO STORE
289145516Sdarrenr	 * ANY POSSIBLE DATA TYPE
290145516Sdarrenr	 */
291145516Sdarrenr	char data[2048];
292145516Sdarrenr
293145516Sdarrenr	int err = 0;
294145516Sdarrenr
295145516Sdarrenr#  if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
296145516Sdarrenr	uio->uio_rw = UIO_WRITE;
297145516Sdarrenr#  endif
298145516Sdarrenr
299145516Sdarrenr	/* Try to get bytes */
300145516Sdarrenr	while (uio->uio_resid > 0) {
301145516Sdarrenr
302145516Sdarrenr		if (uio->uio_resid >= sizeof(sh)) {
303145516Sdarrenr
304172776Sdarrenr			err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio);
305145516Sdarrenr
306145516Sdarrenr			if (err) {
307145516Sdarrenr				if (ipf_sync_debug > 2)
308145516Sdarrenr					printf("uiomove(header) failed: %d\n",
309145516Sdarrenr						err);
310145516Sdarrenr				return err;
311145516Sdarrenr			}
312145516Sdarrenr
313145516Sdarrenr			/* convert to host order */
314145516Sdarrenr			sh.sm_magic = ntohl(sh.sm_magic);
315145516Sdarrenr			sh.sm_len = ntohl(sh.sm_len);
316145516Sdarrenr			sh.sm_num = ntohl(sh.sm_num);
317145516Sdarrenr
318145516Sdarrenr			if (ipf_sync_debug > 8)
319145516Sdarrenr				printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n",
320145516Sdarrenr					sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd,
321145516Sdarrenr					sh.sm_table, sh.sm_rev, sh.sm_len,
322145516Sdarrenr					sh.sm_magic);
323145516Sdarrenr
324145516Sdarrenr			if (sh.sm_magic != SYNHDRMAGIC) {
325145516Sdarrenr				if (ipf_sync_debug > 2)
326145516Sdarrenr					printf("uiomove(header) invalud %s\n",
327145516Sdarrenr						"magic");
328145516Sdarrenr				return EINVAL;
329145516Sdarrenr			}
330145516Sdarrenr
331145516Sdarrenr			if (sh.sm_v != 4 && sh.sm_v != 6) {
332145516Sdarrenr				if (ipf_sync_debug > 2)
333145516Sdarrenr					printf("uiomove(header) invalid %s\n",
334145516Sdarrenr						"protocol");
335145516Sdarrenr				return EINVAL;
336145516Sdarrenr			}
337145516Sdarrenr
338145516Sdarrenr			if (sh.sm_cmd > SMC_MAXCMD) {
339145516Sdarrenr				if (ipf_sync_debug > 2)
340145516Sdarrenr					printf("uiomove(header) invalid %s\n",
341145516Sdarrenr						"command");
342145516Sdarrenr				return EINVAL;
343145516Sdarrenr			}
344145516Sdarrenr
345145516Sdarrenr
346145516Sdarrenr			if (sh.sm_table > SMC_MAXTBL) {
347145516Sdarrenr				if (ipf_sync_debug > 2)
348145516Sdarrenr					printf("uiomove(header) invalid %s\n",
349145516Sdarrenr						"table");
350145516Sdarrenr				return EINVAL;
351145516Sdarrenr			}
352145516Sdarrenr
353145516Sdarrenr		} else {
354145516Sdarrenr			/* unsufficient data, wait until next call */
355145516Sdarrenr			if (ipf_sync_debug > 2)
356145516Sdarrenr				printf("uiomove(header) insufficient data");
357145516Sdarrenr			return EAGAIN;
358145516Sdarrenr	 	}
359145516Sdarrenr
360145516Sdarrenr
361145516Sdarrenr		/*
362145516Sdarrenr		 * We have a header, so try to read the amount of data
363145516Sdarrenr		 * needed for the request
364145516Sdarrenr		 */
365145516Sdarrenr
366145516Sdarrenr		/* not supported */
367145516Sdarrenr		if (sh.sm_len == 0) {
368145516Sdarrenr			if (ipf_sync_debug > 2)
369145516Sdarrenr				printf("uiomove(data zero length %s\n",
370145516Sdarrenr					"not supported");
371145516Sdarrenr			return EINVAL;
372145516Sdarrenr		}
373145516Sdarrenr
374145516Sdarrenr		if (uio->uio_resid >= sh.sm_len) {
375145516Sdarrenr
376172776Sdarrenr			err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio);
377145516Sdarrenr
378145516Sdarrenr			if (err) {
379145516Sdarrenr				if (ipf_sync_debug > 2)
380145516Sdarrenr					printf("uiomove(data) failed: %d\n",
381145516Sdarrenr						err);
382145516Sdarrenr				return err;
383145516Sdarrenr			}
384145516Sdarrenr
385145516Sdarrenr			if (ipf_sync_debug > 7)
386145516Sdarrenr				printf("uiomove(data) %d bytes read\n",
387145516Sdarrenr					sh.sm_len);
388145516Sdarrenr
389145516Sdarrenr			if (sh.sm_table == SMC_STATE)
390145516Sdarrenr				err = ipfsync_state(&sh, data);
391145516Sdarrenr			else if (sh.sm_table == SMC_NAT)
392145516Sdarrenr				err = ipfsync_nat(&sh, data);
393145516Sdarrenr			if (ipf_sync_debug > 7)
394145516Sdarrenr				printf("[%d] Finished with error %d\n",
395145516Sdarrenr					sh.sm_num, err);
396145516Sdarrenr
397145516Sdarrenr		} else {
398145516Sdarrenr			/* insufficient data, wait until next call */
399145516Sdarrenr			if (ipf_sync_debug > 2)
400145516Sdarrenr				printf("uiomove(data) %s %d bytes, got %d\n",
401145516Sdarrenr					"insufficient data, need",
402145516Sdarrenr					sh.sm_len, uio->uio_resid);
403145516Sdarrenr			return EAGAIN;
404145516Sdarrenr		}
405145516Sdarrenr	}
406145516Sdarrenr
407145516Sdarrenr	/* no more data */
408145516Sdarrenr	return 0;
409145516Sdarrenr}
410145516Sdarrenr
411145516Sdarrenr
412145516Sdarrenr/* ------------------------------------------------------------------------ */
413145516Sdarrenr/* Function:    ipfsync_read                                                */
414145516Sdarrenr/* Returns:     int    - 0 == success, else error value.                    */
415145516Sdarrenr/* Parameters:  uio(O) - pointer to information about where to store data   */
416145516Sdarrenr/*                                                                          */
417145516Sdarrenr/* This function is called when a user program wants to read some data      */
418145516Sdarrenr/* for pending state/NAT updates.  If no data is available, the caller is   */
419145516Sdarrenr/* put to sleep, pending a wakeup from the "lower half" of this code.       */
420145516Sdarrenr/* ------------------------------------------------------------------------ */
421145516Sdarrenrint ipfsync_read(uio)
422145516Sdarrenrstruct uio *uio;
423145516Sdarrenr{
424145516Sdarrenr	syncupdent_t *su;
425145516Sdarrenr	synclogent_t *sl;
426145516Sdarrenr	int err = 0;
427145516Sdarrenr
428145516Sdarrenr	if ((uio->uio_resid & 3) || (uio->uio_resid < 8))
429145516Sdarrenr		return EINVAL;
430145516Sdarrenr
431145516Sdarrenr#  if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
432145516Sdarrenr	uio->uio_rw = UIO_READ;
433145516Sdarrenr#  endif
434145516Sdarrenr
435145516Sdarrenr	MUTEX_ENTER(&ipsl_mutex);
436145516Sdarrenr	while ((sl_tail == sl_idx) && (su_tail == su_idx)) {
437145516Sdarrenr#  if SOLARIS && defined(_KERNEL)
438145516Sdarrenr		if (!cv_wait_sig(&ipslwait, &ipsl_mutex)) {
439145516Sdarrenr			MUTEX_EXIT(&ipsl_mutex);
440145516Sdarrenr			return EINTR;
441145516Sdarrenr		}
442145516Sdarrenr#  else
443145516Sdarrenr#   ifdef __hpux
444145516Sdarrenr		{
445145516Sdarrenr		lock_t *l;
446145516Sdarrenr
447145516Sdarrenr		l = get_sleep_lock(&sl_tail);
448145516Sdarrenr		err = sleep(&sl_tail, PZERO+1);
449147367Sdarrenr		if (err) {
450147367Sdarrenr			MUTEX_EXIT(&ipsl_mutex);
451147367Sdarrenr			return EINTR;
452147367Sdarrenr		}
453145516Sdarrenr		spinunlock(l);
454145516Sdarrenr		}
455145516Sdarrenr#   else /* __hpux */
456145516Sdarrenr#    ifdef __osf__
457145516Sdarrenr		err = mpsleep(&sl_tail, PSUSP|PCATCH,  "ipl sleep", 0,
458145516Sdarrenr			      &ipsl_mutex, MS_LOCK_SIMPLE);
459147367Sdarrenr		if (err)
460147367Sdarrenr			return EINTR;
461145516Sdarrenr#    else
462145516Sdarrenr		MUTEX_EXIT(&ipsl_mutex);
463145516Sdarrenr		err = SLEEP(&sl_tail, "ipl sleep");
464147367Sdarrenr		if (err)
465147367Sdarrenr			return EINTR;
466147367Sdarrenr		MUTEX_ENTER(&ipsl_mutex);
467145516Sdarrenr#    endif /* __osf__ */
468145516Sdarrenr#   endif /* __hpux */
469145516Sdarrenr#  endif /* SOLARIS */
470145516Sdarrenr	}
471145516Sdarrenr	MUTEX_EXIT(&ipsl_mutex);
472145516Sdarrenr
473145516Sdarrenr	READ_ENTER(&ipf_syncstate);
474145516Sdarrenr	while ((sl_tail < sl_idx)  && (uio->uio_resid > sizeof(*sl))) {
475145516Sdarrenr		sl = synclog + sl_tail++;
476172776Sdarrenr		err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio);
477145516Sdarrenr		if (err != 0)
478145516Sdarrenr			break;
479145516Sdarrenr	}
480145516Sdarrenr
481145516Sdarrenr	while ((su_tail < su_idx)  && (uio->uio_resid > sizeof(*su))) {
482145516Sdarrenr		su = syncupd + su_tail;
483145516Sdarrenr		su_tail++;
484172776Sdarrenr		err = UIOMOVE(su, sizeof(*su), UIO_READ, uio);
485145516Sdarrenr		if (err != 0)
486145516Sdarrenr			break;
487145516Sdarrenr		if (su->sup_hdr.sm_sl != NULL)
488145516Sdarrenr			su->sup_hdr.sm_sl->sl_idx = -1;
489145516Sdarrenr	}
490145516Sdarrenr
491145516Sdarrenr	MUTEX_ENTER(&ipf_syncadd);
492145516Sdarrenr	if (su_tail == su_idx)
493145516Sdarrenr		su_tail = su_idx = 0;
494145516Sdarrenr	if (sl_tail == sl_idx)
495145516Sdarrenr		sl_tail = sl_idx = 0;
496145516Sdarrenr	MUTEX_EXIT(&ipf_syncadd);
497145516Sdarrenr	RWLOCK_EXIT(&ipf_syncstate);
498145516Sdarrenr	return err;
499145516Sdarrenr}
500145516Sdarrenr
501145516Sdarrenr
502145516Sdarrenr/* ------------------------------------------------------------------------ */
503145516Sdarrenr/* Function:    ipfsync_state                                               */
504145516Sdarrenr/* Returns:     int    - 0 == success, else error value.                    */
505145516Sdarrenr/* Parameters:  sp(I)  - pointer to sync packet data header                 */
506145516Sdarrenr/*              uio(I) - pointer to user data for further information       */
507145516Sdarrenr/*                                                                          */
508145516Sdarrenr/* Updates the state table according to information passed in the sync      */
509145516Sdarrenr/* header.  As required, more data is fetched from the uio structure but    */
510145516Sdarrenr/* varies depending on the contents of the sync header.  This function can  */
511145516Sdarrenr/* create a new state entry or update one.  Deletion is left to the state   */
512145516Sdarrenr/* structures being timed out correctly.                                    */
513145516Sdarrenr/* ------------------------------------------------------------------------ */
514145516Sdarrenrint ipfsync_state(sp, data)
515145516Sdarrenrsynchdr_t *sp;
516145516Sdarrenrvoid *data;
517145516Sdarrenr{
518145516Sdarrenr	synctcp_update_t su;
519145516Sdarrenr	ipstate_t *is, sn;
520145516Sdarrenr	synclist_t *sl;
521145516Sdarrenr	frentry_t *fr;
522145516Sdarrenr	u_int hv;
523145516Sdarrenr	int err = 0;
524145516Sdarrenr
525145516Sdarrenr	hv = sp->sm_num & (SYNC_STATETABSZ - 1);
526145516Sdarrenr
527145516Sdarrenr	switch (sp->sm_cmd)
528145516Sdarrenr	{
529145516Sdarrenr	case SMC_CREATE :
530145516Sdarrenr
531145516Sdarrenr		bcopy(data, &sn, sizeof(sn));
532145516Sdarrenr		KMALLOC(is, ipstate_t *);
533145516Sdarrenr		if (is == NULL) {
534145516Sdarrenr			err = ENOMEM;
535145516Sdarrenr			break;
536145516Sdarrenr		}
537145516Sdarrenr
538145516Sdarrenr		KMALLOC(sl, synclist_t *);
539145516Sdarrenr		if (sl == NULL) {
540145516Sdarrenr			err = ENOMEM;
541145516Sdarrenr			KFREE(is);
542145516Sdarrenr			break;
543145516Sdarrenr		}
544145516Sdarrenr
545145516Sdarrenr		bzero((char *)is, offsetof(ipstate_t, is_die));
546145516Sdarrenr		bcopy((char *)&sn.is_die, (char *)&is->is_die,
547145516Sdarrenr		      sizeof(*is) - offsetof(ipstate_t, is_die));
548145516Sdarrenr		ipfsync_storder(0, is);
549145516Sdarrenr
550145516Sdarrenr		/*
551145516Sdarrenr		 * We need to find the same rule on the slave as was used on
552145516Sdarrenr		 * the master to create this state entry.
553145516Sdarrenr		 */
554145516Sdarrenr		READ_ENTER(&ipf_mutex);
555145516Sdarrenr		fr = fr_getrulen(IPL_LOGIPF, sn.is_group, sn.is_rulen);
556145516Sdarrenr		if (fr != NULL) {
557145516Sdarrenr			MUTEX_ENTER(&fr->fr_lock);
558145516Sdarrenr			fr->fr_ref++;
559145516Sdarrenr			fr->fr_statecnt++;
560145516Sdarrenr			MUTEX_EXIT(&fr->fr_lock);
561145516Sdarrenr		}
562145516Sdarrenr		RWLOCK_EXIT(&ipf_mutex);
563145516Sdarrenr
564145516Sdarrenr		if (ipf_sync_debug > 4)
565145516Sdarrenr			printf("[%d] Filter rules = %p\n", sp->sm_num, fr);
566145516Sdarrenr
567145516Sdarrenr		is->is_rule = fr;
568145516Sdarrenr		is->is_sync = sl;
569145516Sdarrenr
570145516Sdarrenr		sl->sl_idx = -1;
571145516Sdarrenr		sl->sl_ips = is;
572145516Sdarrenr		bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr));
573145516Sdarrenr
574145516Sdarrenr		WRITE_ENTER(&ipf_syncstate);
575145516Sdarrenr		WRITE_ENTER(&ipf_state);
576145516Sdarrenr
577145516Sdarrenr		sl->sl_pnext = syncstatetab + hv;
578145516Sdarrenr		sl->sl_next = syncstatetab[hv];
579145516Sdarrenr		if (syncstatetab[hv] != NULL)
580145516Sdarrenr			syncstatetab[hv]->sl_pnext = &sl->sl_next;
581145516Sdarrenr		syncstatetab[hv] = sl;
582145516Sdarrenr		MUTEX_DOWNGRADE(&ipf_syncstate);
583145516Sdarrenr		fr_stinsert(is, sp->sm_rev);
584145516Sdarrenr		/*
585145516Sdarrenr		 * Do not initialise the interface pointers for the state
586145516Sdarrenr		 * entry as the full complement of interface names may not
587145516Sdarrenr		 * be present.
588145516Sdarrenr		 *
589145516Sdarrenr		 * Put this state entry on its timeout queue.
590145516Sdarrenr		 */
591145516Sdarrenr		/*fr_setstatequeue(is, sp->sm_rev);*/
592145516Sdarrenr		break;
593145516Sdarrenr
594145516Sdarrenr	case SMC_UPDATE :
595145516Sdarrenr		bcopy(data, &su, sizeof(su));
596145516Sdarrenr
597145516Sdarrenr		if (ipf_sync_debug > 4)
598145516Sdarrenr			printf("[%d] Update age %lu state %d/%d \n",
599145516Sdarrenr				sp->sm_num, su.stu_age, su.stu_state[0],
600145516Sdarrenr				su.stu_state[1]);
601145516Sdarrenr
602145516Sdarrenr		READ_ENTER(&ipf_syncstate);
603145516Sdarrenr		for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
604145516Sdarrenr			if (sl->sl_hdr.sm_num == sp->sm_num)
605145516Sdarrenr				break;
606145516Sdarrenr		if (sl == NULL) {
607145516Sdarrenr			if (ipf_sync_debug > 1)
608145516Sdarrenr				printf("[%d] State not found - can't update\n",
609145516Sdarrenr					sp->sm_num);
610145516Sdarrenr			RWLOCK_EXIT(&ipf_syncstate);
611145516Sdarrenr			err = ENOENT;
612145516Sdarrenr			break;
613145516Sdarrenr		}
614145516Sdarrenr
615145516Sdarrenr		READ_ENTER(&ipf_state);
616145516Sdarrenr
617145516Sdarrenr		if (ipf_sync_debug > 6)
618145516Sdarrenr			printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n",
619145516Sdarrenr				sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p,
620145516Sdarrenr				sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table,
621145516Sdarrenr				sl->sl_hdr.sm_rev);
622145516Sdarrenr
623145516Sdarrenr		is = sl->sl_ips;
624145516Sdarrenr
625145516Sdarrenr		MUTEX_ENTER(&is->is_lock);
626145516Sdarrenr		switch (sp->sm_p)
627145516Sdarrenr		{
628145516Sdarrenr		case IPPROTO_TCP :
629145516Sdarrenr			/* XXX FV --- shouldn't we do ntohl/htonl???? XXX */
630145516Sdarrenr			is->is_send = su.stu_data[0].td_end;
631145516Sdarrenr			is->is_maxsend = su.stu_data[0].td_maxend;
632145516Sdarrenr			is->is_maxswin = su.stu_data[0].td_maxwin;
633145516Sdarrenr			is->is_state[0] = su.stu_state[0];
634145516Sdarrenr			is->is_dend = su.stu_data[1].td_end;
635145516Sdarrenr			is->is_maxdend = su.stu_data[1].td_maxend;
636145516Sdarrenr			is->is_maxdwin = su.stu_data[1].td_maxwin;
637145516Sdarrenr			is->is_state[1] = su.stu_state[1];
638145516Sdarrenr			break;
639145516Sdarrenr		default :
640145516Sdarrenr			break;
641145516Sdarrenr		}
642145516Sdarrenr
643145516Sdarrenr		if (ipf_sync_debug > 6)
644145516Sdarrenr			printf("[%d] Setting timers for state\n", sp->sm_num);
645145516Sdarrenr
646145516Sdarrenr		fr_setstatequeue(is, sp->sm_rev);
647145516Sdarrenr
648145516Sdarrenr		MUTEX_EXIT(&is->is_lock);
649145516Sdarrenr		break;
650145516Sdarrenr
651145516Sdarrenr	default :
652145516Sdarrenr		err = EINVAL;
653145516Sdarrenr		break;
654145516Sdarrenr	}
655145516Sdarrenr
656145516Sdarrenr	if (err == 0) {
657145516Sdarrenr		RWLOCK_EXIT(&ipf_state);
658145516Sdarrenr		RWLOCK_EXIT(&ipf_syncstate);
659145516Sdarrenr	}
660145516Sdarrenr
661145516Sdarrenr	if (ipf_sync_debug > 6)
662145516Sdarrenr		printf("[%d] Update completed with error %d\n",
663145516Sdarrenr			sp->sm_num, err);
664145516Sdarrenr
665145516Sdarrenr	return err;
666145516Sdarrenr}
667145516Sdarrenr# endif /* _KERNEL */
668145516Sdarrenr
669145516Sdarrenr
670145516Sdarrenr/* ------------------------------------------------------------------------ */
671145516Sdarrenr/* Function:    ipfsync_del                                                 */
672145516Sdarrenr/* Returns:     Nil                                                         */
673145516Sdarrenr/* Parameters:  sl(I) - pointer to synclist object to delete                */
674145516Sdarrenr/*                                                                          */
675145516Sdarrenr/* Deletes an object from the synclist table and free's its memory.         */
676145516Sdarrenr/* ------------------------------------------------------------------------ */
677145516Sdarrenrvoid ipfsync_del(sl)
678145516Sdarrenrsynclist_t *sl;
679145516Sdarrenr{
680145516Sdarrenr	WRITE_ENTER(&ipf_syncstate);
681145516Sdarrenr	*sl->sl_pnext = sl->sl_next;
682145516Sdarrenr	if (sl->sl_next != NULL)
683145516Sdarrenr		sl->sl_next->sl_pnext = sl->sl_pnext;
684145516Sdarrenr	if (sl->sl_idx != -1)
685145516Sdarrenr		syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
686145516Sdarrenr	RWLOCK_EXIT(&ipf_syncstate);
687145516Sdarrenr	KFREE(sl);
688145516Sdarrenr}
689145516Sdarrenr
690145516Sdarrenr
691145516Sdarrenr/* ------------------------------------------------------------------------ */
692145516Sdarrenr/* Function:    ipfsync_nat                                                 */
693145516Sdarrenr/* Returns:     int    - 0 == success, else error value.                    */
694145516Sdarrenr/* Parameters:  sp(I)  - pointer to sync packet data header                 */
695145516Sdarrenr/*              uio(I) - pointer to user data for further information       */
696145516Sdarrenr/*                                                                          */
697145516Sdarrenr/* Updates the NAT  table according to information passed in the sync       */
698145516Sdarrenr/* header.  As required, more data is fetched from the uio structure but    */
699145516Sdarrenr/* varies depending on the contents of the sync header.  This function can  */
700145516Sdarrenr/* create a new NAT entry or update one.  Deletion is left to the NAT       */
701145516Sdarrenr/* structures being timed out correctly.                                    */
702145516Sdarrenr/* ------------------------------------------------------------------------ */
703145516Sdarrenrint ipfsync_nat(sp, data)
704145516Sdarrenrsynchdr_t *sp;
705145516Sdarrenrvoid *data;
706145516Sdarrenr{
707145516Sdarrenr	syncupdent_t su;
708145516Sdarrenr	nat_t *n, *nat;
709145516Sdarrenr	synclist_t *sl;
710145516Sdarrenr	u_int hv = 0;
711145516Sdarrenr	int err;
712145516Sdarrenr
713145516Sdarrenr	READ_ENTER(&ipf_syncstate);
714145516Sdarrenr
715145516Sdarrenr	switch (sp->sm_cmd)
716145516Sdarrenr	{
717145516Sdarrenr	case SMC_CREATE :
718145516Sdarrenr		KMALLOC(n, nat_t *);
719145516Sdarrenr		if (n == NULL) {
720145516Sdarrenr			err = ENOMEM;
721145516Sdarrenr			break;
722145516Sdarrenr		}
723145516Sdarrenr
724145516Sdarrenr		KMALLOC(sl, synclist_t *);
725145516Sdarrenr		if (sl == NULL) {
726145516Sdarrenr			err = ENOMEM;
727145516Sdarrenr			KFREE(n);
728145516Sdarrenr			break;
729145516Sdarrenr		}
730145516Sdarrenr
731161356Sguido		nat = (nat_t *)data;
732145516Sdarrenr		bzero((char *)n, offsetof(nat_t, nat_age));
733145516Sdarrenr		bcopy((char *)&nat->nat_age, (char *)&n->nat_age,
734145516Sdarrenr		      sizeof(*n) - offsetof(nat_t, nat_age));
735145516Sdarrenr		ipfsync_natorder(0, n);
736145516Sdarrenr		n->nat_sync = sl;
737145516Sdarrenr
738145516Sdarrenr		sl->sl_idx = -1;
739145516Sdarrenr		sl->sl_ipn = n;
740145516Sdarrenr		sl->sl_num = ntohl(sp->sm_num);
741161356Sguido
742161356Sguido		WRITE_ENTER(&ipf_nat);
743145516Sdarrenr		sl->sl_pnext = syncstatetab + hv;
744145516Sdarrenr		sl->sl_next = syncstatetab[hv];
745145516Sdarrenr		if (syncstatetab[hv] != NULL)
746145516Sdarrenr			syncstatetab[hv]->sl_pnext = &sl->sl_next;
747145516Sdarrenr		syncstatetab[hv] = sl;
748145516Sdarrenr		nat_insert(n, sl->sl_rev);
749145516Sdarrenr		RWLOCK_EXIT(&ipf_nat);
750145516Sdarrenr		break;
751145516Sdarrenr
752145516Sdarrenr	case SMC_UPDATE :
753145516Sdarrenr		bcopy(data, &su, sizeof(su));
754145516Sdarrenr
755145516Sdarrenr		READ_ENTER(&ipf_syncstate);
756145516Sdarrenr		for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
757145516Sdarrenr			if (sl->sl_hdr.sm_num == sp->sm_num)
758145516Sdarrenr				break;
759145516Sdarrenr		if (sl == NULL) {
760145516Sdarrenr			err = ENOENT;
761145516Sdarrenr			break;
762145516Sdarrenr		}
763145516Sdarrenr
764145516Sdarrenr		READ_ENTER(&ipf_nat);
765145516Sdarrenr
766145516Sdarrenr		nat = sl->sl_ipn;
767145516Sdarrenr
768145516Sdarrenr		MUTEX_ENTER(&nat->nat_lock);
769145516Sdarrenr		fr_setnatqueue(nat, sl->sl_rev);
770145516Sdarrenr		MUTEX_EXIT(&nat->nat_lock);
771145516Sdarrenr
772145516Sdarrenr		RWLOCK_EXIT(&ipf_nat);
773145516Sdarrenr
774145516Sdarrenr		break;
775145516Sdarrenr
776145516Sdarrenr	default :
777145516Sdarrenr		err = EINVAL;
778145516Sdarrenr		break;
779145516Sdarrenr	}
780145516Sdarrenr
781145516Sdarrenr	RWLOCK_EXIT(&ipf_syncstate);
782145516Sdarrenr	return 0;
783145516Sdarrenr}
784145516Sdarrenr
785145516Sdarrenr
786145516Sdarrenr/* ------------------------------------------------------------------------ */
787145516Sdarrenr/* Function:    ipfsync_new                                                 */
788145516Sdarrenr/* Returns:     synclist_t* - NULL == failure, else pointer to new synclist */
789145516Sdarrenr/*                            data structure.                               */
790145516Sdarrenr/* Parameters:  tab(I) - type of synclist_t to create                       */
791145516Sdarrenr/*              fin(I) - pointer to packet information                      */
792145516Sdarrenr/*              ptr(I) - pointer to owning object                           */
793145516Sdarrenr/*                                                                          */
794145516Sdarrenr/* Creates a new sync table entry and notifies any sleepers that it's there */
795145516Sdarrenr/* waiting to be processed.                                                 */
796145516Sdarrenr/* ------------------------------------------------------------------------ */
797145516Sdarrenrsynclist_t *ipfsync_new(tab, fin, ptr)
798145516Sdarrenrint tab;
799145516Sdarrenrfr_info_t *fin;
800145516Sdarrenrvoid *ptr;
801145516Sdarrenr{
802145516Sdarrenr	synclist_t *sl, *ss;
803145516Sdarrenr	synclogent_t *sle;
804145516Sdarrenr	u_int hv, sz;
805145516Sdarrenr
806145516Sdarrenr	if (sl_idx == SYNCLOG_SZ)
807145516Sdarrenr		return NULL;
808145516Sdarrenr	KMALLOC(sl, synclist_t *);
809145516Sdarrenr	if (sl == NULL)
810145516Sdarrenr		return NULL;
811145516Sdarrenr
812145516Sdarrenr	MUTEX_ENTER(&ipf_syncadd);
813145516Sdarrenr	/*
814145516Sdarrenr	 * Get a unique number for this synclist_t.  The number is only meant
815145516Sdarrenr	 * to be unique for the lifetime of the structure and may be reused
816145516Sdarrenr	 * later.
817145516Sdarrenr	 */
818145516Sdarrenr	ipf_syncnum++;
819145516Sdarrenr	if (ipf_syncnum == 0) {
820145516Sdarrenr		ipf_syncnum = 1;
821145516Sdarrenr		ipf_syncwrap = 1;
822145516Sdarrenr	}
823145516Sdarrenr
824145516Sdarrenr	hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
825145516Sdarrenr	while (ipf_syncwrap != 0) {
826145516Sdarrenr		for (ss = syncstatetab[hv]; ss; ss = ss->sl_next)
827145516Sdarrenr			if (ss->sl_hdr.sm_num == ipf_syncnum)
828145516Sdarrenr				break;
829145516Sdarrenr		if (ss == NULL)
830145516Sdarrenr			break;
831145516Sdarrenr		ipf_syncnum++;
832145516Sdarrenr		hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
833145516Sdarrenr	}
834145516Sdarrenr	/*
835145516Sdarrenr	 * Use the synch number of the object as the hash key.  Should end up
836145516Sdarrenr	 * with relatively even distribution over time.
837145516Sdarrenr	 * XXX - an attacker could lunch an DoS attack, of sorts, if they are
838145516Sdarrenr	 * the only one causing new table entries by only keeping open every
839145516Sdarrenr	 * nth connection they make, where n is a value in the interval
840145516Sdarrenr	 * [0, SYNC_STATETABSZ-1].
841145516Sdarrenr	 */
842145516Sdarrenr	sl->sl_pnext = syncstatetab + hv;
843145516Sdarrenr	sl->sl_next = syncstatetab[hv];
844145516Sdarrenr	syncstatetab[hv] = sl;
845145516Sdarrenr	sl->sl_num = ipf_syncnum;
846145516Sdarrenr	MUTEX_EXIT(&ipf_syncadd);
847145516Sdarrenr
848145516Sdarrenr	sl->sl_magic = htonl(SYNHDRMAGIC);
849145516Sdarrenr	sl->sl_v = fin->fin_v;
850145516Sdarrenr	sl->sl_p = fin->fin_p;
851145516Sdarrenr	sl->sl_cmd = SMC_CREATE;
852145516Sdarrenr	sl->sl_idx = -1;
853145516Sdarrenr	sl->sl_table = tab;
854145516Sdarrenr	sl->sl_rev = fin->fin_rev;
855145516Sdarrenr	if (tab == SMC_STATE) {
856145516Sdarrenr		sl->sl_ips = ptr;
857145516Sdarrenr		sz = sizeof(*sl->sl_ips);
858145516Sdarrenr	} else if (tab == SMC_NAT) {
859145516Sdarrenr		sl->sl_ipn = ptr;
860145516Sdarrenr		sz = sizeof(*sl->sl_ipn);
861145516Sdarrenr	} else {
862145516Sdarrenr		ptr = NULL;
863145516Sdarrenr		sz = 0;
864145516Sdarrenr	}
865145516Sdarrenr	sl->sl_len = sz;
866145516Sdarrenr
867145516Sdarrenr	/*
868145516Sdarrenr	 * Create the log entry to be read by a user daemon.  When it has been
869145516Sdarrenr	 * finished and put on the queue, send a signal to wakeup any waiters.
870145516Sdarrenr	 */
871145516Sdarrenr	MUTEX_ENTER(&ipf_syncadd);
872145516Sdarrenr	sle = synclog + sl_idx++;
873145516Sdarrenr	bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr,
874145516Sdarrenr	      sizeof(sle->sle_hdr));
875145516Sdarrenr	sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num);
876145516Sdarrenr	sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len);
877145516Sdarrenr	if (ptr != NULL) {
878145516Sdarrenr		bcopy((char *)ptr, (char *)&sle->sle_un, sz);
879145516Sdarrenr		if (tab == SMC_STATE) {
880145516Sdarrenr			ipfsync_storder(1, &sle->sle_un.sleu_ips);
881145516Sdarrenr		} else if (tab == SMC_NAT) {
882145516Sdarrenr			ipfsync_natorder(1, &sle->sle_un.sleu_ipn);
883145516Sdarrenr		}
884145516Sdarrenr	}
885145516Sdarrenr	MUTEX_EXIT(&ipf_syncadd);
886145516Sdarrenr
887145516Sdarrenr	MUTEX_ENTER(&ipsl_mutex);
888145516Sdarrenr# if SOLARIS
889145516Sdarrenr#  ifdef _KERNEL
890145516Sdarrenr	cv_signal(&ipslwait);
891145516Sdarrenr#  endif
892145516Sdarrenr	MUTEX_EXIT(&ipsl_mutex);
893145516Sdarrenr# else
894145516Sdarrenr	MUTEX_EXIT(&ipsl_mutex);
895145516Sdarrenr#  ifdef _KERNEL
896145516Sdarrenr	wakeup(&sl_tail);
897145516Sdarrenr#  endif
898145516Sdarrenr# endif
899145516Sdarrenr	return sl;
900145516Sdarrenr}
901145516Sdarrenr
902145516Sdarrenr
903145516Sdarrenr/* ------------------------------------------------------------------------ */
904145516Sdarrenr/* Function:    ipfsync_update                                              */
905145516Sdarrenr/* Returns:     Nil                                                         */
906145516Sdarrenr/* Parameters:  tab(I) - type of synclist_t to create                       */
907145516Sdarrenr/*              fin(I) - pointer to packet information                      */
908145516Sdarrenr/*              sl(I)  - pointer to synchronisation object                  */
909145516Sdarrenr/*                                                                          */
910145516Sdarrenr/* For outbound packets, only, create an sync update record for the user    */
911145516Sdarrenr/* process to read.                                                         */
912145516Sdarrenr/* ------------------------------------------------------------------------ */
913145516Sdarrenrvoid ipfsync_update(tab, fin, sl)
914145516Sdarrenrint tab;
915145516Sdarrenrfr_info_t *fin;
916145516Sdarrenrsynclist_t *sl;
917145516Sdarrenr{
918145516Sdarrenr	synctcp_update_t *st;
919145516Sdarrenr	syncupdent_t *slu;
920145516Sdarrenr	ipstate_t *ips;
921145516Sdarrenr	nat_t *nat;
922145516Sdarrenr
923145516Sdarrenr	if (fin->fin_out == 0 || sl == NULL)
924145516Sdarrenr		return;
925145516Sdarrenr
926145516Sdarrenr	WRITE_ENTER(&ipf_syncstate);
927145516Sdarrenr	MUTEX_ENTER(&ipf_syncadd);
928145516Sdarrenr	if (sl->sl_idx == -1) {
929145516Sdarrenr		slu = syncupd + su_idx;
930145516Sdarrenr		sl->sl_idx = su_idx++;
931145516Sdarrenr		bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr,
932145516Sdarrenr		      sizeof(slu->sup_hdr));
933145516Sdarrenr		slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC);
934145516Sdarrenr		slu->sup_hdr.sm_sl = sl;
935145516Sdarrenr		slu->sup_hdr.sm_cmd = SMC_UPDATE;
936145516Sdarrenr		slu->sup_hdr.sm_table = tab;
937145516Sdarrenr		slu->sup_hdr.sm_num = htonl(sl->sl_num);
938145516Sdarrenr		slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update));
939145516Sdarrenr		slu->sup_hdr.sm_rev = fin->fin_rev;
940145516Sdarrenr# if 0
941145516Sdarrenr		if (fin->fin_p == IPPROTO_TCP) {
942145516Sdarrenr			st->stu_len[0] = 0;
943145516Sdarrenr			st->stu_len[1] = 0;
944145516Sdarrenr		}
945145516Sdarrenr# endif
946145516Sdarrenr	} else
947145516Sdarrenr		slu = syncupd + sl->sl_idx;
948145516Sdarrenr	MUTEX_EXIT(&ipf_syncadd);
949145516Sdarrenr	MUTEX_DOWNGRADE(&ipf_syncstate);
950145516Sdarrenr
951145516Sdarrenr	/*
952145516Sdarrenr	 * Only TCP has complex timeouts, others just use default timeouts.
953145516Sdarrenr	 * For TCP, we only need to track the connection state and window.
954145516Sdarrenr	 */
955145516Sdarrenr	if (fin->fin_p == IPPROTO_TCP) {
956145516Sdarrenr		st = &slu->sup_tcp;
957145516Sdarrenr		if (tab == SMC_STATE) {
958145516Sdarrenr			ips = sl->sl_ips;
959145516Sdarrenr			st->stu_age = htonl(ips->is_die);
960145516Sdarrenr			st->stu_data[0].td_end = ips->is_send;
961145516Sdarrenr			st->stu_data[0].td_maxend = ips->is_maxsend;
962145516Sdarrenr			st->stu_data[0].td_maxwin = ips->is_maxswin;
963145516Sdarrenr			st->stu_state[0] = ips->is_state[0];
964145516Sdarrenr			st->stu_data[1].td_end = ips->is_dend;
965145516Sdarrenr			st->stu_data[1].td_maxend = ips->is_maxdend;
966145516Sdarrenr			st->stu_data[1].td_maxwin = ips->is_maxdwin;
967145516Sdarrenr			st->stu_state[1] = ips->is_state[1];
968145516Sdarrenr		} else if (tab == SMC_NAT) {
969145516Sdarrenr			nat = sl->sl_ipn;
970145516Sdarrenr			st->stu_age = htonl(nat->nat_age);
971145516Sdarrenr		}
972145516Sdarrenr	}
973145516Sdarrenr	RWLOCK_EXIT(&ipf_syncstate);
974145516Sdarrenr
975145516Sdarrenr	MUTEX_ENTER(&ipsl_mutex);
976145516Sdarrenr# if SOLARIS
977145516Sdarrenr#  ifdef _KERNEL
978145516Sdarrenr	cv_signal(&ipslwait);
979145516Sdarrenr#  endif
980145516Sdarrenr	MUTEX_EXIT(&ipsl_mutex);
981145516Sdarrenr# else
982145516Sdarrenr	MUTEX_EXIT(&ipsl_mutex);
983145516Sdarrenr#  ifdef _KERNEL
984145516Sdarrenr	wakeup(&sl_tail);
985145516Sdarrenr#  endif
986145516Sdarrenr# endif
987145516Sdarrenr}
988145516Sdarrenr
989145516Sdarrenr
990145516Sdarrenr/* ------------------------------------------------------------------------ */
991145516Sdarrenr/* Function:    fr_sync_ioctl                                               */
992145516Sdarrenr/* Returns:     int - 0 == success, != 0 == failure                         */
993145516Sdarrenr/* Parameters:  data(I) - pointer to ioctl data                             */
994145516Sdarrenr/*              cmd(I)  - ioctl command integer                             */
995145516Sdarrenr/*              mode(I) - file mode bits used with open                     */
996145516Sdarrenr/*                                                                          */
997145516Sdarrenr/* This function currently does not handle any ioctls and so just returns   */
998145516Sdarrenr/* EINVAL on all occasions.                                                 */
999145516Sdarrenr/* ------------------------------------------------------------------------ */
1000170268Sdarrenrint fr_sync_ioctl(data, cmd, mode, uid, ctx)
1001145516Sdarrenrcaddr_t data;
1002145516Sdarrenrioctlcmd_t cmd;
1003170268Sdarrenrint mode, uid;
1004170268Sdarrenrvoid *ctx;
1005145516Sdarrenr{
1006145516Sdarrenr	return EINVAL;
1007145516Sdarrenr}
1008161356Sguido
1009161356Sguido
1010161356Sguidoint ipfsync_canread()
1011161356Sguido{
1012161356Sguido	return !((sl_tail == sl_idx) && (su_tail == su_idx));
1013161356Sguido}
1014161356Sguido
1015161356Sguido
1016161356Sguidoint ipfsync_canwrite()
1017161356Sguido{
1018161356Sguido	return 1;
1019161356Sguido}
1020145516Sdarrenr#endif /* IPFILTER_SYNC */
1021