ip_fil_freebsd.c revision 195699
1/*	$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 195699 2009-07-14 22:48:30Z rwatson $	*/
2
3/*
4 * Copyright (C) 1993-2003 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#if !defined(lint)
9static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12:51:50 darrenr Exp $";
11#endif
12
13#if defined(KERNEL) || defined(_KERNEL)
14# undef KERNEL
15# undef _KERNEL
16# define	KERNEL	1
17# define	_KERNEL	1
18#endif
19#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21# include "opt_inet6.h"
22#endif
23#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25# include "opt_random_ip_id.h"
26#endif
27#include <sys/param.h>
28#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
29# if defined(IPFILTER_LKM)
30#  ifndef __FreeBSD_cc_version
31#   include <osreldate.h>
32#  else
33#   if __FreeBSD_cc_version < 430000
34#    include <osreldate.h>
35#   endif
36#  endif
37# endif
38#endif
39#include <sys/errno.h>
40#include <sys/types.h>
41#include <sys/file.h>
42#if __FreeBSD_version >= 220000
43# include <sys/fcntl.h>
44# include <sys/filio.h>
45#else
46# include <sys/ioctl.h>
47#endif
48#include <sys/time.h>
49#include <sys/systm.h>
50#if (__FreeBSD_version >= 300000)
51# include <sys/dirent.h>
52#else
53# include <sys/dir.h>
54#endif
55#if !defined(__hpux)
56# include <sys/mbuf.h>
57#endif
58#include <sys/protosw.h>
59#include <sys/socket.h>
60#if __FreeBSD_version >= 500043
61# include <sys/selinfo.h>
62#else
63# include <sys/select.h>
64#endif
65#if __FreeBSD_version >= 800044
66# include <sys/vimage.h>
67# include <netinet/tcp_var.h>
68#else
69#define V_path_mtu_discovery path_mtu_discovery
70#define V_ipforwarding ipforwarding
71#endif
72
73#include <net/if.h>
74#if __FreeBSD_version >= 300000
75# include <net/if_var.h>
76# if __FreeBSD_version >= 500043
77#  include <net/netisr.h>
78# endif
79# if !defined(IPFILTER_LKM)
80#  include "opt_ipfilter.h"
81# endif
82#endif
83#include <net/route.h>
84#include <netinet/in.h>
85#include <netinet/in_var.h>
86#include <netinet/in_systm.h>
87#include <netinet/ip.h>
88#include <netinet/ip_var.h>
89#include <netinet/tcp.h>
90#if defined(__osf__)
91# include <netinet/tcp_timer.h>
92#endif
93#include <netinet/udp.h>
94#include <netinet/tcpip.h>
95#include <netinet/ip_icmp.h>
96#ifndef _KERNEL
97# include "netinet/ipf.h"
98#endif
99#include "netinet/ip_compat.h"
100#ifdef USE_INET6
101# include <netinet/icmp6.h>
102#endif
103#include "netinet/ip_fil.h"
104#include "netinet/ip_nat.h"
105#include "netinet/ip_frag.h"
106#include "netinet/ip_state.h"
107#include "netinet/ip_proxy.h"
108#include "netinet/ip_auth.h"
109#ifdef	IPFILTER_SYNC
110#include "netinet/ip_sync.h"
111#endif
112#ifdef	IPFILTER_SCAN
113#include "netinet/ip_scan.h"
114#endif
115#include "netinet/ip_pool.h"
116#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
117# include <sys/malloc.h>
118#endif
119#include <sys/kernel.h>
120#ifdef CSUM_DATA_VALID
121#include <machine/in_cksum.h>
122#endif
123extern	int	ip_optcopy __P((struct ip *, struct ip *));
124
125#if (__FreeBSD_version > 460000) && (__FreeBSD_version < 800055)
126extern	int	path_mtu_discovery;
127#endif
128
129# ifdef IPFILTER_M_IPFILTER
130MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
131# endif
132
133
134#if !defined(__osf__)
135extern	struct	protosw	inetsw[];
136#endif
137
138static	int	(*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
139static	int	fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
140# ifdef USE_MUTEXES
141ipfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
142ipfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
143ipfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens;
144ipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
145# endif
146int		ipf_locks_done = 0;
147
148#if (__FreeBSD_version >= 300000)
149struct callout_handle fr_slowtimer_ch;
150#endif
151struct	selinfo	ipfselwait[IPL_LOGSIZE];
152
153#if (__FreeBSD_version >= 500011)
154# include <sys/conf.h>
155# if defined(NETBSD_PF)
156#  include <net/pfil.h>
157#  if (__FreeBSD_version < 501108)
158#   include <netinet/ipprotosw.h>
159#  endif
160/*
161 * We provide the fr_checkp name just to minimize changes later.
162 */
163int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
164# endif /* NETBSD_PF */
165#endif /* __FreeBSD_version >= 500011 */
166
167
168#if (__FreeBSD_version >= 502103)
169static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
170
171static void ipf_ifevent(void *arg);
172
173static void ipf_ifevent(arg)
174void *arg;
175{
176        frsync(NULL);
177}
178#endif
179
180
181#if (__FreeBSD_version >= 501108) && defined(_KERNEL)
182
183static int
184fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
185{
186	struct ip *ip = mtod(*mp, struct ip *);
187	return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
188}
189
190# ifdef USE_INET6
191#  include <netinet/ip6.h>
192
193static int
194fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
195{
196	return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
197	    ifp, (dir == PFIL_OUT), mp));
198}
199# endif
200#endif /* __FreeBSD_version >= 501108 */
201#if	defined(IPFILTER_LKM)
202int iplidentify(s)
203char *s;
204{
205	if (strcmp(s, "ipl") == 0)
206		return 1;
207	return 0;
208}
209#endif /* IPFILTER_LKM */
210
211
212int ipfattach()
213{
214#ifdef USE_SPL
215	int s;
216#endif
217
218	SPL_NET(s);
219	if (fr_running > 0) {
220		SPL_X(s);
221		return EBUSY;
222	}
223
224	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
225	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
226	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
227	RWLOCK_INIT(&ipf_tokens, "ipf token rwlock");
228	ipf_locks_done = 1;
229
230	if (fr_initialise() < 0) {
231		SPL_X(s);
232		return EIO;
233	}
234
235
236	if (fr_checkp != fr_check) {
237		fr_savep = fr_checkp;
238		fr_checkp = fr_check;
239	}
240
241	bzero((char *)ipfselwait, sizeof(ipfselwait));
242	bzero((char *)frcache, sizeof(frcache));
243	fr_running = 1;
244
245	if (fr_control_forwarding & 1)
246		V_ipforwarding = 1;
247
248	SPL_X(s);
249#if (__FreeBSD_version >= 300000)
250	fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
251				    (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
252#else
253	timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
254#endif
255	return 0;
256}
257
258
259/*
260 * Disable the filter by removing the hooks from the IP input/output
261 * stream.
262 */
263int ipfdetach()
264{
265#ifdef USE_SPL
266	int s;
267#endif
268	if (fr_control_forwarding & 2)
269		V_ipforwarding = 0;
270
271	SPL_NET(s);
272
273#if (__FreeBSD_version >= 300000)
274	if (fr_slowtimer_ch.callout != NULL)
275		untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
276	bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
277#else
278	untimeout(fr_slowtimer, NULL);
279#endif /* FreeBSD */
280
281#ifndef NETBSD_PF
282	if (fr_checkp != NULL)
283		fr_checkp = fr_savep;
284	fr_savep = NULL;
285#endif
286
287	fr_deinitialise();
288
289	fr_running = -2;
290
291	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
292	(void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
293
294	if (ipf_locks_done == 1) {
295		MUTEX_DESTROY(&ipf_timeoutlock);
296		MUTEX_DESTROY(&ipf_rw);
297		RW_DESTROY(&ipf_ipidfrag);
298		RW_DESTROY(&ipf_tokens);
299		ipf_locks_done = 0;
300	}
301
302	SPL_X(s);
303
304	return 0;
305}
306
307
308/*
309 * Filter ioctl interface.
310 */
311int iplioctl(dev, cmd, data, mode
312# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
313, p)
314#  if (__FreeBSD_version >= 500024)
315struct thread *p;
316#   if (__FreeBSD_version >= 500043)
317#    define	p_cred	td_ucred
318#    define	p_uid	td_ucred->cr_ruid
319#   else
320#    define	p_cred	t_proc->p_cred
321#    define	p_uid	t_proc->p_cred->p_ruid
322#   endif
323#  else
324struct proc *p;
325#   define	p_uid	p_cred->p_ruid
326#  endif /* __FreeBSD_version >= 500024 */
327# else
328)
329# endif
330#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
331struct cdev *dev;
332#else
333dev_t dev;
334#endif
335ioctlcmd_t cmd;
336caddr_t data;
337int mode;
338{
339	int error = 0, unit = 0;
340	SPL_INT(s);
341
342#if (BSD >= 199306) && defined(_KERNEL)
343# if (__FreeBSD_version >= 500034)
344	if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
345# else
346	if ((securelevel >= 3) && (mode & FWRITE))
347# endif
348		return EPERM;
349#endif
350
351	unit = GET_MINOR(dev);
352	if ((IPL_LOGMAX < unit) || (unit < 0))
353		return ENXIO;
354
355	if (fr_running <= 0) {
356		if (unit != IPL_LOGIPF)
357			return EIO;
358		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
359		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
360		    cmd != SIOCGETFS && cmd != SIOCGETFF)
361			return EIO;
362	}
363
364	SPL_NET(s);
365
366	error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p);
367	if (error != -1) {
368		SPL_X(s);
369		return error;
370	}
371
372	SPL_X(s);
373
374	return error;
375}
376
377
378#if 0
379void fr_forgetifp(ifp)
380void *ifp;
381{
382	register frentry_t *f;
383
384	WRITE_ENTER(&ipf_mutex);
385	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
386		if (f->fr_ifa == ifp)
387			f->fr_ifa = (void *)-1;
388	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
389		if (f->fr_ifa == ifp)
390			f->fr_ifa = (void *)-1;
391	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
392		if (f->fr_ifa == ifp)
393			f->fr_ifa = (void *)-1;
394	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
395		if (f->fr_ifa == ifp)
396			f->fr_ifa = (void *)-1;
397#ifdef USE_INET6
398	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
399		if (f->fr_ifa == ifp)
400			f->fr_ifa = (void *)-1;
401	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
402		if (f->fr_ifa == ifp)
403			f->fr_ifa = (void *)-1;
404	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
405		if (f->fr_ifa == ifp)
406			f->fr_ifa = (void *)-1;
407	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
408		if (f->fr_ifa == ifp)
409			f->fr_ifa = (void *)-1;
410#endif
411	RWLOCK_EXIT(&ipf_mutex);
412	fr_natsync(ifp);
413}
414#endif
415
416
417/*
418 * routines below for saving IP headers to buffer
419 */
420int iplopen(dev, flags
421#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
422, devtype, p)
423int devtype;
424# if (__FreeBSD_version >= 500024)
425struct thread *p;
426# else
427struct proc *p;
428# endif /* __FreeBSD_version >= 500024 */
429#else
430)
431#endif
432#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
433struct cdev *dev;
434#else
435dev_t dev;
436#endif
437int flags;
438{
439	u_int min = GET_MINOR(dev);
440
441	if (IPL_LOGMAX < min)
442		min = ENXIO;
443	else
444		min = 0;
445	return min;
446}
447
448
449int iplclose(dev, flags
450#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
451, devtype, p)
452int devtype;
453# if (__FreeBSD_version >= 500024)
454struct thread *p;
455# else
456struct proc *p;
457# endif /* __FreeBSD_version >= 500024 */
458#else
459)
460#endif
461#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
462struct cdev *dev;
463#else
464dev_t dev;
465#endif
466int flags;
467{
468	u_int	min = GET_MINOR(dev);
469
470	if (IPL_LOGMAX < min)
471		min = ENXIO;
472	else
473		min = 0;
474	return min;
475}
476
477/*
478 * iplread/ipllog
479 * both of these must operate with at least splnet() lest they be
480 * called during packet processing and cause an inconsistancy to appear in
481 * the filter lists.
482 */
483#if (BSD >= 199306)
484int iplread(dev, uio, ioflag)
485int ioflag;
486#else
487int iplread(dev, uio)
488#endif
489#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
490struct cdev *dev;
491#else
492dev_t dev;
493#endif
494register struct uio *uio;
495{
496	u_int	xmin = GET_MINOR(dev);
497
498	if (fr_running < 1)
499		return EIO;
500
501	if (xmin < 0)
502		return ENXIO;
503
504# ifdef	IPFILTER_SYNC
505	if (xmin == IPL_LOGSYNC)
506		return ipfsync_read(uio);
507# endif
508
509#ifdef IPFILTER_LOG
510	return ipflog_read(xmin, uio);
511#else
512	return ENXIO;
513#endif
514}
515
516
517/*
518 * iplwrite
519 * both of these must operate with at least splnet() lest they be
520 * called during packet processing and cause an inconsistancy to appear in
521 * the filter lists.
522 */
523#if (BSD >= 199306)
524int iplwrite(dev, uio, ioflag)
525int ioflag;
526#else
527int iplwrite(dev, uio)
528#endif
529#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
530struct cdev *dev;
531#else
532dev_t dev;
533#endif
534register struct uio *uio;
535{
536
537	if (fr_running < 1)
538		return EIO;
539
540#ifdef	IPFILTER_SYNC
541	if (GET_MINOR(dev) == IPL_LOGSYNC)
542		return ipfsync_write(uio);
543#endif
544	return ENXIO;
545}
546
547
548/*
549 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
550 * requires a large amount of setting up and isn't any more efficient.
551 */
552int fr_send_reset(fin)
553fr_info_t *fin;
554{
555	struct tcphdr *tcp, *tcp2;
556	int tlen = 0, hlen;
557	struct mbuf *m;
558#ifdef USE_INET6
559	ip6_t *ip6;
560#endif
561	ip_t *ip;
562
563	tcp = fin->fin_dp;
564	if (tcp->th_flags & TH_RST)
565		return -1;		/* feedback loop */
566
567	if (fr_checkl4sum(fin) == -1)
568		return -1;
569
570	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
571			((tcp->th_flags & TH_SYN) ? 1 : 0) +
572			((tcp->th_flags & TH_FIN) ? 1 : 0);
573
574#ifdef USE_INET6
575	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
576#else
577	hlen = sizeof(ip_t);
578#endif
579#ifdef MGETHDR
580	MGETHDR(m, M_DONTWAIT, MT_HEADER);
581#else
582	MGET(m, M_DONTWAIT, MT_HEADER);
583#endif
584	if (m == NULL)
585		return -1;
586	if (sizeof(*tcp2) + hlen > MLEN) {
587		MCLGET(m, M_DONTWAIT);
588		if ((m->m_flags & M_EXT) == 0) {
589			FREE_MB_T(m);
590			return -1;
591		}
592	}
593
594	m->m_len = sizeof(*tcp2) + hlen;
595#if (BSD >= 199103)
596	m->m_data += max_linkhdr;
597	m->m_pkthdr.len = m->m_len;
598	m->m_pkthdr.rcvif = (struct ifnet *)0;
599#endif
600	ip = mtod(m, struct ip *);
601	bzero((char *)ip, hlen);
602#ifdef USE_INET6
603	ip6 = (ip6_t *)ip;
604#endif
605	tcp2 = (struct tcphdr *)((char *)ip + hlen);
606	tcp2->th_sport = tcp->th_dport;
607	tcp2->th_dport = tcp->th_sport;
608
609	if (tcp->th_flags & TH_ACK) {
610		tcp2->th_seq = tcp->th_ack;
611		tcp2->th_flags = TH_RST;
612		tcp2->th_ack = 0;
613	} else {
614		tcp2->th_seq = 0;
615		tcp2->th_ack = ntohl(tcp->th_seq);
616		tcp2->th_ack += tlen;
617		tcp2->th_ack = htonl(tcp2->th_ack);
618		tcp2->th_flags = TH_RST|TH_ACK;
619	}
620	TCP_X2_A(tcp2, 0);
621	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
622	tcp2->th_win = tcp->th_win;
623	tcp2->th_sum = 0;
624	tcp2->th_urp = 0;
625
626#ifdef USE_INET6
627	if (fin->fin_v == 6) {
628		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
629		ip6->ip6_plen = htons(sizeof(struct tcphdr));
630		ip6->ip6_nxt = IPPROTO_TCP;
631		ip6->ip6_hlim = 0;
632		ip6->ip6_src = fin->fin_dst6;
633		ip6->ip6_dst = fin->fin_src6;
634		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
635					 sizeof(*ip6), sizeof(*tcp2));
636		return fr_send_ip(fin, m, &m);
637	}
638#endif
639	ip->ip_p = IPPROTO_TCP;
640	ip->ip_len = htons(sizeof(struct tcphdr));
641	ip->ip_src.s_addr = fin->fin_daddr;
642	ip->ip_dst.s_addr = fin->fin_saddr;
643	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
644	ip->ip_len = hlen + sizeof(*tcp2);
645	return fr_send_ip(fin, m, &m);
646}
647
648
649static int fr_send_ip(fin, m, mpp)
650fr_info_t *fin;
651mb_t *m, **mpp;
652{
653	fr_info_t fnew;
654	ip_t *ip, *oip;
655	int hlen;
656
657	ip = mtod(m, ip_t *);
658	bzero((char *)&fnew, sizeof(fnew));
659
660	IP_V_A(ip, fin->fin_v);
661	switch (fin->fin_v)
662	{
663	case 4 :
664		fnew.fin_v = 4;
665		oip = fin->fin_ip;
666		IP_HL_A(ip, sizeof(*oip) >> 2);
667		ip->ip_tos = oip->ip_tos;
668		ip->ip_id = fin->fin_ip->ip_id;
669#if (__FreeBSD_version > 460000)
670		ip->ip_off = V_path_mtu_discovery ? IP_DF : 0;
671#else
672		ip->ip_off = 0;
673#endif
674		ip->ip_ttl = V_ip_defttl;
675		ip->ip_sum = 0;
676		hlen = sizeof(*oip);
677		break;
678#ifdef USE_INET6
679	case 6 :
680	{
681		ip6_t *ip6 = (ip6_t *)ip;
682
683		ip6->ip6_vfc = 0x60;
684		ip6->ip6_hlim = IPDEFTTL;
685
686		fnew.fin_v = 6;
687		hlen = sizeof(*ip6);
688		break;
689	}
690#endif
691	default :
692		return EINVAL;
693	}
694#ifdef IPSEC
695	m->m_pkthdr.rcvif = NULL;
696#endif
697
698	fnew.fin_ifp = fin->fin_ifp;
699	fnew.fin_flx = FI_NOCKSUM;
700	fnew.fin_m = m;
701	fnew.fin_ip = ip;
702	fnew.fin_mp = mpp;
703	fnew.fin_hlen = hlen;
704	fnew.fin_dp = (char *)ip + hlen;
705	(void) fr_makefrip(hlen, ip, &fnew);
706
707	return fr_fastroute(m, mpp, &fnew, NULL);
708}
709
710
711int fr_send_icmp_err(type, fin, dst)
712int type;
713fr_info_t *fin;
714int dst;
715{
716	int err, hlen, xtra, iclen, ohlen, avail, code;
717	struct in_addr dst4;
718	struct icmp *icmp;
719	struct mbuf *m;
720	void *ifp;
721#ifdef USE_INET6
722	ip6_t *ip6;
723	struct in6_addr dst6;
724#endif
725	ip_t *ip, *ip2;
726
727	if ((type < 0) || (type >= ICMP_MAXTYPE))
728		return -1;
729
730	code = fin->fin_icode;
731#ifdef USE_INET6
732	if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
733		return -1;
734#endif
735
736	if (fr_checkl4sum(fin) == -1)
737		return -1;
738#ifdef MGETHDR
739	MGETHDR(m, M_DONTWAIT, MT_HEADER);
740#else
741	MGET(m, M_DONTWAIT, MT_HEADER);
742#endif
743	if (m == NULL)
744		return -1;
745	avail = MHLEN;
746
747	xtra = 0;
748	hlen = 0;
749	ohlen = 0;
750	ifp = fin->fin_ifp;
751	if (fin->fin_v == 4) {
752		if ((fin->fin_p == IPPROTO_ICMP) &&
753		    !(fin->fin_flx & FI_SHORT))
754			switch (ntohs(fin->fin_data[0]) >> 8)
755			{
756			case ICMP_ECHO :
757			case ICMP_TSTAMP :
758			case ICMP_IREQ :
759			case ICMP_MASKREQ :
760				break;
761			default :
762				FREE_MB_T(m);
763				return 0;
764			}
765
766		if (dst == 0) {
767			if (fr_ifpaddr(4, FRI_NORMAL, ifp,
768				       &dst4, NULL) == -1) {
769				FREE_MB_T(m);
770				return -1;
771			}
772		} else
773			dst4.s_addr = fin->fin_daddr;
774
775		hlen = sizeof(ip_t);
776		ohlen = fin->fin_hlen;
777		if (fin->fin_hlen < fin->fin_plen)
778			xtra = MIN(fin->fin_dlen, 8);
779		else
780			xtra = 0;
781	}
782
783#ifdef USE_INET6
784	else if (fin->fin_v == 6) {
785		hlen = sizeof(ip6_t);
786		ohlen = sizeof(ip6_t);
787		type = icmptoicmp6types[type];
788		if (type == ICMP6_DST_UNREACH)
789			code = icmptoicmp6unreach[code];
790
791		if (hlen + sizeof(*icmp) + max_linkhdr +
792		    fin->fin_plen > avail) {
793			MCLGET(m, M_DONTWAIT);
794			if ((m->m_flags & M_EXT) == 0) {
795				FREE_MB_T(m);
796				return -1;
797			}
798			avail = MCLBYTES;
799		}
800		xtra = MIN(fin->fin_plen,
801			   avail - hlen - sizeof(*icmp) - max_linkhdr);
802		if (dst == 0) {
803			if (fr_ifpaddr(6, FRI_NORMAL, ifp,
804				       (struct in_addr *)&dst6, NULL) == -1) {
805				FREE_MB_T(m);
806				return -1;
807			}
808		} else
809			dst6 = fin->fin_dst6;
810	}
811#endif
812	else {
813		FREE_MB_T(m);
814		return -1;
815	}
816
817	iclen = hlen + sizeof(*icmp);
818	avail -= (max_linkhdr + iclen);
819	if (avail < 0) {
820		FREE_MB_T(m);
821		return -1;
822	}
823	if (xtra > avail)
824		xtra = avail;
825	iclen += xtra;
826	m->m_data += max_linkhdr;
827	m->m_pkthdr.rcvif = (struct ifnet *)0;
828	m->m_pkthdr.len = iclen;
829	m->m_len = iclen;
830	ip = mtod(m, ip_t *);
831	icmp = (struct icmp *)((char *)ip + hlen);
832	ip2 = (ip_t *)&icmp->icmp_ip;
833
834	icmp->icmp_type = type;
835	icmp->icmp_code = fin->fin_icode;
836	icmp->icmp_cksum = 0;
837#ifdef icmp_nextmtu
838	if (type == ICMP_UNREACH &&
839	    fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
840		icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu);
841#endif
842
843	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
844
845#ifdef USE_INET6
846	ip6 = (ip6_t *)ip;
847	if (fin->fin_v == 6) {
848		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
849		ip6->ip6_plen = htons(iclen - hlen);
850		ip6->ip6_nxt = IPPROTO_ICMPV6;
851		ip6->ip6_hlim = 0;
852		ip6->ip6_src = dst6;
853		ip6->ip6_dst = fin->fin_src6;
854		if (xtra > 0)
855			bcopy((char *)fin->fin_ip + ohlen,
856			      (char *)&icmp->icmp_ip + ohlen, xtra);
857		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
858					     sizeof(*ip6), iclen - hlen);
859	} else
860#endif
861	{
862		ip2->ip_len = htons(ip2->ip_len);
863		ip2->ip_off = htons(ip2->ip_off);
864		ip->ip_p = IPPROTO_ICMP;
865		ip->ip_src.s_addr = dst4.s_addr;
866		ip->ip_dst.s_addr = fin->fin_saddr;
867
868		if (xtra > 0)
869			bcopy((char *)fin->fin_ip + ohlen,
870			      (char *)&icmp->icmp_ip + ohlen, xtra);
871		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
872					     sizeof(*icmp) + 8);
873		ip->ip_len = iclen;
874		ip->ip_p = IPPROTO_ICMP;
875	}
876	err = fr_send_ip(fin, m, &m);
877	return err;
878}
879
880
881#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
882# if	(BSD < 199306)
883int iplinit __P((void));
884
885int
886# else
887void iplinit __P((void));
888
889void
890# endif
891iplinit()
892{
893	if (ipfattach() != 0)
894		printf("IP Filter failed to attach\n");
895	ip_init();
896}
897#endif /* __FreeBSD_version < 300000 */
898
899
900/*
901 * m0 - pointer to mbuf where the IP packet starts
902 * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
903 */
904int fr_fastroute(m0, mpp, fin, fdp)
905mb_t *m0, **mpp;
906fr_info_t *fin;
907frdest_t *fdp;
908{
909	register struct ip *ip, *mhip;
910	register struct mbuf *m = *mpp;
911	register struct route *ro;
912	int len, off, error = 0, hlen, code;
913	struct ifnet *ifp, *sifp;
914	struct sockaddr_in *dst;
915	struct route iproute;
916	u_short ip_off;
917	frentry_t *fr;
918
919	ro = NULL;
920
921#ifdef M_WRITABLE
922	/*
923	* HOT FIX/KLUDGE:
924	*
925	* If the mbuf we're about to send is not writable (because of
926	* a cluster reference, for example) we'll need to make a copy
927	* of it since this routine modifies the contents.
928	*
929	* If you have non-crappy network hardware that can transmit data
930	* from the mbuf, rather than making a copy, this is gonna be a
931	* problem.
932	*/
933	if (M_WRITABLE(m) == 0) {
934		m0 = m_dup(m, M_DONTWAIT);
935		if (m0 != 0) {
936			FREE_MB_T(m);
937			m = m0;
938			*mpp = m;
939		} else {
940			error = ENOBUFS;
941			FREE_MB_T(m);
942			goto done;
943		}
944	}
945#endif
946
947#ifdef USE_INET6
948	if (fin->fin_v == 6) {
949		/*
950		 * currently "to <if>" and "to <if>:ip#" are not supported
951		 * for IPv6
952		 */
953#if  (__FreeBSD_version >= 490000)
954		return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
955#else
956		return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
957#endif
958	}
959#endif
960
961	hlen = fin->fin_hlen;
962	ip = mtod(m0, struct ip *);
963
964	/*
965	 * Route packet.
966	 */
967	ro = &iproute;
968	bzero((caddr_t)ro, sizeof (*ro));
969	dst = (struct sockaddr_in *)&ro->ro_dst;
970	dst->sin_family = AF_INET;
971	dst->sin_addr = ip->ip_dst;
972
973	fr = fin->fin_fr;
974	if (fdp != NULL)
975		ifp = fdp->fd_ifp;
976	else
977		ifp = fin->fin_ifp;
978
979	if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
980		error = -2;
981		goto bad;
982	}
983
984	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
985		dst->sin_addr = fdp->fd_ip;
986
987	dst->sin_len = sizeof(*dst);
988	in_rtalloc(ro, 0);
989
990	if ((ifp == NULL) && (ro->ro_rt != NULL))
991		ifp = ro->ro_rt->rt_ifp;
992
993	if ((ro->ro_rt == NULL) || (ifp == NULL)) {
994		if (in_localaddr(ip->ip_dst))
995			error = EHOSTUNREACH;
996		else
997			error = ENETUNREACH;
998		goto bad;
999	}
1000	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
1001		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
1002	if (ro->ro_rt)
1003		ro->ro_rt->rt_use++;
1004
1005	/*
1006	 * For input packets which are being "fastrouted", they won't
1007	 * go back through output filtering and miss their chance to get
1008	 * NAT'd and counted.  Duplicated packets aren't considered to be
1009	 * part of the normal packet stream, so do not NAT them or pass
1010	 * them through stateful checking, etc.
1011	 */
1012	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
1013		sifp = fin->fin_ifp;
1014		fin->fin_ifp = ifp;
1015		fin->fin_out = 1;
1016		(void) fr_acctpkt(fin, NULL);
1017		fin->fin_fr = NULL;
1018		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
1019			u_32_t pass;
1020
1021			if (fr_checkstate(fin, &pass) != NULL)
1022				fr_statederef((ipstate_t **)&fin->fin_state);
1023		}
1024
1025		switch (fr_checknatout(fin, NULL))
1026		{
1027		case 0 :
1028			break;
1029		case 1 :
1030			fr_natderef((nat_t **)&fin->fin_nat);
1031			ip->ip_sum = 0;
1032			break;
1033		case -1 :
1034			error = -1;
1035			goto bad;
1036			break;
1037		}
1038
1039		fin->fin_ifp = sifp;
1040		fin->fin_out = 0;
1041	} else
1042		ip->ip_sum = 0;
1043	/*
1044	 * If small enough for interface, can just send directly.
1045	 */
1046	if (ip->ip_len <= ifp->if_mtu) {
1047		ip->ip_len = htons(ip->ip_len);
1048		ip->ip_off = htons(ip->ip_off);
1049
1050		if (!ip->ip_sum)
1051			ip->ip_sum = in_cksum(m, hlen);
1052		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
1053					  ro);
1054		goto done;
1055	}
1056	/*
1057	 * Too large for interface; fragment if possible.
1058	 * Must be able to put at least 8 bytes per fragment.
1059	 */
1060	ip_off = ntohs(ip->ip_off);
1061	if (ip_off & IP_DF) {
1062		error = EMSGSIZE;
1063		goto bad;
1064	}
1065	len = (ifp->if_mtu - hlen) &~ 7;
1066	if (len < 8) {
1067		error = EMSGSIZE;
1068		goto bad;
1069	}
1070
1071    {
1072	int mhlen, firstlen = len;
1073	struct mbuf **mnext = &m->m_act;
1074
1075	/*
1076	 * Loop through length of segment after first fragment,
1077	 * make new header and copy data of each part and link onto chain.
1078	 */
1079	m0 = m;
1080	mhlen = sizeof (struct ip);
1081	for (off = hlen + len; off < ip->ip_len; off += len) {
1082#ifdef MGETHDR
1083		MGETHDR(m, M_DONTWAIT, MT_HEADER);
1084#else
1085		MGET(m, M_DONTWAIT, MT_HEADER);
1086#endif
1087		if (m == 0) {
1088			m = m0;
1089			error = ENOBUFS;
1090			goto bad;
1091		}
1092		m->m_data += max_linkhdr;
1093		mhip = mtod(m, struct ip *);
1094		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
1095		if (hlen > sizeof (struct ip)) {
1096			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
1097			IP_HL_A(mhip, mhlen >> 2);
1098		}
1099		m->m_len = mhlen;
1100		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
1101		if (off + len >= ip->ip_len)
1102			len = ip->ip_len - off;
1103		else
1104			mhip->ip_off |= IP_MF;
1105		mhip->ip_len = htons((u_short)(len + mhlen));
1106		*mnext = m;
1107		m->m_next = m_copy(m0, off, len);
1108		if (m->m_next == 0) {
1109			error = ENOBUFS;	/* ??? */
1110			goto sendorfree;
1111		}
1112		m->m_pkthdr.len = mhlen + len;
1113		m->m_pkthdr.rcvif = NULL;
1114		mhip->ip_off = htons((u_short)mhip->ip_off);
1115		mhip->ip_sum = 0;
1116		mhip->ip_sum = in_cksum(m, mhlen);
1117		mnext = &m->m_act;
1118	}
1119	/*
1120	 * Update first fragment by trimming what's been copied out
1121	 * and updating header, then send each fragment (in order).
1122	 */
1123	m_adj(m0, hlen + firstlen - ip->ip_len);
1124	ip->ip_len = htons((u_short)(hlen + firstlen));
1125	ip->ip_off = htons((u_short)IP_MF);
1126	ip->ip_sum = 0;
1127	ip->ip_sum = in_cksum(m0, hlen);
1128sendorfree:
1129	for (m = m0; m; m = m0) {
1130		m0 = m->m_act;
1131		m->m_act = 0;
1132		if (error == 0)
1133			error = (*ifp->if_output)(ifp, m,
1134			    (struct sockaddr *)dst, ro);
1135		else
1136			FREE_MB_T(m);
1137	}
1138    }
1139done:
1140	if (!error)
1141		fr_frouteok[0]++;
1142	else
1143		fr_frouteok[1]++;
1144
1145	if ((ro != NULL) && (ro->ro_rt != NULL)) {
1146		RTFREE(ro->ro_rt);
1147	}
1148	*mpp = NULL;
1149	return 0;
1150bad:
1151	if (error == EMSGSIZE) {
1152		sifp = fin->fin_ifp;
1153		code = fin->fin_icode;
1154		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
1155		fin->fin_ifp = ifp;
1156		(void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
1157		fin->fin_ifp = sifp;
1158		fin->fin_icode = code;
1159	}
1160	FREE_MB_T(m);
1161	goto done;
1162}
1163
1164
1165int fr_verifysrc(fin)
1166fr_info_t *fin;
1167{
1168	struct sockaddr_in *dst;
1169	struct route iproute;
1170
1171	bzero((char *)&iproute, sizeof(iproute));
1172	dst = (struct sockaddr_in *)&iproute.ro_dst;
1173	dst->sin_len = sizeof(*dst);
1174	dst->sin_family = AF_INET;
1175	dst->sin_addr = fin->fin_src;
1176	in_rtalloc(&iproute, 0);
1177	if (iproute.ro_rt == NULL)
1178		return 0;
1179	return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
1180}
1181
1182
1183/*
1184 * return the first IP Address associated with an interface
1185 */
1186int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
1187int v, atype;
1188void *ifptr;
1189struct in_addr *inp, *inpmask;
1190{
1191#ifdef USE_INET6
1192	struct in6_addr *inp6 = NULL;
1193#endif
1194	struct sockaddr *sock, *mask;
1195	struct sockaddr_in *sin;
1196	struct ifaddr *ifa;
1197	struct ifnet *ifp;
1198
1199	if ((ifptr == NULL) || (ifptr == (void *)-1))
1200		return -1;
1201
1202	sin = NULL;
1203	ifp = ifptr;
1204
1205	if (v == 4)
1206		inp->s_addr = 0;
1207#ifdef USE_INET6
1208	else if (v == 6)
1209		bzero((char *)inp, sizeof(struct in6_addr));
1210#endif
1211#if  (__FreeBSD_version >= 300000)
1212	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1213#else
1214	ifa = ifp->if_addrlist;
1215#endif /* __FreeBSD_version >= 300000 */
1216
1217	sock = ifa->ifa_addr;
1218	while (sock != NULL && ifa != NULL) {
1219		sin = (struct sockaddr_in *)sock;
1220		if ((v == 4) && (sin->sin_family == AF_INET))
1221			break;
1222#ifdef USE_INET6
1223		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1224			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1225			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1226			    !IN6_IS_ADDR_LOOPBACK(inp6))
1227				break;
1228		}
1229#endif
1230#if (__FreeBSD_version >= 300000)
1231		ifa = TAILQ_NEXT(ifa, ifa_link);
1232#else
1233		ifa = ifa->ifa_next;
1234#endif /* __FreeBSD_version >= 300000 */
1235		if (ifa != NULL)
1236			sock = ifa->ifa_addr;
1237	}
1238
1239	if (ifa == NULL || sin == NULL)
1240		return -1;
1241
1242	mask = ifa->ifa_netmask;
1243	if (atype == FRI_BROADCAST)
1244		sock = ifa->ifa_broadaddr;
1245	else if (atype == FRI_PEERADDR)
1246		sock = ifa->ifa_dstaddr;
1247
1248	if (sock == NULL)
1249		return -1;
1250
1251#ifdef USE_INET6
1252	if (v == 6) {
1253		return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1254					(struct sockaddr_in6 *)mask,
1255					inp, inpmask);
1256	}
1257#endif
1258	return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1259				(struct sockaddr_in *)mask, inp, inpmask);
1260}
1261
1262
1263u_32_t fr_newisn(fin)
1264fr_info_t *fin;
1265{
1266	u_32_t newiss;
1267#if  (__FreeBSD_version >= 400000)
1268	newiss = arc4random();
1269#else
1270	static iss_seq_off = 0;
1271	u_char hash[16];
1272	MD5_CTX ctx;
1273
1274	/*
1275	 * Compute the base value of the ISS.  It is a hash
1276	 * of (saddr, sport, daddr, dport, secret).
1277	 */
1278	MD5Init(&ctx);
1279
1280	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
1281		  sizeof(fin->fin_fi.fi_src));
1282	MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
1283		  sizeof(fin->fin_fi.fi_dst));
1284	MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
1285
1286	MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
1287
1288	MD5Final(hash, &ctx);
1289
1290	memcpy(&newiss, hash, sizeof(newiss));
1291
1292	/*
1293	 * Now increment our "timer", and add it in to
1294	 * the computed value.
1295	 *
1296	 * XXX Use `addin'?
1297	 * XXX TCP_ISSINCR too large to use?
1298	 */
1299	iss_seq_off += 0x00010000;
1300	newiss += iss_seq_off;
1301#endif
1302	return newiss;
1303}
1304
1305
1306/* ------------------------------------------------------------------------ */
1307/* Function:    fr_nextipid                                                 */
1308/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1309/* Parameters:  fin(I) - pointer to packet information                      */
1310/*                                                                          */
1311/* Returns the next IPv4 ID to use for this packet.                         */
1312/* ------------------------------------------------------------------------ */
1313u_short fr_nextipid(fin)
1314fr_info_t *fin;
1315{
1316#ifndef	RANDOM_IP_ID
1317	static u_short ipid = 0;
1318	u_short id;
1319
1320	MUTEX_ENTER(&ipf_rw);
1321	id = ipid++;
1322	MUTEX_EXIT(&ipf_rw);
1323#else
1324	u_short id;
1325
1326	id = ip_randomid();
1327#endif
1328
1329	return id;
1330}
1331
1332
1333INLINE void fr_checkv4sum(fin)
1334fr_info_t *fin;
1335{
1336#ifdef CSUM_DATA_VALID
1337	int manual = 0;
1338	u_short sum;
1339	ip_t *ip;
1340	mb_t *m;
1341
1342	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1343		return;
1344
1345	if (fin->fin_cksum != 0)
1346		return;
1347
1348	m = fin->fin_m;
1349	if (m == NULL) {
1350		manual = 1;
1351		goto skipauto;
1352	}
1353	ip = fin->fin_ip;
1354
1355	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1356		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1357			sum = m->m_pkthdr.csum_data;
1358		else
1359			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1360					htonl(m->m_pkthdr.csum_data +
1361					fin->fin_ip->ip_len + fin->fin_p));
1362		sum ^= 0xffff;
1363		if (sum != 0) {
1364			fin->fin_flx |= FI_BAD;
1365			fin->fin_cksum = -1;
1366		} else {
1367			fin->fin_cksum = 1;
1368		}
1369	} else
1370		manual = 1;
1371skipauto:
1372# ifdef IPFILTER_CKSUM
1373	if (manual != 0)
1374		if (fr_checkl4sum(fin) == -1)
1375			fin->fin_flx |= FI_BAD;
1376# else
1377	;
1378# endif
1379#else
1380# ifdef IPFILTER_CKSUM
1381	if (fr_checkl4sum(fin) == -1)
1382		fin->fin_flx |= FI_BAD;
1383# endif
1384#endif
1385}
1386
1387
1388#ifdef USE_INET6
1389INLINE void fr_checkv6sum(fin)
1390fr_info_t *fin;
1391{
1392# ifdef IPFILTER_CKSUM
1393	if (fr_checkl4sum(fin) == -1)
1394		fin->fin_flx |= FI_BAD;
1395# endif
1396}
1397#endif /* USE_INET6 */
1398
1399
1400size_t mbufchainlen(m0)
1401struct mbuf *m0;
1402{
1403	size_t len;
1404
1405	if ((m0->m_flags & M_PKTHDR) != 0) {
1406		len = m0->m_pkthdr.len;
1407	} else {
1408		struct mbuf *m;
1409
1410		for (m = m0, len = 0; m != NULL; m = m->m_next)
1411			len += m->m_len;
1412	}
1413	return len;
1414}
1415
1416
1417/* ------------------------------------------------------------------------ */
1418/* Function:    fr_pullup                                                   */
1419/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1420/* Parameters:  m(I)   - pointer to buffer where data packet starts         */
1421/*              fin(I) - pointer to packet information                      */
1422/*              len(I) - number of bytes to pullup                          */
1423/*                                                                          */
1424/* Attempt to move at least len bytes (from the start of the buffer) into a */
1425/* single buffer for ease of access.  Operating system native functions are */
1426/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1427/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has  */
1428/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1429/* and ONLY if the pullup succeeds.                                         */
1430/*                                                                          */
1431/* We assume that 'min' is a pointer to a buffer that is part of the chain  */
1432/* of buffers that starts at *fin->fin_mp.                                  */
1433/* ------------------------------------------------------------------------ */
1434void *fr_pullup(min, fin, len)
1435mb_t *min;
1436fr_info_t *fin;
1437int len;
1438{
1439	int out = fin->fin_out, dpoff, ipoff;
1440	mb_t *m = min;
1441	char *ip;
1442
1443	if (m == NULL)
1444		return NULL;
1445
1446	ip = (char *)fin->fin_ip;
1447	if ((fin->fin_flx & FI_COALESCE) != 0)
1448		return ip;
1449
1450	ipoff = fin->fin_ipoff;
1451	if (fin->fin_dp != NULL)
1452		dpoff = (char *)fin->fin_dp - (char *)ip;
1453	else
1454		dpoff = 0;
1455
1456	if (M_LEN(m) < len) {
1457#ifdef MHLEN
1458		/*
1459		 * Assume that M_PKTHDR is set and just work with what is left
1460		 * rather than check..
1461		 * Should not make any real difference, anyway.
1462		 */
1463		if (len > MHLEN)
1464#else
1465		if (len > MLEN)
1466#endif
1467		{
1468#ifdef HAVE_M_PULLDOWN
1469			if (m_pulldown(m, 0, len, NULL) == NULL)
1470				m = NULL;
1471#else
1472			FREE_MB_T(*fin->fin_mp);
1473			m = NULL;
1474#endif
1475		} else
1476		{
1477			m = m_pullup(m, len);
1478		}
1479		*fin->fin_mp = m;
1480		if (m == NULL) {
1481			fin->fin_m = NULL;
1482			ATOMIC_INCL(frstats[out].fr_pull[1]);
1483			return NULL;
1484		}
1485
1486		while (M_LEN(m) == 0) {
1487			m = m->m_next;
1488		}
1489		fin->fin_m = m;
1490		ip = MTOD(m, char *) + ipoff;
1491	}
1492
1493	ATOMIC_INCL(frstats[out].fr_pull[0]);
1494	fin->fin_ip = (ip_t *)ip;
1495	if (fin->fin_dp != NULL)
1496		fin->fin_dp = (char *)fin->fin_ip + dpoff;
1497
1498	if (len == fin->fin_plen)
1499		fin->fin_flx |= FI_COALESCE;
1500	return ip;
1501}
1502
1503
1504int ipf_inject(fin, m)
1505fr_info_t *fin;
1506mb_t *m;
1507{
1508	int error = 0;
1509
1510	if (fin->fin_out == 0) {
1511#if (__FreeBSD_version >= 501000)
1512		netisr_dispatch(NETISR_IP, m);
1513#else
1514		struct ifqueue *ifq;
1515
1516		ifq = &ipintrq;
1517
1518# ifdef _IF_QFULL
1519		if (_IF_QFULL(ifq))
1520# else
1521		if (IF_QFULL(ifq))
1522# endif
1523		{
1524# ifdef _IF_DROP
1525			_IF_DROP(ifq);
1526# else
1527			IF_DROP(ifq);
1528# endif
1529			FREE_MB_T(m);
1530			error = ENOBUFS;
1531		} else {
1532			IF_ENQUEUE(ifq, m);
1533		}
1534#endif
1535	} else {
1536		fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1537		fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1538#if (__FreeBSD_version >= 470102)
1539		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1540#else
1541		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
1542#endif
1543	}
1544
1545	return error;
1546}
1547
1548int ipf_pfil_unhook(void) {
1549#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1550# if __FreeBSD_version >= 501108
1551	struct pfil_head *ph_inet;
1552#  ifdef USE_INET6
1553	struct pfil_head *ph_inet6;
1554#  endif
1555# endif
1556#endif
1557
1558#ifdef NETBSD_PF
1559# if (__FreeBSD_version >= 500011)
1560#  if (__FreeBSD_version >= 501108)
1561	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1562	if (ph_inet != NULL)
1563		pfil_remove_hook((void *)fr_check_wrapper, NULL,
1564		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1565#  else
1566	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1567	    &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1568#  endif
1569# else
1570	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1571# endif
1572# ifdef USE_INET6
1573#  if (__FreeBSD_version >= 501108)
1574	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1575	if (ph_inet6 != NULL)
1576		pfil_remove_hook((void *)fr_check_wrapper6, NULL,
1577		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1578#  else
1579	pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1580				 &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1581#  endif
1582# endif
1583#endif
1584
1585	return (0);
1586}
1587
1588int ipf_pfil_hook(void) {
1589#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1590# if __FreeBSD_version >= 501108
1591	struct pfil_head *ph_inet;
1592#  ifdef USE_INET6
1593	struct pfil_head *ph_inet6;
1594#  endif
1595# endif
1596#endif
1597
1598# ifdef NETBSD_PF
1599#  if __FreeBSD_version >= 500011
1600#   if __FreeBSD_version >= 501108
1601	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1602#    ifdef USE_INET6
1603	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1604#    endif
1605	if (ph_inet == NULL
1606#    ifdef USE_INET6
1607	    && ph_inet6 == NULL
1608#    endif
1609	   )
1610		return ENODEV;
1611
1612	if (ph_inet != NULL)
1613		pfil_add_hook((void *)fr_check_wrapper, NULL,
1614		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1615#  else
1616	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1617			      &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
1618#  endif
1619#  else
1620	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
1621#  endif
1622#  ifdef USE_INET6
1623#   if __FreeBSD_version >= 501108
1624	if (ph_inet6 != NULL)
1625		pfil_add_hook((void *)fr_check_wrapper6, NULL,
1626				      PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1627#   else
1628	pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
1629			      &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
1630#   endif
1631#  endif
1632# endif
1633	return (0);
1634}
1635
1636void
1637ipf_event_reg(void)
1638{
1639#if (__FreeBSD_version >= 502103)
1640	ipf_arrivetag =  EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1641					       ipf_ifevent, NULL, \
1642					       EVENTHANDLER_PRI_ANY);
1643	ipf_departtag =  EVENTHANDLER_REGISTER(ifnet_departure_event, \
1644					       ipf_ifevent, NULL, \
1645					       EVENTHANDLER_PRI_ANY);
1646	ipf_clonetag =  EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1647					      NULL, EVENTHANDLER_PRI_ANY);
1648#endif
1649}
1650
1651void
1652ipf_event_dereg(void)
1653{
1654#if (__FreeBSD_version >= 502103)
1655	if (ipf_arrivetag != NULL) {
1656		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1657	}
1658	if (ipf_departtag != NULL) {
1659		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1660	}
1661	if (ipf_clonetag != NULL) {
1662		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1663	}
1664#endif
1665}
1666