ip_fil_freebsd.c revision 161356
1190501Smr/*	$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 161356 2006-08-16 12:06:35Z guido $	*/
2190501Smr
3190501Smr/*
4190501Smr * Copyright (C) 1993-2003 by Darren Reed.
5190501Smr *
6190501Smr * See the IPFILTER.LICENCE file for details on licencing.
7190501Smr */
8190501Smr#if !defined(lint)
9190501Smrstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10190501Smrstatic const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.32 2006/03/25 13:03:01 darrenr Exp $";
11190521Smr#endif
12190501Smr
13190501Smr#if defined(KERNEL) || defined(_KERNEL)
14190501Smr# undef KERNEL
15190501Smr# undef _KERNEL
16190501Smr# define	KERNEL	1
17190501Smr# define	_KERNEL	1
18190501Smr#endif
19190501Smr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20190501Smr    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21190501Smr# include "opt_inet6.h"
22190501Smr#endif
23190501Smr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24190501Smr    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25190501Smr# include "opt_random_ip_id.h"
26190501Smr#endif
27190501Smr#include <sys/param.h>
28190501Smr#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
29190501Smr# if defined(IPFILTER_LKM)
30190501Smr#  ifndef __FreeBSD_cc_version
31190501Smr#   include <osreldate.h>
32190501Smr#  else
33190501Smr#   if __FreeBSD_cc_version < 430000
34190501Smr#    include <osreldate.h>
35190501Smr#   endif
36190501Smr#  endif
37190501Smr# endif
38190501Smr#endif
39190501Smr#include <sys/errno.h>
40190501Smr#include <sys/types.h>
41190501Smr#include <sys/file.h>
42190501Smr#if __FreeBSD_version >= 220000
43190501Smr# include <sys/fcntl.h>
44190501Smr# include <sys/filio.h>
45190501Smr#else
46190501Smr# include <sys/ioctl.h>
47190501Smr#endif
48190501Smr#include <sys/time.h>
49190501Smr#include <sys/systm.h>
50190501Smr#if (__FreeBSD_version >= 300000)
51190501Smr# include <sys/dirent.h>
52190501Smr#else
53190501Smr# include <sys/dir.h>
54190501Smr#endif
55190501Smr#if !defined(__hpux)
56190501Smr# include <sys/mbuf.h>
57190501Smr#endif
58190501Smr#include <sys/protosw.h>
59190501Smr#include <sys/socket.h>
60190501Smr#include <sys/selinfo.h>
61190501Smr
62190501Smr#include <net/if.h>
63190501Smr#if __FreeBSD_version >= 300000
64193530Sjkim# include <net/if_var.h>
65193530Sjkim# if !defined(IPFILTER_LKM)
66190501Smr#  include "opt_ipfilter.h"
67190501Smr# endif
68190501Smr#endif
69190501Smr#include <net/route.h>
70190501Smr#include <netinet/in.h>
71190501Smr#include <netinet/in_var.h>
72190501Smr#include <netinet/in_systm.h>
73190501Smr#include <netinet/ip.h>
74190501Smr#include <netinet/ip_var.h>
75190501Smr#include <netinet/tcp.h>
76190501Smr#if defined(__osf__)
77190501Smr# include <netinet/tcp_timer.h>
78190501Smr#endif
79190501Smr#include <netinet/udp.h>
80190501Smr#include <netinet/tcpip.h>
81190501Smr#include <netinet/ip_icmp.h>
82190501Smr#ifndef _KERNEL
83190501Smr# include "netinet/ipf.h"
84190501Smr#endif
85190501Smr#include "netinet/ip_compat.h"
86190501Smr#ifdef USE_INET6
87190501Smr# include <netinet/icmp6.h>
88190501Smr#endif
89190501Smr#include "netinet/ip_fil.h"
90190501Smr#include "netinet/ip_nat.h"
91190501Smr#include "netinet/ip_frag.h"
92190501Smr#include "netinet/ip_state.h"
93190501Smr#include "netinet/ip_proxy.h"
94190501Smr#include "netinet/ip_auth.h"
95190501Smr#ifdef	IPFILTER_SYNC
96190501Smr#include "netinet/ip_sync.h"
97190501Smr#endif
98190501Smr#ifdef	IPFILTER_SCAN
99190501Smr#include "netinet/ip_scan.h"
100190501Smr#endif
101190501Smr#include "netinet/ip_pool.h"
102190501Smr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
103190501Smr# include <sys/malloc.h>
104190501Smr#endif
105190501Smr#include <sys/kernel.h>
106190501Smr#ifdef CSUM_DATA_VALID
107190501Smr#include <machine/in_cksum.h>
108190501Smr#endif
109190501Smrextern	int	ip_optcopy __P((struct ip *, struct ip *));
110190501Smr
111190501Smr#if (__FreeBSD_version > 460000)
112190501Smrextern	int	path_mtu_discovery;
113190501Smr#endif
114190501Smr
115190501Smr# ifdef IPFILTER_M_IPFILTER
116190501SmrMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
117190501Smr# endif
118190501Smr
119190501Smr
120190501Smr#if !defined(__osf__)
121215131Savgextern	struct	protosw	inetsw[];
122190501Smr#endif
123215131Savg
124190501Smrstatic	int	(*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
125190501Smrstatic	int	fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
126190501Smr# ifdef USE_MUTEXES
127190501Smripfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
128190501Smripfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
129190501Smripfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache;
130190501Smripfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
131190501Smr# endif
132190501Smrint		ipf_locks_done = 0;
133190501Smr
134190501Smr#if (__FreeBSD_version >= 300000)
135190501Smrstruct callout_handle fr_slowtimer_ch;
136190501Smr#endif
137190501Smrstruct	selinfo	ipfselwait[IPL_LOGSIZE];
138190501Smr
139190501Smr#if (__FreeBSD_version >= 500011)
140190501Smr# include <sys/conf.h>
141190501Smr# if defined(NETBSD_PF)
142190501Smr#  include <net/pfil.h>
143190501Smr#  include <netinet/ipprotosw.h>
144190501Smr/*
145190501Smr * We provide the fr_checkp name just to minimize changes later.
146190501Smr */
147190501Smrint (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
148190501Smr# endif /* NETBSD_PF */
149190501Smr#endif /* __FreeBSD_version >= 500011 */
150190501Smr
151190501Smr
152190501Smr#if (__FreeBSD_version >= 502103)
153190501Smrstatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
154190501Smr
155190501Smrstatic void ipf_ifevent(void *arg);
156190501Smr
157190501Smrstatic void ipf_ifevent(arg)
158190501Smrvoid *arg;
159190501Smr{
160190501Smr        frsync(NULL);
161190501Smr}
162190501Smr#endif
163190501Smr
164190501Smr
165190501Smr#if (__FreeBSD_version >= 501108) && defined(_KERNEL)
166190501Smr
167190501Smrstatic int
168190501Smrfr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
169190501Smr{
170190501Smr	struct ip *ip = mtod(*mp, struct ip *);
171190501Smr	return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
172190501Smr}
173190501Smr
174190501Smr# ifdef USE_INET6
175215398Savg#  include <netinet/ip6.h>
176190501Smr
177215398Savgstatic int
178215398Savgfr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
179215398Savg{
180190501Smr	return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
181215398Savg	    ifp, (dir == PFIL_OUT), mp));
182190501Smr}
183190501Smr# endif
184190501Smr#endif /* __FreeBSD_version >= 501108 */
185190501Smr#if	defined(IPFILTER_LKM)
186190501Smrint iplidentify(s)
187190501Smrchar *s;
188190501Smr{
189190501Smr	if (strcmp(s, "ipl") == 0)
190190501Smr		return 1;
191190501Smr	return 0;
192190501Smr}
193190501Smr#endif /* IPFILTER_LKM */
194190501Smr
195190501Smr
196190501Smrint iplattach()
197190501Smr{
198190501Smr#ifdef USE_SPL
199190501Smr	int s;
200190501Smr#endif
201190501Smr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
202190501Smr	int error = 0;
203190501Smr# if __FreeBSD_version >= 501108
204215398Savg	struct pfil_head *ph_inet;
205215398Savg#  ifdef USE_INET6
206215398Savg	struct pfil_head *ph_inet6;
207190501Smr#  endif
208190501Smr# endif
209190501Smr#endif
210190501Smr
211190501Smr	SPL_NET(s);
212190501Smr	if (fr_running > 0) {
213190501Smr		SPL_X(s);
214190501Smr		return EBUSY;
215190501Smr	}
216190501Smr
217190501Smr	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
218190501Smr	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
219190501Smr	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
220190501Smr	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
221190501Smr	RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
222190501Smr	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
223190501Smr	ipf_locks_done = 1;
224190501Smr
225190501Smr	if (fr_initialise() < 0) {
226190501Smr		SPL_X(s);
227190501Smr		return EIO;
228190501Smr	}
229190501Smr
230190501Smr
231190501Smr# ifdef NETBSD_PF
232190501Smr#  if __FreeBSD_version >= 500011
233190501Smr#   if __FreeBSD_version >= 501108
234190501Smr	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
235190501Smr#    ifdef USE_INET6
236190501Smr	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
237190501Smr#    endif
238190501Smr	if (ph_inet == NULL
239190501Smr#    ifdef USE_INET6
240190501Smr	    && ph_inet6 == NULL
241190501Smr#    endif
242190501Smr	   )
243190501Smr		return ENODEV;
244190501Smr
245190501Smr	if (ph_inet != NULL)
246190501Smr		error = pfil_add_hook((void *)fr_check_wrapper, NULL,
247190501Smr				      PFIL_IN|PFIL_OUT, ph_inet);
248190501Smr	else
249190501Smr		error = 0;
250190501Smr#  else
251190501Smr	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
252190501Smr			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
253190501Smr#  endif
254190501Smr	if (error) {
255190501Smr#   ifdef USE_INET6
256190501Smr		goto pfil_error;
257190501Smr#   else
258190501Smr		fr_deinitialise();
259190501Smr		SPL_X(s);
260190501Smr		return error;
261190501Smr#   endif
262190501Smr	}
263190501Smr#  else
264190501Smr	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
265190501Smr#  endif
266190501Smr#  ifdef USE_INET6
267190501Smr#   if __FreeBSD_version >= 501108
268190501Smr	if (ph_inet6 != NULL)
269190501Smr		error = pfil_add_hook((void *)fr_check_wrapper6, NULL,
270190501Smr				      PFIL_IN|PFIL_OUT, ph_inet6);
271190501Smr	else
272190501Smr		error = 0;
273190501Smr	if (error) {
274190501Smr		pfil_remove_hook((void *)fr_check_wrapper6, NULL,
275190501Smr				 PFIL_IN|PFIL_OUT, ph_inet6);
276190501Smr#   else
277190501Smr	error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
278190501Smr			      &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
279190501Smr	if (error) {
280190501Smr		pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
281190501Smr				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
282190501Smr#   endif
283190501Smrpfil_error:
284190501Smr		fr_deinitialise();
285190501Smr		SPL_X(s);
286190501Smr		return error;
287190501Smr	}
288190501Smr#  endif
289190501Smr# endif
290190501Smr
291190501Smr#if (__FreeBSD_version >= 502103)
292190501Smr	ipf_arrivetag =  EVENTHANDLER_REGISTER(ifnet_arrival_event, \
293190501Smr					       ipf_ifevent, NULL, \
294190501Smr					       EVENTHANDLER_PRI_ANY);
295190501Smr	ipf_departtag =  EVENTHANDLER_REGISTER(ifnet_departure_event, \
296197070Sjkim					       ipf_ifevent, NULL, \
297190501Smr					       EVENTHANDLER_PRI_ANY);
298190501Smr	ipf_clonetag =  EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
299190501Smr					      NULL, EVENTHANDLER_PRI_ANY);
300190501Smr#endif
301190501Smr
302190501Smr	if (fr_checkp != fr_check) {
303190501Smr		fr_savep = fr_checkp;
304190501Smr		fr_checkp = fr_check;
305190501Smr	}
306190501Smr
307190501Smr	bzero((char *)ipfselwait, sizeof(ipfselwait));
308190501Smr	bzero((char *)frcache, sizeof(frcache));
309190501Smr	fr_running = 1;
310192029Sbrueffer
311190501Smr	if (fr_control_forwarding & 1)
312190501Smr		ipforwarding = 1;
313190501Smr
314190501Smr	SPL_X(s);
315190501Smr#if (__FreeBSD_version >= 300000)
316190501Smr	fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
317190501Smr				    (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
318190501Smr#else
319190501Smr	timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
320190501Smr#endif
321190501Smr	return 0;
322190501Smr}
323190501Smr
324190501Smr
325190501Smr/*
326190501Smr * Disable the filter by removing the hooks from the IP input/output
327190501Smr * stream.
328190501Smr */
329190501Smrint ipldetach()
330190501Smr{
331190501Smr#ifdef USE_SPL
332190501Smr	int s;
333190501Smr#endif
334190501Smr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
335190501Smr	int error = 0;
336190501Smr# if __FreeBSD_version >= 501108
337190501Smr	struct pfil_head *ph_inet;
338190501Smr#  ifdef USE_INET6
339190501Smr	struct pfil_head *ph_inet6;
340190501Smr#  endif
341190501Smr# endif
342190501Smr#endif
343190501Smr
344190501Smr	if (fr_control_forwarding & 2)
345190501Smr		ipforwarding = 0;
346190501Smr
347190501Smr#if (__FreeBSD_version >= 502103)
348190501Smr	if (ipf_arrivetag != NULL) {
349190501Smr		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
350190501Smr	}
351190501Smr	if (ipf_departtag != NULL) {
352190501Smr		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
353190501Smr	}
354190501Smr	if (ipf_clonetag != NULL) {
355190501Smr		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
356190501Smr	}
357190501Smr#endif
358190501Smr
359190501Smr	SPL_NET(s);
360190501Smr
361190501Smr#if (__FreeBSD_version >= 300000)
362190501Smr	if (fr_slowtimer_ch.callout != NULL)
363190501Smr		untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
364190501Smr	bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
365190501Smr#else
366190501Smr	untimeout(fr_slowtimer, NULL);
367190501Smr#endif /* FreeBSD */
368190501Smr
369190501Smr#ifndef NETBSD_PF
370190501Smr	if (fr_checkp != NULL)
371190501Smr		fr_checkp = fr_savep;
372190501Smr	fr_savep = NULL;
373190501Smr#endif
374190501Smr
375190501Smr#ifdef NETBSD_PF
376190501Smr# if (__FreeBSD_version >= 500011)
377190501Smr#  if (__FreeBSD_version >= 501108)
378190501Smr	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
379190501Smr	if (ph_inet != NULL)
380190501Smr		error = pfil_remove_hook((void *)fr_check_wrapper, NULL,
381190501Smr					 PFIL_IN|PFIL_OUT, ph_inet);
382190501Smr	else
383190501Smr		error = 0;
384190501Smr#  else
385190501Smr	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
386190501Smr				 &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
387190501Smr#  endif
388190501Smr	if (error) {
389190501Smr		SPL_X(s);
390190501Smr		return error;
391190501Smr	}
392190501Smr# else
393190501Smr	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT);
394190501Smr# endif
395190501Smr# ifdef USE_INET6
396190501Smr#  if (__FreeBSD_version >= 501108)
397190501Smr	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
398190501Smr	if (ph_inet6 != NULL)
399197070Sjkim		error = pfil_remove_hook((void *)fr_check_wrapper6, NULL,
400190501Smr					 PFIL_IN|PFIL_OUT, ph_inet6);
401190501Smr	else
402190501Smr		error = 0;
403190501Smr#  else
404190501Smr	error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT,
405190501Smr				 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
406190501Smr#  endif
407190501Smr	if (error) {
408190501Smr		SPL_X(s);
409190501Smr		return error;
410190501Smr	}
411190501Smr# endif
412190501Smr#endif
413190501Smr	fr_deinitialise();
414190501Smr
415190501Smr	fr_running = -2;
416190501Smr
417190501Smr	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
418190501Smr	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
419190501Smr
420190501Smr	if (ipf_locks_done == 1) {
421190501Smr		MUTEX_DESTROY(&ipf_timeoutlock);
422190501Smr		MUTEX_DESTROY(&ipf_rw);
423190501Smr		RW_DESTROY(&ipf_mutex);
424190501Smr		RW_DESTROY(&ipf_frcache);
425190501Smr		RW_DESTROY(&ipf_ipidfrag);
426190501Smr		RW_DESTROY(&ipf_global);
427190501Smr		ipf_locks_done = 0;
428190501Smr	}
429190501Smr
430190501Smr	SPL_X(s);
431190501Smr
432190501Smr	return 0;
433190501Smr}
434190501Smr
435190501Smr
436190501Smr/*
437190501Smr * Filter ioctl interface.
438190501Smr */
439190501Smrint iplioctl(dev, cmd, data, mode
440190501Smr# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
441190501Smr, p)
442190501Smr#  if (__FreeBSD_version >= 500024)
443190501Smrstruct thread *p;
444190501Smr#  else
445190501Smrstruct proc *p;
446190501Smr#  endif /* __FreeBSD_version >= 500024 */
447190501Smr# else
448190501Smr)
449190501Smr# endif
450190501Smr#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
451190501Smrstruct cdev *dev;
452190501Smr#else
453190501Smrdev_t dev;
454190501Smr#endif
455190501Smrioctlcmd_t cmd;
456190501Smrcaddr_t data;
457190501Smrint mode;
458190501Smr{
459190501Smr#ifdef USE_SPL
460190501Smr	int s;
461190501Smr#endif
462190501Smr	int error = 0, unit = 0, tmp;
463190501Smr	friostat_t fio;
464190501Smr
465190501Smr#if (BSD >= 199306) && defined(_KERNEL)
466190501Smr	if ((securelevel >= 3) && (mode & FWRITE))
467190501Smr		return EPERM;
468190501Smr#endif
469190501Smr
470190501Smr	unit = GET_MINOR(dev);
471190501Smr	if ((IPL_LOGMAX < unit) || (unit < 0))
472190501Smr		return ENXIO;
473190501Smr
474190501Smr	if (fr_running <= 0) {
475190501Smr		if (unit != IPL_LOGIPF)
476190501Smr			return EIO;
477190501Smr		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
478190501Smr		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
479190501Smr		    cmd != SIOCGETFS && cmd != SIOCGETFF)
480190501Smr			return EIO;
481190501Smr	}
482190501Smr
483190501Smr	SPL_NET(s);
484190501Smr	READ_ENTER(&ipf_global);
485190501Smr
486190501Smr	error = fr_ioctlswitch(unit, data, cmd, mode);
487190501Smr	if (error != -1) {
488190501Smr		RWLOCK_EXIT(&ipf_global);
489190501Smr		SPL_X(s);
490190501Smr		return error;
491190501Smr	}
492190501Smr	error = 0;
493190501Smr
494190501Smr	switch (cmd)
495190501Smr	{
496190501Smr	case FIONREAD :
497190501Smr#ifdef IPFILTER_LOG
498190501Smr		BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data,
499190501Smr			 sizeof(iplused[IPL_LOGIPF]));
500190501Smr#endif
501190501Smr		break;
502190501Smr	case SIOCFRENB :
503190501Smr		if (!(mode & FWRITE))
504190501Smr			error = EPERM;
505		else {
506			BCOPYIN(data, &tmp, sizeof(tmp));
507			if (tmp) {
508				if (fr_running > 0)
509					error = 0;
510				else
511					error = iplattach();
512				if (error == 0)
513					fr_running = 1;
514				else
515					(void) ipldetach();
516			} else {
517				error = ipldetach();
518				if (error == 0)
519					fr_running = -1;
520			}
521		}
522		break;
523	case SIOCIPFSET :
524		if (!(mode & FWRITE)) {
525			error = EPERM;
526			break;
527		}
528	case SIOCIPFGETNEXT :
529	case SIOCIPFGET :
530		error = fr_ipftune(cmd, data);
531		break;
532	case SIOCSETFF :
533		if (!(mode & FWRITE))
534			error = EPERM;
535		else
536			BCOPYIN(data, &fr_flags, sizeof(fr_flags));
537		break;
538	case SIOCGETFF :
539		BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
540		break;
541	case SIOCFUNCL :
542		error = fr_resolvefunc(data);
543		break;
544	case SIOCINAFR :
545	case SIOCRMAFR :
546	case SIOCADAFR :
547	case SIOCZRLST :
548		if (!(mode & FWRITE))
549			error = EPERM;
550		else
551			error = frrequest(unit, cmd, data, fr_active, 1);
552		break;
553	case SIOCINIFR :
554	case SIOCRMIFR :
555	case SIOCADIFR :
556		if (!(mode & FWRITE))
557			error = EPERM;
558		else
559			error = frrequest(unit, cmd, data, 1 - fr_active, 1);
560		break;
561	case SIOCSWAPA :
562		if (!(mode & FWRITE))
563			error = EPERM;
564		else {
565			bzero((char *)frcache, sizeof(frcache[0]) * 2);
566			*(u_int *)data = fr_active;
567			fr_active = 1 - fr_active;
568		}
569		break;
570	case SIOCGETFS :
571		fr_getstat(&fio);
572		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
573		break;
574	case SIOCFRZST :
575		if (!(mode & FWRITE))
576			error = EPERM;
577		else
578			error = fr_zerostats(data);
579		break;
580	case SIOCIPFFL :
581		if (!(mode & FWRITE))
582			error = EPERM;
583		else {
584			BCOPYIN(data, &tmp, sizeof(tmp));
585			tmp = frflush(unit, 4, tmp);
586			BCOPYOUT(&tmp, data, sizeof(tmp));
587		}
588		break;
589#ifdef USE_INET6
590	case SIOCIPFL6 :
591		if (!(mode & FWRITE))
592			error = EPERM;
593		else {
594			BCOPYIN(data, &tmp, sizeof(tmp));
595			tmp = frflush(unit, 6, tmp);
596			BCOPYOUT(&tmp, data, sizeof(tmp));
597		}
598		break;
599#endif
600	case SIOCSTLCK :
601		BCOPYIN(data, &tmp, sizeof(tmp));
602		fr_state_lock = tmp;
603		fr_nat_lock = tmp;
604		fr_frag_lock = tmp;
605		fr_auth_lock = tmp;
606		break;
607#ifdef IPFILTER_LOG
608	case SIOCIPFFB :
609		if (!(mode & FWRITE))
610			error = EPERM;
611		else
612			*(int *)data = ipflog_clear(unit);
613		break;
614#endif /* IPFILTER_LOG */
615	case SIOCGFRST :
616		error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT);
617		break;
618	case SIOCFRSYN :
619		if (!(mode & FWRITE))
620			error = EPERM;
621		else {
622			frsync(NULL);
623		}
624		break;
625	default :
626		error = EINVAL;
627		break;
628	}
629
630	RWLOCK_EXIT(&ipf_global);
631	SPL_X(s);
632
633	return error;
634}
635
636
637#if 0
638void fr_forgetifp(ifp)
639void *ifp;
640{
641	register frentry_t *f;
642
643	WRITE_ENTER(&ipf_mutex);
644	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
645		if (f->fr_ifa == ifp)
646			f->fr_ifa = (void *)-1;
647	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
648		if (f->fr_ifa == ifp)
649			f->fr_ifa = (void *)-1;
650	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
651		if (f->fr_ifa == ifp)
652			f->fr_ifa = (void *)-1;
653	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
654		if (f->fr_ifa == ifp)
655			f->fr_ifa = (void *)-1;
656#ifdef USE_INET6
657	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
658		if (f->fr_ifa == ifp)
659			f->fr_ifa = (void *)-1;
660	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
661		if (f->fr_ifa == ifp)
662			f->fr_ifa = (void *)-1;
663	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
664		if (f->fr_ifa == ifp)
665			f->fr_ifa = (void *)-1;
666	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
667		if (f->fr_ifa == ifp)
668			f->fr_ifa = (void *)-1;
669#endif
670	RWLOCK_EXIT(&ipf_mutex);
671	fr_natsync(ifp);
672}
673#endif
674
675
676/*
677 * routines below for saving IP headers to buffer
678 */
679int iplopen(dev, flags
680#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
681, devtype, p)
682int devtype;
683# if (__FreeBSD_version >= 500024)
684struct thread *p;
685# else
686struct proc *p;
687# endif /* __FreeBSD_version >= 500024 */
688#else
689)
690#endif
691#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
692struct cdev *dev;
693#else
694dev_t dev;
695#endif
696int flags;
697{
698	u_int min = GET_MINOR(dev);
699
700	if (IPL_LOGMAX < min)
701		min = ENXIO;
702	else
703		min = 0;
704	return min;
705}
706
707
708int iplclose(dev, flags
709#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
710, devtype, p)
711int devtype;
712# if (__FreeBSD_version >= 500024)
713struct thread *p;
714# else
715struct proc *p;
716# endif /* __FreeBSD_version >= 500024 */
717#else
718)
719#endif
720#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
721struct cdev *dev;
722#else
723dev_t dev;
724#endif
725int flags;
726{
727	u_int	min = GET_MINOR(dev);
728
729	if (IPL_LOGMAX < min)
730		min = ENXIO;
731	else
732		min = 0;
733	return min;
734}
735
736/*
737 * iplread/ipllog
738 * both of these must operate with at least splnet() lest they be
739 * called during packet processing and cause an inconsistancy to appear in
740 * the filter lists.
741 */
742#if (BSD >= 199306)
743int iplread(dev, uio, ioflag)
744int ioflag;
745#else
746int iplread(dev, uio)
747#endif
748#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
749struct cdev *dev;
750#else
751dev_t dev;
752#endif
753register struct uio *uio;
754{
755	u_int	xmin = GET_MINOR(dev);
756
757	if (xmin < 0)
758		return ENXIO;
759
760# ifdef	IPFILTER_SYNC
761	if (xmin == IPL_LOGSYNC)
762		return ipfsync_read(uio);
763# endif
764
765#ifdef IPFILTER_LOG
766	return ipflog_read(xmin, uio);
767#else
768	return ENXIO;
769#endif
770}
771
772
773/*
774 * iplwrite
775 * both of these must operate with at least splnet() lest they be
776 * called during packet processing and cause an inconsistancy to appear in
777 * the filter lists.
778 */
779#if (BSD >= 199306)
780int iplwrite(dev, uio, ioflag)
781int ioflag;
782#else
783int iplwrite(dev, uio)
784#endif
785#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
786struct cdev *dev;
787#else
788dev_t dev;
789#endif
790register struct uio *uio;
791{
792
793#ifdef	IPFILTER_SYNC
794	if (GET_MINOR(dev) == IPL_LOGSYNC)
795		return ipfsync_write(uio);
796#endif
797	return ENXIO;
798}
799
800
801/*
802 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
803 * requires a large amount of setting up and isn't any more efficient.
804 */
805int fr_send_reset(fin)
806fr_info_t *fin;
807{
808	struct tcphdr *tcp, *tcp2;
809	int tlen = 0, hlen;
810	struct mbuf *m;
811#ifdef USE_INET6
812	ip6_t *ip6;
813#endif
814	ip_t *ip;
815
816	tcp = fin->fin_dp;
817	if (tcp->th_flags & TH_RST)
818		return -1;		/* feedback loop */
819
820#ifndef	IPFILTER_CKSUM
821	if (fr_checkl4sum(fin) == -1)
822		return -1;
823#endif
824
825	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
826			((tcp->th_flags & TH_SYN) ? 1 : 0) +
827			((tcp->th_flags & TH_FIN) ? 1 : 0);
828
829#ifdef USE_INET6
830	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
831#else
832	hlen = sizeof(ip_t);
833#endif
834#ifdef MGETHDR
835	MGETHDR(m, M_DONTWAIT, MT_HEADER);
836#else
837	MGET(m, M_DONTWAIT, MT_HEADER);
838#endif
839	if (m == NULL)
840		return -1;
841	if (sizeof(*tcp2) + hlen > MLEN) {
842		MCLGET(m, M_DONTWAIT);
843		if ((m->m_flags & M_EXT) == 0) {
844			FREE_MB_T(m);
845			return -1;
846		}
847	}
848
849	m->m_len = sizeof(*tcp2) + hlen;
850#if (BSD >= 199103)
851	m->m_data += max_linkhdr;
852	m->m_pkthdr.len = m->m_len;
853	m->m_pkthdr.rcvif = (struct ifnet *)0;
854#endif
855	ip = mtod(m, struct ip *);
856	bzero((char *)ip, hlen);
857#ifdef USE_INET6
858	ip6 = (ip6_t *)ip;
859#endif
860	tcp2 = (struct tcphdr *)((char *)ip + hlen);
861	tcp2->th_sport = tcp->th_dport;
862	tcp2->th_dport = tcp->th_sport;
863
864	if (tcp->th_flags & TH_ACK) {
865		tcp2->th_seq = tcp->th_ack;
866		tcp2->th_flags = TH_RST;
867		tcp2->th_ack = 0;
868	} else {
869		tcp2->th_seq = 0;
870		tcp2->th_ack = ntohl(tcp->th_seq);
871		tcp2->th_ack += tlen;
872		tcp2->th_ack = htonl(tcp2->th_ack);
873		tcp2->th_flags = TH_RST|TH_ACK;
874	}
875	TCP_X2_A(tcp2, 0);
876	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
877	tcp2->th_win = tcp->th_win;
878	tcp2->th_sum = 0;
879	tcp2->th_urp = 0;
880
881#ifdef USE_INET6
882	if (fin->fin_v == 6) {
883		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
884		ip6->ip6_plen = htons(sizeof(struct tcphdr));
885		ip6->ip6_nxt = IPPROTO_TCP;
886		ip6->ip6_hlim = 0;
887		ip6->ip6_src = fin->fin_dst6;
888		ip6->ip6_dst = fin->fin_src6;
889		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
890					 sizeof(*ip6), sizeof(*tcp2));
891		return fr_send_ip(fin, m, &m);
892	}
893#endif
894	ip->ip_p = IPPROTO_TCP;
895	ip->ip_len = htons(sizeof(struct tcphdr));
896	ip->ip_src.s_addr = fin->fin_daddr;
897	ip->ip_dst.s_addr = fin->fin_saddr;
898	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
899	ip->ip_len = hlen + sizeof(*tcp2);
900	return fr_send_ip(fin, m, &m);
901}
902
903
904static int fr_send_ip(fin, m, mpp)
905fr_info_t *fin;
906mb_t *m, **mpp;
907{
908	fr_info_t fnew;
909	ip_t *ip, *oip;
910	int hlen;
911
912	ip = mtod(m, ip_t *);
913	bzero((char *)&fnew, sizeof(fnew));
914
915	IP_V_A(ip, fin->fin_v);
916	switch (fin->fin_v)
917	{
918	case 4 :
919		fnew.fin_v = 4;
920		oip = fin->fin_ip;
921		IP_HL_A(ip, sizeof(*oip) >> 2);
922		ip->ip_tos = oip->ip_tos;
923		ip->ip_id = fin->fin_ip->ip_id;
924#if (__FreeBSD_version > 460000)
925		ip->ip_off = path_mtu_discovery ? IP_DF : 0;
926#else
927		ip->ip_off = 0;
928#endif
929		ip->ip_ttl = ip_defttl;
930		ip->ip_sum = 0;
931		hlen = sizeof(*oip);
932		break;
933#ifdef USE_INET6
934	case 6 :
935	{
936		ip6_t *ip6 = (ip6_t *)ip;
937
938		ip6->ip6_vfc = 0x60;
939		ip6->ip6_hlim = IPDEFTTL;
940
941		fnew.fin_v = 6;
942		hlen = sizeof(*ip6);
943		break;
944	}
945#endif
946	default :
947		return EINVAL;
948	}
949#ifdef IPSEC
950	m->m_pkthdr.rcvif = NULL;
951#endif
952
953	fnew.fin_ifp = fin->fin_ifp;
954	fnew.fin_flx = FI_NOCKSUM;
955	fnew.fin_m = m;
956	fnew.fin_ip = ip;
957	fnew.fin_mp = mpp;
958	fnew.fin_hlen = hlen;
959	fnew.fin_dp = (char *)ip + hlen;
960	(void) fr_makefrip(hlen, ip, &fnew);
961
962	return fr_fastroute(m, mpp, &fnew, NULL);
963}
964
965
966int fr_send_icmp_err(type, fin, dst)
967int type;
968fr_info_t *fin;
969int dst;
970{
971	int err, hlen, xtra, iclen, ohlen, avail, code;
972	struct in_addr dst4;
973	struct icmp *icmp;
974	struct mbuf *m;
975	void *ifp;
976#ifdef USE_INET6
977	ip6_t *ip6;
978	struct in6_addr dst6;
979#endif
980	ip_t *ip, *ip2;
981
982	if ((type < 0) || (type > ICMP_MAXTYPE))
983		return -1;
984
985	code = fin->fin_icode;
986#ifdef USE_INET6
987	if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
988		return -1;
989#endif
990
991#ifndef	IPFILTER_CKSUM
992	if (fr_checkl4sum(fin) == -1)
993		return -1;
994#endif
995#ifdef MGETHDR
996	MGETHDR(m, M_DONTWAIT, MT_HEADER);
997#else
998	MGET(m, M_DONTWAIT, MT_HEADER);
999#endif
1000	if (m == NULL)
1001		return -1;
1002	avail = MHLEN;
1003
1004	xtra = 0;
1005	hlen = 0;
1006	ohlen = 0;
1007	ifp = fin->fin_ifp;
1008	if (fin->fin_v == 4) {
1009		if ((fin->fin_p == IPPROTO_ICMP) &&
1010		    !(fin->fin_flx & FI_SHORT))
1011			switch (ntohs(fin->fin_data[0]) >> 8)
1012			{
1013			case ICMP_ECHO :
1014			case ICMP_TSTAMP :
1015			case ICMP_IREQ :
1016			case ICMP_MASKREQ :
1017				break;
1018			default :
1019				FREE_MB_T(m);
1020				return 0;
1021			}
1022
1023		if (dst == 0) {
1024			if (fr_ifpaddr(4, FRI_NORMAL, ifp,
1025				       &dst4, NULL) == -1) {
1026				FREE_MB_T(m);
1027				return -1;
1028			}
1029		} else
1030			dst4.s_addr = fin->fin_daddr;
1031
1032		hlen = sizeof(ip_t);
1033		ohlen = fin->fin_hlen;
1034		if (fin->fin_hlen < fin->fin_plen)
1035			xtra = MIN(fin->fin_dlen, 8);
1036		else
1037			xtra = 0;
1038	}
1039
1040#ifdef USE_INET6
1041	else if (fin->fin_v == 6) {
1042		hlen = sizeof(ip6_t);
1043		ohlen = sizeof(ip6_t);
1044		type = icmptoicmp6types[type];
1045		if (type == ICMP6_DST_UNREACH)
1046			code = icmptoicmp6unreach[code];
1047
1048		if (hlen + sizeof(*icmp) + max_linkhdr +
1049		    fin->fin_plen > avail) {
1050			MCLGET(m, M_DONTWAIT);
1051			if ((m->m_flags & M_EXT) == 0) {
1052				FREE_MB_T(m);
1053				return -1;
1054			}
1055			avail = MCLBYTES;
1056		}
1057		xtra = MIN(fin->fin_plen,
1058			   avail - hlen - sizeof(*icmp) - max_linkhdr);
1059		if (dst == 0) {
1060			if (fr_ifpaddr(6, FRI_NORMAL, ifp,
1061				       (struct in_addr *)&dst6, NULL) == -1) {
1062				FREE_MB_T(m);
1063				return -1;
1064			}
1065		} else
1066			dst6 = fin->fin_dst6;
1067	}
1068#endif
1069	else {
1070		FREE_MB_T(m);
1071		return -1;
1072	}
1073
1074	iclen = hlen + sizeof(*icmp);
1075	avail -= (max_linkhdr + iclen);
1076	if (avail < 0) {
1077		FREE_MB_T(m);
1078		return -1;
1079	}
1080	if (xtra > avail)
1081		xtra = avail;
1082	iclen += xtra;
1083	m->m_data += max_linkhdr;
1084	m->m_pkthdr.rcvif = (struct ifnet *)0;
1085	m->m_pkthdr.len = iclen;
1086	m->m_len = iclen;
1087	ip = mtod(m, ip_t *);
1088	icmp = (struct icmp *)((char *)ip + hlen);
1089	ip2 = (ip_t *)&icmp->icmp_ip;
1090
1091	icmp->icmp_type = type;
1092	icmp->icmp_code = fin->fin_icode;
1093	icmp->icmp_cksum = 0;
1094#ifdef icmp_nextmtu
1095	if (type == ICMP_UNREACH &&
1096	    fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
1097		icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
1098#endif
1099
1100	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
1101
1102#ifdef USE_INET6
1103	ip6 = (ip6_t *)ip;
1104	if (fin->fin_v == 6) {
1105		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
1106		ip6->ip6_plen = htons(iclen - hlen);
1107		ip6->ip6_nxt = IPPROTO_ICMPV6;
1108		ip6->ip6_hlim = 0;
1109		ip6->ip6_src = dst6;
1110		ip6->ip6_dst = fin->fin_src6;
1111		if (xtra > 0)
1112			bcopy((char *)fin->fin_ip + ohlen,
1113			      (char *)&icmp->icmp_ip + ohlen, xtra);
1114		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
1115					     sizeof(*ip6), iclen - hlen);
1116	} else
1117#endif
1118	{
1119		ip2->ip_len = htons(ip2->ip_len);
1120		ip2->ip_off = htons(ip2->ip_off);
1121		ip->ip_p = IPPROTO_ICMP;
1122		ip->ip_src.s_addr = dst4.s_addr;
1123		ip->ip_dst.s_addr = fin->fin_saddr;
1124
1125		if (xtra > 0)
1126			bcopy((char *)fin->fin_ip + ohlen,
1127			      (char *)&icmp->icmp_ip + ohlen, xtra);
1128		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
1129					     sizeof(*icmp) + 8);
1130		ip->ip_len = iclen;
1131		ip->ip_p = IPPROTO_ICMP;
1132	}
1133	err = fr_send_ip(fin, m, &m);
1134	return err;
1135}
1136
1137
1138#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
1139# if	(BSD < 199306)
1140int iplinit __P((void));
1141
1142int
1143# else
1144void iplinit __P((void));
1145
1146void
1147# endif
1148iplinit()
1149{
1150	if (iplattach() != 0)
1151		printf("IP Filter failed to attach\n");
1152	ip_init();
1153}
1154#endif /* __FreeBSD_version < 300000 */
1155
1156
1157int fr_fastroute(m0, mpp, fin, fdp)
1158mb_t *m0, **mpp;
1159fr_info_t *fin;
1160frdest_t *fdp;
1161{
1162	register struct ip *ip, *mhip;
1163	register struct mbuf *m = m0;
1164	register struct route *ro;
1165	int len, off, error = 0, hlen, code;
1166	struct ifnet *ifp, *sifp;
1167	struct sockaddr_in *dst;
1168	struct route iproute;
1169	u_short ip_off;
1170	frentry_t *fr;
1171
1172	ro = NULL;
1173
1174#ifdef M_WRITABLE
1175	/*
1176	* HOT FIX/KLUDGE:
1177	*
1178	* If the mbuf we're about to send is not writable (because of
1179	* a cluster reference, for example) we'll need to make a copy
1180	* of it since this routine modifies the contents.
1181	*
1182	* If you have non-crappy network hardware that can transmit data
1183	* from the mbuf, rather than making a copy, this is gonna be a
1184	* problem.
1185	*/
1186	if (M_WRITABLE(m) == 0) {
1187		m0 = m_dup(m, M_DONTWAIT);
1188		if (m0 != 0) {
1189			FREE_MB_T(m);
1190			m = m0;
1191			*mpp = m;
1192		} else {
1193			error = ENOBUFS;
1194			FREE_MB_T(m);
1195			goto done;
1196		}
1197	}
1198#endif
1199
1200#ifdef USE_INET6
1201	if (fin->fin_v == 6) {
1202		/*
1203		 * currently "to <if>" and "to <if>:ip#" are not supported
1204		 * for IPv6
1205		 */
1206#if  (__FreeBSD_version >= 490000)
1207		return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
1208#else
1209		return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
1210#endif
1211	}
1212#endif
1213
1214	hlen = fin->fin_hlen;
1215	ip = mtod(m0, struct ip *);
1216
1217	/*
1218	 * Route packet.
1219	 */
1220	ro = &iproute;
1221	bzero((caddr_t)ro, sizeof (*ro));
1222	dst = (struct sockaddr_in *)&ro->ro_dst;
1223	dst->sin_family = AF_INET;
1224	dst->sin_addr = ip->ip_dst;
1225
1226	fr = fin->fin_fr;
1227	if (fdp != NULL)
1228		ifp = fdp->fd_ifp;
1229	else
1230		ifp = fin->fin_ifp;
1231
1232	if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
1233		error = -2;
1234		goto bad;
1235	}
1236
1237	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
1238		dst->sin_addr = fdp->fd_ip;
1239
1240	dst->sin_len = sizeof(*dst);
1241	rtalloc(ro);
1242
1243	if ((ifp == NULL) && (ro->ro_rt != NULL))
1244		ifp = ro->ro_rt->rt_ifp;
1245
1246	if ((ro->ro_rt == NULL) || (ifp == NULL)) {
1247		if (in_localaddr(ip->ip_dst))
1248			error = EHOSTUNREACH;
1249		else
1250			error = ENETUNREACH;
1251		goto bad;
1252	}
1253	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
1254		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
1255	if (ro->ro_rt)
1256		ro->ro_rt->rt_use++;
1257
1258	/*
1259	 * For input packets which are being "fastrouted", they won't
1260	 * go back through output filtering and miss their chance to get
1261	 * NAT'd and counted.
1262	 */
1263	if (fin->fin_out == 0) {
1264		sifp = fin->fin_ifp;
1265		fin->fin_ifp = ifp;
1266		fin->fin_out = 1;
1267		(void) fr_acctpkt(fin, NULL);
1268		fin->fin_fr = NULL;
1269		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
1270			u_32_t pass;
1271
1272			(void) fr_checkstate(fin, &pass);
1273		}
1274
1275		switch (fr_checknatout(fin, NULL))
1276		{
1277		case 0 :
1278			break;
1279		case 1 :
1280			ip->ip_sum = 0;
1281			break;
1282		case -1 :
1283			error = -1;
1284			goto done;
1285			break;
1286		}
1287
1288		fin->fin_ifp = sifp;
1289		fin->fin_out = 0;
1290	} else
1291		ip->ip_sum = 0;
1292	/*
1293	 * If small enough for interface, can just send directly.
1294	 */
1295	if (ip->ip_len <= ifp->if_mtu) {
1296		ip->ip_len = htons(ip->ip_len);
1297		ip->ip_off = htons(ip->ip_off);
1298
1299		if (!ip->ip_sum)
1300			ip->ip_sum = in_cksum(m, hlen);
1301		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1302					  ro->ro_rt);
1303		goto done;
1304	}
1305	/*
1306	 * Too large for interface; fragment if possible.
1307	 * Must be able to put at least 8 bytes per fragment.
1308	 */
1309	ip_off = ntohs(ip->ip_off);
1310	if (ip_off & IP_DF) {
1311		error = EMSGSIZE;
1312		goto bad;
1313	}
1314	len = (ifp->if_mtu - hlen) &~ 7;
1315	if (len < 8) {
1316		error = EMSGSIZE;
1317		goto bad;
1318	}
1319
1320    {
1321	int mhlen, firstlen = len;
1322	struct mbuf **mnext = &m->m_act;
1323
1324	/*
1325	 * Loop through length of segment after first fragment,
1326	 * make new header and copy data of each part and link onto chain.
1327	 */
1328	m0 = m;
1329	mhlen = sizeof (struct ip);
1330	for (off = hlen + len; off < ip->ip_len; off += len) {
1331#ifdef MGETHDR
1332		MGETHDR(m, M_DONTWAIT, MT_HEADER);
1333#else
1334		MGET(m, M_DONTWAIT, MT_HEADER);
1335#endif
1336		if (m == 0) {
1337			m = m0;
1338			error = ENOBUFS;
1339			goto bad;
1340		}
1341		m->m_data += max_linkhdr;
1342		mhip = mtod(m, struct ip *);
1343		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1344		if (hlen > sizeof (struct ip)) {
1345			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1346			IP_HL_A(mhip, mhlen >> 2);
1347		}
1348		m->m_len = mhlen;
1349		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
1350		if (off + len >= ip->ip_len)
1351			len = ip->ip_len - off;
1352		else
1353			mhip->ip_off |= IP_MF;
1354		mhip->ip_len = htons((u_short)(len + mhlen));
1355		*mnext = m;
1356		m->m_next = m_copy(m0, off, len);
1357		if (m->m_next == 0) {
1358			error = ENOBUFS;	/* ??? */
1359			goto sendorfree;
1360		}
1361		m->m_pkthdr.len = mhlen + len;
1362		m->m_pkthdr.rcvif = NULL;
1363		mhip->ip_off = htons((u_short)mhip->ip_off);
1364		mhip->ip_sum = 0;
1365		mhip->ip_sum = in_cksum(m, mhlen);
1366		mnext = &m->m_act;
1367	}
1368	/*
1369	 * Update first fragment by trimming what's been copied out
1370	 * and updating header, then send each fragment (in order).
1371	 */
1372	m_adj(m0, hlen + firstlen - ip->ip_len);
1373	ip->ip_len = htons((u_short)(hlen + firstlen));
1374	ip->ip_off = htons((u_short)IP_MF);
1375	ip->ip_sum = 0;
1376	ip->ip_sum = in_cksum(m0, hlen);
1377sendorfree:
1378	for (m = m0; m; m = m0) {
1379		m0 = m->m_act;
1380		m->m_act = 0;
1381		if (error == 0)
1382			error = (*ifp->if_output)(ifp, m,
1383			    (struct sockaddr *)dst, ro->ro_rt);
1384		else
1385			FREE_MB_T(m);
1386	}
1387    }
1388done:
1389	if (!error)
1390		fr_frouteok[0]++;
1391	else
1392		fr_frouteok[1]++;
1393
1394	if ((ro != NULL) && (ro->ro_rt != NULL)) {
1395		RTFREE(ro->ro_rt);
1396	}
1397	*mpp = NULL;
1398	return 0;
1399bad:
1400	if (error == EMSGSIZE) {
1401		sifp = fin->fin_ifp;
1402		code = fin->fin_icode;
1403		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1404		fin->fin_ifp = ifp;
1405		(void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
1406		fin->fin_ifp = sifp;
1407		fin->fin_icode = code;
1408	}
1409	FREE_MB_T(m);
1410	goto done;
1411}
1412
1413
1414int fr_verifysrc(fin)
1415fr_info_t *fin;
1416{
1417	struct sockaddr_in *dst;
1418	struct route iproute;
1419
1420	bzero((char *)&iproute, sizeof(iproute));
1421	dst = (struct sockaddr_in *)&iproute.ro_dst;
1422	dst->sin_len = sizeof(*dst);
1423	dst->sin_family = AF_INET;
1424	dst->sin_addr = fin->fin_src;
1425	rtalloc(&iproute);
1426	if (iproute.ro_rt == NULL)
1427		return 0;
1428	return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
1429}
1430
1431
1432/*
1433 * return the first IP Address associated with an interface
1434 */
1435int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
1436int v, atype;
1437void *ifptr;
1438struct in_addr *inp, *inpmask;
1439{
1440#ifdef USE_INET6
1441	struct in6_addr *inp6 = NULL;
1442#endif
1443	struct sockaddr *sock, *mask;
1444	struct sockaddr_in *sin;
1445	struct ifaddr *ifa;
1446	struct ifnet *ifp;
1447
1448	if ((ifptr == NULL) || (ifptr == (void *)-1))
1449		return -1;
1450
1451	sin = NULL;
1452	ifp = ifptr;
1453
1454	if (v == 4)
1455		inp->s_addr = 0;
1456#ifdef USE_INET6
1457	else if (v == 6)
1458		bzero((char *)inp, sizeof(struct in6_addr));
1459#endif
1460#if  (__FreeBSD_version >= 300000)
1461	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1462#else
1463	ifa = ifp->if_addrlist;
1464#endif /* __FreeBSD_version >= 300000 */
1465
1466	sock = ifa->ifa_addr;
1467	while (sock != NULL && ifa != NULL) {
1468		sin = (struct sockaddr_in *)sock;
1469		if ((v == 4) && (sin->sin_family == AF_INET))
1470			break;
1471#ifdef USE_INET6
1472		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1473			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1474			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1475			    !IN6_IS_ADDR_LOOPBACK(inp6))
1476				break;
1477		}
1478#endif
1479#if (__FreeBSD_version >= 300000)
1480		ifa = TAILQ_NEXT(ifa, ifa_link);
1481#else
1482		ifa = ifa->ifa_next;
1483#endif /* __FreeBSD_version >= 300000 */
1484		if (ifa != NULL)
1485			sock = ifa->ifa_addr;
1486	}
1487
1488	if (ifa == NULL || sin == NULL)
1489		return -1;
1490
1491	mask = ifa->ifa_netmask;
1492	if (atype == FRI_BROADCAST)
1493		sock = ifa->ifa_broadaddr;
1494	else if (atype == FRI_PEERADDR)
1495		sock = ifa->ifa_dstaddr;
1496
1497	if (sock == NULL)
1498		return -1;
1499
1500#ifdef USE_INET6
1501	if (v == 6) {
1502		return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1503					(struct sockaddr_in6 *)mask,
1504					inp, inpmask);
1505	}
1506#endif
1507	return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1508				(struct sockaddr_in *)mask, inp, inpmask);
1509}
1510
1511
1512u_32_t fr_newisn(fin)
1513fr_info_t *fin;
1514{
1515	u_32_t newiss;
1516#if  (__FreeBSD_version >= 400000)
1517	newiss = arc4random();
1518#else
1519	static iss_seq_off = 0;
1520	u_char hash[16];
1521	MD5_CTX ctx;
1522
1523	/*
1524	 * Compute the base value of the ISS.  It is a hash
1525	 * of (saddr, sport, daddr, dport, secret).
1526	 */
1527	MD5Init(&ctx);
1528
1529	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1530		  sizeof(fin->fin_fi.fi_src));
1531	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1532		  sizeof(fin->fin_fi.fi_dst));
1533	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1534
1535	MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
1536
1537	MD5Final(hash, &ctx);
1538
1539	memcpy(&newiss, hash, sizeof(newiss));
1540
1541	/*
1542	 * Now increment our "timer", and add it in to
1543	 * the computed value.
1544	 *
1545	 * XXX Use `addin'?
1546	 * XXX TCP_ISSINCR too large to use?
1547	 */
1548	iss_seq_off += 0x00010000;
1549	newiss += iss_seq_off;
1550#endif
1551	return newiss;
1552}
1553
1554
1555/* ------------------------------------------------------------------------ */
1556/* Function:    fr_nextipid                                                 */
1557/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1558/* Parameters:  fin(I) - pointer to packet information                      */
1559/*                                                                          */
1560/* Returns the next IPv4 ID to use for this packet.                         */
1561/* ------------------------------------------------------------------------ */
1562u_short fr_nextipid(fin)
1563fr_info_t *fin;
1564{
1565#ifndef	RANDOM_IP_ID
1566	static u_short ipid = 0;
1567	u_short id;
1568
1569	MUTEX_ENTER(&ipf_rw);
1570	id = ipid++;
1571	MUTEX_EXIT(&ipf_rw);
1572#else
1573	u_short id;
1574
1575	id = ip_randomid();
1576#endif
1577
1578	return id;
1579}
1580
1581
1582INLINE void fr_checkv4sum(fin)
1583fr_info_t *fin;
1584{
1585#ifdef CSUM_DATA_VALID
1586	int manual = 0;
1587	u_short sum;
1588	ip_t *ip;
1589	mb_t *m;
1590
1591	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1592		return;
1593
1594	m = fin->fin_m;
1595	if (m == NULL) {
1596		manual = 1;
1597		goto skipauto;
1598	}
1599	ip = fin->fin_ip;
1600
1601	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1602		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1603			sum = m->m_pkthdr.csum_data;
1604		else
1605			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1606					htonl(m->m_pkthdr.csum_data +
1607					fin->fin_ip->ip_len + fin->fin_p));
1608		sum ^= 0xffff;
1609		if (sum != 0)
1610			fin->fin_flx |= FI_BAD;
1611	} else
1612		manual = 1;
1613skipauto:
1614# ifdef IPFILTER_CKSUM
1615	if (manual != 0)
1616		if (fr_checkl4sum(fin) == -1)
1617			fin->fin_flx |= FI_BAD;
1618# else
1619	;
1620# endif
1621#else
1622# ifdef IPFILTER_CKSUM
1623	if (fr_checkl4sum(fin) == -1)
1624		fin->fin_flx |= FI_BAD;
1625# endif
1626#endif
1627}
1628
1629
1630#ifdef USE_INET6
1631INLINE void fr_checkv6sum(fin)
1632fr_info_t *fin;
1633{
1634# ifdef IPFILTER_CKSUM
1635	if (fr_checkl4sum(fin) == -1)
1636		fin->fin_flx |= FI_BAD;
1637# endif
1638}
1639#endif /* USE_INET6 */
1640
1641
1642size_t mbufchainlen(m0)
1643struct mbuf *m0;
1644{
1645	size_t len;
1646
1647	if ((m0->m_flags & M_PKTHDR) != 0) {
1648		len = m0->m_pkthdr.len;
1649	} else {
1650		struct mbuf *m;
1651
1652		for (m = m0, len = 0; m != NULL; m = m->m_next)
1653			len += m->m_len;
1654	}
1655	return len;
1656}
1657
1658
1659/* ------------------------------------------------------------------------ */
1660/* Function:    fr_pullup                                                   */
1661/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1662/* Parameters:  m(I)   - pointer to buffer where data packet starts         */
1663/*              fin(I) - pointer to packet information                      */
1664/*              len(I) - number of bytes to pullup                          */
1665/*                                                                          */
1666/* Attempt to move at least len bytes (from the start of the buffer) into a */
1667/* single buffer for ease of access.  Operating system native functions are */
1668/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1669/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
1670/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1671/* and ONLY if the pullup succeeds.                                         */
1672/*                                                                          */
1673/* We assume that 'min' is a pointer to a buffer that is part of the chain  */
1674/* of buffers that starts at *fin->fin_mp.                                  */
1675/* ------------------------------------------------------------------------ */
1676void *fr_pullup(min, fin, len)
1677mb_t *min;
1678fr_info_t *fin;
1679int len;
1680{
1681	int out = fin->fin_out, dpoff, ipoff;
1682	mb_t *m = min;
1683	char *ip;
1684
1685	if (m == NULL)
1686		return NULL;
1687
1688	ip = (char *)fin->fin_ip;
1689	if ((fin->fin_flx & FI_COALESCE) != 0)
1690		return ip;
1691
1692	ipoff = fin->fin_ipoff;
1693	if (fin->fin_dp != NULL)
1694		dpoff = (char *)fin->fin_dp - (char *)ip;
1695	else
1696		dpoff = 0;
1697
1698	if (M_LEN(m) < len) {
1699#ifdef MHLEN
1700		/*
1701		 * Assume that M_PKTHDR is set and just work with what is left
1702		 * rather than check..
1703		 * Should not make any real difference, anyway.
1704		 */
1705		if (len > MHLEN)
1706#else
1707		if (len > MLEN)
1708#endif
1709		{
1710#ifdef HAVE_M_PULLDOWN
1711			if (m_pulldown(m, 0, len, NULL) == NULL)
1712				m = NULL;
1713#else
1714			FREE_MB_T(*fin->fin_mp);
1715			m = NULL;
1716#endif
1717		} else
1718		{
1719			m = m_pullup(m, len);
1720		}
1721		*fin->fin_mp = m;
1722		fin->fin_m = m;
1723		if (m == NULL) {
1724			ATOMIC_INCL(frstats[out].fr_pull[1]);
1725			return NULL;
1726		}
1727		ip = MTOD(m, char *) + ipoff;
1728	}
1729
1730	ATOMIC_INCL(frstats[out].fr_pull[0]);
1731	fin->fin_ip = (ip_t *)ip;
1732	if (fin->fin_dp != NULL)
1733		fin->fin_dp = (char *)fin->fin_ip + dpoff;
1734
1735	if (len == fin->fin_plen)
1736		fin->fin_flx |= FI_COALESCE;
1737	return ip;
1738}
1739