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