ip_fil.c revision 145554
1/*	$FreeBSD: head/contrib/ipfilter/ip_fil.c 145554 2005-04-26 15:18:45Z darrenr $	*/
2
3/*
4 * Copyright (C) 1993-2001 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#if !defined(lint)
9static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.133.2.9 2005/01/08 14:22:18 darrenr Exp $";
11#endif
12
13#ifndef	SOLARIS
14#define	SOLARIS	(defined(sun) && (defined(__svr4__) || defined(__SVR4)))
15#endif
16
17#include <sys/param.h>
18#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
19# if defined(IPFILTER_LKM)
20#  ifndef __FreeBSD_cc_version
21#   include <osreldate.h>
22#  else
23#   if __FreeBSD_cc_version < 430000
24#    include <osreldate.h>
25#   endif
26#  endif
27# endif
28#endif
29#include <sys/errno.h>
30#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL)
31# include <sys/kern_svcs.h>
32#endif
33#include <sys/types.h>
34#define _KERNEL
35#define KERNEL
36#ifdef __OpenBSD__
37struct file;
38#endif
39#include <sys/uio.h>
40#undef _KERNEL
41#undef KERNEL
42#include <sys/file.h>
43#include <sys/ioctl.h>
44#ifdef __sgi
45# include <sys/ptimers.h>
46#endif
47#include <sys/time.h>
48#if !SOLARIS
49# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000)
50#  include <sys/dirent.h>
51# else
52#  include <sys/dir.h>
53# endif
54#else
55# include <sys/filio.h>
56#endif
57#ifndef linux
58# include <sys/protosw.h>
59#endif
60#include <sys/socket.h>
61
62#include <stdio.h>
63#include <string.h>
64#include <stdlib.h>
65#include <ctype.h>
66#include <fcntl.h>
67#include <arpa/inet.h>
68
69#ifdef __hpux
70# define _NET_ROUTE_INCLUDED
71#endif
72#include <net/if.h>
73#ifdef sun
74# include <net/af.h>
75#endif
76#if __FreeBSD_version >= 300000
77# include <net/if_var.h>
78#endif
79#ifdef __sgi
80#include <sys/debug.h>
81# ifdef IFF_DRVRLOCK /* IRIX6 */
82#include <sys/hashing.h>
83# endif
84#endif
85#if defined(__FreeBSD__)
86# include "radix_ipf.h"
87#endif
88#include <net/route.h>
89#include <netinet/in.h>
90#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \
91    !defined(__hpux) && !defined(linux)
92# include <netinet/in_var.h>
93#endif
94#include <netinet/in_systm.h>
95#include <netinet/ip.h>
96#if !defined(linux)
97# include <netinet/ip_var.h>
98#endif
99#include <netinet/tcp.h>
100#if defined(__osf__)
101# include <netinet/tcp_timer.h>
102#endif
103#if defined(__osf__) || defined(__hpux) || defined(__sgi)
104# include "radix_ipf_local.h"
105# define _RADIX_H_
106#endif
107#include <netinet/udp.h>
108#include <netinet/tcpip.h>
109#include <netinet/ip_icmp.h>
110#include <unistd.h>
111#include <syslog.h>
112#ifdef __hpux
113# undef _NET_ROUTE_INCLUDED
114#endif
115#include "netinet/ip_compat.h"
116#include "netinet/ip_fil.h"
117#include "netinet/ip_nat.h"
118#include "netinet/ip_frag.h"
119#include "netinet/ip_state.h"
120#include "netinet/ip_proxy.h"
121#include "netinet/ip_auth.h"
122#ifdef	IPFILTER_SYNC
123#include "netinet/ip_sync.h"
124#endif
125#ifdef	IPFILTER_SCAN
126#include "netinet/ip_scan.h"
127#endif
128#include "netinet/ip_pool.h"
129#ifdef IPFILTER_COMPILED
130# include "netinet/ip_rules.h"
131#endif
132#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
133# include <sys/malloc.h>
134#endif
135#ifdef __hpux
136struct rtentry;
137#endif
138#include "md5.h"
139
140
141#if !defined(__osf__)
142extern	struct	protosw	inetsw[];
143#endif
144
145#include "ipt.h"
146static	struct	ifnet **ifneta = NULL;
147static	int	nifs = 0;
148
149static	int	frzerostats __P((caddr_t));
150static	void	fr_setifpaddr __P((struct ifnet *, char *));
151void	init_ifp __P((void));
152#if defined(__sgi) && (IRIX < 60500)
153static int 	no_output __P((struct ifnet *, struct mbuf *,
154			       struct sockaddr *));
155static int	write_output __P((struct ifnet *, struct mbuf *,
156				  struct sockaddr *));
157#else
158# if TRU64 >= 1885
159static int 	no_output __P((struct ifnet *, struct mbuf *,
160			       struct sockaddr *, struct rtentry *, char *));
161static int	write_output __P((struct ifnet *, struct mbuf *,
162				  struct sockaddr *, struct rtentry *, char *));
163# else
164static int 	no_output __P((struct ifnet *, struct mbuf *,
165			       struct sockaddr *, struct rtentry *));
166static int	write_output __P((struct ifnet *, struct mbuf *,
167				  struct sockaddr *, struct rtentry *));
168# endif
169#endif
170
171
172int iplattach()
173{
174	fr_running = 1;
175	return 0;
176}
177
178
179int ipldetach()
180{
181	fr_running = -1;
182	return 0;
183}
184
185
186static	int	frzerostats(data)
187caddr_t	data;
188{
189	friostat_t fio;
190	int error;
191
192	fr_getstat(&fio);
193	error = copyoutptr(&fio, data, sizeof(fio));
194	if (error)
195		return EFAULT;
196
197	bzero((char *)frstats, sizeof(*frstats) * 2);
198
199	return 0;
200}
201
202
203/*
204 * Filter ioctl interface.
205 */
206int iplioctl(dev, cmd, data, mode)
207int dev;
208ioctlcmd_t cmd;
209caddr_t data;
210int mode;
211{
212	int error = 0, unit = 0, tmp;
213	friostat_t fio;
214
215	unit = dev;
216
217	SPL_NET(s);
218
219	if (unit == IPL_LOGNAT) {
220		if (fr_running > 0)
221			error = fr_nat_ioctl(data, cmd, mode);
222		else
223			error = EIO;
224		SPL_X(s);
225		return error;
226	}
227	if (unit == IPL_LOGSTATE) {
228		if (fr_running > 0)
229			error = fr_state_ioctl(data, cmd, mode);
230		else
231			error = EIO;
232		SPL_X(s);
233		return error;
234	}
235	if (unit == IPL_LOGAUTH) {
236		if (fr_running > 0) {
237			if ((cmd == (ioctlcmd_t)SIOCADAFR) ||
238			    (cmd == (ioctlcmd_t)SIOCRMAFR)) {
239				if (!(mode & FWRITE)) {
240					error = EPERM;
241				} else {
242					error = frrequest(unit, cmd, data,
243							  fr_active, 1);
244				}
245			} else {
246				error = fr_auth_ioctl(data, mode, cmd);
247			}
248		} else
249			error = EIO;
250		SPL_X(s);
251		return error;
252	}
253	if (unit == IPL_LOGSYNC) {
254#ifdef	IPFILTER_SYNC
255		if (fr_running > 0)
256			error = fr_sync_ioctl(data, cmd, mode);
257		else
258#endif
259			error = EIO;
260		SPL_X(s);
261		return error;
262	}
263	if (unit == IPL_LOGSCAN) {
264#ifdef	IPFILTER_SCAN
265		if (fr_running > 0)
266			error = fr_scan_ioctl(data, cmd, mode);
267		else
268#endif
269			error = EIO;
270		SPL_X(s);
271		return error;
272	}
273	if (unit == IPL_LOGLOOKUP) {
274		if (fr_running > 0)
275			error = ip_lookup_ioctl(data, cmd, mode);
276		else
277			error = EIO;
278		SPL_X(s);
279		return error;
280	}
281
282	switch (cmd)
283	{
284	case FIONREAD :
285#ifdef IPFILTER_LOG
286		error = COPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data,
287			       sizeof(iplused[IPL_LOGIPF]));
288#endif
289		break;
290	case SIOCFRENB :
291		if (!(mode & FWRITE))
292			error = EPERM;
293		else {
294			error = COPYIN(data, &tmp, sizeof(tmp));
295			if (error)
296				break;
297			if (tmp)
298				error = iplattach();
299			else
300				error = ipldetach();
301		}
302		break;
303	case SIOCIPFSET :
304		if (!(mode & FWRITE)) {
305			error = EPERM;
306			break;
307		}
308	case SIOCIPFGETNEXT :
309	case SIOCIPFGET :
310		error = fr_ipftune(cmd, (void *)data);
311		break;
312	case SIOCSETFF :
313		if (!(mode & FWRITE))
314			error = EPERM;
315		else
316			error = COPYIN(data, &fr_flags, sizeof(fr_flags));
317		break;
318	case SIOCGETFF :
319		error = COPYOUT(&fr_flags, data, sizeof(fr_flags));
320		break;
321	case SIOCFUNCL :
322		error = fr_resolvefunc(data);
323		break;
324	case SIOCINAFR :
325	case SIOCRMAFR :
326	case SIOCADAFR :
327	case SIOCZRLST :
328		if (!(mode & FWRITE))
329			error = EPERM;
330		else
331			error = frrequest(unit, cmd, data, fr_active, 1);
332		break;
333	case SIOCINIFR :
334	case SIOCRMIFR :
335	case SIOCADIFR :
336		if (!(mode & FWRITE))
337			error = EPERM;
338		else
339			error = frrequest(unit, cmd, data, 1 - fr_active, 1);
340		break;
341	case SIOCSWAPA :
342		if (!(mode & FWRITE))
343			error = EPERM;
344		else {
345			bzero((char *)frcache, sizeof(frcache[0]) * 2);
346			*(u_int *)data = fr_active;
347			fr_active = 1 - fr_active;
348		}
349		break;
350	case SIOCGETFS :
351		fr_getstat(&fio);
352		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
353		break;
354	case	SIOCFRZST :
355		if (!(mode & FWRITE))
356			error = EPERM;
357		else
358			error = frzerostats(data);
359		break;
360	case	SIOCIPFFL :
361		if (!(mode & FWRITE))
362			error = EPERM;
363		else {
364			error = COPYIN(data, &tmp, sizeof(tmp));
365			if (!error) {
366				tmp = frflush(unit, 4, tmp);
367				error = COPYOUT(&tmp, data, sizeof(tmp));
368			}
369		}
370		break;
371#ifdef	USE_INET6
372	case	SIOCIPFL6 :
373		if (!(mode & FWRITE))
374			error = EPERM;
375		else {
376			error = COPYIN(data, &tmp, sizeof(tmp));
377			if (!error) {
378				tmp = frflush(unit, 6, tmp);
379				error = COPYOUT(&tmp, data, sizeof(tmp));
380			}
381		}
382		break;
383#endif
384	case SIOCSTLCK :
385		error = COPYIN(data, &tmp, sizeof(tmp));
386		if (error == 0) {
387			fr_state_lock = tmp;
388			fr_nat_lock = tmp;
389			fr_frag_lock = tmp;
390			fr_auth_lock = tmp;
391		} else
392			error = EFAULT;
393		break;
394#ifdef	IPFILTER_LOG
395	case	SIOCIPFFB :
396		if (!(mode & FWRITE))
397			error = EPERM;
398		else
399			*(int *)data = ipflog_clear(unit);
400		break;
401#endif /* IPFILTER_LOG */
402	case SIOCGFRST :
403		error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT);
404		break;
405	case SIOCFRSYN :
406		if (!(mode & FWRITE))
407			error = EPERM;
408		else {
409			frsync(NULL);
410		}
411		break;
412	default :
413		error = EINVAL;
414		break;
415	}
416	SPL_X(s);
417	return error;
418}
419
420
421void fr_forgetifp(ifp)
422void *ifp;
423{
424	register frentry_t *f;
425
426	WRITE_ENTER(&ipf_mutex);
427	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
428		if (f->fr_ifa == ifp)
429			f->fr_ifa = (void *)-1;
430	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
431		if (f->fr_ifa == ifp)
432			f->fr_ifa = (void *)-1;
433	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
434		if (f->fr_ifa == ifp)
435			f->fr_ifa = (void *)-1;
436	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
437		if (f->fr_ifa == ifp)
438			f->fr_ifa = (void *)-1;
439#ifdef	USE_INET6
440	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
441		if (f->fr_ifa == ifp)
442			f->fr_ifa = (void *)-1;
443	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
444		if (f->fr_ifa == ifp)
445			f->fr_ifa = (void *)-1;
446	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
447		if (f->fr_ifa == ifp)
448			f->fr_ifa = (void *)-1;
449	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
450		if (f->fr_ifa == ifp)
451			f->fr_ifa = (void *)-1;
452#endif
453	RWLOCK_EXIT(&ipf_mutex);
454	fr_natsync(ifp);
455}
456
457
458#if defined(__sgi) && (IRIX < 60500)
459static int no_output(ifp, m, s)
460#else
461# if TRU64 >= 1885
462static int no_output (ifp, m, s, rt, cp)
463char *cp;
464# else
465static int no_output(ifp, m, s, rt)
466# endif
467struct rtentry *rt;
468#endif
469struct ifnet *ifp;
470struct mbuf *m;
471struct sockaddr *s;
472{
473	return 0;
474}
475
476
477#if defined(__sgi) && (IRIX < 60500)
478static int write_output(ifp, m, s)
479#else
480# if TRU64 >= 1885
481static int write_output (ifp, m, s, rt, cp)
482char *cp;
483# else
484static int write_output(ifp, m, s, rt)
485# endif
486struct rtentry *rt;
487#endif
488struct ifnet *ifp;
489struct mbuf *m;
490struct sockaddr *s;
491{
492	char fname[32];
493	mb_t *mb;
494	ip_t *ip;
495	int fd;
496
497	mb = (mb_t *)m;
498	ip = MTOD(mb, ip_t *);
499
500#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
501    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
502    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
503	sprintf(fname, "/tmp/%s", ifp->if_xname);
504#else
505	sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
506#endif
507	fd = open(fname, O_WRONLY|O_APPEND);
508	if (fd == -1) {
509		perror("open");
510		return -1;
511	}
512	write(fd, (char *)ip, ntohs(ip->ip_len));
513	close(fd);
514	return 0;
515}
516
517
518static void fr_setifpaddr(ifp, addr)
519struct ifnet *ifp;
520char *addr;
521{
522#ifdef __sgi
523	struct in_ifaddr *ifa;
524#else
525	struct ifaddr *ifa;
526#endif
527
528#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
529	if (ifp->if_addrlist.tqh_first != NULL)
530#else
531# ifdef __sgi
532	if (ifp->in_ifaddr != NULL)
533# else
534	if (ifp->if_addrlist != NULL)
535# endif
536#endif
537		return;
538
539	ifa = (struct ifaddr *)malloc(sizeof(*ifa));
540#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
541	ifp->if_addrlist.tqh_first = ifa;
542#else
543# ifdef __sgi
544	ifp->in_ifaddr = ifa;
545# else
546	ifp->if_addrlist = ifa;
547# endif
548#endif
549
550	if (ifa != NULL) {
551		struct sockaddr_in *sin;
552
553#ifdef __sgi
554		sin = (struct sockaddr_in *)&ifa->ia_addr;
555#else
556		sin = (struct sockaddr_in *)&ifa->ifa_addr;
557#endif
558		sin->sin_addr.s_addr = inet_addr(addr);
559		if (sin->sin_addr.s_addr == 0)
560			abort();
561	}
562}
563
564struct ifnet *get_unit(name, v)
565char *name;
566int v;
567{
568	struct ifnet *ifp, **ifpp, **old_ifneta;
569	char *addr;
570#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
571    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
572    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
573
574	if (name == NULL)
575		name = "anon0";
576
577	addr = strchr(name, '=');
578	if (addr != NULL)
579		*addr++ = '\0';
580
581	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
582		if (!strcmp(name, ifp->if_xname)) {
583			if (addr != NULL)
584				fr_setifpaddr(ifp, addr);
585			return ifp;
586		}
587	}
588#else
589	char *s, ifname[LIFNAMSIZ+1];
590
591	if (name == NULL)
592		name = "anon0";
593
594	addr = strchr(name, '=');
595	if (addr != NULL)
596		*addr++ = '\0';
597
598	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
599		COPYIFNAME(ifp, ifname);
600		if (!strcmp(name, ifname)) {
601			if (addr != NULL)
602				fr_setifpaddr(ifp, addr);
603			return ifp;
604		}
605	}
606#endif
607
608	if (!ifneta) {
609		ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
610		if (!ifneta)
611			return NULL;
612		ifneta[1] = NULL;
613		ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
614		if (!ifneta[0]) {
615			free(ifneta);
616			return NULL;
617		}
618		nifs = 1;
619	} else {
620		old_ifneta = ifneta;
621		nifs++;
622		ifneta = (struct ifnet **)realloc(ifneta,
623						  (nifs + 1) * sizeof(ifp));
624		if (!ifneta) {
625			free(old_ifneta);
626			nifs = 0;
627			return NULL;
628		}
629		ifneta[nifs] = NULL;
630		ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
631		if (!ifneta[nifs - 1]) {
632			nifs--;
633			return NULL;
634		}
635	}
636	ifp = ifneta[nifs - 1];
637
638#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
639    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
640    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
641	(void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
642#else
643	for (s = name; *s && !ISDIGIT(*s); s++)
644		;
645	if (*s && ISDIGIT(*s)) {
646		ifp->if_unit = atoi(s);
647		ifp->if_name = (char *)malloc(s - name + 1);
648		(void) strncpy(ifp->if_name, name, s - name);
649		ifp->if_name[s - name] = '\0';
650	} else {
651		ifp->if_name = strdup(name);
652		ifp->if_unit = -1;
653	}
654#endif
655	ifp->if_output = no_output;
656
657	if (addr != NULL) {
658		fr_setifpaddr(ifp, addr);
659	}
660
661	return ifp;
662}
663
664
665char *get_ifname(ifp)
666struct ifnet *ifp;
667{
668	static char ifname[LIFNAMSIZ];
669
670#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
671    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
672	sprintf(ifname, "%s", ifp->if_xname);
673#else
674	sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
675#endif
676	return ifname;
677}
678
679
680
681void init_ifp()
682{
683	struct ifnet *ifp, **ifpp;
684	char fname[32];
685	int fd;
686
687#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
688    (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
689    (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
690	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
691		ifp->if_output = write_output;
692		sprintf(fname, "/tmp/%s", ifp->if_xname);
693		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
694		if (fd == -1)
695			perror("open");
696		else
697			close(fd);
698	}
699#else
700
701	for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
702		ifp->if_output = write_output;
703		sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
704		fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
705		if (fd == -1)
706			perror("open");
707		else
708			close(fd);
709	}
710#endif
711}
712
713
714int fr_fastroute(m, mpp, fin, fdp)
715mb_t *m, **mpp;
716fr_info_t *fin;
717frdest_t *fdp;
718{
719	struct ifnet *ifp = fdp->fd_ifp;
720	ip_t *ip = fin->fin_ip;
721
722	if (!ifp)
723		return 0;	/* no routing table out here */
724
725	ip->ip_len = htons((u_short)ip->ip_len);
726	ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
727	ip->ip_sum = 0;
728#if defined(__sgi) && (IRIX < 60500)
729	(*ifp->if_output)(ifp, (void *)ip, NULL);
730# if TRU64 >= 1885
731	(*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
732# else
733	(*ifp->if_output)(ifp, (void *)m, NULL, 0);
734# endif
735#endif
736	return 0;
737}
738
739
740int fr_send_reset(fin)
741fr_info_t *fin;
742{
743	verbose("- TCP RST sent\n");
744	return 0;
745}
746
747
748int fr_send_icmp_err(type, fin, dst)
749int type;
750fr_info_t *fin;
751int dst;
752{
753	verbose("- ICMP unreachable sent\n");
754	return 0;
755}
756
757
758void frsync(ifp)
759void *ifp;
760{
761	return;
762}
763
764
765void m_freem(m)
766mb_t *m;
767{
768	return;
769}
770
771
772void m_copydata(m, off, len, cp)
773mb_t *m;
774int off, len;
775caddr_t cp;
776{
777	bcopy((char *)m + off, cp, len);
778}
779
780
781int ipfuiomove(buf, len, rwflag, uio)
782caddr_t buf;
783int len, rwflag;
784struct uio *uio;
785{
786	int left, ioc, num, offset;
787	struct iovec *io;
788	char *start;
789
790	if (rwflag == UIO_READ) {
791		left = len;
792		ioc = 0;
793
794		offset = uio->uio_offset;
795
796		while ((left > 0) && (ioc < uio->uio_iovcnt)) {
797			io = uio->uio_iov + ioc;
798			num = io->iov_len;
799			if (num > left)
800				num = left;
801			start = (char *)io->iov_base + offset;
802			if (start > (char *)io->iov_base + io->iov_len) {
803				offset -= io->iov_len;
804				ioc++;
805				continue;
806			}
807			bcopy(buf, start, num);
808			uio->uio_resid -= num;
809			uio->uio_offset += num;
810			left -= num;
811			if (left > 0)
812				ioc++;
813		}
814		if (left > 0)
815			return EFAULT;
816	}
817	return 0;
818}
819
820
821u_32_t fr_newisn(fin)
822fr_info_t *fin;
823{
824	static int iss_seq_off = 0;
825	u_char hash[16];
826	u_32_t newiss;
827	MD5_CTX ctx;
828
829	/*
830	 * Compute the base value of the ISS.  It is a hash
831	 * of (saddr, sport, daddr, dport, secret).
832	 */
833	MD5Init(&ctx);
834
835	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
836		  sizeof(fin->fin_fi.fi_src));
837	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
838		  sizeof(fin->fin_fi.fi_dst));
839	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
840
841	/* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
842
843	MD5Final(hash, &ctx);
844
845	memcpy(&newiss, hash, sizeof(newiss));
846
847	/*
848	 * Now increment our "timer", and add it in to
849	 * the computed value.
850	 *
851	 * XXX Use `addin'?
852	 * XXX TCP_ISSINCR too large to use?
853	 */
854	iss_seq_off += 0x00010000;
855	newiss += iss_seq_off;
856	return newiss;
857}
858
859
860/* ------------------------------------------------------------------------ */
861/* Function:    fr_nextipid                                                 */
862/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
863/* Parameters:  fin(I) - pointer to packet information                      */
864/*                                                                          */
865/* Returns the next IPv4 ID to use for this packet.                         */
866/* ------------------------------------------------------------------------ */
867INLINE u_short fr_nextipid(fin)
868fr_info_t *fin;
869{
870	static u_short ipid = 0;
871	u_short id;
872
873	MUTEX_ENTER(&ipf_rw);
874	id = ipid++;
875	MUTEX_EXIT(&ipf_rw);
876
877	return id;
878}
879
880
881INLINE void fr_checkv4sum(fin)
882fr_info_t *fin;
883{
884	if (fr_checkl4sum(fin) == -1)
885		fin->fin_flx |= FI_BAD;
886}
887
888
889#ifdef	USE_INET6
890INLINE void fr_checkv6sum(fin)
891fr_info_t *fin;
892{
893	if (fr_checkl4sum(fin) == -1)
894		fin->fin_flx |= FI_BAD;
895}
896#endif
897
898
899/*
900 * See above for description, except that all addressing is in user space.
901 */
902int copyoutptr(src, dst, size)
903void *src, *dst;
904size_t size;
905{
906	caddr_t ca;
907
908	bcopy(dst, (char *)&ca, sizeof(ca));
909	bcopy(src, ca, size);
910	return 0;
911}
912
913
914/*
915 * See above for description, except that all addressing is in user space.
916 */
917int copyinptr(src, dst, size)
918void *src, *dst;
919size_t size;
920{
921	caddr_t ca;
922
923	bcopy(src, (char *)&ca, sizeof(ca));
924	bcopy(ca, dst, size);
925	return 0;
926}
927
928
929/*
930 * return the first IP Address associated with an interface
931 */
932int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
933int v, atype;
934void *ifptr;
935struct in_addr *inp, *inpmask;
936{
937	struct ifnet *ifp = ifptr;
938#ifdef __sgi
939	struct in_ifaddr *ifa;
940#else
941	struct ifaddr *ifa;
942#endif
943
944#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
945	ifa = ifp->if_addrlist.tqh_first;
946#else
947# ifdef __sgi
948	ifa = (struct in_ifaddr *)ifp->in_ifaddr;
949# else
950	ifa = ifp->if_addrlist;
951# endif
952#endif
953	if (ifa != NULL) {
954		struct sockaddr_in *sin, mask;
955
956		mask.sin_addr.s_addr = 0xffffffff;
957
958#ifdef __sgi
959		sin = (struct sockaddr_in *)&ifa->ia_addr;
960#else
961		sin = (struct sockaddr_in *)&ifa->ifa_addr;
962#endif
963
964		return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask);
965	}
966	return 0;
967}
968