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