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