ip_sync.c revision 147367
1/*	$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_sync.c 147367 2005-06-14 09:18:26Z darrenr $	*/
2
3/*
4 * Copyright (C) 1995-1998 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__
25struct 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#endif
36#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
37# include <sys/proc.h>
38#endif
39#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
40# include <sys/filio.h>
41# include <sys/fcntl.h>
42# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
43#  include "opt_ipfilter.h"
44# endif
45#else
46# include <sys/ioctl.h>
47#endif
48#include <sys/time.h>
49#if !defined(linux)
50# include <sys/protosw.h>
51#endif
52#include <sys/socket.h>
53#if defined(__SVR4) || defined(__svr4__)
54# include <sys/filio.h>
55# include <sys/byteorder.h>
56# ifdef _KERNEL
57#  include <sys/dditypes.h>
58# endif
59# include <sys/stream.h>
60# include <sys/kmem.h>
61#endif
62
63#include <net/if.h>
64#ifdef sun
65# include <net/af.h>
66#endif
67#include <net/route.h>
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)
101static const char rcsid[] = "@(#)Id: ip_sync.c,v 2.40.2.3 2005/02/18 13:06:29 darrenr Exp";
102#endif
103
104#define	SYNC_STATETABSZ	256
105#define	SYNC_NATTABSZ	256
106
107#ifdef	IPFILTER_SYNC
108ipfmutex_t	ipf_syncadd, ipsl_mutex;
109ipfrwlock_t	ipf_syncstate, ipf_syncnat;
110#if SOLARIS && defined(_KERNEL)
111kcondvar_t	ipslwait;
112#endif
113synclist_t	*syncstatetab[SYNC_STATETABSZ];
114synclist_t	*syncnattab[SYNC_NATTABSZ];
115synclogent_t	synclog[SYNCLOG_SZ];
116syncupdent_t	syncupd[SYNCLOG_SZ];
117u_int		ipf_syncnum = 1;
118u_int		ipf_syncwrap = 0;
119u_int		sl_idx = 0,	/* next available sync log entry */
120		su_idx = 0,	/* next available sync update entry */
121		sl_tail = 0,	/* next sync log entry to read */
122		su_tail = 0;	/* next sync update entry to read */
123int		ipf_sync_debug = 0;
124
125
126# if !defined(sparc) && !defined(__hppa)
127void ipfsync_tcporder __P((int, struct tcpdata *));
128void ipfsync_natorder __P((int, struct nat *));
129void ipfsync_storder __P((int, struct ipstate *));
130# endif
131
132
133/* ------------------------------------------------------------------------ */
134/* Function:    ipfsync_init                                                */
135/* Returns:     int - 0 == success, -1 == failure                           */
136/* Parameters:  Nil                                                         */
137/*                                                                          */
138/* Initialise all of the locks required for the sync code and initialise    */
139/* any data structures, as required.                                        */
140/* ------------------------------------------------------------------------ */
141int ipfsync_init()
142{
143	RWLOCK_INIT(&ipf_syncstate, "add things to state sync table");
144	RWLOCK_INIT(&ipf_syncnat, "add things to nat sync table");
145	MUTEX_INIT(&ipf_syncadd, "add things to sync table");
146	MUTEX_INIT(&ipsl_mutex, "add things to sync table");
147# if SOLARIS && defined(_KERNEL)
148	cv_init(&ipslwait, "ipsl condvar", CV_DRIVER, NULL);
149# endif
150
151	bzero((char *)syncnattab, sizeof(syncnattab));
152	bzero((char *)syncstatetab, sizeof(syncstatetab));
153
154	return 0;
155}
156
157
158# if !defined(sparc) && !defined(__hppa)
159/* ------------------------------------------------------------------------ */
160/* Function:    ipfsync_tcporder                                            */
161/* Returns:     Nil                                                         */
162/* Parameters:  way(I) - direction of byte order conversion.                */
163/*              td(IO) - pointer to data to be converted.                   */
164/*                                                                          */
165/* Do byte swapping on values in the TCP state information structure that   */
166/* need to be used at both ends by the host in their native byte order.     */
167/* ------------------------------------------------------------------------ */
168void ipfsync_tcporder(way, td)
169int way;
170tcpdata_t *td;
171{
172	if (way) {
173		td->td_maxwin = htons(td->td_maxwin);
174		td->td_end = htonl(td->td_end);
175		td->td_maxend = htonl(td->td_maxend);
176	} else {
177		td->td_maxwin = ntohs(td->td_maxwin);
178		td->td_end = ntohl(td->td_end);
179		td->td_maxend = ntohl(td->td_maxend);
180	}
181}
182
183
184/* ------------------------------------------------------------------------ */
185/* Function:    ipfsync_natorder                                            */
186/* Returns:     Nil                                                         */
187/* Parameters:  way(I)  - direction of byte order conversion.               */
188/*              nat(IO) - pointer to data to be converted.                  */
189/*                                                                          */
190/* Do byte swapping on values in the NAT data structure that need to be     */
191/* used at both ends by the host in their native byte order.                */
192/* ------------------------------------------------------------------------ */
193void ipfsync_natorder(way, n)
194int way;
195nat_t *n;
196{
197	if (way) {
198		n->nat_age = htonl(n->nat_age);
199		n->nat_flags = htonl(n->nat_flags);
200		n->nat_ipsumd = htonl(n->nat_ipsumd);
201		n->nat_use = htonl(n->nat_use);
202		n->nat_dir = htonl(n->nat_dir);
203	} else {
204		n->nat_age = ntohl(n->nat_age);
205		n->nat_flags = ntohl(n->nat_flags);
206		n->nat_ipsumd = ntohl(n->nat_ipsumd);
207		n->nat_use = ntohl(n->nat_use);
208		n->nat_dir = ntohl(n->nat_dir);
209	}
210}
211
212
213/* ------------------------------------------------------------------------ */
214/* Function:    ipfsync_storder                                             */
215/* Returns:     Nil                                                         */
216/* Parameters:  way(I)  - direction of byte order conversion.               */
217/*              ips(IO) - pointer to data to be converted.                  */
218/*                                                                          */
219/* Do byte swapping on values in the IP state data structure that need to   */
220/* be used at both ends by the host in their native byte order.             */
221/* ------------------------------------------------------------------------ */
222void ipfsync_storder(way, ips)
223int way;
224ipstate_t *ips;
225{
226	ipfsync_tcporder(way, &ips->is_tcp.ts_data[0]);
227	ipfsync_tcporder(way, &ips->is_tcp.ts_data[1]);
228
229	if (way) {
230		ips->is_hv = htonl(ips->is_hv);
231		ips->is_die = htonl(ips->is_die);
232		ips->is_pass = htonl(ips->is_pass);
233		ips->is_flags = htonl(ips->is_flags);
234		ips->is_opt = htonl(ips->is_opt);
235		ips->is_optmsk = htonl(ips->is_optmsk);
236		ips->is_sec = htons(ips->is_sec);
237		ips->is_secmsk = htons(ips->is_secmsk);
238		ips->is_auth = htons(ips->is_auth);
239		ips->is_authmsk = htons(ips->is_authmsk);
240		ips->is_s0[0] = htonl(ips->is_s0[0]);
241		ips->is_s0[1] = htonl(ips->is_s0[1]);
242		ips->is_smsk[0] = htons(ips->is_smsk[0]);
243		ips->is_smsk[1] = htons(ips->is_smsk[1]);
244	} else {
245		ips->is_hv = ntohl(ips->is_hv);
246		ips->is_die = ntohl(ips->is_die);
247		ips->is_pass = ntohl(ips->is_pass);
248		ips->is_flags = ntohl(ips->is_flags);
249		ips->is_opt = ntohl(ips->is_opt);
250		ips->is_optmsk = ntohl(ips->is_optmsk);
251		ips->is_sec = ntohs(ips->is_sec);
252		ips->is_secmsk = ntohs(ips->is_secmsk);
253		ips->is_auth = ntohs(ips->is_auth);
254		ips->is_authmsk = ntohs(ips->is_authmsk);
255		ips->is_s0[0] = ntohl(ips->is_s0[0]);
256		ips->is_s0[1] = ntohl(ips->is_s0[1]);
257		ips->is_smsk[0] = ntohl(ips->is_smsk[0]);
258		ips->is_smsk[1] = ntohl(ips->is_smsk[1]);
259	}
260}
261# else /* !defined(sparc) && !defined(__hppa) */
262#  define	ipfsync_tcporder(x,y)
263#  define	ipfsync_natorder(x,y)
264#  define	ipfsync_storder(x,y)
265# endif /* !defined(sparc) && !defined(__hppa) */
266
267/* enable this for debugging */
268
269# ifdef _KERNEL
270/* ------------------------------------------------------------------------ */
271/* Function:    ipfsync_write                                               */
272/* Returns:     int    - 0 == success, else error value.                    */
273/* Parameters:  uio(I) - pointer to information about data to write         */
274/*                                                                          */
275/* Moves data from user space into the kernel and uses it for updating data */
276/* structures in the state/NAT tables.                                      */
277/* ------------------------------------------------------------------------ */
278int ipfsync_write(uio)
279struct uio *uio;
280{
281	synchdr_t sh;
282
283	/*
284	 * THIS MUST BE SUFFICIENT LARGE TO STORE
285	 * ANY POSSIBLE DATA TYPE
286	 */
287	char data[2048];
288
289	int err = 0;
290
291#  if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
292	uio->uio_rw = UIO_WRITE;
293#  endif
294
295	/* Try to get bytes */
296	while (uio->uio_resid > 0) {
297
298		if (uio->uio_resid >= sizeof(sh)) {
299
300			err = UIOMOVE((caddr_t)&sh, sizeof(sh), UIO_WRITE, uio);
301
302			if (err) {
303				if (ipf_sync_debug > 2)
304					printf("uiomove(header) failed: %d\n",
305						err);
306				return err;
307			}
308
309			/* convert to host order */
310			sh.sm_magic = ntohl(sh.sm_magic);
311			sh.sm_len = ntohl(sh.sm_len);
312			sh.sm_num = ntohl(sh.sm_num);
313
314			if (ipf_sync_debug > 8)
315				printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n",
316					sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd,
317					sh.sm_table, sh.sm_rev, sh.sm_len,
318					sh.sm_magic);
319
320			if (sh.sm_magic != SYNHDRMAGIC) {
321				if (ipf_sync_debug > 2)
322					printf("uiomove(header) invalud %s\n",
323						"magic");
324				return EINVAL;
325			}
326
327			if (sh.sm_v != 4 && sh.sm_v != 6) {
328				if (ipf_sync_debug > 2)
329					printf("uiomove(header) invalid %s\n",
330						"protocol");
331				return EINVAL;
332			}
333
334			if (sh.sm_cmd > SMC_MAXCMD) {
335				if (ipf_sync_debug > 2)
336					printf("uiomove(header) invalid %s\n",
337						"command");
338				return EINVAL;
339			}
340
341
342			if (sh.sm_table > SMC_MAXTBL) {
343				if (ipf_sync_debug > 2)
344					printf("uiomove(header) invalid %s\n",
345						"table");
346				return EINVAL;
347			}
348
349		} else {
350			/* unsufficient data, wait until next call */
351			if (ipf_sync_debug > 2)
352				printf("uiomove(header) insufficient data");
353			return EAGAIN;
354	 	}
355
356
357		/*
358		 * We have a header, so try to read the amount of data
359		 * needed for the request
360		 */
361
362		/* not supported */
363		if (sh.sm_len == 0) {
364			if (ipf_sync_debug > 2)
365				printf("uiomove(data zero length %s\n",
366					"not supported");
367			return EINVAL;
368		}
369
370		if (uio->uio_resid >= sh.sm_len) {
371
372			err = UIOMOVE((caddr_t)data, sh.sm_len, UIO_WRITE, uio);
373
374			if (err) {
375				if (ipf_sync_debug > 2)
376					printf("uiomove(data) failed: %d\n",
377						err);
378				return err;
379			}
380
381			if (ipf_sync_debug > 7)
382				printf("uiomove(data) %d bytes read\n",
383					sh.sm_len);
384
385			if (sh.sm_table == SMC_STATE)
386				err = ipfsync_state(&sh, data);
387			else if (sh.sm_table == SMC_NAT)
388				err = ipfsync_nat(&sh, data);
389			if (ipf_sync_debug > 7)
390				printf("[%d] Finished with error %d\n",
391					sh.sm_num, err);
392
393		} else {
394			/* insufficient data, wait until next call */
395			if (ipf_sync_debug > 2)
396				printf("uiomove(data) %s %d bytes, got %d\n",
397					"insufficient data, need",
398					sh.sm_len, uio->uio_resid);
399			return EAGAIN;
400		}
401	}
402
403	/* no more data */
404	return 0;
405}
406
407
408/* ------------------------------------------------------------------------ */
409/* Function:    ipfsync_read                                                */
410/* Returns:     int    - 0 == success, else error value.                    */
411/* Parameters:  uio(O) - pointer to information about where to store data   */
412/*                                                                          */
413/* This function is called when a user program wants to read some data      */
414/* for pending state/NAT updates.  If no data is available, the caller is   */
415/* put to sleep, pending a wakeup from the "lower half" of this code.       */
416/* ------------------------------------------------------------------------ */
417int ipfsync_read(uio)
418struct uio *uio;
419{
420	syncupdent_t *su;
421	synclogent_t *sl;
422	int err = 0;
423
424	if ((uio->uio_resid & 3) || (uio->uio_resid < 8))
425		return EINVAL;
426
427#  if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
428	uio->uio_rw = UIO_READ;
429#  endif
430
431	MUTEX_ENTER(&ipsl_mutex);
432	while ((sl_tail == sl_idx) && (su_tail == su_idx)) {
433#  if SOLARIS && defined(_KERNEL)
434		if (!cv_wait_sig(&ipslwait, &ipsl_mutex)) {
435			MUTEX_EXIT(&ipsl_mutex);
436			return EINTR;
437		}
438#  else
439#   ifdef __hpux
440		{
441		lock_t *l;
442
443		l = get_sleep_lock(&sl_tail);
444		err = sleep(&sl_tail, PZERO+1);
445		if (err) {
446			MUTEX_EXIT(&ipsl_mutex);
447			return EINTR;
448		}
449		spinunlock(l);
450		}
451#   else /* __hpux */
452#    ifdef __osf__
453		err = mpsleep(&sl_tail, PSUSP|PCATCH,  "ipl sleep", 0,
454			      &ipsl_mutex, MS_LOCK_SIMPLE);
455		if (err)
456			return EINTR;
457#    else
458		MUTEX_EXIT(&ipsl_mutex);
459		err = SLEEP(&sl_tail, "ipl sleep");
460		if (err)
461			return EINTR;
462		MUTEX_ENTER(&ipsl_mutex);
463#    endif /* __osf__ */
464#   endif /* __hpux */
465#  endif /* SOLARIS */
466	}
467	MUTEX_EXIT(&ipsl_mutex);
468
469	READ_ENTER(&ipf_syncstate);
470	while ((sl_tail < sl_idx)  && (uio->uio_resid > sizeof(*sl))) {
471		sl = synclog + sl_tail++;
472		err = UIOMOVE((caddr_t)sl, sizeof(*sl), UIO_READ, uio);
473		if (err != 0)
474			break;
475	}
476
477	while ((su_tail < su_idx)  && (uio->uio_resid > sizeof(*su))) {
478		su = syncupd + su_tail;
479		su_tail++;
480		err = UIOMOVE((caddr_t)su, sizeof(*su), UIO_READ, uio);
481		if (err != 0)
482			break;
483		if (su->sup_hdr.sm_sl != NULL)
484			su->sup_hdr.sm_sl->sl_idx = -1;
485	}
486
487	MUTEX_ENTER(&ipf_syncadd);
488	if (su_tail == su_idx)
489		su_tail = su_idx = 0;
490	if (sl_tail == sl_idx)
491		sl_tail = sl_idx = 0;
492	MUTEX_EXIT(&ipf_syncadd);
493	RWLOCK_EXIT(&ipf_syncstate);
494	return err;
495}
496
497
498/* ------------------------------------------------------------------------ */
499/* Function:    ipfsync_state                                               */
500/* Returns:     int    - 0 == success, else error value.                    */
501/* Parameters:  sp(I)  - pointer to sync packet data header                 */
502/*              uio(I) - pointer to user data for further information       */
503/*                                                                          */
504/* Updates the state table according to information passed in the sync      */
505/* header.  As required, more data is fetched from the uio structure but    */
506/* varies depending on the contents of the sync header.  This function can  */
507/* create a new state entry or update one.  Deletion is left to the state   */
508/* structures being timed out correctly.                                    */
509/* ------------------------------------------------------------------------ */
510int ipfsync_state(sp, data)
511synchdr_t *sp;
512void *data;
513{
514	synctcp_update_t su;
515	ipstate_t *is, sn;
516	synclist_t *sl;
517	frentry_t *fr;
518	u_int hv;
519	int err = 0;
520
521	hv = sp->sm_num & (SYNC_STATETABSZ - 1);
522
523	switch (sp->sm_cmd)
524	{
525	case SMC_CREATE :
526
527		bcopy(data, &sn, sizeof(sn));
528		KMALLOC(is, ipstate_t *);
529		if (is == NULL) {
530			err = ENOMEM;
531			break;
532		}
533
534		KMALLOC(sl, synclist_t *);
535		if (sl == NULL) {
536			err = ENOMEM;
537			KFREE(is);
538			break;
539		}
540
541		bzero((char *)is, offsetof(ipstate_t, is_die));
542		bcopy((char *)&sn.is_die, (char *)&is->is_die,
543		      sizeof(*is) - offsetof(ipstate_t, is_die));
544		ipfsync_storder(0, is);
545
546		/*
547		 * We need to find the same rule on the slave as was used on
548		 * the master to create this state entry.
549		 */
550		READ_ENTER(&ipf_mutex);
551		fr = fr_getrulen(IPL_LOGIPF, sn.is_group, sn.is_rulen);
552		if (fr != NULL) {
553			MUTEX_ENTER(&fr->fr_lock);
554			fr->fr_ref++;
555			fr->fr_statecnt++;
556			MUTEX_EXIT(&fr->fr_lock);
557		}
558		RWLOCK_EXIT(&ipf_mutex);
559
560		if (ipf_sync_debug > 4)
561			printf("[%d] Filter rules = %p\n", sp->sm_num, fr);
562
563		is->is_rule = fr;
564		is->is_sync = sl;
565
566		sl->sl_idx = -1;
567		sl->sl_ips = is;
568		bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr));
569
570		WRITE_ENTER(&ipf_syncstate);
571		WRITE_ENTER(&ipf_state);
572
573		sl->sl_pnext = syncstatetab + hv;
574		sl->sl_next = syncstatetab[hv];
575		if (syncstatetab[hv] != NULL)
576			syncstatetab[hv]->sl_pnext = &sl->sl_next;
577		syncstatetab[hv] = sl;
578		MUTEX_DOWNGRADE(&ipf_syncstate);
579		fr_stinsert(is, sp->sm_rev);
580		/*
581		 * Do not initialise the interface pointers for the state
582		 * entry as the full complement of interface names may not
583		 * be present.
584		 *
585		 * Put this state entry on its timeout queue.
586		 */
587		/*fr_setstatequeue(is, sp->sm_rev);*/
588		break;
589
590	case SMC_UPDATE :
591		bcopy(data, &su, sizeof(su));
592
593		if (ipf_sync_debug > 4)
594			printf("[%d] Update age %lu state %d/%d \n",
595				sp->sm_num, su.stu_age, su.stu_state[0],
596				su.stu_state[1]);
597
598		READ_ENTER(&ipf_syncstate);
599		for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
600			if (sl->sl_hdr.sm_num == sp->sm_num)
601				break;
602		if (sl == NULL) {
603			if (ipf_sync_debug > 1)
604				printf("[%d] State not found - can't update\n",
605					sp->sm_num);
606			RWLOCK_EXIT(&ipf_syncstate);
607			err = ENOENT;
608			break;
609		}
610
611		READ_ENTER(&ipf_state);
612
613		if (ipf_sync_debug > 6)
614			printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n",
615				sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p,
616				sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table,
617				sl->sl_hdr.sm_rev);
618
619		is = sl->sl_ips;
620
621		MUTEX_ENTER(&is->is_lock);
622		switch (sp->sm_p)
623		{
624		case IPPROTO_TCP :
625			/* XXX FV --- shouldn't we do ntohl/htonl???? XXX */
626			is->is_send = su.stu_data[0].td_end;
627			is->is_maxsend = su.stu_data[0].td_maxend;
628			is->is_maxswin = su.stu_data[0].td_maxwin;
629			is->is_state[0] = su.stu_state[0];
630			is->is_dend = su.stu_data[1].td_end;
631			is->is_maxdend = su.stu_data[1].td_maxend;
632			is->is_maxdwin = su.stu_data[1].td_maxwin;
633			is->is_state[1] = su.stu_state[1];
634			break;
635		default :
636			break;
637		}
638
639		if (ipf_sync_debug > 6)
640			printf("[%d] Setting timers for state\n", sp->sm_num);
641
642		fr_setstatequeue(is, sp->sm_rev);
643
644		MUTEX_EXIT(&is->is_lock);
645		break;
646
647	default :
648		err = EINVAL;
649		break;
650	}
651
652	if (err == 0) {
653		RWLOCK_EXIT(&ipf_state);
654		RWLOCK_EXIT(&ipf_syncstate);
655	}
656
657	if (ipf_sync_debug > 6)
658		printf("[%d] Update completed with error %d\n",
659			sp->sm_num, err);
660
661	return err;
662}
663# endif /* _KERNEL */
664
665
666/* ------------------------------------------------------------------------ */
667/* Function:    ipfsync_del                                                 */
668/* Returns:     Nil                                                         */
669/* Parameters:  sl(I) - pointer to synclist object to delete                */
670/*                                                                          */
671/* Deletes an object from the synclist table and free's its memory.         */
672/* ------------------------------------------------------------------------ */
673void ipfsync_del(sl)
674synclist_t *sl;
675{
676	WRITE_ENTER(&ipf_syncstate);
677	*sl->sl_pnext = sl->sl_next;
678	if (sl->sl_next != NULL)
679		sl->sl_next->sl_pnext = sl->sl_pnext;
680	if (sl->sl_idx != -1)
681		syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
682	RWLOCK_EXIT(&ipf_syncstate);
683	KFREE(sl);
684}
685
686
687/* ------------------------------------------------------------------------ */
688/* Function:    ipfsync_nat                                                 */
689/* Returns:     int    - 0 == success, else error value.                    */
690/* Parameters:  sp(I)  - pointer to sync packet data header                 */
691/*              uio(I) - pointer to user data for further information       */
692/*                                                                          */
693/* Updates the NAT  table according to information passed in the sync       */
694/* header.  As required, more data is fetched from the uio structure but    */
695/* varies depending on the contents of the sync header.  This function can  */
696/* create a new NAT entry or update one.  Deletion is left to the NAT       */
697/* structures being timed out correctly.                                    */
698/* ------------------------------------------------------------------------ */
699int ipfsync_nat(sp, data)
700synchdr_t *sp;
701void *data;
702{
703	synclogent_t sle;
704	syncupdent_t su;
705	nat_t *n, *nat;
706	synclist_t *sl;
707	u_int hv = 0;
708	int err;
709
710	READ_ENTER(&ipf_syncstate);
711
712	switch (sp->sm_cmd)
713	{
714	case SMC_CREATE :
715		bcopy(data, &sle, sizeof(sle));
716
717		KMALLOC(n, nat_t *);
718		if (n == NULL) {
719			err = ENOMEM;
720			break;
721		}
722
723		KMALLOC(sl, synclist_t *);
724		if (sl == NULL) {
725			err = ENOMEM;
726			KFREE(n);
727			break;
728		}
729
730		WRITE_ENTER(&ipf_nat);
731
732		nat = &sle.sle_un.sleu_ipn;
733		bzero((char *)n, offsetof(nat_t, nat_age));
734		bcopy((char *)&nat->nat_age, (char *)&n->nat_age,
735		      sizeof(*n) - offsetof(nat_t, nat_age));
736		ipfsync_natorder(0, n);
737		n->nat_sync = sl;
738
739		sl->sl_idx = -1;
740		sl->sl_ipn = n;
741		sl->sl_num = ntohl(sp->sm_num);
742		sl->sl_pnext = syncstatetab + hv;
743		sl->sl_next = syncstatetab[hv];
744		if (syncstatetab[hv] != NULL)
745			syncstatetab[hv]->sl_pnext = &sl->sl_next;
746		syncstatetab[hv] = sl;
747		nat_insert(n, sl->sl_rev);
748		RWLOCK_EXIT(&ipf_nat);
749		break;
750
751	case SMC_UPDATE :
752		bcopy(data, &su, sizeof(su));
753
754		READ_ENTER(&ipf_syncstate);
755		for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
756			if (sl->sl_hdr.sm_num == sp->sm_num)
757				break;
758		if (sl == NULL) {
759			err = ENOENT;
760			break;
761		}
762
763		READ_ENTER(&ipf_nat);
764
765		nat = sl->sl_ipn;
766
767		MUTEX_ENTER(&nat->nat_lock);
768		fr_setnatqueue(nat, sl->sl_rev);
769		MUTEX_EXIT(&nat->nat_lock);
770
771		RWLOCK_EXIT(&ipf_nat);
772
773		break;
774
775	default :
776		err = EINVAL;
777		break;
778	}
779
780	RWLOCK_EXIT(&ipf_syncstate);
781	return 0;
782}
783
784
785/* ------------------------------------------------------------------------ */
786/* Function:    ipfsync_new                                                 */
787/* Returns:     synclist_t* - NULL == failure, else pointer to new synclist */
788/*                            data structure.                               */
789/* Parameters:  tab(I) - type of synclist_t to create                       */
790/*              fin(I) - pointer to packet information                      */
791/*              ptr(I) - pointer to owning object                           */
792/*                                                                          */
793/* Creates a new sync table entry and notifies any sleepers that it's there */
794/* waiting to be processed.                                                 */
795/* ------------------------------------------------------------------------ */
796synclist_t *ipfsync_new(tab, fin, ptr)
797int tab;
798fr_info_t *fin;
799void *ptr;
800{
801	synclist_t *sl, *ss;
802	synclogent_t *sle;
803	u_int hv, sz;
804
805	if (sl_idx == SYNCLOG_SZ)
806		return NULL;
807	KMALLOC(sl, synclist_t *);
808	if (sl == NULL)
809		return NULL;
810
811	MUTEX_ENTER(&ipf_syncadd);
812	/*
813	 * Get a unique number for this synclist_t.  The number is only meant
814	 * to be unique for the lifetime of the structure and may be reused
815	 * later.
816	 */
817	ipf_syncnum++;
818	if (ipf_syncnum == 0) {
819		ipf_syncnum = 1;
820		ipf_syncwrap = 1;
821	}
822
823	hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
824	while (ipf_syncwrap != 0) {
825		for (ss = syncstatetab[hv]; ss; ss = ss->sl_next)
826			if (ss->sl_hdr.sm_num == ipf_syncnum)
827				break;
828		if (ss == NULL)
829			break;
830		ipf_syncnum++;
831		hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
832	}
833	/*
834	 * Use the synch number of the object as the hash key.  Should end up
835	 * with relatively even distribution over time.
836	 * XXX - an attacker could lunch an DoS attack, of sorts, if they are
837	 * the only one causing new table entries by only keeping open every
838	 * nth connection they make, where n is a value in the interval
839	 * [0, SYNC_STATETABSZ-1].
840	 */
841	sl->sl_pnext = syncstatetab + hv;
842	sl->sl_next = syncstatetab[hv];
843	syncstatetab[hv] = sl;
844	sl->sl_num = ipf_syncnum;
845	MUTEX_EXIT(&ipf_syncadd);
846
847	sl->sl_magic = htonl(SYNHDRMAGIC);
848	sl->sl_v = fin->fin_v;
849	sl->sl_p = fin->fin_p;
850	sl->sl_cmd = SMC_CREATE;
851	sl->sl_idx = -1;
852	sl->sl_table = tab;
853	sl->sl_rev = fin->fin_rev;
854	if (tab == SMC_STATE) {
855		sl->sl_ips = ptr;
856		sz = sizeof(*sl->sl_ips);
857	} else if (tab == SMC_NAT) {
858		sl->sl_ipn = ptr;
859		sz = sizeof(*sl->sl_ipn);
860	} else {
861		ptr = NULL;
862		sz = 0;
863	}
864	sl->sl_len = sz;
865
866	/*
867	 * Create the log entry to be read by a user daemon.  When it has been
868	 * finished and put on the queue, send a signal to wakeup any waiters.
869	 */
870	MUTEX_ENTER(&ipf_syncadd);
871	sle = synclog + sl_idx++;
872	bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr,
873	      sizeof(sle->sle_hdr));
874	sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num);
875	sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len);
876	if (ptr != NULL) {
877		bcopy((char *)ptr, (char *)&sle->sle_un, sz);
878		if (tab == SMC_STATE) {
879			ipfsync_storder(1, &sle->sle_un.sleu_ips);
880		} else if (tab == SMC_NAT) {
881			ipfsync_natorder(1, &sle->sle_un.sleu_ipn);
882		}
883	}
884	MUTEX_EXIT(&ipf_syncadd);
885
886	MUTEX_ENTER(&ipsl_mutex);
887# if SOLARIS
888#  ifdef _KERNEL
889	cv_signal(&ipslwait);
890#  endif
891	MUTEX_EXIT(&ipsl_mutex);
892# else
893	MUTEX_EXIT(&ipsl_mutex);
894#  ifdef _KERNEL
895	wakeup(&sl_tail);
896#  endif
897# endif
898	return sl;
899}
900
901
902/* ------------------------------------------------------------------------ */
903/* Function:    ipfsync_update                                              */
904/* Returns:     Nil                                                         */
905/* Parameters:  tab(I) - type of synclist_t to create                       */
906/*              fin(I) - pointer to packet information                      */
907/*              sl(I)  - pointer to synchronisation object                  */
908/*                                                                          */
909/* For outbound packets, only, create an sync update record for the user    */
910/* process to read.                                                         */
911/* ------------------------------------------------------------------------ */
912void ipfsync_update(tab, fin, sl)
913int tab;
914fr_info_t *fin;
915synclist_t *sl;
916{
917	synctcp_update_t *st;
918	syncupdent_t *slu;
919	ipstate_t *ips;
920	nat_t *nat;
921
922	if (fin->fin_out == 0 || sl == NULL)
923		return;
924
925	WRITE_ENTER(&ipf_syncstate);
926	MUTEX_ENTER(&ipf_syncadd);
927	if (sl->sl_idx == -1) {
928		slu = syncupd + su_idx;
929		sl->sl_idx = su_idx++;
930		bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr,
931		      sizeof(slu->sup_hdr));
932		slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC);
933		slu->sup_hdr.sm_sl = sl;
934		slu->sup_hdr.sm_cmd = SMC_UPDATE;
935		slu->sup_hdr.sm_table = tab;
936		slu->sup_hdr.sm_num = htonl(sl->sl_num);
937		slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update));
938		slu->sup_hdr.sm_rev = fin->fin_rev;
939# if 0
940		if (fin->fin_p == IPPROTO_TCP) {
941			st->stu_len[0] = 0;
942			st->stu_len[1] = 0;
943		}
944# endif
945	} else
946		slu = syncupd + sl->sl_idx;
947	MUTEX_EXIT(&ipf_syncadd);
948	MUTEX_DOWNGRADE(&ipf_syncstate);
949
950	/*
951	 * Only TCP has complex timeouts, others just use default timeouts.
952	 * For TCP, we only need to track the connection state and window.
953	 */
954	if (fin->fin_p == IPPROTO_TCP) {
955		st = &slu->sup_tcp;
956		if (tab == SMC_STATE) {
957			ips = sl->sl_ips;
958			st->stu_age = htonl(ips->is_die);
959			st->stu_data[0].td_end = ips->is_send;
960			st->stu_data[0].td_maxend = ips->is_maxsend;
961			st->stu_data[0].td_maxwin = ips->is_maxswin;
962			st->stu_state[0] = ips->is_state[0];
963			st->stu_data[1].td_end = ips->is_dend;
964			st->stu_data[1].td_maxend = ips->is_maxdend;
965			st->stu_data[1].td_maxwin = ips->is_maxdwin;
966			st->stu_state[1] = ips->is_state[1];
967		} else if (tab == SMC_NAT) {
968			nat = sl->sl_ipn;
969			st->stu_age = htonl(nat->nat_age);
970		}
971	}
972	RWLOCK_EXIT(&ipf_syncstate);
973
974	MUTEX_ENTER(&ipsl_mutex);
975# if SOLARIS
976#  ifdef _KERNEL
977	cv_signal(&ipslwait);
978#  endif
979	MUTEX_EXIT(&ipsl_mutex);
980# else
981	MUTEX_EXIT(&ipsl_mutex);
982#  ifdef _KERNEL
983	wakeup(&sl_tail);
984#  endif
985# endif
986}
987
988
989/* ------------------------------------------------------------------------ */
990/* Function:    fr_sync_ioctl                                               */
991/* Returns:     int - 0 == success, != 0 == failure                         */
992/* Parameters:  data(I) - pointer to ioctl data                             */
993/*              cmd(I)  - ioctl command integer                             */
994/*              mode(I) - file mode bits used with open                     */
995/*                                                                          */
996/* This function currently does not handle any ioctls and so just returns   */
997/* EINVAL on all occasions.                                                 */
998/* ------------------------------------------------------------------------ */
999int fr_sync_ioctl(data, cmd, mode)
1000caddr_t data;
1001ioctlcmd_t cmd;
1002int mode;
1003{
1004	return EINVAL;
1005}
1006#endif /* IPFILTER_SYNC */
1007