fil.c revision 111119
1251881Speter/*
2251881Speter * Copyright (C) 1993-2001 by Darren Reed.
3251881Speter *
4251881Speter * See the IPFILTER.LICENCE file for details on licencing.
5251881Speter */
6251881Speter#if defined(__sgi) && (IRIX > 602)
7251881Speter# include <sys/ptimers.h>
8251881Speter#endif
9251881Speter#include <sys/errno.h>
10251881Speter#include <sys/types.h>
11251881Speter#include <sys/param.h>
12251881Speter#include <sys/time.h>
13251881Speter#include <sys/file.h>
14251881Speter#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
15251881Speter    defined(_KERNEL)
16251881Speter# include "opt_ipfilter_log.h"
17251881Speter#endif
18251881Speter#if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \
19251881Speter    (__FreeBSD_version >= 220000)
20251881Speter# if (__FreeBSD_version >= 400000)
21251881Speter#  ifndef KLD_MODULE
22251881Speter#   include "opt_inet6.h"
23251881Speter#  endif
24251881Speter#  if (__FreeBSD_version == 400019)
25251881Speter#   define CSUM_DELAY_DATA
26251881Speter#  endif
27251881Speter# endif
28251881Speter# include <sys/filio.h>
29251881Speter# include <sys/fcntl.h>
30251881Speter#else
31251881Speter# include <sys/ioctl.h>
32251881Speter#endif
33251881Speter#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
34251881Speter# include <sys/systm.h>
35251881Speter#else
36251881Speter# include <stdio.h>
37251881Speter# include <string.h>
38251881Speter# include <stdlib.h>
39251881Speter#endif
40251881Speter#if !defined(__SVR4) && !defined(__svr4__)
41251881Speter# ifndef linux
42251881Speter#  include <sys/mbuf.h>
43251881Speter# endif
44251881Speter#else
45251881Speter# include <sys/byteorder.h>
46251881Speter# if SOLARIS2 < 5
47251881Speter#  include <sys/dditypes.h>
48251881Speter# endif
49251881Speter#  include <sys/stream.h>
50251881Speter#endif
51251881Speter#ifndef linux
52251881Speter# include <sys/protosw.h>
53251881Speter# include <sys/socket.h>
54251881Speter#endif
55251881Speter#include <net/if.h>
56251881Speter#ifdef sun
57251881Speter# include <net/af.h>
58251881Speter#endif
59251881Speter#include <net/route.h>
60251881Speter#include <netinet/in.h>
61251881Speter#include <netinet/in_systm.h>
62251881Speter#include <netinet/ip.h>
63251881Speter#ifndef linux
64251881Speter# include <netinet/ip_var.h>
65251881Speter#endif
66251881Speter#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
67251881Speter# include <sys/hashing.h>
68251881Speter# include <netinet/in_var.h>
69251881Speter#endif
70251881Speter#include <netinet/tcp.h>
71251881Speter#include <netinet/udp.h>
72251881Speter#include <netinet/ip_icmp.h>
73251881Speter#include "netinet/ip_compat.h"
74251881Speter#ifdef	USE_INET6
75251881Speter# include <netinet/icmp6.h>
76251881Speter# if !SOLARIS && defined(_KERNEL)
77251881Speter#  include <netinet6/in6_var.h>
78251881Speter# endif
79251881Speter#endif
80251881Speter#include <netinet/tcpip.h>
81251881Speter#include "netinet/ip_fil.h"
82251881Speter#include "netinet/ip_nat.h"
83251881Speter#include "netinet/ip_frag.h"
84251881Speter#include "netinet/ip_state.h"
85251881Speter#include "netinet/ip_proxy.h"
86251881Speter#include "netinet/ip_auth.h"
87251881Speter# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
88251881Speter#  include <sys/malloc.h>
89251881Speter#  if defined(_KERNEL) && !defined(IPFILTER_LKM)
90251881Speter#   include "opt_ipfilter.h"
91251881Speter#  endif
92251881Speter# endif
93251881Speter#ifndef	MIN
94251881Speter# define	MIN(a,b)	(((a)<(b))?(a):(b))
95251881Speter#endif
96251881Speter#include "netinet/ipl.h"
97251881Speter
98251881Speter#include <machine/in_cksum.h>
99251881Speter
100251881Speter#if !defined(lint)
101251881Speterstatic const char sccsid[] = "@(#)fil.c	1.36 6/5/96 (C) 1993-2000 Darren Reed";
102251881Speterstatic const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/fil.c 111119 2003-02-19 05:47:46Z imp $";
103251881Speter#endif
104251881Speter
105251881Speter#ifndef	_KERNEL
106251881Speter# include "ipf.h"
107251881Speter# include "ipt.h"
108251881Speterextern	int	opts;
109251881Speter
110251881Speter# define	FR_VERBOSE(verb_pr)			verbose verb_pr
111251881Speter# define	FR_DEBUG(verb_pr)			debug verb_pr
112251881Speter# define	IPLLOG(a, c, d, e)		ipflog(a, c, d, e)
113251881Speter#else /* #ifndef _KERNEL */
114251881Speter# define	FR_VERBOSE(verb_pr)
115251881Speter# define	FR_DEBUG(verb_pr)
116251881Speter# define	IPLLOG(a, c, d, e)		ipflog(a, c, d, e)
117251881Speter# if SOLARIS || defined(__sgi)
118251881Speterextern	KRWLOCK_T	ipf_mutex, ipf_auth, ipf_nat;
119251881Speterextern	kmutex_t	ipf_rw;
120251881Speter# endif /* SOLARIS || __sgi */
121251881Speter#endif /* _KERNEL */
122251881Speter
123251881Speter
124251881Speterstruct	filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
125251881Speterstruct	frentry	*ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
126251881Speter#ifdef	USE_INET6
127251881Speter		*ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } },
128251881Speter		*ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } },
129251881Speter#endif
130251881Speter		*ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
131251881Speterstruct	frgroup *ipfgroups[3][2];
132251881Speterint	fr_flags = IPF_LOGGING;
133251881Speterint	fr_active = 0;
134251881Speterint	fr_chksrc = 0;
135251881Speterint	fr_minttl = 3;
136251881Speterint	fr_minttllog = 1;
137251881Speter#if defined(IPFILTER_DEFAULT_BLOCK)
138251881Speterint	fr_pass = FR_NOMATCH|FR_BLOCK;
139251881Speter#else
140251881Speterint	fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH);
141251881Speter#endif
142251881Speterchar	ipfilter_version[] = IPL_VERSION;
143251881Speter
144251881Speterfr_info_t	frcache[2];
145251881Speter
146251881Speterstatic	int	frflushlist __P((int, minor_t, int *, frentry_t **));
147251881Speter#ifdef	_KERNEL
148251881Speterstatic	void	frsynclist __P((frentry_t *));
149251881Speter#endif
150251881Speter
151251881Speter
152251881Speter/*
153251881Speter * bit values for identifying presence of individual IP options
154251881Speter */
155251881Speterstruct	optlist	ipopts[20] = {
156251881Speter	{ IPOPT_NOP,	0x000001 },
157251881Speter	{ IPOPT_RR,	0x000002 },
158251881Speter	{ IPOPT_ZSU,	0x000004 },
159251881Speter	{ IPOPT_MTUP,	0x000008 },
160251881Speter	{ IPOPT_MTUR,	0x000010 },
161251881Speter	{ IPOPT_ENCODE,	0x000020 },
162251881Speter	{ IPOPT_TS,	0x000040 },
163251881Speter	{ IPOPT_TR,	0x000080 },
164251881Speter	{ IPOPT_SECURITY, 0x000100 },
165251881Speter	{ IPOPT_LSRR,	0x000200 },
166251881Speter	{ IPOPT_E_SEC,	0x000400 },
167251881Speter	{ IPOPT_CIPSO,	0x000800 },
168251881Speter	{ IPOPT_SATID,	0x001000 },
169251881Speter	{ IPOPT_SSRR,	0x002000 },
170251881Speter	{ IPOPT_ADDEXT,	0x004000 },
171251881Speter	{ IPOPT_VISA,	0x008000 },
172251881Speter	{ IPOPT_IMITD,	0x010000 },
173251881Speter	{ IPOPT_EIP,	0x020000 },
174251881Speter	{ IPOPT_FINN,	0x040000 },
175251881Speter	{ 0,		0x000000 }
176251881Speter};
177251881Speter
178251881Speter/*
179251881Speter * bit values for identifying presence of individual IP security options
180251881Speter */
181251881Speterstruct	optlist	secopt[8] = {
182251881Speter	{ IPSO_CLASS_RES4,	0x01 },
183251881Speter	{ IPSO_CLASS_TOPS,	0x02 },
184251881Speter	{ IPSO_CLASS_SECR,	0x04 },
185251881Speter	{ IPSO_CLASS_RES3,	0x08 },
186251881Speter	{ IPSO_CLASS_CONF,	0x10 },
187251881Speter	{ IPSO_CLASS_UNCL,	0x20 },
188251881Speter	{ IPSO_CLASS_RES2,	0x40 },
189251881Speter	{ IPSO_CLASS_RES1,	0x80 }
190251881Speter};
191251881Speter
192251881Speter
193251881Speter/*
194251881Speter * compact the IP header into a structure which contains just the info.
195251881Speter * which is useful for comparing IP headers with.
196251881Speter */
197251881Spetervoid	fr_makefrip(hlen, ip, fin)
198251881Speterint hlen;
199251881Speterip_t *ip;
200251881Speterfr_info_t *fin;
201251881Speter{
202251881Speter	u_short optmsk = 0, secmsk = 0, auth = 0;
203251881Speter	int i, mv, ol, off, p, plen, v;
204251881Speter	fr_ip_t *fi = &fin->fin_fi;
205251881Speter	struct optlist *op;
206251881Speter	u_char *s, opt;
207251881Speter	tcphdr_t *tcp;
208251881Speter
209251881Speter	fin->fin_rev = 0;
210251881Speter	fin->fin_fr = NULL;
211251881Speter	fin->fin_tcpf = 0;
212251881Speter	fin->fin_data[0] = 0;
213251881Speter	fin->fin_data[1] = 0;
214251881Speter	fin->fin_rule = -1;
215251881Speter	fin->fin_group = -1;
216251881Speter	fin->fin_icode = ipl_unreach;
217251881Speter	v = fin->fin_v;
218251881Speter	fi->fi_v = v;
219251881Speter	fin->fin_hlen = hlen;
220251881Speter	if (v == 4) {
221251881Speter		fin->fin_id = ip->ip_id;
222251881Speter		fi->fi_tos = ip->ip_tos;
223251881Speter		off = (ip->ip_off & IP_OFFMASK);
224251881Speter		tcp = (tcphdr_t *)((char *)ip + hlen);
225251881Speter		(*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
226251881Speter		fi->fi_src.i6[1] = 0;
227251881Speter		fi->fi_src.i6[2] = 0;
228251881Speter		fi->fi_src.i6[3] = 0;
229251881Speter		fi->fi_dst.i6[1] = 0;
230251881Speter		fi->fi_dst.i6[2] = 0;
231251881Speter		fi->fi_dst.i6[3] = 0;
232251881Speter		fi->fi_saddr = ip->ip_src.s_addr;
233251881Speter		fi->fi_daddr = ip->ip_dst.s_addr;
234251881Speter		p = ip->ip_p;
235251881Speter		fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0;
236251881Speter		if (ip->ip_off & (IP_MF|IP_OFFMASK))
237251881Speter			fi->fi_fl |= FI_FRAG;
238251881Speter		plen = ip->ip_len;
239251881Speter		fin->fin_dlen = plen - hlen;
240251881Speter	}
241251881Speter#ifdef	USE_INET6
242251881Speter	else if (v == 6) {
243251881Speter		ip6_t *ip6 = (ip6_t *)ip;
244251881Speter
245251881Speter		off = 0;
246251881Speter		p = ip6->ip6_nxt;
247251881Speter		fi->fi_p = p;
248251881Speter		fi->fi_ttl = ip6->ip6_hlim;
249251881Speter		tcp = (tcphdr_t *)(ip6 + 1);
250251881Speter		fi->fi_src.in6 = ip6->ip6_src;
251251881Speter		fi->fi_dst.in6 = ip6->ip6_dst;
252251881Speter		fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff);
253251881Speter		fi->fi_tos = 0;
254251881Speter		fi->fi_fl = 0;
255251881Speter		plen = ntohs(ip6->ip6_plen);
256251881Speter		fin->fin_dlen = plen;
257251881Speter		plen += sizeof(*ip6);
258251881Speter	}
259251881Speter#endif
260251881Speter	else
261251881Speter		return;
262251881Speter
263251881Speter	fin->fin_off = off;
264251881Speter	fin->fin_plen = plen;
265251881Speter	fin->fin_dp = (char *)tcp;
266251881Speter	fin->fin_misc = 0;
267251881Speter	off <<= 3;
268251881Speter
269251881Speter	switch (p)
270251881Speter	{
271251881Speter#ifdef USE_INET6
272251881Speter	case IPPROTO_ICMPV6 :
273251881Speter	{
274251881Speter		int minicmpsz = sizeof(struct icmp6_hdr);
275251881Speter		struct icmp6_hdr *icmp6;
276251881Speter
277251881Speter		if (fin->fin_dlen > 1) {
278251881Speter			fin->fin_data[0] = *(u_short *)tcp;
279251881Speter
280251881Speter			icmp6 = (struct icmp6_hdr *)tcp;
281251881Speter
282251881Speter			switch (icmp6->icmp6_type)
283251881Speter			{
284251881Speter			case ICMP6_ECHO_REPLY :
285251881Speter			case ICMP6_ECHO_REQUEST :
286251881Speter				minicmpsz = ICMP6_MINLEN;
287251881Speter				break;
288251881Speter			case ICMP6_DST_UNREACH :
289251881Speter			case ICMP6_PACKET_TOO_BIG :
290251881Speter			case ICMP6_TIME_EXCEEDED :
291251881Speter			case ICMP6_PARAM_PROB :
292251881Speter				minicmpsz = ICMP6ERR_IPICMPHLEN;
293251881Speter				break;
294251881Speter			default :
295251881Speter				break;
296251881Speter			}
297251881Speter		}
298251881Speter
299251881Speter		if (!(plen >= minicmpsz))
300251881Speter			fi->fi_fl |= FI_SHORT;
301251881Speter
302251881Speter		break;
303251881Speter	}
304251881Speter#endif
305251881Speter	case IPPROTO_ICMP :
306251881Speter	{
307251881Speter		int minicmpsz = sizeof(struct icmp);
308251881Speter		icmphdr_t *icmp;
309251881Speter
310251881Speter		if (!off && (fin->fin_dlen > 1)) {
311251881Speter			fin->fin_data[0] = *(u_short *)tcp;
312251881Speter
313251881Speter			icmp = (icmphdr_t *)tcp;
314251881Speter
315251881Speter			switch (icmp->icmp_type)
316251881Speter			{
317251881Speter			case ICMP_ECHOREPLY :
318251881Speter			case ICMP_ECHO :
319251881Speter			/* Router discovery messages - RFC 1256 */
320251881Speter			case ICMP_ROUTERADVERT :
321251881Speter			case ICMP_ROUTERSOLICIT :
322251881Speter				minicmpsz = ICMP_MINLEN;
323251881Speter				break;
324251881Speter			/*
325251881Speter			 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
326251881Speter			 * 3*timestamp(3*4)
327251881Speter			 */
328251881Speter			case ICMP_TSTAMP :
329251881Speter			case ICMP_TSTAMPREPLY :
330251881Speter				minicmpsz = 20;
331251881Speter				break;
332251881Speter			/*
333251881Speter			 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
334251881Speter			 * mask(4)
335251881Speter			 */
336251881Speter			case ICMP_MASKREQ :
337251881Speter			case ICMP_MASKREPLY :
338251881Speter				minicmpsz = 12;
339251881Speter				break;
340251881Speter			default :
341251881Speter				break;
342251881Speter			}
343251881Speter		}
344251881Speter
345251881Speter		if ((!(plen >= hlen + minicmpsz) && !off) ||
346251881Speter		    (off && off < sizeof(struct icmp)))
347251881Speter			fi->fi_fl |= FI_SHORT;
348251881Speter
349251881Speter		break;
350251881Speter	}
351251881Speter	case IPPROTO_TCP :
352251881Speter		fi->fi_fl |= FI_TCPUDP;
353251881Speter#ifdef	USE_INET6
354251881Speter		if (v == 6) {
355251881Speter			if (plen < sizeof(struct tcphdr))
356251881Speter				fi->fi_fl |= FI_SHORT;
357251881Speter		} else
358251881Speter#endif
359251881Speter		if (v == 4) {
360251881Speter			if ((!IPMINLEN(ip, tcphdr) && !off) ||
361251881Speter			     (off && off < sizeof(struct tcphdr)))
362251881Speter				fi->fi_fl |= FI_SHORT;
363251881Speter		}
364251881Speter		if (!(fi->fi_fl & FI_SHORT) && !off)
365251881Speter			fin->fin_tcpf = tcp->th_flags;
366251881Speter		goto getports;
367251881Speter	case IPPROTO_UDP :
368251881Speter		fi->fi_fl |= FI_TCPUDP;
369251881Speter#ifdef	USE_INET6
370251881Speter		if (v == 6) {
371251881Speter			if (plen < sizeof(struct udphdr))
372251881Speter				fi->fi_fl |= FI_SHORT;
373251881Speter		} else
374251881Speter#endif
375251881Speter		if (v == 4) {
376251881Speter			if ((!IPMINLEN(ip, udphdr) && !off) ||
377251881Speter			    (off && off < sizeof(struct udphdr)))
378251881Speter				fi->fi_fl |= FI_SHORT;
379251881Speter		}
380251881Spetergetports:
381251881Speter		if (!off && (fin->fin_dlen > 3)) {
382251881Speter			fin->fin_data[0] = ntohs(tcp->th_sport);
383251881Speter			fin->fin_data[1] = ntohs(tcp->th_dport);
384251881Speter		}
385251881Speter		break;
386251881Speter	case IPPROTO_ESP :
387251881Speter#ifdef	USE_INET6
388251881Speter		if (v == 6) {
389251881Speter			if (plen < 8)
390251881Speter				fi->fi_fl |= FI_SHORT;
391251881Speter		} else
392251881Speter#endif
393251881Speter		if (v == 4) {
394251881Speter			if (((ip->ip_len < hlen + 8) && !off) ||
395251881Speter			    (off && off < 8))
396251881Speter				fi->fi_fl |= FI_SHORT;
397251881Speter		}
398251881Speter		break;
399251881Speter	default :
400251881Speter		break;
401251881Speter	}
402251881Speter
403251881Speter#ifdef	USE_INET6
404251881Speter	if (v == 6) {
405251881Speter		fi->fi_optmsk = 0;
406251881Speter		fi->fi_secmsk = 0;
407251881Speter		fi->fi_auth = 0;
408251881Speter		return;
409251881Speter	}
410251881Speter#endif
411251881Speter
412251881Speter	for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
413251881Speter		opt = *s;
414251881Speter		if (opt == '\0')
415251881Speter			break;
416251881Speter		else if (opt == IPOPT_NOP)
417251881Speter			ol = 1;
418251881Speter		else {
419251881Speter			if (hlen < 2)
420251881Speter				break;
421251881Speter			ol = (int)*(s + 1);
422251881Speter			if (ol < 2 || ol > hlen)
423251881Speter				break;
424251881Speter		}
425251881Speter		for (i = 9, mv = 4; mv >= 0; ) {
426251881Speter			op = ipopts + i;
427251881Speter			if (opt == (u_char)op->ol_val) {
428251881Speter				optmsk |= op->ol_bit;
429251881Speter				if (opt == IPOPT_SECURITY) {
430251881Speter					struct optlist *sp;
431251881Speter					u_char	sec;
432251881Speter					int j, m;
433251881Speter
434251881Speter					sec = *(s + 2);	/* classification */
435251881Speter					for (j = 3, m = 2; m >= 0; ) {
436251881Speter						sp = secopt + j;
437251881Speter						if (sec == sp->ol_val) {
438251881Speter							secmsk |= sp->ol_bit;
439251881Speter							auth = *(s + 3);
440251881Speter							auth *= 256;
441251881Speter							auth += *(s + 4);
442251881Speter							break;
443251881Speter						}
444251881Speter						if (sec < sp->ol_val)
445251881Speter							j -= m--;
446251881Speter						else
447251881Speter							j += m--;
448251881Speter					}
449251881Speter				}
450251881Speter				break;
451251881Speter			}
452251881Speter			if (opt < op->ol_val)
453251881Speter				i -= mv--;
454251881Speter			else
455251881Speter				i += mv--;
456251881Speter		}
457251881Speter		hlen -= ol;
458251881Speter		s += ol;
459251881Speter	}
460251881Speter	if (auth && !(auth & 0x0100))
461251881Speter		auth &= 0xff00;
462251881Speter	fi->fi_optmsk = optmsk;
463251881Speter	fi->fi_secmsk = secmsk;
464251881Speter	fi->fi_auth = auth;
465251881Speter}
466251881Speter
467251881Speter
468251881Speter/*
469251881Speter * check an IP packet for TCP/UDP characteristics such as ports and flags.
470251881Speter */
471251881Speterint fr_tcpudpchk(ft, fin)
472251881Speterfrtuc_t *ft;
473251881Speterfr_info_t *fin;
474251881Speter{
475251881Speter	register u_short po, tup;
476251881Speter	register char i;
477251881Speter	register int err = 1;
478251881Speter
479251881Speter	/*
480251881Speter	 * Both ports should *always* be in the first fragment.
481251881Speter	 * So far, I cannot find any cases where they can not be.
482251881Speter	 *
483251881Speter	 * compare destination ports
484251881Speter	 */
485251881Speter	if ((i = (int)ft->ftu_dcmp)) {
486251881Speter		po = ft->ftu_dport;
487251881Speter		tup = fin->fin_data[1];
488251881Speter		/*
489251881Speter		 * Do opposite test to that required and
490251881Speter		 * continue if that succeeds.
491251881Speter		 */
492251881Speter		if (!--i && tup != po) /* EQUAL */
493251881Speter			err = 0;
494251881Speter		else if (!--i && tup == po) /* NOTEQUAL */
495251881Speter			err = 0;
496251881Speter		else if (!--i && tup >= po) /* LESSTHAN */
497251881Speter			err = 0;
498251881Speter		else if (!--i && tup <= po) /* GREATERTHAN */
499251881Speter			err = 0;
500251881Speter		else if (!--i && tup > po) /* LT or EQ */
501251881Speter			err = 0;
502251881Speter		else if (!--i && tup < po) /* GT or EQ */
503251881Speter			err = 0;
504251881Speter		else if (!--i &&	   /* Out of range */
505251881Speter			 (tup >= po && tup <= ft->ftu_dtop))
506251881Speter			err = 0;
507251881Speter		else if (!--i &&	   /* In range */
508251881Speter			 (tup <= po || tup >= ft->ftu_dtop))
509251881Speter			err = 0;
510251881Speter	}
511251881Speter	/*
512251881Speter	 * compare source ports
513251881Speter	 */
514251881Speter	if (err && (i = (int)ft->ftu_scmp)) {
515251881Speter		po = ft->ftu_sport;
516251881Speter		tup = fin->fin_data[0];
517251881Speter		if (!--i && tup != po)
518251881Speter			err = 0;
519251881Speter		else if (!--i && tup == po)
520251881Speter			err = 0;
521251881Speter		else if (!--i && tup >= po)
522251881Speter			err = 0;
523251881Speter		else if (!--i && tup <= po)
524251881Speter			err = 0;
525251881Speter		else if (!--i && tup > po)
526251881Speter			err = 0;
527251881Speter		else if (!--i && tup < po)
528251881Speter			err = 0;
529251881Speter		else if (!--i &&	   /* Out of range */
530251881Speter			 (tup >= po && tup <= ft->ftu_stop))
531251881Speter			err = 0;
532251881Speter		else if (!--i &&	   /* In range */
533251881Speter			 (tup <= po || tup >= ft->ftu_stop))
534251881Speter			err = 0;
535251881Speter	}
536251881Speter
537251881Speter	/*
538251881Speter	 * If we don't have all the TCP/UDP header, then how can we
539251881Speter	 * expect to do any sort of match on it ?  If we were looking for
540251881Speter	 * TCP flags, then NO match.  If not, then match (which should
541251881Speter	 * satisfy the "short" class too).
542251881Speter	 */
543251881Speter	if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) {
544251881Speter		if (fin->fin_fl & FI_SHORT)
545251881Speter			return !(ft->ftu_tcpf | ft->ftu_tcpfm);
546251881Speter		/*
547251881Speter		 * Match the flags ?  If not, abort this match.
548251881Speter		 */
549251881Speter		if (ft->ftu_tcpfm &&
550251881Speter		    ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) {
551251881Speter			FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
552251881Speter				 ft->ftu_tcpfm, ft->ftu_tcpf));
553251881Speter			err = 0;
554251881Speter		}
555251881Speter	}
556251881Speter	return err;
557251881Speter}
558251881Speter
559251881Speter/*
560251881Speter * Check the input/output list of rules for a match and result.
561251881Speter * Could be per interface, but this gets real nasty when you don't have
562251881Speter * kernel sauce.
563251881Speter */
564251881Speterint fr_scanlist(passin, ip, fin, m)
565251881Speteru_32_t passin;
566251881Speterip_t *ip;
567251881Speterregister fr_info_t *fin;
568251881Spetervoid *m;
569251881Speter{
570251881Speter	register struct frentry *fr;
571251881Speter	register fr_ip_t *fi = &fin->fin_fi;
572251881Speter	int rulen, portcmp = 0, off, skip = 0, logged = 0;
573251881Speter	u_32_t pass, passt, passl;
574251881Speter	frentry_t *frl;
575251881Speter
576251881Speter	frl = NULL;
577251881Speter	pass = passin;
578251881Speter	fr = fin->fin_fr;
579251881Speter	fin->fin_fr = NULL;
580251881Speter	off = fin->fin_off;
581251881Speter
582251881Speter	if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
583251881Speter		portcmp = 1;
584251881Speter
585251881Speter	for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
586251881Speter		if (skip) {
587251881Speter			FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags));
588251881Speter			skip--;
589251881Speter			continue;
590251881Speter		}
591251881Speter		/*
592251881Speter		 * In all checks below, a null (zero) value in the
593251881Speter		 * filter struture is taken to mean a wildcard.
594251881Speter		 *
595251881Speter		 * check that we are working for the right interface
596251881Speter		 */
597251881Speter#ifdef	_KERNEL
598251881Speter# if	(BSD >= 199306)
599251881Speter		if (fin->fin_out != 0) {
600251881Speter			if ((fr->fr_oifa &&
601251881Speter			     (fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif)))
602251881Speter				continue;
603251881Speter		}
604251881Speter# endif
605251881Speter#else
606251881Speter		if (opts & (OPT_VERBOSE|OPT_DEBUG))
607251881Speter			printf("\n");
608251881Speter#endif
609251881Speter
610251881Speter		FR_VERBOSE(("%c", fr->fr_skip ? 's' :
611251881Speter				  (pass & FR_PASS) ? 'p' :
612251881Speter				  (pass & FR_AUTH) ? 'a' :
613251881Speter				  (pass & FR_ACCOUNT) ? 'A' :
614251881Speter				  (pass & FR_NOMATCH) ? 'n' : 'b'));
615251881Speter
616251881Speter		if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
617251881Speter			continue;
618251881Speter
619251881Speter		FR_VERBOSE((":i"));
620251881Speter		{
621251881Speter			register u_32_t	*ld, *lm, *lip;
622251881Speter			register int i;
623251881Speter
624251881Speter			lip = (u_32_t *)fi;
625251881Speter			lm = (u_32_t *)&fr->fr_mip;
626251881Speter			ld = (u_32_t *)&fr->fr_ip;
627251881Speter			i = ((*lip & *lm) != *ld);
628251881Speter			FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
629251881Speter				   *lip, *lm, *ld));
630251881Speter			if (i)
631251881Speter				continue;
632251881Speter			/*
633251881Speter			 * We now know whether the packet version and the
634251881Speter			 * rule version match, along with protocol, ttl and
635251881Speter			 * tos.
636251881Speter			 */
637251881Speter			lip++, lm++, ld++;
638251881Speter			/*
639251881Speter			 * Unrolled loops (4 each, for 32 bits).
640251881Speter			 */
641251881Speter			FR_DEBUG(("1a. %#08x & %#08x != %#08x\n",
642251881Speter				   *lip, *lm, *ld));
643251881Speter			i |= ((*lip++ & *lm++) != *ld++) << 5;
644251881Speter			if (fi->fi_v == 6) {
645251881Speter				FR_DEBUG(("1b. %#08x & %#08x != %#08x\n",
646251881Speter					   *lip, *lm, *ld));
647251881Speter				i |= ((*lip++ & *lm++) != *ld++) << 5;
648251881Speter				FR_DEBUG(("1c. %#08x & %#08x != %#08x\n",
649251881Speter					   *lip, *lm, *ld));
650251881Speter				i |= ((*lip++ & *lm++) != *ld++) << 5;
651251881Speter				FR_DEBUG(("1d. %#08x & %#08x != %#08x\n",
652251881Speter					   *lip, *lm, *ld));
653251881Speter				i |= ((*lip++ & *lm++) != *ld++) << 5;
654251881Speter			} else {
655251881Speter				lip += 3;
656251881Speter				lm += 3;
657251881Speter				ld += 3;
658251881Speter			}
659251881Speter			i ^= (fr->fr_flags & FR_NOTSRCIP);
660251881Speter			if (i)
661251881Speter				continue;
662251881Speter			FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
663251881Speter				   *lip, *lm, *ld));
664251881Speter			i |= ((*lip++ & *lm++) != *ld++) << 6;
665251881Speter			if (fi->fi_v == 6) {
666251881Speter				FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
667251881Speter					   *lip, *lm, *ld));
668251881Speter				i |= ((*lip++ & *lm++) != *ld++) << 6;
669251881Speter				FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
670251881Speter					   *lip, *lm, *ld));
671251881Speter				i |= ((*lip++ & *lm++) != *ld++) << 6;
672251881Speter				FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
673251881Speter					   *lip, *lm, *ld));
674251881Speter				i |= ((*lip++ & *lm++) != *ld++) << 6;
675251881Speter			} else {
676251881Speter				lip += 3;
677251881Speter				lm += 3;
678251881Speter				ld += 3;
679251881Speter			}
680251881Speter			i ^= (fr->fr_flags & FR_NOTDSTIP);
681251881Speter			if (i)
682251881Speter				continue;
683251881Speter			FR_DEBUG(("3. %#08x & %#08x != %#08x\n",
684251881Speter				   *lip, *lm, *ld));
685251881Speter			i |= ((*lip++ & *lm++) != *ld++);
686251881Speter			FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
687251881Speter				   *lip, *lm, *ld));
688251881Speter			i |= ((*lip & *lm) != *ld);
689251881Speter			if (i)
690251881Speter				continue;
691251881Speter		}
692251881Speter
693251881Speter		/*
694251881Speter		 * If a fragment, then only the first has what we're looking
695251881Speter		 * for here...
696251881Speter		 */
697251881Speter		if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
698251881Speter				 fr->fr_tcpfm))
699251881Speter			continue;
700251881Speter		if (fi->fi_fl & FI_TCPUDP) {
701251881Speter			if (!fr_tcpudpchk(&fr->fr_tuc, fin))
702251881Speter				continue;
703251881Speter		} else if (fr->fr_icmpm || fr->fr_icmp) {
704251881Speter			if (((fi->fi_p != IPPROTO_ICMP) &&
705251881Speter			    (fi->fi_p != IPPROTO_ICMPV6)) || off ||
706251881Speter			    (fin->fin_dlen < 2))
707251881Speter				continue;
708251881Speter			if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) {
709251881Speter				FR_DEBUG(("i. %#x & %#x != %#x\n",
710251881Speter					 fin->fin_data[0], fr->fr_icmpm,
711251881Speter					 fr->fr_icmp));
712251881Speter				continue;
713251881Speter			}
714251881Speter		}
715251881Speter		FR_VERBOSE(("*"));
716251881Speter
717251881Speter		if (fr->fr_flags & FR_NOMATCH) {
718251881Speter			passt = passl;
719251881Speter			passl = passin;
720251881Speter			fin->fin_fr = frl;
721251881Speter			frl = NULL;
722251881Speter			if (fr->fr_flags & FR_QUICK)
723251881Speter				break;
724251881Speter			continue;
725251881Speter		}
726251881Speter
727251881Speter		passl = passt;
728251881Speter		passt = fr->fr_flags;
729251881Speter		frl = fin->fin_fr;
730251881Speter		fin->fin_fr = fr;
731251881Speter#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL))
732251881Speter		if (securelevel <= 0)
733251881Speter#endif
734251881Speter			if ((passt & FR_CALLNOW) && fr->fr_func)
735251881Speter				passt = (*fr->fr_func)(passt, ip, fin);
736251881Speter#ifdef  IPFILTER_LOG
737251881Speter		/*
738251881Speter		 * Just log this packet...
739251881Speter		 */
740251881Speter		if ((passt & FR_LOGMASK) == FR_LOG) {
741251881Speter			if (!IPLLOG(passt, ip, fin, m)) {
742251881Speter				if (passt & FR_LOGORBLOCK)
743251881Speter					passt |= FR_BLOCK|FR_QUICK;
744251881Speter				ATOMIC_INCL(frstats[fin->fin_out].fr_skip);
745251881Speter			}
746251881Speter			ATOMIC_INCL(frstats[fin->fin_out].fr_pkl);
747251881Speter			logged = 1;
748251881Speter		}
749251881Speter#endif /* IPFILTER_LOG */
750251881Speter		ATOMIC_INCL(fr->fr_hits);
751251881Speter		if (passt & FR_ACCOUNT)
752251881Speter			fr->fr_bytes += (U_QUAD_T)ip->ip_len;
753251881Speter		else
754251881Speter			fin->fin_icode = fr->fr_icode;
755251881Speter		fin->fin_rule = rulen;
756251881Speter		fin->fin_group = fr->fr_group;
757251881Speter		if (fr->fr_grp != NULL) {
758251881Speter			fin->fin_fr = fr->fr_grp;
759251881Speter			passt = fr_scanlist(passt, ip, fin, m);
760251881Speter			if (fin->fin_fr == NULL) {
761251881Speter				fin->fin_rule = rulen;
762251881Speter				fin->fin_group = fr->fr_group;
763251881Speter				fin->fin_fr = fr;
764251881Speter			}
765251881Speter			if (passt & FR_DONTCACHE)
766251881Speter				logged = 1;
767251881Speter		}
768251881Speter		if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG)
769251881Speter			pass = passt;
770251881Speter		FR_DEBUG(("pass %#x\n", pass));
771251881Speter		if (passt & FR_QUICK)
772251881Speter			break;
773251881Speter	}
774251881Speter	if (logged)
775251881Speter		pass |= FR_DONTCACHE;
776251881Speter	pass |= (fi->fi_fl << 24);
777251881Speter	return pass;
778251881Speter}
779251881Speter
780251881Speter
781251881Speter/*
782251881Speter * frcheck - filter check
783251881Speter * check using source and destination addresses/ports in a packet whether
784251881Speter * or not to pass it on or not.
785251881Speter */
786251881Speterint fr_check(ip, hlen, ifp, out
787251881Speter#if defined(_KERNEL) && SOLARIS
788251881Speter, qif, mp)
789251881Speterqif_t *qif;
790251881Speter#else
791251881Speter, mp)
792251881Speter#endif
793251881Spetermb_t **mp;
794251881Speterip_t *ip;
795251881Speterint hlen;
796251881Spetervoid *ifp;
797251881Speterint out;
798251881Speter{
799251881Speter	/*
800251881Speter	 * The above really sucks, but short of writing a diff
801251881Speter	 */
802251881Speter	fr_info_t frinfo, *fc;
803251881Speter	register fr_info_t *fin = &frinfo;
804251881Speter	int changed, error = EHOSTUNREACH, v = ip->ip_v;
805251881Speter	frentry_t *fr = NULL, *list;
806251881Speter	u_32_t pass, apass;
807251881Speter#if !SOLARIS || !defined(_KERNEL)
808251881Speter	register mb_t *m = *mp;
809251881Speter#endif
810251881Speter
811251881Speter#ifdef	_KERNEL
812251881Speter	int p, len, drop = 0, logit = 0;
813251881Speter	mb_t *mc = NULL;
814251881Speter# if !defined(__SVR4) && !defined(__svr4__)
815251881Speter#  ifdef __sgi
816251881Speter	char hbuf[128];
817251881Speter#  endif
818251881Speter	int up;
819251881Speter
820251881Speter#  if !SOLARIS && !defined(NETBSD_PF) && \
821251881Speter      ((defined(__FreeBSD__) && (__FreeBSD_version < 500011)) || \
822251881Speter       defined(__OpenBSD__) || defined(_BSDI_VERSION))
823251881Speter	if (fr_checkp != fr_check && fr_running > 0) {
824251881Speter		static int counter = 0;
825251881Speter
826251881Speter		if (counter == 0) {
827251881Speter			printf("WARNING: fr_checkp corrupt: value %lx\n",
828251881Speter				(u_long)fr_checkp);
829251881Speter			printf("WARNING: fr_checkp should be %lx\n",
830251881Speter				(u_long)fr_check);
831251881Speter			printf("WARNING: fixing fr_checkp\n");
832251881Speter		}
833251881Speter		fr_checkp = fr_check;
834251881Speter		counter++;
835251881Speter		if (counter == 10000)
836251881Speter			counter = 0;
837251881Speter	}
838251881Speter#  endif
839251881Speter
840251881Speter#  ifdef M_CANFASTFWD
841251881Speter	/*
842251881Speter	 * XXX For now, IP Filter and fast-forwarding of cached flows
843251881Speter	 * XXX are mutually exclusive.  Eventually, IP Filter should
844251881Speter	 * XXX get a "can-fast-forward" filter rule.
845251881Speter	 */
846251881Speter	m->m_flags &= ~M_CANFASTFWD;
847251881Speter#  endif /* M_CANFASTFWD */
848251881Speter#  ifdef CSUM_DELAY_DATA
849251881Speter	/*
850251881Speter	 * disable delayed checksums.
851251881Speter	 */
852251881Speter	if ((out != 0) && (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)) {
853251881Speter		in_delayed_cksum(m);
854251881Speter		m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
855251881Speter	}
856251881Speter#  endif /* CSUM_DELAY_DATA */
857251881Speter
858251881Speter# ifdef	USE_INET6
859251881Speter	if (v == 6) {
860251881Speter		len = ntohs(((ip6_t*)ip)->ip6_plen);
861251881Speter		if (!len)
862251881Speter			return -1;	/* potential jumbo gram */
863251881Speter		len += sizeof(ip6_t);
864251881Speter		p = ((ip6_t *)ip)->ip6_nxt;
865251881Speter	} else
866251881Speter# endif
867251881Speter	{
868251881Speter		p = ip->ip_p;
869251881Speter		len = ip->ip_len;
870251881Speter	}
871251881Speter
872251881Speter	if ((p == IPPROTO_TCP || p == IPPROTO_UDP ||
873251881Speter	    (v == 4 && p == IPPROTO_ICMP)
874251881Speter# ifdef USE_INET6
875251881Speter	    || (v == 6 && p == IPPROTO_ICMPV6)
876251881Speter# endif
877251881Speter	   )) {
878251881Speter		int plen = 0;
879251881Speter
880251881Speter		if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0)
881251881Speter			switch(p)
882251881Speter			{
883251881Speter			case IPPROTO_TCP:
884251881Speter				plen = sizeof(tcphdr_t);
885251881Speter				break;
886251881Speter			case IPPROTO_UDP:
887251881Speter				plen = sizeof(udphdr_t);
888251881Speter				break;
889251881Speter			/* 96 - enough for complete ICMP error IP header */
890251881Speter			case IPPROTO_ICMP:
891251881Speter				plen = ICMPERR_MAXPKTLEN - sizeof(ip_t);
892251881Speter				break;
893251881Speter			case IPPROTO_ESP:
894251881Speter				plen = 8;
895251881Speter				break;
896251881Speter# ifdef USE_INET6
897251881Speter	    		case IPPROTO_ICMPV6 :
898251881Speter				/*
899251881Speter				 * XXX does not take intermediate header
900251881Speter				 * into account
901251881Speter				 */
902251881Speter				plen = ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t);
903251881Speter				break;
904251881Speter# endif
905251881Speter			}
906251881Speter		up = MIN(hlen + plen, len);
907251881Speter
908251881Speter		if (up > m->m_len) {
909251881Speter#  ifdef __sgi
910251881Speter	/* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */
911251881Speter			if ((up > sizeof(hbuf)) || (m_length(m) < up)) {
912251881Speter				ATOMIC_INCL(frstats[out].fr_pull[1]);
913251881Speter				return -1;
914251881Speter			}
915251881Speter			m_copydata(m, 0, up, hbuf);
916251881Speter			ATOMIC_INCL(frstats[out].fr_pull[0]);
917251881Speter			ip = (ip_t *)hbuf;
918251881Speter#  else /* __ sgi */
919251881Speter#   ifndef linux
920251881Speter			if ((*mp = m_pullup(m, up)) == 0) {
921251881Speter				ATOMIC_INCL(frstats[out].fr_pull[1]);
922251881Speter				return -1;
923251881Speter			} else {
924251881Speter				ATOMIC_INCL(frstats[out].fr_pull[0]);
925251881Speter				m = *mp;
926251881Speter				ip = mtod(m, ip_t *);
927251881Speter			}
928251881Speter#   endif /* !linux */
929251881Speter#  endif /* __sgi */
930251881Speter		} else
931251881Speter			up = 0;
932251881Speter	} else
933251881Speter		up = 0;
934251881Speter# endif /* !defined(__SVR4) && !defined(__svr4__) */
935251881Speter# if SOLARIS
936251881Speter	mb_t *m = qif->qf_m;
937251881Speter
938251881Speter	if ((u_int)ip & 0x3)
939251881Speter		return 2;
940251881Speter	fin->fin_qfm = m;
941251881Speter	fin->fin_qif = qif;
942251881Speter# endif
943251881Speter#endif /* _KERNEL */
944251881Speter
945251881Speter#ifndef __FreeBSD__
946251881Speter	/*
947251881Speter	 * Be careful here: ip_id is in network byte order when called
948251881Speter	 * from ip_output()
949251881Speter	 */
950251881Speter	if ((out) && (v == 4))
951251881Speter		ip->ip_id = ntohs(ip->ip_id);
952251881Speter#endif
953251881Speter
954251881Speter	changed = 0;
955251881Speter	fin->fin_ifp = ifp;
956251881Speter	fin->fin_v = v;
957251881Speter	fin->fin_out = out;
958251881Speter	fin->fin_mp = mp;
959251881Speter	fr_makefrip(hlen, ip, fin);
960251881Speter
961251881Speter#ifdef _KERNEL
962251881Speter# ifdef	USE_INET6
963251881Speter	if (v == 6) {
964251881Speter		ATOMIC_INCL(frstats[0].fr_ipv6[out]);
965251881Speter		if (((ip6_t *)ip)->ip6_hlim < fr_minttl) {
966251881Speter			ATOMIC_INCL(frstats[0].fr_badttl);
967251881Speter			if (fr_minttllog & 1)
968251881Speter				logit = -3;
969251881Speter			if (fr_minttllog & 2)
970251881Speter				drop = 1;
971251881Speter		}
972251881Speter	} else
973251881Speter# endif
974251881Speter	if (!out) {
975251881Speter		if (fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) {
976251881Speter			ATOMIC_INCL(frstats[0].fr_badsrc);
977251881Speter			if (fr_chksrc & 1)
978251881Speter				drop = 1;
979251881Speter			if (fr_chksrc & 2)
980251881Speter				logit = -2;
981251881Speter		} else if (ip->ip_ttl < fr_minttl) {
982251881Speter			ATOMIC_INCL(frstats[0].fr_badttl);
983251881Speter			if (fr_minttllog & 1)
984251881Speter				logit = -3;
985251881Speter			if (fr_minttllog & 2)
986251881Speter				drop = 1;
987251881Speter		}
988251881Speter	}
989251881Speter	if (drop) {
990251881Speter# ifdef	IPFILTER_LOG
991251881Speter		if (logit) {
992251881Speter			fin->fin_group = logit;
993251881Speter			pass = FR_INQUE|FR_NOMATCH|FR_LOGB;
994251881Speter			(void) IPLLOG(pass, ip, fin, m);
995251881Speter		}
996251881Speter# endif
997251881Speter# if !SOLARIS
998251881Speter		m_freem(m);
999251881Speter# endif
1000251881Speter		return error;
1001251881Speter	}
1002251881Speter#endif
1003251881Speter	pass = fr_pass;
1004251881Speter	if (fin->fin_fl & FI_SHORT) {
1005251881Speter		ATOMIC_INCL(frstats[out].fr_short);
1006251881Speter	}
1007251881Speter
1008251881Speter	READ_ENTER(&ipf_mutex);
1009251881Speter
1010251881Speter	/*
1011251881Speter	 * Check auth now.  This, combined with the check below to see if apass
1012251881Speter	 * is 0 is to ensure that we don't count the packet twice, which can
1013251881Speter	 * otherwise occur when we reprocess it.  As it is, we only count it
1014251881Speter	 * after it has no auth. table matchup.  This also stops NAT from
1015251881Speter	 * occuring until after the packet has been auth'd.
1016251881Speter	 */
1017251881Speter	apass = fr_checkauth(ip, fin);
1018251881Speter
1019251881Speter	if (!out) {
1020251881Speter#ifdef	USE_INET6
1021251881Speter		if (v == 6)
1022251881Speter			list = ipacct6[0][fr_active];
1023251881Speter		else
1024251881Speter#endif
1025251881Speter			list = ipacct[0][fr_active];
1026251881Speter		changed = ip_natin(ip, fin);
1027251881Speter		if (!apass && (fin->fin_fr = list) &&
1028251881Speter		    (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
1029251881Speter			ATOMIC_INCL(frstats[0].fr_acct);
1030251881Speter		}
1031251881Speter	}
1032251881Speter
1033251881Speter	if (!apass) {
1034251881Speter		if ((fin->fin_fl & FI_FRAG) == FI_FRAG)
1035251881Speter			fr = ipfr_knownfrag(ip, fin);
1036251881Speter		if (!fr && !(fin->fin_fl & FI_SHORT))
1037251881Speter			fr = fr_checkstate(ip, fin);
1038251881Speter		if (fr != NULL)
1039251881Speter			pass = fr->fr_flags;
1040251881Speter		if (fr && (pass & FR_LOGFIRST))
1041251881Speter			pass &= ~(FR_LOGFIRST|FR_LOG);
1042251881Speter	}
1043251881Speter
1044251881Speter	if (apass || !fr) {
1045251881Speter		/*
1046251881Speter		 * If a packet is found in the auth table, then skip checking
1047251881Speter		 * the access lists for permission but we do need to consider
1048251881Speter		 * the result as if it were from the ACL's.
1049251881Speter		 */
1050251881Speter		if (!apass) {
1051251881Speter			fc = frcache + out;
1052251881Speter			if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
1053251881Speter				/*
1054251881Speter				 * copy cached data so we can unlock the mutex
1055251881Speter				 * earlier.
1056251881Speter				 */
1057251881Speter				bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
1058251881Speter				ATOMIC_INCL(frstats[out].fr_chit);
1059251881Speter				if ((fr = fin->fin_fr)) {
1060251881Speter					ATOMIC_INCL(fr->fr_hits);
1061251881Speter					pass = fr->fr_flags;
1062251881Speter				}
1063251881Speter			} else {
1064251881Speter#ifdef	USE_INET6
1065251881Speter				if (v == 6)
1066251881Speter					list = ipfilter6[out][fr_active];
1067251881Speter				else
1068251881Speter#endif
1069251881Speter					list = ipfilter[out][fr_active];
1070251881Speter				if ((fin->fin_fr = list))
1071251881Speter					pass = fr_scanlist(fr_pass, ip, fin, m);
1072251881Speter				if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE)))
1073251881Speter					bcopy((char *)fin, (char *)fc,
1074251881Speter					      FI_COPYSIZE);
1075251881Speter				if (pass & FR_NOMATCH) {
1076251881Speter					ATOMIC_INCL(frstats[out].fr_nom);
1077251881Speter					fin->fin_fr = NULL;
1078251881Speter				}
1079251881Speter			}
1080251881Speter		} else
1081251881Speter			pass = apass;
1082251881Speter		fr = fin->fin_fr;
1083251881Speter
1084251881Speter		/*
1085251881Speter		 * If we fail to add a packet to the authorization queue,
1086251881Speter		 * then we drop the packet later.  However, if it was added
1087251881Speter		 * then pretend we've dropped it already.
1088251881Speter		 */
1089251881Speter		if ((pass & FR_AUTH)) {
1090251881Speter			if (fr_newauth((mb_t *)m, fin, ip) != 0) {
1091251881Speter				m = *mp = NULL;
1092251881Speter				error = 0;
1093251881Speter			} else
1094251881Speter				error = ENOSPC;
1095251881Speter		}
1096251881Speter
1097251881Speter		if (pass & FR_PREAUTH) {
1098251881Speter			READ_ENTER(&ipf_auth);
1099251881Speter			if ((fin->fin_fr = ipauth) &&
1100251881Speter			    (pass = fr_scanlist(0, ip, fin, m))) {
1101251881Speter				ATOMIC_INCL(fr_authstats.fas_hits);
1102251881Speter			} else {
1103251881Speter				ATOMIC_INCL(fr_authstats.fas_miss);
1104251881Speter			}
1105251881Speter			RWLOCK_EXIT(&ipf_auth);
1106251881Speter		}
1107251881Speter
1108251881Speter		fin->fin_fr = fr;
1109251881Speter		if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
1110251881Speter			if (fin->fin_fl & FI_FRAG) {
1111251881Speter				if (ipfr_newfrag(ip, fin) == -1) {
1112251881Speter					ATOMIC_INCL(frstats[out].fr_bnfr);
1113251881Speter				} else {
1114251881Speter					ATOMIC_INCL(frstats[out].fr_nfr);
1115251881Speter				}
1116251881Speter			} else {
1117251881Speter				ATOMIC_INCL(frstats[out].fr_cfr);
1118251881Speter			}
1119251881Speter		}
1120251881Speter		if (pass & FR_KEEPSTATE) {
1121251881Speter			if (fr_addstate(ip, fin, NULL, 0) == NULL) {
1122251881Speter				ATOMIC_INCL(frstats[out].fr_bads);
1123251881Speter			} else {
1124251881Speter				ATOMIC_INCL(frstats[out].fr_ads);
1125251881Speter			}
1126251881Speter		}
1127251881Speter	} else if (fr != NULL) {
1128251881Speter		pass = fr->fr_flags;
1129251881Speter		if (pass & FR_LOGFIRST)
1130251881Speter			pass &= ~(FR_LOGFIRST|FR_LOG);
1131251881Speter	}
1132251881Speter
1133251881Speter#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL))
1134251881Speter	if (securelevel <= 0)
1135251881Speter#endif
1136251881Speter		if (fr && fr->fr_func && !(pass & FR_CALLNOW))
1137251881Speter			pass = (*fr->fr_func)(pass, ip, fin);
1138251881Speter
1139251881Speter	/*
1140251881Speter	 * Only count/translate packets which will be passed on, out the
1141251881Speter	 * interface.
1142251881Speter	 */
1143251881Speter	if (out && (pass & FR_PASS)) {
1144251881Speter#ifdef	USE_INET6
1145251881Speter		if (v == 6)
1146251881Speter			list = ipacct6[1][fr_active];
1147251881Speter		else
1148251881Speter#endif
1149251881Speter			list = ipacct[1][fr_active];
1150251881Speter		if (list != NULL) {
1151251881Speter			u_32_t sg, sr;
1152251881Speter
1153251881Speter			fin->fin_fr = list;
1154251881Speter			sg = fin->fin_group;
1155251881Speter			sr = fin->fin_rule;
1156251881Speter			if (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT) {
1157251881Speter				ATOMIC_INCL(frstats[1].fr_acct);
1158251881Speter			}
1159251881Speter			fin->fin_group = sg;
1160251881Speter			fin->fin_rule = sr;
1161251881Speter			fin->fin_fr = fr;
1162251881Speter		}
1163251881Speter		changed = ip_natout(ip, fin);
1164251881Speter	} else
1165251881Speter		fin->fin_fr = fr;
1166251881Speter	RWLOCK_EXIT(&ipf_mutex);
1167251881Speter
1168251881Speter#ifdef	IPFILTER_LOG
1169251881Speter	if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
1170251881Speter		if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
1171251881Speter			pass |= FF_LOGNOMATCH;
1172251881Speter			ATOMIC_INCL(frstats[out].fr_npkl);
1173251881Speter			goto logit;
1174251881Speter		} else if (((pass & FR_LOGMASK) == FR_LOGP) ||
1175251881Speter		    ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
1176251881Speter			if ((pass & FR_LOGMASK) != FR_LOGP)
1177251881Speter				pass |= FF_LOGPASS;
1178251881Speter			ATOMIC_INCL(frstats[out].fr_ppkl);
1179251881Speter			goto logit;
1180251881Speter		} else if (((pass & FR_LOGMASK) == FR_LOGB) ||
1181251881Speter			   ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
1182251881Speter			if ((pass & FR_LOGMASK) != FR_LOGB)
1183251881Speter				pass |= FF_LOGBLOCK;
1184251881Speter			ATOMIC_INCL(frstats[out].fr_bpkl);
1185251881Speterlogit:
1186251881Speter			if (!IPLLOG(pass, ip, fin, m)) {
1187251881Speter				ATOMIC_INCL(frstats[out].fr_skip);
1188251881Speter				if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
1189251881Speter				    (FR_PASS|FR_LOGORBLOCK))
1190251881Speter					pass ^= FR_PASS|FR_BLOCK;
1191251881Speter			}
1192251881Speter		}
1193251881Speter	}
1194251881Speter#endif /* IPFILTER_LOG */
1195251881Speter
1196251881Speter#ifndef __FreeBSD__
1197251881Speter	if ((out) && (v == 4))
1198251881Speter		ip->ip_id = htons(ip->ip_id);
1199251881Speter#endif
1200251881Speter
1201251881Speter#ifdef	_KERNEL
1202251881Speter	/*
1203251881Speter	 * Only allow FR_DUP to work if a rule matched - it makes no sense to
1204251881Speter	 * set FR_DUP as a "default" as there are no instructions about where
1205251881Speter	 * to send the packet.
1206251881Speter	 */
1207251881Speter	if (fr && (pass & FR_DUP))
1208251881Speter# if	SOLARIS
1209251881Speter		mc = dupmsg(m);
1210251881Speter# else
1211251881Speter#  if defined(__OpenBSD__) && (OpenBSD >= 199905)
1212251881Speter		mc = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
1213251881Speter#  else
1214251881Speter		mc = m_copy(m, 0, M_COPYALL);
1215251881Speter#  endif
1216251881Speter# endif
1217251881Speter#endif
1218251881Speter	if (pass & FR_PASS) {
1219251881Speter		ATOMIC_INCL(frstats[out].fr_pass);
1220251881Speter	} else if (pass & FR_BLOCK) {
1221251881Speter		ATOMIC_INCL(frstats[out].fr_block);
1222251881Speter		/*
1223251881Speter		 * Should we return an ICMP packet to indicate error
1224251881Speter		 * status passing through the packet filter ?
1225251881Speter		 * WARNING: ICMP error packets AND TCP RST packets should
1226251881Speter		 * ONLY be sent in repsonse to incoming packets.  Sending them
1227251881Speter		 * in response to outbound packets can result in a panic on
1228251881Speter		 * some operating systems.
1229251881Speter		 */
1230251881Speter		if (!out) {
1231251881Speter			if (changed == -1)
1232251881Speter				/*
1233251881Speter				 * If a packet results in a NAT error, do not
1234251881Speter				 * send a reset or ICMP error as it may disrupt
1235251881Speter				 * an existing flow.  This is the proxy saying
1236251881Speter				 * the content is bad so just drop the packet
1237251881Speter				 * silently.
1238251881Speter				 */
1239251881Speter				;
1240251881Speter			else if (pass & FR_RETICMP) {
1241251881Speter				int dst;
1242251881Speter
1243251881Speter				if ((pass & FR_RETMASK) == FR_FAKEICMP)
1244251881Speter					dst = 1;
1245251881Speter				else
1246251881Speter					dst = 0;
1247251881Speter				send_icmp_err(ip, ICMP_UNREACH, fin, dst);
1248251881Speter				ATOMIC_INCL(frstats[0].fr_ret);
1249251881Speter			} else if (((pass & FR_RETMASK) == FR_RETRST) &&
1250251881Speter				   !(fin->fin_fl & FI_SHORT)) {
1251251881Speter				if (send_reset(ip, fin) == 0) {
1252251881Speter					ATOMIC_INCL(frstats[1].fr_ret);
1253251881Speter				}
1254251881Speter			}
1255251881Speter		} else {
1256251881Speter			if (pass & FR_RETRST)
1257251881Speter				error = ECONNRESET;
1258251881Speter		}
1259251881Speter	}
1260251881Speter
1261251881Speter	/*
1262251881Speter	 * If we didn't drop off the bottom of the list of rules (and thus
1263251881Speter	 * the 'current' rule fr is not NULL), then we may have some extra
1264251881Speter	 * instructions about what to do with a packet.
1265251881Speter	 * Once we're finished return to our caller, freeing the packet if
1266251881Speter	 * we are dropping it (* BSD ONLY *).
1267251881Speter	 */
1268251881Speter	if ((changed == -1) && (pass & FR_PASS)) {
1269251881Speter		pass &= ~FR_PASS;
1270251881Speter		pass |= FR_BLOCK;
1271251881Speter	}
1272251881Speter#if defined(_KERNEL)
1273251881Speter# if !SOLARIS
1274251881Speter#  if !defined(linux)
1275251881Speter	if (fr) {
1276251881Speter		frdest_t *fdp = &fr->fr_tif;
1277251881Speter
1278251881Speter		if (((pass & FR_FASTROUTE) && !out) ||
1279251881Speter		    (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
1280251881Speter			(void) ipfr_fastroute(m, mp, fin, fdp);
1281251881Speter			m = *mp;
1282251881Speter		}
1283251881Speter
1284251881Speter		if (mc != NULL)
1285251881Speter			(void) ipfr_fastroute(mc, &mc, fin, &fr->fr_dif);
1286251881Speter	}
1287251881Speter
1288251881Speter	if (!(pass & FR_PASS) && m) {
1289251881Speter		m_freem(m);
1290251881Speter		m = *mp = NULL;
1291251881Speter	}
1292251881Speter#   ifdef __sgi
1293251881Speter	else if (changed && up && m)
1294251881Speter		m_copyback(m, 0, up, hbuf);
1295251881Speter#   endif
1296251881Speter#  endif /* !linux */
1297251881Speter# else /* !SOLARIS */
1298251881Speter	if (fr) {
1299251881Speter		frdest_t *fdp = &fr->fr_tif;
1300251881Speter
1301251881Speter		if (((pass & FR_FASTROUTE) && !out) ||
1302251881Speter		    (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1))
1303251881Speter			(void) ipfr_fastroute(ip, m, mp, fin, fdp);
1304251881Speter
1305251881Speter		if (mc != NULL)
1306251881Speter			(void) ipfr_fastroute(ip, mc, &mc, fin, &fr->fr_dif);
1307251881Speter	}
1308251881Speter# endif /* !SOLARIS */
1309251881Speter	return (pass & FR_PASS) ? 0 : error;
1310251881Speter#else /* _KERNEL */
1311251881Speter	if (pass & FR_NOMATCH)
1312251881Speter		return 1;
1313251881Speter	if (pass & FR_PASS)
1314251881Speter		return 0;
1315251881Speter	if (pass & FR_AUTH)
1316251881Speter		return -2;
1317251881Speter	if ((pass & FR_RETMASK) == FR_RETRST)
1318251881Speter		return -3;
1319251881Speter	if ((pass & FR_RETMASK) == FR_RETICMP)
1320251881Speter		return -4;
1321251881Speter	if ((pass & FR_RETMASK) == FR_FAKEICMP)
1322251881Speter		return -5;
1323251881Speter	return -1;
1324251881Speter#endif /* _KERNEL */
1325251881Speter}
1326251881Speter
1327251881Speter
1328251881Speter/*
1329251881Speter * ipf_cksum
1330251881Speter * addr should be 16bit aligned and len is in bytes.
1331251881Speter * length is in bytes
1332251881Speter */
1333251881Speteru_short ipf_cksum(addr, len)
1334251881Speterregister u_short *addr;
1335251881Speterregister int len;
1336251881Speter{
1337251881Speter	register u_32_t sum = 0;
1338251881Speter
1339251881Speter	for (sum = 0; len > 1; len -= 2)
1340251881Speter		sum += *addr++;
1341251881Speter
1342251881Speter	/* mop up an odd byte, if necessary */
1343251881Speter	if (len == 1)
1344251881Speter		sum += *(u_char *)addr;
1345251881Speter
1346251881Speter	/*
1347251881Speter	 * add back carry outs from top 16 bits to low 16 bits
1348251881Speter	 */
1349251881Speter	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
1350251881Speter	sum += (sum >> 16);			/* add carry */
1351251881Speter	return (u_short)(~sum);
1352251881Speter}
1353251881Speter
1354251881Speter
1355251881Speter/*
1356251881Speter * NB: This function assumes we've pullup'd enough for all of the IP header
1357251881Speter * and the TCP header.  We also assume that data blocks aren't allocated in
1358251881Speter * odd sizes.
1359251881Speter */
1360251881Speteru_short fr_tcpsum(m, ip, tcp)
1361251881Spetermb_t *m;
1362251881Speterip_t *ip;
1363251881Spetertcphdr_t *tcp;
1364251881Speter{
1365251881Speter	u_short *sp, slen, ts;
1366251881Speter	u_int sum, sum2;
1367251881Speter	int hlen;
1368251881Speter
1369251881Speter	/*
1370251881Speter	 * Add up IP Header portion
1371251881Speter	 */
1372251881Speter	hlen = ip->ip_hl << 2;
1373251881Speter	slen = ip->ip_len - hlen;
1374251881Speter	sum = htons((u_short)ip->ip_p);
1375251881Speter	sum += htons(slen);
1376251881Speter	sp = (u_short *)&ip->ip_src;
1377251881Speter	sum += *sp++;	/* ip_src */
1378251881Speter	sum += *sp++;
1379251881Speter	sum += *sp++;	/* ip_dst */
1380251881Speter	sum += *sp++;
1381251881Speter	ts = tcp->th_sum;
1382251881Speter	tcp->th_sum = 0;
1383251881Speter#ifdef	KERNEL
1384251881Speter# if SOLARIS
1385251881Speter	sum2 = ip_cksum(m, hlen, sum);	/* hlen == offset */
1386251881Speter	sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1387251881Speter	sum2 = ~sum2 & 0xffff;
1388251881Speter# else /* SOLARIS */
1389251881Speter#  if defined(BSD) || defined(sun)
1390251881Speter#   if BSD >= 199306
1391251881Speter	m->m_data += hlen;
1392251881Speter#   else
1393251881Speter	m->m_off += hlen;
1394251881Speter#   endif
1395251881Speter	m->m_len -= hlen;
1396251881Speter	sum2 = in_cksum(m, slen);
1397251881Speter	m->m_len += hlen;
1398251881Speter#   if BSD >= 199306
1399251881Speter	m->m_data -= hlen;
1400251881Speter#   else
1401251881Speter	m->m_off -= hlen;
1402251881Speter#   endif
1403251881Speter	/*
1404251881Speter	 * Both sum and sum2 are partial sums, so combine them together.
1405251881Speter	 */
1406251881Speter	sum = (sum & 0xffff) + (sum >> 16);
1407251881Speter	sum = ~sum & 0xffff;
1408251881Speter	sum2 += sum;
1409251881Speter	sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1410251881Speter#  else /* defined(BSD) || defined(sun) */
1411251881Speter{
1412251881Speter	union {
1413251881Speter		u_char	c[2];
1414251881Speter		u_short	s;
1415251881Speter	} bytes;
1416251881Speter	u_short len = ip->ip_len;
1417251881Speter# if defined(__sgi)
1418251881Speter	int add;
1419251881Speter# endif
1420251881Speter
1421251881Speter	/*
1422251881Speter	 * Add up IP Header portion
1423251881Speter	 */
1424251881Speter	sp = (u_short *)&ip->ip_src;
1425251881Speter	len -= (ip->ip_hl << 2);
1426251881Speter	sum = ntohs(IPPROTO_TCP);
1427251881Speter	sum += htons(len);
1428251881Speter	sum += *sp++;	/* ip_src */
1429251881Speter	sum += *sp++;
1430251881Speter	sum += *sp++;	/* ip_dst */
1431251881Speter	sum += *sp++;
1432251881Speter	if (sp != (u_short *)tcp)
1433251881Speter		sp = (u_short *)tcp;
1434251881Speter	sum += *sp++;	/* sport */
1435251881Speter	sum += *sp++;	/* dport */
1436251881Speter	sum += *sp++;	/* seq */
1437251881Speter	sum += *sp++;
1438251881Speter	sum += *sp++;	/* ack */
1439251881Speter	sum += *sp++;
1440251881Speter	sum += *sp++;	/* off */
1441251881Speter	sum += *sp++;	/* win */
1442251881Speter	sum += *sp++;	/* Skip over checksum */
1443251881Speter	sum += *sp++;	/* urp */
1444251881Speter
1445251881Speter# ifdef	__sgi
1446251881Speter	/*
1447251881Speter	 * In case we had to copy the IP & TCP header out of mbufs,
1448251881Speter	 * skip over the mbuf bits which are the header
1449251881Speter	 */
1450251881Speter	if ((caddr_t)ip != mtod(m, caddr_t)) {
1451251881Speter		hlen = (caddr_t)sp - (caddr_t)ip;
1452251881Speter		while (hlen) {
1453251881Speter			add = MIN(hlen, m->m_len);
1454251881Speter			sp = (u_short *)(mtod(m, caddr_t) + add);
1455251881Speter			hlen -= add;
1456251881Speter			if (add == m->m_len) {
1457251881Speter				m = m->m_next;
1458251881Speter				if (!hlen) {
1459251881Speter					if (!m)
1460251881Speter						break;
1461251881Speter					sp = mtod(m, u_short *);
1462251881Speter				}
1463251881Speter				PANIC((!m),("fr_tcpsum(1): not enough data"));
1464251881Speter			}
1465251881Speter		}
1466251881Speter	}
1467251881Speter# endif
1468251881Speter
1469251881Speter	if (!(len -= sizeof(*tcp)))
1470251881Speter		goto nodata;
1471251881Speter	while (len > 1) {
1472251881Speter		if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) {
1473251881Speter			m = m->m_next;
1474251881Speter			PANIC((!m),("fr_tcpsum(2): not enough data"));
1475251881Speter			sp = mtod(m, u_short *);
1476251881Speter		}
1477251881Speter		if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) {
1478251881Speter			bytes.c[0] = *(u_char *)sp;
1479251881Speter			m = m->m_next;
1480251881Speter			PANIC((!m),("fr_tcpsum(3): not enough data"));
1481251881Speter			sp = mtod(m, u_short *);
1482251881Speter			bytes.c[1] = *(u_char *)sp;
1483251881Speter			sum += bytes.s;
1484251881Speter			sp = (u_short *)((u_char *)sp + 1);
1485251881Speter		}
1486251881Speter		if ((u_long)sp & 1) {
1487251881Speter			bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
1488251881Speter			sum += bytes.s;
1489251881Speter		} else
1490251881Speter			sum += *sp++;
1491251881Speter		len -= 2;
1492251881Speter	}
1493251881Speter	if (len)
1494251881Speter		sum += ntohs(*(u_char *)sp << 8);
1495251881Speternodata:
1496251881Speter	while (sum > 0xffff)
1497251881Speter		sum = (sum & 0xffff) + (sum >> 16);
1498251881Speter	sum2 = (u_short)(~sum & 0xffff);
1499251881Speter}
1500251881Speter#  endif /*  defined(BSD) || defined(sun) */
1501251881Speter# endif /* SOLARIS */
1502251881Speter#else /* KERNEL */
1503251881Speter	for (; slen > 1; slen -= 2)
1504251881Speter		sum += *sp++;
1505251881Speter	if (slen)
1506251881Speter		sum += ntohs(*(u_char *)sp << 8);
1507251881Speter	while (sum > 0xffff)
1508251881Speter		sum = (sum & 0xffff) + (sum >> 16);
1509251881Speter	sum2 = (u_short)(~sum & 0xffff);
1510251881Speter#endif /* KERNEL */
1511251881Speter	tcp->th_sum = ts;
1512251881Speter	return sum2;
1513251881Speter}
1514251881Speter
1515251881Speter
1516251881Speter#if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) )
1517251881Speter/*
1518251881Speter * Copyright (c) 1982, 1986, 1988, 1991, 1993
1519251881Speter *	The Regents of the University of California.  All rights reserved.
1520251881Speter *
1521251881Speter * Redistribution and use in source and binary forms, with or without
1522251881Speter * modification, are permitted provided that the following conditions
1523251881Speter * are met:
1524251881Speter * 1. Redistributions of source code must retain the above copyright
1525251881Speter *    notice, this list of conditions and the following disclaimer.
1526251881Speter * 2. Redistributions in binary form must reproduce the above copyright
1527251881Speter *    notice, this list of conditions and the following disclaimer in the
1528251881Speter *    documentation and/or other materials provided with the distribution.
1529251881Speter * 3. All advertising materials mentioning features or use of this software
1530251881Speter *    must display the following acknowledgement:
1531251881Speter *	This product includes software developed by the University of
1532251881Speter *	California, Berkeley and its contributors.
1533251881Speter * 4. Neither the name of the University nor the names of its contributors
1534251881Speter *    may be used to endorse or promote products derived from this software
1535251881Speter *    without specific prior written permission.
1536251881Speter *
1537251881Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1538251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1539251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1540251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1541251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1542251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1543251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1544251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1545251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1546251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1547251881Speter * SUCH DAMAGE.
1548251881Speter *
1549251881Speter *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94
1550251881Speter * $Id: fil.c,v 2.35.2.67 2002/12/06 13:28:05 darrenr Exp $
1551251881Speter */
1552251881Speter/*
1553251881Speter * Copy data from an mbuf chain starting "off" bytes from the beginning,
1554251881Speter * continuing for "len" bytes, into the indicated buffer.
1555251881Speter */
1556251881Spetervoid
1557251881Speterm_copydata(m, off, len, cp)
1558251881Speter	register mb_t *m;
1559251881Speter	register int off;
1560251881Speter	register int len;
1561251881Speter	caddr_t cp;
1562251881Speter{
1563251881Speter	register unsigned count;
1564251881Speter
1565251881Speter	if (off < 0 || len < 0)
1566251881Speter		panic("m_copydata");
1567251881Speter	while (off > 0) {
1568251881Speter		if (m == 0)
1569251881Speter			panic("m_copydata");
1570251881Speter		if (off < m->m_len)
1571251881Speter			break;
1572251881Speter		off -= m->m_len;
1573251881Speter		m = m->m_next;
1574251881Speter	}
1575251881Speter	while (len > 0) {
1576251881Speter		if (m == 0)
1577251881Speter			panic("m_copydata");
1578251881Speter		count = MIN(m->m_len - off, len);
1579251881Speter		bcopy(mtod(m, caddr_t) + off, cp, count);
1580251881Speter		len -= count;
1581251881Speter		cp += count;
1582251881Speter		off = 0;
1583251881Speter		m = m->m_next;
1584251881Speter	}
1585251881Speter}
1586251881Speter
1587251881Speter
1588251881Speter# ifndef linux
1589251881Speter/*
1590251881Speter * Copy data from a buffer back into the indicated mbuf chain,
1591251881Speter * starting "off" bytes from the beginning, extending the mbuf
1592251881Speter * chain if necessary.
1593251881Speter */
1594251881Spetervoid
1595251881Speterm_copyback(m0, off, len, cp)
1596251881Speter	struct	mbuf *m0;
1597251881Speter	register int off;
1598251881Speter	register int len;
1599251881Speter	caddr_t cp;
1600251881Speter{
1601251881Speter	register int mlen;
1602251881Speter	register struct mbuf *m = m0, *n;
1603251881Speter	int totlen = 0;
1604251881Speter
1605251881Speter	if (m0 == 0)
1606251881Speter		return;
1607251881Speter	while (off > (mlen = m->m_len)) {
1608251881Speter		off -= mlen;
1609251881Speter		totlen += mlen;
1610251881Speter		if (m->m_next == 0) {
1611251881Speter			n = m_getclr(M_DONTWAIT, m->m_type);
1612251881Speter			if (n == 0)
1613251881Speter				goto out;
1614251881Speter			n->m_len = min(MLEN, len + off);
1615251881Speter			m->m_next = n;
1616251881Speter		}
1617251881Speter		m = m->m_next;
1618251881Speter	}
1619251881Speter	while (len > 0) {
1620251881Speter		mlen = min (m->m_len - off, len);
1621251881Speter		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
1622251881Speter		cp += mlen;
1623251881Speter		len -= mlen;
1624251881Speter		mlen += off;
1625251881Speter		off = 0;
1626251881Speter		totlen += mlen;
1627251881Speter		if (len == 0)
1628251881Speter			break;
1629251881Speter		if (m->m_next == 0) {
1630251881Speter			n = m_get(M_DONTWAIT, m->m_type);
1631251881Speter			if (n == 0)
1632251881Speter				break;
1633251881Speter			n->m_len = min(MLEN, len);
1634251881Speter			m->m_next = n;
1635251881Speter		}
1636251881Speter		m = m->m_next;
1637251881Speter	}
1638251881Speterout:
1639251881Speter#if 0
1640251881Speter	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
1641251881Speter		m->m_pkthdr.len = totlen;
1642251881Speter#endif
1643251881Speter	return;
1644251881Speter}
1645251881Speter# endif /* linux */
1646251881Speter#endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */
1647251881Speter
1648251881Speter
1649251881Speterfrgroup_t *fr_findgroup(num, flags, which, set, fgpp)
1650251881Speteru_32_t num, flags;
1651251881Speterminor_t which;
1652251881Speterint set;
1653251881Speterfrgroup_t ***fgpp;
1654251881Speter{
1655251881Speter	frgroup_t *fg, **fgp;
1656251881Speter
1657251881Speter	if (which == IPL_LOGAUTH)
1658251881Speter		fgp = &ipfgroups[2][set];
1659251881Speter	else if (flags & FR_ACCOUNT)
1660251881Speter		fgp = &ipfgroups[1][set];
1661251881Speter	else if (flags & (FR_OUTQUE|FR_INQUE))
1662251881Speter		fgp = &ipfgroups[0][set];
1663251881Speter	else
1664251881Speter		return NULL;
1665251881Speter
1666251881Speter	while ((fg = *fgp))
1667251881Speter		if (fg->fg_num == num)
1668251881Speter			break;
1669251881Speter		else
1670251881Speter			fgp = &fg->fg_next;
1671251881Speter	if (fgpp)
1672251881Speter		*fgpp = fgp;
1673251881Speter	return fg;
1674251881Speter}
1675251881Speter
1676251881Speter
1677251881Speterfrgroup_t *fr_addgroup(num, fp, which, set)
1678251881Speteru_32_t num;
1679251881Speterfrentry_t *fp;
1680251881Speterminor_t which;
1681251881Speterint set;
1682251881Speter{
1683251881Speter	frgroup_t *fg, **fgp;
1684251881Speter
1685251881Speter	if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp)))
1686251881Speter		return fg;
1687251881Speter
1688251881Speter	KMALLOC(fg, frgroup_t *);
1689251881Speter	if (fg) {
1690251881Speter		fg->fg_num = num;
1691251881Speter		fg->fg_next = *fgp;
1692251881Speter		fg->fg_head = fp;
1693251881Speter		fg->fg_start = &fp->fr_grp;
1694251881Speter		*fgp = fg;
1695251881Speter	}
1696251881Speter	return fg;
1697251881Speter}
1698251881Speter
1699251881Speter
1700251881Spetervoid fr_delgroup(num, flags, which, set)
1701251881Speteru_32_t num, flags;
1702251881Speterminor_t which;
1703251881Speterint set;
1704251881Speter{
1705251881Speter	frgroup_t *fg, **fgp;
1706251881Speter
1707251881Speter	if (!(fg = fr_findgroup(num, flags, which, set, &fgp)))
1708251881Speter		return;
1709251881Speter
1710251881Speter	*fgp = fg->fg_next;
1711251881Speter	KFREE(fg);
1712251881Speter}
1713251881Speter
1714251881Speter
1715251881Speter
1716251881Speter/*
1717251881Speter * recursively flush rules from the list, descending groups as they are
1718251881Speter * encountered.  if a rule is the head of a group and it has lost all its
1719251881Speter * group members, then also delete the group reference.
1720251881Speter */
1721251881Speterstatic int frflushlist(set, unit, nfreedp, listp)
1722251881Speterint set;
1723251881Speterminor_t unit;
1724251881Speterint *nfreedp;
1725251881Speterfrentry_t **listp;
1726251881Speter{
1727251881Speter	register int freed = 0, i;
1728251881Speter	register frentry_t *fp;
1729251881Speter
1730251881Speter	while ((fp = *listp)) {
1731251881Speter		*listp = fp->fr_next;
1732251881Speter		if (fp->fr_grp) {
1733251881Speter			i = frflushlist(set, unit, nfreedp, &fp->fr_grp);
1734251881Speter			MUTEX_ENTER(&ipf_rw);
1735251881Speter			fp->fr_ref -= i;
1736251881Speter			MUTEX_EXIT(&ipf_rw);
1737251881Speter		}
1738251881Speter
1739251881Speter		ATOMIC_DEC32(fp->fr_ref);
1740251881Speter		if (fp->fr_grhead) {
1741251881Speter			fr_delgroup(fp->fr_grhead, fp->fr_flags,
1742251881Speter				    unit, set);
1743251881Speter			fp->fr_grhead = 0;
1744251881Speter		}
1745251881Speter		if (fp->fr_ref == 0) {
1746251881Speter			KFREE(fp);
1747251881Speter			freed++;
1748251881Speter		} else
1749251881Speter			fp->fr_next = NULL;
1750251881Speter	}
1751251881Speter	*nfreedp += freed;
1752251881Speter	return freed;
1753251881Speter}
1754251881Speter
1755251881Speter
1756251881Speterint frflush(unit, proto, flags)
1757251881Speterminor_t unit;
1758251881Speterint proto, flags;
1759251881Speter{
1760251881Speter	int flushed = 0, set;
1761251881Speter
1762251881Speter	if (unit != IPL_LOGIPF)
1763251881Speter		return 0;
1764251881Speter	WRITE_ENTER(&ipf_mutex);
1765251881Speter	bzero((char *)frcache, sizeof(frcache[0]) * 2);
1766251881Speter
1767251881Speter	set = fr_active;
1768251881Speter	if (flags & FR_INACTIVE)
1769251881Speter		set = 1 - set;
1770251881Speter
1771251881Speter	if (flags & FR_OUTQUE) {
1772251881Speter#ifdef	USE_INET6
1773251881Speter		if (proto == 0 || proto == 6) {
1774251881Speter			(void) frflushlist(set, unit,
1775251881Speter					   &flushed, &ipfilter6[1][set]);
1776251881Speter			(void) frflushlist(set, unit,
1777251881Speter					   &flushed, &ipacct6[1][set]);
1778251881Speter		}
1779251881Speter#endif
1780251881Speter		if (proto == 0 || proto == 4) {
1781251881Speter			(void) frflushlist(set, unit,
1782251881Speter					   &flushed, &ipfilter[1][set]);
1783251881Speter			(void) frflushlist(set, unit,
1784251881Speter					   &flushed, &ipacct[1][set]);
1785251881Speter		}
1786251881Speter	}
1787251881Speter	if (flags & FR_INQUE) {
1788251881Speter#ifdef	USE_INET6
1789251881Speter		if (proto == 0 || proto == 6) {
1790251881Speter			(void) frflushlist(set, unit,
1791251881Speter					    &flushed, &ipfilter6[0][set]);
1792251881Speter			(void) frflushlist(set, unit,
1793251881Speter					   &flushed, &ipacct6[0][set]);
1794251881Speter		}
1795251881Speter#endif
1796251881Speter		if (proto == 0 || proto == 4) {
1797251881Speter			(void) frflushlist(set, unit,
1798251881Speter					   &flushed, &ipfilter[0][set]);
1799251881Speter			(void) frflushlist(set, unit,
1800251881Speter					   &flushed, &ipacct[0][set]);
1801251881Speter		}
1802251881Speter	}
1803251881Speter	RWLOCK_EXIT(&ipf_mutex);
1804251881Speter	return flushed;
1805251881Speter}
1806251881Speter
1807251881Speter
1808251881Speterchar *memstr(src, dst, slen, dlen)
1809251881Speterchar *src, *dst;
1810251881Speterint slen, dlen;
1811251881Speter{
1812251881Speter	char *s = NULL;
1813251881Speter
1814251881Speter	while (dlen >= slen) {
1815251881Speter		if (bcmp(src, dst, slen) == 0) {
1816251881Speter			s = dst;
1817251881Speter			break;
1818251881Speter		}
1819251881Speter		dst++;
1820251881Speter		dlen--;
1821251881Speter	}
1822251881Speter	return s;
1823251881Speter}
1824251881Speter
1825251881Speter
1826251881Spetervoid fixskip(listp, rp, addremove)
1827251881Speterfrentry_t **listp, *rp;
1828251881Speterint addremove;
1829251881Speter{
1830251881Speter	frentry_t *fp;
1831251881Speter	int rules = 0, rn = 0;
1832251881Speter
1833251881Speter	for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++)
1834251881Speter		;
1835251881Speter
1836251881Speter	if (!fp)
1837251881Speter		return;
1838251881Speter
1839251881Speter	for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
1840251881Speter		if (fp->fr_skip && (rn + fp->fr_skip >= rules))
1841251881Speter			fp->fr_skip += addremove;
1842251881Speter}
1843251881Speter
1844251881Speter
1845251881Speter#ifdef	_KERNEL
1846251881Speter/*
1847251881Speter * count consecutive 1's in bit mask.  If the mask generated by counting
1848251881Speter * consecutive 1's is different to that passed, return -1, else return #
1849251881Speter * of bits.
1850251881Speter */
1851251881Speterint	countbits(ip)
1852251881Speteru_32_t	ip;
1853251881Speter{
1854251881Speter	u_32_t	ipn;
1855251881Speter	int	cnt = 0, i, j;
1856251881Speter
1857251881Speter	ip = ipn = ntohl(ip);
1858251881Speter	for (i = 32; i; i--, ipn *= 2)
1859251881Speter		if (ipn & 0x80000000)
1860251881Speter			cnt++;
1861251881Speter		else
1862251881Speter			break;
1863251881Speter	ipn = 0;
1864251881Speter	for (i = 32, j = cnt; i; i--, j--) {
1865251881Speter		ipn *= 2;
1866251881Speter		if (j > 0)
1867251881Speter			ipn++;
1868251881Speter	}
1869251881Speter	if (ipn == ip)
1870251881Speter		return cnt;
1871251881Speter	return -1;
1872251881Speter}
1873251881Speter
1874251881Speter
1875251881Speter/*
1876251881Speter * return the first IP Address associated with an interface
1877251881Speter */
1878251881Speterint fr_ifpaddr(v, ifptr, inp)
1879251881Speterint v;
1880251881Spetervoid *ifptr;
1881251881Speterstruct in_addr *inp;
1882251881Speter{
1883251881Speter# ifdef	USE_INET6
1884251881Speter	struct in6_addr *inp6 = NULL;
1885251881Speter# endif
1886251881Speter# if SOLARIS
1887251881Speter	ill_t *ill = ifptr;
1888251881Speter# else
1889251881Speter	struct ifnet *ifp = ifptr;
1890251881Speter# endif
1891251881Speter	struct in_addr in;
1892251881Speter
1893251881Speter# if SOLARIS
1894251881Speter#  ifdef	USE_INET6
1895251881Speter	if (v == 6) {
1896251881Speter		struct in6_addr in6;
1897251881Speter
1898251881Speter		/*
1899251881Speter		 * First is always link local.
1900251881Speter		 */
1901251881Speter		if (ill->ill_ipif->ipif_next)
1902251881Speter			in6 = ill->ill_ipif->ipif_next->ipif_v6lcl_addr;
1903251881Speter		else
1904251881Speter			bzero((char *)&in6, sizeof(in6));
1905251881Speter		bcopy((char *)&in6, (char *)inp, sizeof(in6));
1906251881Speter	} else
1907251881Speter#  endif
1908251881Speter	{
1909251881Speter		in.s_addr = ill->ill_ipif->ipif_local_addr;
1910251881Speter		*inp = in;
1911251881Speter	}
1912251881Speter# else /* SOLARIS */
1913251881Speter#  if linux
1914251881Speter	;
1915251881Speter#  else /* linux */
1916251881Speter	struct sockaddr_in *sin;
1917251881Speter	struct ifaddr *ifa;
1918251881Speter
1919251881Speter#   if	(__FreeBSD_version >= 300000)
1920251881Speter	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1921251881Speter#   else
1922251881Speter#    if defined(__NetBSD__) || defined(__OpenBSD__)
1923251881Speter	ifa = ifp->if_addrlist.tqh_first;
1924251881Speter#    else
1925251881Speter#     if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
1926251881Speter	ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa;
1927251881Speter#     else
1928251881Speter	ifa = ifp->if_addrlist;
1929251881Speter#     endif
1930251881Speter#    endif /* __NetBSD__ || __OpenBSD__ */
1931251881Speter#   endif /* __FreeBSD_version >= 300000 */
1932251881Speter#   if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK))
1933251881Speter	sin = (struct sockaddr_in *)&ifa->ifa_addr;
1934251881Speter#   else
1935251881Speter	sin = (struct sockaddr_in *)ifa->ifa_addr;
1936251881Speter	while (sin && ifa) {
1937251881Speter		if ((v == 4) && (sin->sin_family == AF_INET))
1938251881Speter			break;
1939251881Speter#    ifdef USE_INET6
1940251881Speter		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1941251881Speter			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1942251881Speter			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1943251881Speter			    !IN6_IS_ADDR_LOOPBACK(inp6))
1944251881Speter				break;
1945251881Speter		}
1946251881Speter#    endif
1947251881Speter#    if	(__FreeBSD_version >= 300000)
1948251881Speter		ifa = TAILQ_NEXT(ifa, ifa_link);
1949251881Speter#    else
1950251881Speter#     if defined(__NetBSD__) || defined(__OpenBSD__)
1951251881Speter		ifa = ifa->ifa_list.tqe_next;
1952251881Speter#     else
1953251881Speter		ifa = ifa->ifa_next;
1954251881Speter#     endif
1955251881Speter#    endif /* __FreeBSD_version >= 300000 */
1956251881Speter		if (ifa)
1957251881Speter			sin = (struct sockaddr_in *)ifa->ifa_addr;
1958251881Speter	}
1959251881Speter	if (ifa == NULL)
1960251881Speter		sin = NULL;
1961251881Speter	if (sin == NULL)
1962251881Speter		return -1;
1963251881Speter#   endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */
1964251881Speter#    ifdef	USE_INET6
1965251881Speter	if (v == 6)
1966251881Speter		bcopy((char *)inp6, (char *)inp, sizeof(*inp6));
1967251881Speter	else
1968251881Speter#    endif
1969251881Speter	{
1970251881Speter		in = sin->sin_addr;
1971251881Speter		*inp = in;
1972251881Speter	}
1973251881Speter#  endif /* linux */
1974251881Speter# endif /* SOLARIS */
1975251881Speter	return 0;
1976251881Speter}
1977251881Speter
1978251881Speter
1979251881Speterstatic void frsynclist(fr)
1980251881Speterregister frentry_t *fr;
1981251881Speter{
1982251881Speter	for (; fr; fr = fr->fr_next) {
1983251881Speter		if (fr->fr_ifa != NULL) {
1984251881Speter			fr->fr_ifa = GETUNIT(fr->fr_ifname, fr->fr_ip.fi_v);
1985251881Speter			if (fr->fr_ifa == NULL)
1986251881Speter				fr->fr_ifa = (void *)-1;
1987251881Speter		}
1988251881Speter		if (fr->fr_grp)
1989251881Speter			frsynclist(fr->fr_grp);
1990251881Speter	}
1991251881Speter}
1992251881Speter
1993251881Speter
1994251881Spetervoid frsync()
1995251881Speter{
1996251881Speter# if !SOLARIS
1997251881Speter	register struct ifnet *ifp;
1998251881Speter
1999251881Speter#  if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \
2000251881Speter     (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000))
2001251881Speter#   if (NetBSD >= 199905) || defined(__OpenBSD__)
2002251881Speter	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
2003251881Speter#   elif defined(__FreeBSD_version) && (__FreeBSD_version >= 500043)
2004251881Speter	IFNET_RLOCK();
2005251881Speter	TAILQ_FOREACH(ifp, &ifnet, if_link)
2006251881Speter#   else
2007251881Speter	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
2008251881Speter#   endif
2009251881Speter#  else
2010251881Speter	for (ifp = ifnet; ifp; ifp = ifp->if_next)
2011251881Speter#  endif
2012251881Speter	{
2013251881Speter		ip_natsync(ifp);
2014251881Speter		ip_statesync(ifp);
2015251881Speter	}
2016251881Speter#  if defined(__FreeBSD_version) && (__FreeBSD_version >= 500043)
2017251881Speter	IFNET_RUNLOCK();
2018251881Speter#  endif
2019251881Speter	ip_natsync((struct ifnet *)-1);
2020251881Speter# endif /* !SOLARIS */
2021251881Speter
2022251881Speter	WRITE_ENTER(&ipf_mutex);
2023251881Speter	frsynclist(ipacct[0][fr_active]);
2024251881Speter	frsynclist(ipacct[1][fr_active]);
2025251881Speter	frsynclist(ipfilter[0][fr_active]);
2026251881Speter	frsynclist(ipfilter[1][fr_active]);
2027251881Speter#ifdef	USE_INET6
2028251881Speter	frsynclist(ipacct6[0][fr_active]);
2029251881Speter	frsynclist(ipacct6[1][fr_active]);
2030251881Speter	frsynclist(ipfilter6[0][fr_active]);
2031251881Speter	frsynclist(ipfilter6[1][fr_active]);
2032251881Speter#endif
2033251881Speter	RWLOCK_EXIT(&ipf_mutex);
2034251881Speter}
2035251881Speter
2036251881Speter
2037251881Speter/*
2038251881Speter * In the functions below, bcopy() is called because the pointer being
2039251881Speter * copied _from_ in this instance is a pointer to a char buf (which could
2040251881Speter * end up being unaligned) and on the kernel's local stack.
2041251881Speter */
2042251881Speterint ircopyptr(a, b, c)
2043251881Spetervoid *a, *b;
2044251881Spetersize_t c;
2045251881Speter{
2046251881Speter	caddr_t ca;
2047251881Speter	int err;
2048251881Speter
2049251881Speter#if SOLARIS
2050251881Speter	if (copyin(a, (char *)&ca, sizeof(ca)))
2051251881Speter		return EFAULT;
2052251881Speter#else
2053251881Speter	bcopy(a, &ca, sizeof(ca));
2054251881Speter#endif
2055251881Speter	err = copyin(ca, b, c);
2056251881Speter	if (err)
2057251881Speter		err = EFAULT;
2058251881Speter	return err;
2059251881Speter}
2060251881Speter
2061251881Speter
2062251881Speterint iwcopyptr(a, b, c)
2063251881Spetervoid *a, *b;
2064251881Spetersize_t c;
2065251881Speter{
2066251881Speter	caddr_t ca;
2067251881Speter	int err;
2068251881Speter
2069251881Speter#if SOLARIS
2070251881Speter	if (copyin(b, (char *)&ca, sizeof(ca)))
2071251881Speter		return EFAULT;
2072251881Speter#else
2073251881Speter	bcopy(b, &ca, sizeof(ca));
2074251881Speter#endif
2075251881Speter	err = copyout(a, ca, c);
2076251881Speter	if (err)
2077251881Speter		err = EFAULT;
2078251881Speter	return err;
2079251881Speter}
2080251881Speter
2081251881Speter#else /* _KERNEL */
2082251881Speter
2083251881Speter
2084251881Speter/*
2085251881Speter * return the first IP Address associated with an interface
2086251881Speter */
2087251881Speterint fr_ifpaddr(v, ifptr, inp)
2088251881Speterint v;
2089251881Spetervoid *ifptr;
2090251881Speterstruct in_addr *inp;
2091251881Speter{
2092251881Speter	return 0;
2093251881Speter}
2094251881Speter
2095251881Speter
2096251881Speterint ircopyptr(a, b, c)
2097251881Spetervoid *a, *b;
2098251881Spetersize_t c;
2099251881Speter{
2100251881Speter	caddr_t ca;
2101251881Speter
2102251881Speter	bcopy(a, &ca, sizeof(ca));
2103251881Speter	bcopy(ca, b, c);
2104251881Speter	return 0;
2105251881Speter}
2106251881Speter
2107251881Speter
2108251881Speterint iwcopyptr(a, b, c)
2109251881Spetervoid *a, *b;
2110251881Spetersize_t c;
2111251881Speter{
2112251881Speter	caddr_t ca;
2113251881Speter
2114251881Speter	bcopy(b, &ca, sizeof(ca));
2115251881Speter	bcopy(a, ca, c);
2116251881Speter	return 0;
2117251881Speter}
2118251881Speter
2119251881Speter
2120251881Speter#endif
2121251881Speter
2122251881Speter
2123251881Speterint fr_lock(data, lockp)
2124251881Spetercaddr_t data;
2125251881Speterint *lockp;
2126251881Speter{
2127251881Speter	int arg, error;
2128251881Speter
2129251881Speter	error = IRCOPY(data, (caddr_t)&arg, sizeof(arg));
2130251881Speter	if (!error) {
2131251881Speter		error = IWCOPY((caddr_t)lockp, data, sizeof(*lockp));
2132251881Speter		if (!error)
2133251881Speter			*lockp = arg;
2134251881Speter	}
2135251881Speter	return error;
2136251881Speter}
2137251881Speter
2138251881Speter
2139251881Spetervoid fr_getstat(fiop)
2140251881Speterfriostat_t *fiop;
2141251881Speter{
2142251881Speter	bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2);
2143251881Speter	fiop->f_locks[0] = fr_state_lock;
2144251881Speter	fiop->f_locks[1] = fr_nat_lock;
2145251881Speter	fiop->f_locks[2] = fr_frag_lock;
2146251881Speter	fiop->f_locks[3] = fr_auth_lock;
2147251881Speter	fiop->f_fin[0] = ipfilter[0][0];
2148251881Speter	fiop->f_fin[1] = ipfilter[0][1];
2149251881Speter	fiop->f_fout[0] = ipfilter[1][0];
2150251881Speter	fiop->f_fout[1] = ipfilter[1][1];
2151251881Speter	fiop->f_acctin[0] = ipacct[0][0];
2152251881Speter	fiop->f_acctin[1] = ipacct[0][1];
2153251881Speter	fiop->f_acctout[0] = ipacct[1][0];
2154251881Speter	fiop->f_acctout[1] = ipacct[1][1];
2155251881Speter#ifdef	USE_INET6
2156251881Speter	fiop->f_fin6[0] = ipfilter6[0][0];
2157251881Speter	fiop->f_fin6[1] = ipfilter6[0][1];
2158251881Speter	fiop->f_fout6[0] = ipfilter6[1][0];
2159251881Speter	fiop->f_fout6[1] = ipfilter6[1][1];
2160251881Speter	fiop->f_acctin6[0] = ipacct6[0][0];
2161251881Speter	fiop->f_acctin6[1] = ipacct6[0][1];
2162251881Speter	fiop->f_acctout6[0] = ipacct6[1][0];
2163251881Speter	fiop->f_acctout6[1] = ipacct6[1][1];
2164251881Speter#else
2165251881Speter	fiop->f_fin6[0] = NULL;
2166251881Speter	fiop->f_fin6[1] = NULL;
2167251881Speter	fiop->f_fout6[0] = NULL;
2168251881Speter	fiop->f_fout6[1] = NULL;
2169251881Speter	fiop->f_acctin6[0] = NULL;
2170251881Speter	fiop->f_acctin6[1] = NULL;
2171251881Speter	fiop->f_acctout6[0] = NULL;
2172251881Speter	fiop->f_acctout6[1] = NULL;
2173251881Speter#endif
2174251881Speter	fiop->f_active = fr_active;
2175251881Speter	fiop->f_froute[0] = ipl_frouteok[0];
2176251881Speter	fiop->f_froute[1] = ipl_frouteok[1];
2177251881Speter
2178251881Speter	fiop->f_running = fr_running;
2179251881Speter	fiop->f_groups[0][0] = ipfgroups[0][0];
2180251881Speter	fiop->f_groups[0][1] = ipfgroups[0][1];
2181251881Speter	fiop->f_groups[1][0] = ipfgroups[1][0];
2182251881Speter	fiop->f_groups[1][1] = ipfgroups[1][1];
2183251881Speter	fiop->f_groups[2][0] = ipfgroups[2][0];
2184251881Speter	fiop->f_groups[2][1] = ipfgroups[2][1];
2185251881Speter#ifdef  IPFILTER_LOG
2186251881Speter	fiop->f_logging = 1;
2187251881Speter#else
2188251881Speter	fiop->f_logging = 0;
2189251881Speter#endif
2190251881Speter	fiop->f_defpass = fr_pass;
2191251881Speter	strncpy(fiop->f_version, ipfilter_version, sizeof(fiop->f_version));
2192251881Speter}
2193251881Speter
2194251881Speter
2195251881Speter#ifdef	USE_INET6
2196251881Speterint icmptoicmp6types[ICMP_MAXTYPE+1] = {
2197251881Speter	ICMP6_ECHO_REPLY,	/* 0: ICMP_ECHOREPLY */
2198251881Speter	-1,			/* 1: UNUSED */
2199251881Speter	-1,			/* 2: UNUSED */
2200251881Speter	ICMP6_DST_UNREACH,	/* 3: ICMP_UNREACH */
2201251881Speter	-1,			/* 4: ICMP_SOURCEQUENCH */
2202251881Speter	ND_REDIRECT,		/* 5: ICMP_REDIRECT */
2203251881Speter	-1,			/* 6: UNUSED */
2204251881Speter	-1,			/* 7: UNUSED */
2205251881Speter	ICMP6_ECHO_REQUEST,	/* 8: ICMP_ECHO */
2206251881Speter	-1,			/* 9: UNUSED */
2207251881Speter	-1,			/* 10: UNUSED */
2208251881Speter	ICMP6_TIME_EXCEEDED,	/* 11: ICMP_TIMXCEED */
2209251881Speter	ICMP6_PARAM_PROB,	/* 12: ICMP_PARAMPROB */
2210251881Speter	-1,			/* 13: ICMP_TSTAMP */
2211251881Speter	-1,			/* 14: ICMP_TSTAMPREPLY */
2212251881Speter	-1,			/* 15: ICMP_IREQ */
2213251881Speter	-1,			/* 16: ICMP_IREQREPLY */
2214251881Speter	-1,			/* 17: ICMP_MASKREQ */
2215251881Speter	-1,			/* 18: ICMP_MASKREPLY */
2216251881Speter};
2217251881Speter
2218251881Speter
2219251881Speterint	icmptoicmp6unreach[ICMP_MAX_UNREACH] = {
2220251881Speter	ICMP6_DST_UNREACH_ADDR,		/* 0: ICMP_UNREACH_NET */
2221251881Speter	ICMP6_DST_UNREACH_ADDR,		/* 1: ICMP_UNREACH_HOST */
2222251881Speter	-1,				/* 2: ICMP_UNREACH_PROTOCOL */
2223251881Speter	ICMP6_DST_UNREACH_NOPORT,	/* 3: ICMP_UNREACH_PORT */
2224251881Speter	-1,				/* 4: ICMP_UNREACH_NEEDFRAG */
2225251881Speter	ICMP6_DST_UNREACH_NOTNEIGHBOR,	/* 5: ICMP_UNREACH_SRCFAIL */
2226251881Speter	ICMP6_DST_UNREACH_ADDR,		/* 6: ICMP_UNREACH_NET_UNKNOWN */
2227251881Speter	ICMP6_DST_UNREACH_ADDR,		/* 7: ICMP_UNREACH_HOST_UNKNOWN */
2228251881Speter	-1,				/* 8: ICMP_UNREACH_ISOLATED */
2229251881Speter	ICMP6_DST_UNREACH_ADMIN,	/* 9: ICMP_UNREACH_NET_PROHIB */
2230251881Speter	ICMP6_DST_UNREACH_ADMIN,	/* 10: ICMP_UNREACH_HOST_PROHIB */
2231251881Speter	-1,				/* 11: ICMP_UNREACH_TOSNET */
2232251881Speter	-1,				/* 12: ICMP_UNREACH_TOSHOST */
2233251881Speter	ICMP6_DST_UNREACH_ADMIN,	/* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
2234251881Speter};
2235251881Speter#endif
2236251881Speter
2237251881Speter
2238251881Speter#ifndef	_KERNEL
2239251881Speterint mbuflen(buf)
2240251881Spetermb_t *buf;
2241251881Speter{
2242251881Speter	ip_t *ip;
2243251881Speter
2244251881Speter	ip = (ip_t *)buf;
2245251881Speter	return ip->ip_len;
2246251881Speter}
2247251881Speter#endif
2248251881Speter