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