ip_fil_freebsd.c revision 255332
1145516Sdarrenr/*	$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 255332 2013-09-06 23:11:19Z cy $	*/
2145516Sdarrenr
3145516Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145516Sdarrenr *
6145516Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145516Sdarrenr */
8145516Sdarrenr#if !defined(lint)
9145516Sdarrenrstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10255332Scystatic const char rcsid[] = "@(#)$Id$";
11145516Sdarrenr#endif
12145516Sdarrenr
13145516Sdarrenr#if defined(KERNEL) || defined(_KERNEL)
14145516Sdarrenr# undef KERNEL
15145516Sdarrenr# undef _KERNEL
16145516Sdarrenr# define	KERNEL	1
17145516Sdarrenr# define	_KERNEL	1
18145516Sdarrenr#endif
19145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20145516Sdarrenr    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21145516Sdarrenr# include "opt_inet6.h"
22145516Sdarrenr#endif
23145516Sdarrenr#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24145516Sdarrenr    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25145516Sdarrenr# include "opt_random_ip_id.h"
26145516Sdarrenr#endif
27145516Sdarrenr#include <sys/param.h>
28145516Sdarrenr#include <sys/errno.h>
29145516Sdarrenr#include <sys/types.h>
30145516Sdarrenr#include <sys/file.h>
31145516Sdarrenr# include <sys/fcntl.h>
32145516Sdarrenr# include <sys/filio.h>
33145516Sdarrenr#include <sys/time.h>
34145516Sdarrenr#include <sys/systm.h>
35145516Sdarrenr# include <sys/dirent.h>
36255332Scy# include <sys/mbuf.h>
37255332Scy# include <sys/sockopt.h>
38145516Sdarrenr#if !defined(__hpux)
39145516Sdarrenr# include <sys/mbuf.h>
40145516Sdarrenr#endif
41145516Sdarrenr#include <sys/socket.h>
42170268Sdarrenr# include <sys/selinfo.h>
43195699Srwatson# include <netinet/tcp_var.h>
44145516Sdarrenr
45145516Sdarrenr#include <net/if.h>
46145516Sdarrenr# include <net/if_var.h>
47170268Sdarrenr#  include <net/netisr.h>
48145516Sdarrenr#include <net/route.h>
49145516Sdarrenr#include <netinet/in.h>
50145516Sdarrenr#include <netinet/in_var.h>
51145516Sdarrenr#include <netinet/in_systm.h>
52145516Sdarrenr#include <netinet/ip.h>
53145516Sdarrenr#include <netinet/ip_var.h>
54145516Sdarrenr#include <netinet/tcp.h>
55145516Sdarrenr#if defined(__osf__)
56145516Sdarrenr# include <netinet/tcp_timer.h>
57145516Sdarrenr#endif
58145516Sdarrenr#include <netinet/udp.h>
59145516Sdarrenr#include <netinet/tcpip.h>
60145516Sdarrenr#include <netinet/ip_icmp.h>
61145516Sdarrenr#include "netinet/ip_compat.h"
62145516Sdarrenr#ifdef USE_INET6
63145516Sdarrenr# include <netinet/icmp6.h>
64145516Sdarrenr#endif
65145516Sdarrenr#include "netinet/ip_fil.h"
66145516Sdarrenr#include "netinet/ip_nat.h"
67145516Sdarrenr#include "netinet/ip_frag.h"
68145516Sdarrenr#include "netinet/ip_state.h"
69145516Sdarrenr#include "netinet/ip_proxy.h"
70145516Sdarrenr#include "netinet/ip_auth.h"
71145516Sdarrenr#include "netinet/ip_sync.h"
72255332Scy#include "netinet/ip_lookup.h"
73255332Scy#include "netinet/ip_dstlist.h"
74145516Sdarrenr#ifdef	IPFILTER_SCAN
75145516Sdarrenr#include "netinet/ip_scan.h"
76145516Sdarrenr#endif
77145516Sdarrenr#include "netinet/ip_pool.h"
78145516Sdarrenr# include <sys/malloc.h>
79145516Sdarrenr#include <sys/kernel.h>
80145516Sdarrenr#ifdef CSUM_DATA_VALID
81145516Sdarrenr#include <machine/in_cksum.h>
82145516Sdarrenr#endif
83145516Sdarrenrextern	int	ip_optcopy __P((struct ip *, struct ip *));
84145516Sdarrenr
85145516Sdarrenr
86145516Sdarrenr# ifdef IPFILTER_M_IPFILTER
87151897SrwatsonMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
88145516Sdarrenr# endif
89145516Sdarrenr
90145516Sdarrenr
91255332Scystatic	u_short	ipid = 0;
92255332Scystatic	int	(*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **));
93255332Scystatic	int	ipf_send_ip __P((fr_info_t *, mb_t *));
94255332Scystatic void	ipf_timer_func __P((void *arg));
95145516Sdarrenrint		ipf_locks_done = 0;
96145516Sdarrenr
97255332Scyipf_main_softc_t ipfmain;
98145516Sdarrenr
99145516Sdarrenr# include <sys/conf.h>
100145516Sdarrenr# if defined(NETBSD_PF)
101145516Sdarrenr#  include <net/pfil.h>
102255332Scy# endif /* NETBSD_PF */
103145516Sdarrenr/*
104255332Scy * We provide the ipf_checkp name just to minimize changes later.
105145516Sdarrenr */
106255332Scyint (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
107145516Sdarrenr
108145516Sdarrenr
109153876Sguidostatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
110153876Sguido
111153876Sguidostatic void ipf_ifevent(void *arg);
112153876Sguido
113153876Sguidostatic void ipf_ifevent(arg)
114255332Scy	void *arg;
115153876Sguido{
116255332Scy        ipf_sync(arg, NULL);
117153876Sguido}
118153876Sguido
119153876Sguido
120145516Sdarrenr
121145516Sdarrenrstatic int
122255332Scyipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
123145516Sdarrenr{
124145516Sdarrenr	struct ip *ip = mtod(*mp, struct ip *);
125255332Scy	int rv;
126255332Scy
127255332Scy	/*
128255332Scy	 * IPFilter expects evreything in network byte order
129255332Scy	 */
130255332Scy#if (__FreeBSD_version < 1000019)
131255332Scy	ip->ip_len = htons(ip->ip_len);
132255332Scy	ip->ip_off = htons(ip->ip_off);
133255332Scy#endif
134255332Scy	rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT),
135255332Scy		       mp);
136255332Scy#if (__FreeBSD_version < 1000019)
137255332Scy	if ((rv == 0) && (*mp != NULL)) {
138255332Scy		ip = mtod(*mp, struct ip *);
139255332Scy		ip->ip_len = ntohs(ip->ip_len);
140255332Scy		ip->ip_off = ntohs(ip->ip_off);
141255332Scy	}
142255332Scy#endif
143255332Scy	return rv;
144145516Sdarrenr}
145145516Sdarrenr
146145516Sdarrenr# ifdef USE_INET6
147145516Sdarrenr#  include <netinet/ip6.h>
148145516Sdarrenr
149145516Sdarrenrstatic int
150255332Scyipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
151145516Sdarrenr{
152255332Scy	return (ipf_check(&ipfmain, mtod(*mp, struct ip *),
153255332Scy			  sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp));
154145516Sdarrenr}
155145516Sdarrenr# endif
156145516Sdarrenr#if	defined(IPFILTER_LKM)
157255332Scyint ipf_identify(s)
158255332Scy	char *s;
159145516Sdarrenr{
160145516Sdarrenr	if (strcmp(s, "ipl") == 0)
161145516Sdarrenr		return 1;
162145516Sdarrenr	return 0;
163145516Sdarrenr}
164145516Sdarrenr#endif /* IPFILTER_LKM */
165145516Sdarrenr
166145516Sdarrenr
167255332Scystatic void
168255332Scyipf_timer_func(arg)
169255332Scy	void *arg;
170145516Sdarrenr{
171255332Scy	ipf_main_softc_t *softc = arg;
172255332Scy	SPL_INT(s);
173255332Scy
174255332Scy	SPL_NET(s);
175255332Scy	READ_ENTER(&softc->ipf_global);
176255332Scy
177255332Scy        if (softc->ipf_running > 0)
178255332Scy		ipf_slowtimer(softc);
179255332Scy
180255332Scy	if (softc->ipf_running == -1 || softc->ipf_running == 1) {
181255332Scy#if FREEBSD_GE_REV(300000)
182255332Scy		softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
183255332Scy#else
184255332Scy		timeout(ipf_timer_func, softc, hz/2);
185255332Scy#endif
186255332Scy	}
187255332Scy	RWLOCK_EXIT(&softc->ipf_global);
188255332Scy	SPL_X(s);
189255332Scy}
190255332Scy
191255332Scy
192255332Scyint
193255332Scyipfattach(softc)
194255332Scy	ipf_main_softc_t *softc;
195255332Scy{
196145516Sdarrenr#ifdef USE_SPL
197145516Sdarrenr	int s;
198145516Sdarrenr#endif
199145516Sdarrenr
200145516Sdarrenr	SPL_NET(s);
201255332Scy	if (softc->ipf_running > 0) {
202145516Sdarrenr		SPL_X(s);
203145516Sdarrenr		return EBUSY;
204145516Sdarrenr	}
205145516Sdarrenr
206255332Scy	if (ipf_init_all(softc) < 0) {
207145516Sdarrenr		SPL_X(s);
208145516Sdarrenr		return EIO;
209145516Sdarrenr	}
210145516Sdarrenr
211145516Sdarrenr
212255332Scy	if (ipf_checkp != ipf_check) {
213255332Scy		ipf_savep = ipf_checkp;
214255332Scy		ipf_checkp = ipf_check;
215145516Sdarrenr	}
216145516Sdarrenr
217255332Scy	bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait));
218255332Scy	softc->ipf_running = 1;
219145516Sdarrenr
220255332Scy	if (softc->ipf_control_forwarding & 1)
221181803Sbz		V_ipforwarding = 1;
222145516Sdarrenr
223255332Scy	ipid = 0;
224255332Scy
225145516Sdarrenr	SPL_X(s);
226255332Scy	softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
227255332Scy				     (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
228145516Sdarrenr	return 0;
229145516Sdarrenr}
230145516Sdarrenr
231145516Sdarrenr
232145516Sdarrenr/*
233145516Sdarrenr * Disable the filter by removing the hooks from the IP input/output
234145516Sdarrenr * stream.
235145516Sdarrenr */
236255332Scyint
237255332Scyipfdetach(softc)
238255332Scy	ipf_main_softc_t *softc;
239145516Sdarrenr{
240145516Sdarrenr#ifdef USE_SPL
241145516Sdarrenr	int s;
242145516Sdarrenr#endif
243255332Scy
244255332Scy	if (softc->ipf_control_forwarding & 2)
245181803Sbz		V_ipforwarding = 0;
246145516Sdarrenr
247145516Sdarrenr	SPL_NET(s);
248145516Sdarrenr
249255332Scy	if (softc->ipf_slow_ch.callout != NULL)
250255332Scy		untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
251255332Scy	bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
252145516Sdarrenr
253145516Sdarrenr#ifndef NETBSD_PF
254255332Scy	if (ipf_checkp != NULL)
255255332Scy		ipf_checkp = ipf_savep;
256255332Scy	ipf_savep = NULL;
257145516Sdarrenr#endif
258145516Sdarrenr
259255332Scy	ipf_fini_all(softc);
260145516Sdarrenr
261255332Scy	softc->ipf_running = -2;
262145516Sdarrenr
263145516Sdarrenr	SPL_X(s);
264145516Sdarrenr
265145516Sdarrenr	return 0;
266145516Sdarrenr}
267145516Sdarrenr
268145516Sdarrenr
269145516Sdarrenr/*
270145516Sdarrenr * Filter ioctl interface.
271145516Sdarrenr */
272255332Scyint
273255332Scyipfioctl(dev, cmd, data, mode
274145516Sdarrenr, p)
275255332Scy	struct thread *p;
276192895Sjamie#    define	p_cred	td_ucred
277170268Sdarrenr#    define	p_uid	td_ucred->cr_ruid
278255332Scy	struct cdev *dev;
279255332Scy	ioctlcmd_t cmd;
280255332Scy	caddr_t data;
281255332Scy	int mode;
282145516Sdarrenr{
283170268Sdarrenr	int error = 0, unit = 0;
284170268Sdarrenr	SPL_INT(s);
285145516Sdarrenr
286255332Scy#if (BSD >= 199306)
287255332Scy        if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
288255332Scy	{
289255332Scy		ipfmain.ipf_interror = 130001;
290145516Sdarrenr		return EPERM;
291255332Scy	}
292145516Sdarrenr#endif
293145516Sdarrenr
294145516Sdarrenr	unit = GET_MINOR(dev);
295255332Scy	if ((IPL_LOGMAX < unit) || (unit < 0)) {
296255332Scy		ipfmain.ipf_interror = 130002;
297145516Sdarrenr		return ENXIO;
298255332Scy	}
299145516Sdarrenr
300255332Scy	if (ipfmain.ipf_running <= 0) {
301255332Scy		if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
302255332Scy			ipfmain.ipf_interror = 130003;
303145516Sdarrenr			return EIO;
304255332Scy		}
305145516Sdarrenr		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
306173181Sdarrenr		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
307255332Scy		    cmd != SIOCGETFS && cmd != SIOCGETFF &&
308255332Scy		    cmd != SIOCIPFINTERROR) {
309255332Scy			ipfmain.ipf_interror = 130004;
310145516Sdarrenr			return EIO;
311255332Scy		}
312145516Sdarrenr	}
313145516Sdarrenr
314145516Sdarrenr	SPL_NET(s);
315145516Sdarrenr
316255332Scy	error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p);
317145516Sdarrenr	if (error != -1) {
318145516Sdarrenr		SPL_X(s);
319145516Sdarrenr		return error;
320145516Sdarrenr	}
321145516Sdarrenr
322145516Sdarrenr	SPL_X(s);
323161356Sguido
324145516Sdarrenr	return error;
325145516Sdarrenr}
326145516Sdarrenr
327145516Sdarrenr
328145516Sdarrenr/*
329255332Scy * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
330145516Sdarrenr * requires a large amount of setting up and isn't any more efficient.
331145516Sdarrenr */
332255332Scyint
333255332Scyipf_send_reset(fin)
334255332Scy	fr_info_t *fin;
335145516Sdarrenr{
336145516Sdarrenr	struct tcphdr *tcp, *tcp2;
337145516Sdarrenr	int tlen = 0, hlen;
338145516Sdarrenr	struct mbuf *m;
339145516Sdarrenr#ifdef USE_INET6
340145516Sdarrenr	ip6_t *ip6;
341145516Sdarrenr#endif
342145516Sdarrenr	ip_t *ip;
343145516Sdarrenr
344145516Sdarrenr	tcp = fin->fin_dp;
345145516Sdarrenr	if (tcp->th_flags & TH_RST)
346145516Sdarrenr		return -1;		/* feedback loop */
347145516Sdarrenr
348255332Scy	if (ipf_checkl4sum(fin) == -1)
349145516Sdarrenr		return -1;
350145516Sdarrenr
351145516Sdarrenr	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
352145516Sdarrenr			((tcp->th_flags & TH_SYN) ? 1 : 0) +
353145516Sdarrenr			((tcp->th_flags & TH_FIN) ? 1 : 0);
354145516Sdarrenr
355145516Sdarrenr#ifdef USE_INET6
356145516Sdarrenr	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
357145516Sdarrenr#else
358145516Sdarrenr	hlen = sizeof(ip_t);
359145516Sdarrenr#endif
360145516Sdarrenr#ifdef MGETHDR
361145516Sdarrenr	MGETHDR(m, M_DONTWAIT, MT_HEADER);
362145516Sdarrenr#else
363145516Sdarrenr	MGET(m, M_DONTWAIT, MT_HEADER);
364145516Sdarrenr#endif
365145516Sdarrenr	if (m == NULL)
366145516Sdarrenr		return -1;
367145516Sdarrenr	if (sizeof(*tcp2) + hlen > MLEN) {
368145516Sdarrenr		MCLGET(m, M_DONTWAIT);
369145516Sdarrenr		if ((m->m_flags & M_EXT) == 0) {
370145516Sdarrenr			FREE_MB_T(m);
371145516Sdarrenr			return -1;
372145516Sdarrenr		}
373145516Sdarrenr	}
374145516Sdarrenr
375145516Sdarrenr	m->m_len = sizeof(*tcp2) + hlen;
376145516Sdarrenr#if (BSD >= 199103)
377145516Sdarrenr	m->m_data += max_linkhdr;
378145516Sdarrenr	m->m_pkthdr.len = m->m_len;
379145516Sdarrenr	m->m_pkthdr.rcvif = (struct ifnet *)0;
380145516Sdarrenr#endif
381145516Sdarrenr	ip = mtod(m, struct ip *);
382145516Sdarrenr	bzero((char *)ip, hlen);
383145516Sdarrenr#ifdef USE_INET6
384145516Sdarrenr	ip6 = (ip6_t *)ip;
385145516Sdarrenr#endif
386145516Sdarrenr	tcp2 = (struct tcphdr *)((char *)ip + hlen);
387145516Sdarrenr	tcp2->th_sport = tcp->th_dport;
388145516Sdarrenr	tcp2->th_dport = tcp->th_sport;
389145516Sdarrenr
390145516Sdarrenr	if (tcp->th_flags & TH_ACK) {
391145516Sdarrenr		tcp2->th_seq = tcp->th_ack;
392145516Sdarrenr		tcp2->th_flags = TH_RST;
393145516Sdarrenr		tcp2->th_ack = 0;
394145516Sdarrenr	} else {
395145516Sdarrenr		tcp2->th_seq = 0;
396145516Sdarrenr		tcp2->th_ack = ntohl(tcp->th_seq);
397145516Sdarrenr		tcp2->th_ack += tlen;
398145516Sdarrenr		tcp2->th_ack = htonl(tcp2->th_ack);
399145516Sdarrenr		tcp2->th_flags = TH_RST|TH_ACK;
400145516Sdarrenr	}
401145516Sdarrenr	TCP_X2_A(tcp2, 0);
402145516Sdarrenr	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
403145516Sdarrenr	tcp2->th_win = tcp->th_win;
404145516Sdarrenr	tcp2->th_sum = 0;
405145516Sdarrenr	tcp2->th_urp = 0;
406145516Sdarrenr
407145516Sdarrenr#ifdef USE_INET6
408145516Sdarrenr	if (fin->fin_v == 6) {
409145516Sdarrenr		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
410145516Sdarrenr		ip6->ip6_plen = htons(sizeof(struct tcphdr));
411145516Sdarrenr		ip6->ip6_nxt = IPPROTO_TCP;
412145516Sdarrenr		ip6->ip6_hlim = 0;
413255332Scy		ip6->ip6_src = fin->fin_dst6.in6;
414255332Scy		ip6->ip6_dst = fin->fin_src6.in6;
415145516Sdarrenr		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
416145516Sdarrenr					 sizeof(*ip6), sizeof(*tcp2));
417255332Scy		return ipf_send_ip(fin, m);
418145516Sdarrenr	}
419145516Sdarrenr#endif
420145516Sdarrenr	ip->ip_p = IPPROTO_TCP;
421145516Sdarrenr	ip->ip_len = htons(sizeof(struct tcphdr));
422145516Sdarrenr	ip->ip_src.s_addr = fin->fin_daddr;
423145516Sdarrenr	ip->ip_dst.s_addr = fin->fin_saddr;
424145516Sdarrenr	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
425255332Scy	ip->ip_len = htons(hlen + sizeof(*tcp2));
426255332Scy	return ipf_send_ip(fin, m);
427145516Sdarrenr}
428145516Sdarrenr
429145516Sdarrenr
430255332Scy/*
431255332Scy * ip_len must be in network byte order when called.
432255332Scy */
433255332Scystatic int
434255332Scyipf_send_ip(fin, m)
435255332Scy	fr_info_t *fin;
436255332Scy	mb_t *m;
437145516Sdarrenr{
438145516Sdarrenr	fr_info_t fnew;
439145516Sdarrenr	ip_t *ip, *oip;
440145516Sdarrenr	int hlen;
441145516Sdarrenr
442145516Sdarrenr	ip = mtod(m, ip_t *);
443145516Sdarrenr	bzero((char *)&fnew, sizeof(fnew));
444255332Scy	fnew.fin_main_soft = fin->fin_main_soft;
445145516Sdarrenr
446145516Sdarrenr	IP_V_A(ip, fin->fin_v);
447145516Sdarrenr	switch (fin->fin_v)
448145516Sdarrenr	{
449145516Sdarrenr	case 4 :
450255332Scy		oip = fin->fin_ip;
451255332Scy		hlen = sizeof(*oip);
452145516Sdarrenr		fnew.fin_v = 4;
453255332Scy		fnew.fin_p = ip->ip_p;
454255332Scy		fnew.fin_plen = ntohs(ip->ip_len);
455145516Sdarrenr		IP_HL_A(ip, sizeof(*oip) >> 2);
456145516Sdarrenr		ip->ip_tos = oip->ip_tos;
457145516Sdarrenr		ip->ip_id = fin->fin_ip->ip_id;
458255332Scy#if defined(FreeBSD) && (__FreeBSD_version > 460000)
459255332Scy		ip->ip_off = htons(path_mtu_discovery ? IP_DF : 0);
460145516Sdarrenr#else
461145516Sdarrenr		ip->ip_off = 0;
462145516Sdarrenr#endif
463181803Sbz		ip->ip_ttl = V_ip_defttl;
464145516Sdarrenr		ip->ip_sum = 0;
465145516Sdarrenr		break;
466145516Sdarrenr#ifdef USE_INET6
467145516Sdarrenr	case 6 :
468145516Sdarrenr	{
469145516Sdarrenr		ip6_t *ip6 = (ip6_t *)ip;
470145516Sdarrenr
471145516Sdarrenr		ip6->ip6_vfc = 0x60;
472145516Sdarrenr		ip6->ip6_hlim = IPDEFTTL;
473145516Sdarrenr
474255332Scy		hlen = sizeof(*ip6);
475255332Scy		fnew.fin_p = ip6->ip6_nxt;
476145516Sdarrenr		fnew.fin_v = 6;
477255332Scy		fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
478145516Sdarrenr		break;
479145516Sdarrenr	}
480145516Sdarrenr#endif
481145516Sdarrenr	default :
482145516Sdarrenr		return EINVAL;
483145516Sdarrenr	}
484145516Sdarrenr#ifdef IPSEC
485145516Sdarrenr	m->m_pkthdr.rcvif = NULL;
486145516Sdarrenr#endif
487145516Sdarrenr
488145516Sdarrenr	fnew.fin_ifp = fin->fin_ifp;
489145516Sdarrenr	fnew.fin_flx = FI_NOCKSUM;
490145516Sdarrenr	fnew.fin_m = m;
491145516Sdarrenr	fnew.fin_ip = ip;
492255332Scy	fnew.fin_mp = &m;
493145516Sdarrenr	fnew.fin_hlen = hlen;
494145516Sdarrenr	fnew.fin_dp = (char *)ip + hlen;
495255332Scy	(void) ipf_makefrip(hlen, ip, &fnew);
496145516Sdarrenr
497255332Scy	return ipf_fastroute(m, &m, &fnew, NULL);
498145516Sdarrenr}
499145516Sdarrenr
500145516Sdarrenr
501255332Scyint
502255332Scyipf_send_icmp_err(type, fin, dst)
503255332Scy	int type;
504255332Scy	fr_info_t *fin;
505255332Scy	int dst;
506145516Sdarrenr{
507145516Sdarrenr	int err, hlen, xtra, iclen, ohlen, avail, code;
508145516Sdarrenr	struct in_addr dst4;
509145516Sdarrenr	struct icmp *icmp;
510145516Sdarrenr	struct mbuf *m;
511255332Scy	i6addr_t dst6;
512145516Sdarrenr	void *ifp;
513145516Sdarrenr#ifdef USE_INET6
514145516Sdarrenr	ip6_t *ip6;
515145516Sdarrenr#endif
516145516Sdarrenr	ip_t *ip, *ip2;
517145516Sdarrenr
518172776Sdarrenr	if ((type < 0) || (type >= ICMP_MAXTYPE))
519145516Sdarrenr		return -1;
520145516Sdarrenr
521145516Sdarrenr	code = fin->fin_icode;
522145516Sdarrenr#ifdef USE_INET6
523255332Scy#if 0
524255332Scy	/* XXX Fix an off by one error: s/>/>=/
525255332Scy	 was:
526255332Scy	 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
527255332Scy	 Fix obtained from NetBSD ip_fil_netbsd.c r1.4: */
528255332Scy#endif
529255332Scy	if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
530145516Sdarrenr		return -1;
531145516Sdarrenr#endif
532145516Sdarrenr
533255332Scy	if (ipf_checkl4sum(fin) == -1)
534145516Sdarrenr		return -1;
535145516Sdarrenr#ifdef MGETHDR
536145516Sdarrenr	MGETHDR(m, M_DONTWAIT, MT_HEADER);
537145516Sdarrenr#else
538145516Sdarrenr	MGET(m, M_DONTWAIT, MT_HEADER);
539145516Sdarrenr#endif
540145516Sdarrenr	if (m == NULL)
541145516Sdarrenr		return -1;
542145516Sdarrenr	avail = MHLEN;
543145516Sdarrenr
544145516Sdarrenr	xtra = 0;
545145516Sdarrenr	hlen = 0;
546145516Sdarrenr	ohlen = 0;
547255332Scy	dst4.s_addr = 0;
548145516Sdarrenr	ifp = fin->fin_ifp;
549145516Sdarrenr	if (fin->fin_v == 4) {
550255332Scy		if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
551145516Sdarrenr			switch (ntohs(fin->fin_data[0]) >> 8)
552145516Sdarrenr			{
553145516Sdarrenr			case ICMP_ECHO :
554145516Sdarrenr			case ICMP_TSTAMP :
555145516Sdarrenr			case ICMP_IREQ :
556145516Sdarrenr			case ICMP_MASKREQ :
557145516Sdarrenr				break;
558145516Sdarrenr			default :
559145516Sdarrenr				FREE_MB_T(m);
560145516Sdarrenr				return 0;
561145516Sdarrenr			}
562145516Sdarrenr
563145516Sdarrenr		if (dst == 0) {
564255332Scy			if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp,
565255332Scy					&dst6, NULL) == -1) {
566145516Sdarrenr				FREE_MB_T(m);
567145516Sdarrenr				return -1;
568145516Sdarrenr			}
569255332Scy			dst4 = dst6.in4;
570145516Sdarrenr		} else
571145516Sdarrenr			dst4.s_addr = fin->fin_daddr;
572145516Sdarrenr
573145516Sdarrenr		hlen = sizeof(ip_t);
574145516Sdarrenr		ohlen = fin->fin_hlen;
575255332Scy		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
576145516Sdarrenr		if (fin->fin_hlen < fin->fin_plen)
577145516Sdarrenr			xtra = MIN(fin->fin_dlen, 8);
578145516Sdarrenr		else
579145516Sdarrenr			xtra = 0;
580145516Sdarrenr	}
581145516Sdarrenr
582145516Sdarrenr#ifdef USE_INET6
583145516Sdarrenr	else if (fin->fin_v == 6) {
584145516Sdarrenr		hlen = sizeof(ip6_t);
585145516Sdarrenr		ohlen = sizeof(ip6_t);
586255332Scy		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
587145516Sdarrenr		type = icmptoicmp6types[type];
588145516Sdarrenr		if (type == ICMP6_DST_UNREACH)
589145516Sdarrenr			code = icmptoicmp6unreach[code];
590145516Sdarrenr
591255332Scy		if (iclen + max_linkhdr + fin->fin_plen > avail) {
592145516Sdarrenr			MCLGET(m, M_DONTWAIT);
593145516Sdarrenr			if ((m->m_flags & M_EXT) == 0) {
594145516Sdarrenr				FREE_MB_T(m);
595145516Sdarrenr				return -1;
596145516Sdarrenr			}
597145516Sdarrenr			avail = MCLBYTES;
598145516Sdarrenr		}
599255332Scy		xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
600255332Scy		xtra = MIN(xtra, IPV6_MMTU - iclen);
601145516Sdarrenr		if (dst == 0) {
602255332Scy			if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp,
603255332Scy					&dst6, NULL) == -1) {
604145516Sdarrenr				FREE_MB_T(m);
605145516Sdarrenr				return -1;
606145516Sdarrenr			}
607145516Sdarrenr		} else
608145516Sdarrenr			dst6 = fin->fin_dst6;
609145516Sdarrenr	}
610145516Sdarrenr#endif
611145516Sdarrenr	else {
612145516Sdarrenr		FREE_MB_T(m);
613145516Sdarrenr		return -1;
614145516Sdarrenr	}
615145516Sdarrenr
616145516Sdarrenr	avail -= (max_linkhdr + iclen);
617145516Sdarrenr	if (avail < 0) {
618145516Sdarrenr		FREE_MB_T(m);
619145516Sdarrenr		return -1;
620145516Sdarrenr	}
621145516Sdarrenr	if (xtra > avail)
622145516Sdarrenr		xtra = avail;
623145516Sdarrenr	iclen += xtra;
624145516Sdarrenr	m->m_data += max_linkhdr;
625145516Sdarrenr	m->m_pkthdr.rcvif = (struct ifnet *)0;
626145516Sdarrenr	m->m_pkthdr.len = iclen;
627145516Sdarrenr	m->m_len = iclen;
628145516Sdarrenr	ip = mtod(m, ip_t *);
629145516Sdarrenr	icmp = (struct icmp *)((char *)ip + hlen);
630145516Sdarrenr	ip2 = (ip_t *)&icmp->icmp_ip;
631145516Sdarrenr
632145516Sdarrenr	icmp->icmp_type = type;
633145516Sdarrenr	icmp->icmp_code = fin->fin_icode;
634145516Sdarrenr	icmp->icmp_cksum = 0;
635145516Sdarrenr#ifdef icmp_nextmtu
636255332Scy	if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
637255332Scy		if (fin->fin_mtu != 0) {
638255332Scy			icmp->icmp_nextmtu = htons(fin->fin_mtu);
639255332Scy
640255332Scy		} else if (ifp != NULL) {
641255332Scy			icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
642255332Scy
643255332Scy		} else {	/* make up a number... */
644255332Scy			icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
645255332Scy		}
646255332Scy	}
647145516Sdarrenr#endif
648145516Sdarrenr
649145516Sdarrenr	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
650145516Sdarrenr
651145516Sdarrenr#ifdef USE_INET6
652145516Sdarrenr	ip6 = (ip6_t *)ip;
653145516Sdarrenr	if (fin->fin_v == 6) {
654145516Sdarrenr		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
655145516Sdarrenr		ip6->ip6_plen = htons(iclen - hlen);
656145516Sdarrenr		ip6->ip6_nxt = IPPROTO_ICMPV6;
657145516Sdarrenr		ip6->ip6_hlim = 0;
658255332Scy		ip6->ip6_src = dst6.in6;
659255332Scy		ip6->ip6_dst = fin->fin_src6.in6;
660145516Sdarrenr		if (xtra > 0)
661145516Sdarrenr			bcopy((char *)fin->fin_ip + ohlen,
662145516Sdarrenr			      (char *)&icmp->icmp_ip + ohlen, xtra);
663145516Sdarrenr		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
664145516Sdarrenr					     sizeof(*ip6), iclen - hlen);
665145516Sdarrenr	} else
666145516Sdarrenr#endif
667145516Sdarrenr	{
668145516Sdarrenr		ip->ip_p = IPPROTO_ICMP;
669145516Sdarrenr		ip->ip_src.s_addr = dst4.s_addr;
670145516Sdarrenr		ip->ip_dst.s_addr = fin->fin_saddr;
671145516Sdarrenr
672145516Sdarrenr		if (xtra > 0)
673145516Sdarrenr			bcopy((char *)fin->fin_ip + ohlen,
674145516Sdarrenr			      (char *)&icmp->icmp_ip + ohlen, xtra);
675145516Sdarrenr		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
676145516Sdarrenr					     sizeof(*icmp) + 8);
677255332Scy		ip->ip_len = htons(iclen);
678145516Sdarrenr		ip->ip_p = IPPROTO_ICMP;
679145516Sdarrenr	}
680255332Scy	err = ipf_send_ip(fin, m);
681145516Sdarrenr	return err;
682145516Sdarrenr}
683145516Sdarrenr
684145516Sdarrenr
685145516Sdarrenr
686145516Sdarrenr
687173181Sdarrenr/*
688173181Sdarrenr * m0 - pointer to mbuf where the IP packet starts
689173181Sdarrenr * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
690173181Sdarrenr */
691255332Scyint
692255332Scyipf_fastroute(m0, mpp, fin, fdp)
693255332Scy	mb_t *m0, **mpp;
694255332Scy	fr_info_t *fin;
695255332Scy	frdest_t *fdp;
696145516Sdarrenr{
697145516Sdarrenr	register struct ip *ip, *mhip;
698173181Sdarrenr	register struct mbuf *m = *mpp;
699145516Sdarrenr	register struct route *ro;
700145516Sdarrenr	int len, off, error = 0, hlen, code;
701145516Sdarrenr	struct ifnet *ifp, *sifp;
702145516Sdarrenr	struct sockaddr_in *dst;
703145516Sdarrenr	struct route iproute;
704145516Sdarrenr	u_short ip_off;
705255332Scy	frdest_t node;
706145516Sdarrenr	frentry_t *fr;
707145516Sdarrenr
708161356Sguido	ro = NULL;
709161356Sguido
710145516Sdarrenr#ifdef M_WRITABLE
711145516Sdarrenr	/*
712145516Sdarrenr	* HOT FIX/KLUDGE:
713145516Sdarrenr	*
714145516Sdarrenr	* If the mbuf we're about to send is not writable (because of
715145516Sdarrenr	* a cluster reference, for example) we'll need to make a copy
716145516Sdarrenr	* of it since this routine modifies the contents.
717145516Sdarrenr	*
718145516Sdarrenr	* If you have non-crappy network hardware that can transmit data
719145516Sdarrenr	* from the mbuf, rather than making a copy, this is gonna be a
720145516Sdarrenr	* problem.
721145516Sdarrenr	*/
722145516Sdarrenr	if (M_WRITABLE(m) == 0) {
723161356Sguido		m0 = m_dup(m, M_DONTWAIT);
724161356Sguido		if (m0 != 0) {
725145516Sdarrenr			FREE_MB_T(m);
726145516Sdarrenr			m = m0;
727145516Sdarrenr			*mpp = m;
728145516Sdarrenr		} else {
729145516Sdarrenr			error = ENOBUFS;
730145516Sdarrenr			FREE_MB_T(m);
731161356Sguido			goto done;
732145516Sdarrenr		}
733145516Sdarrenr	}
734145516Sdarrenr#endif
735145516Sdarrenr
736145516Sdarrenr#ifdef USE_INET6
737145516Sdarrenr	if (fin->fin_v == 6) {
738145516Sdarrenr		/*
739145516Sdarrenr		 * currently "to <if>" and "to <if>:ip#" are not supported
740145516Sdarrenr		 * for IPv6
741145516Sdarrenr		 */
742255332Scy		return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
743145516Sdarrenr	}
744145516Sdarrenr#endif
745145516Sdarrenr
746145516Sdarrenr	hlen = fin->fin_hlen;
747145516Sdarrenr	ip = mtod(m0, struct ip *);
748255332Scy	ifp = NULL;
749145516Sdarrenr
750145516Sdarrenr	/*
751145516Sdarrenr	 * Route packet.
752145516Sdarrenr	 */
753145516Sdarrenr	ro = &iproute;
754255332Scy	bzero(ro, sizeof (*ro));
755145516Sdarrenr	dst = (struct sockaddr_in *)&ro->ro_dst;
756145516Sdarrenr	dst->sin_family = AF_INET;
757145516Sdarrenr	dst->sin_addr = ip->ip_dst;
758145516Sdarrenr
759145516Sdarrenr	fr = fin->fin_fr;
760255332Scy	if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
761255332Scy	    (fdp->fd_type == FRD_DSTLIST)) {
762255332Scy		if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
763255332Scy			fdp = &node;
764255332Scy	}
765255332Scy
766145516Sdarrenr	if (fdp != NULL)
767255332Scy		ifp = fdp->fd_ptr;
768145516Sdarrenr	else
769145516Sdarrenr		ifp = fin->fin_ifp;
770145516Sdarrenr
771255332Scy	if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
772145516Sdarrenr		error = -2;
773145516Sdarrenr		goto bad;
774145516Sdarrenr	}
775145516Sdarrenr
776161356Sguido	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
777161356Sguido		dst->sin_addr = fdp->fd_ip;
778145516Sdarrenr
779145516Sdarrenr	dst->sin_len = sizeof(*dst);
780178888Sjulian	in_rtalloc(ro, 0);
781145516Sdarrenr
782145516Sdarrenr	if ((ifp == NULL) && (ro->ro_rt != NULL))
783145516Sdarrenr		ifp = ro->ro_rt->rt_ifp;
784145516Sdarrenr
785145516Sdarrenr	if ((ro->ro_rt == NULL) || (ifp == NULL)) {
786145516Sdarrenr		if (in_localaddr(ip->ip_dst))
787145516Sdarrenr			error = EHOSTUNREACH;
788145516Sdarrenr		else
789145516Sdarrenr			error = ENETUNREACH;
790145516Sdarrenr		goto bad;
791145516Sdarrenr	}
792145516Sdarrenr	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
793145516Sdarrenr		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
794145516Sdarrenr	if (ro->ro_rt)
795145516Sdarrenr		ro->ro_rt->rt_use++;
796145516Sdarrenr
797145516Sdarrenr	/*
798145516Sdarrenr	 * For input packets which are being "fastrouted", they won't
799145516Sdarrenr	 * go back through output filtering and miss their chance to get
800170268Sdarrenr	 * NAT'd and counted.  Duplicated packets aren't considered to be
801170268Sdarrenr	 * part of the normal packet stream, so do not NAT them or pass
802170268Sdarrenr	 * them through stateful checking, etc.
803145516Sdarrenr	 */
804170268Sdarrenr	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
805145516Sdarrenr		sifp = fin->fin_ifp;
806145516Sdarrenr		fin->fin_ifp = ifp;
807145516Sdarrenr		fin->fin_out = 1;
808255332Scy		(void) ipf_acctpkt(fin, NULL);
809145516Sdarrenr		fin->fin_fr = NULL;
810145516Sdarrenr		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
811145516Sdarrenr			u_32_t pass;
812145516Sdarrenr
813255332Scy			(void) ipf_state_check(fin, &pass);
814145516Sdarrenr		}
815145516Sdarrenr
816255332Scy		switch (ipf_nat_checkout(fin, NULL))
817145516Sdarrenr		{
818145516Sdarrenr		case 0 :
819145516Sdarrenr			break;
820145516Sdarrenr		case 1 :
821145516Sdarrenr			ip->ip_sum = 0;
822145516Sdarrenr			break;
823145516Sdarrenr		case -1 :
824145516Sdarrenr			error = -1;
825173181Sdarrenr			goto bad;
826145516Sdarrenr			break;
827145516Sdarrenr		}
828145516Sdarrenr
829145516Sdarrenr		fin->fin_ifp = sifp;
830145516Sdarrenr		fin->fin_out = 0;
831145516Sdarrenr	} else
832145516Sdarrenr		ip->ip_sum = 0;
833145516Sdarrenr	/*
834145516Sdarrenr	 * If small enough for interface, can just send directly.
835145516Sdarrenr	 */
836255332Scy	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
837145516Sdarrenr		if (!ip->ip_sum)
838145516Sdarrenr			ip->ip_sum = in_cksum(m, hlen);
839145516Sdarrenr		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
840255332Scy			    ro
841255332Scy			);
842145516Sdarrenr		goto done;
843145516Sdarrenr	}
844145516Sdarrenr	/*
845145516Sdarrenr	 * Too large for interface; fragment if possible.
846145516Sdarrenr	 * Must be able to put at least 8 bytes per fragment.
847145516Sdarrenr	 */
848145516Sdarrenr	ip_off = ntohs(ip->ip_off);
849145516Sdarrenr	if (ip_off & IP_DF) {
850145516Sdarrenr		error = EMSGSIZE;
851145516Sdarrenr		goto bad;
852145516Sdarrenr	}
853145516Sdarrenr	len = (ifp->if_mtu - hlen) &~ 7;
854145516Sdarrenr	if (len < 8) {
855145516Sdarrenr		error = EMSGSIZE;
856145516Sdarrenr		goto bad;
857145516Sdarrenr	}
858145516Sdarrenr
859145516Sdarrenr    {
860145516Sdarrenr	int mhlen, firstlen = len;
861145516Sdarrenr	struct mbuf **mnext = &m->m_act;
862145516Sdarrenr
863145516Sdarrenr	/*
864145516Sdarrenr	 * Loop through length of segment after first fragment,
865145516Sdarrenr	 * make new header and copy data of each part and link onto chain.
866145516Sdarrenr	 */
867145516Sdarrenr	m0 = m;
868145516Sdarrenr	mhlen = sizeof (struct ip);
869255332Scy	for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
870145516Sdarrenr#ifdef MGETHDR
871145516Sdarrenr		MGETHDR(m, M_DONTWAIT, MT_HEADER);
872145516Sdarrenr#else
873145516Sdarrenr		MGET(m, M_DONTWAIT, MT_HEADER);
874145516Sdarrenr#endif
875145516Sdarrenr		if (m == 0) {
876145516Sdarrenr			m = m0;
877145516Sdarrenr			error = ENOBUFS;
878145516Sdarrenr			goto bad;
879145516Sdarrenr		}
880145516Sdarrenr		m->m_data += max_linkhdr;
881145516Sdarrenr		mhip = mtod(m, struct ip *);
882145516Sdarrenr		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
883145516Sdarrenr		if (hlen > sizeof (struct ip)) {
884145516Sdarrenr			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
885145516Sdarrenr			IP_HL_A(mhip, mhlen >> 2);
886145516Sdarrenr		}
887145516Sdarrenr		m->m_len = mhlen;
888145516Sdarrenr		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
889255332Scy		if (off + len >= ntohs(ip->ip_len))
890255332Scy			len = ntohs(ip->ip_len) - off;
891145516Sdarrenr		else
892145516Sdarrenr			mhip->ip_off |= IP_MF;
893145516Sdarrenr		mhip->ip_len = htons((u_short)(len + mhlen));
894161356Sguido		*mnext = m;
895145516Sdarrenr		m->m_next = m_copy(m0, off, len);
896145516Sdarrenr		if (m->m_next == 0) {
897145516Sdarrenr			error = ENOBUFS;	/* ??? */
898145516Sdarrenr			goto sendorfree;
899145516Sdarrenr		}
900145516Sdarrenr		m->m_pkthdr.len = mhlen + len;
901145516Sdarrenr		m->m_pkthdr.rcvif = NULL;
902145516Sdarrenr		mhip->ip_off = htons((u_short)mhip->ip_off);
903145516Sdarrenr		mhip->ip_sum = 0;
904145516Sdarrenr		mhip->ip_sum = in_cksum(m, mhlen);
905145516Sdarrenr		mnext = &m->m_act;
906145516Sdarrenr	}
907145516Sdarrenr	/*
908145516Sdarrenr	 * Update first fragment by trimming what's been copied out
909145516Sdarrenr	 * and updating header, then send each fragment (in order).
910145516Sdarrenr	 */
911145516Sdarrenr	m_adj(m0, hlen + firstlen - ip->ip_len);
912145516Sdarrenr	ip->ip_len = htons((u_short)(hlen + firstlen));
913145516Sdarrenr	ip->ip_off = htons((u_short)IP_MF);
914145516Sdarrenr	ip->ip_sum = 0;
915145516Sdarrenr	ip->ip_sum = in_cksum(m0, hlen);
916145516Sdarrenrsendorfree:
917145516Sdarrenr	for (m = m0; m; m = m0) {
918145516Sdarrenr		m0 = m->m_act;
919145516Sdarrenr		m->m_act = 0;
920145516Sdarrenr		if (error == 0)
921145516Sdarrenr			error = (*ifp->if_output)(ifp, m,
922255332Scy			    (struct sockaddr *)dst,
923255332Scy			    ro
924255332Scy			    );
925145516Sdarrenr		else
926145516Sdarrenr			FREE_MB_T(m);
927145516Sdarrenr	}
928255332Scy    }
929145516Sdarrenrdone:
930145516Sdarrenr	if (!error)
931255332Scy		ipfmain.ipf_frouteok[0]++;
932145516Sdarrenr	else
933255332Scy		ipfmain.ipf_frouteok[1]++;
934145516Sdarrenr
935161356Sguido	if ((ro != NULL) && (ro->ro_rt != NULL)) {
936145516Sdarrenr		RTFREE(ro->ro_rt);
937145516Sdarrenr	}
938145516Sdarrenr	return 0;
939145516Sdarrenrbad:
940145516Sdarrenr	if (error == EMSGSIZE) {
941145516Sdarrenr		sifp = fin->fin_ifp;
942145516Sdarrenr		code = fin->fin_icode;
943145516Sdarrenr		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
944145516Sdarrenr		fin->fin_ifp = ifp;
945255332Scy		(void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
946145516Sdarrenr		fin->fin_ifp = sifp;
947145516Sdarrenr		fin->fin_icode = code;
948145516Sdarrenr	}
949145516Sdarrenr	FREE_MB_T(m);
950145516Sdarrenr	goto done;
951145516Sdarrenr}
952145516Sdarrenr
953145516Sdarrenr
954255332Scyint
955255332Scyipf_verifysrc(fin)
956255332Scy	fr_info_t *fin;
957145516Sdarrenr{
958145516Sdarrenr	struct sockaddr_in *dst;
959145516Sdarrenr	struct route iproute;
960145516Sdarrenr
961145516Sdarrenr	bzero((char *)&iproute, sizeof(iproute));
962145516Sdarrenr	dst = (struct sockaddr_in *)&iproute.ro_dst;
963145516Sdarrenr	dst->sin_len = sizeof(*dst);
964145516Sdarrenr	dst->sin_family = AF_INET;
965145516Sdarrenr	dst->sin_addr = fin->fin_src;
966178888Sjulian	in_rtalloc(&iproute, 0);
967145516Sdarrenr	if (iproute.ro_rt == NULL)
968145516Sdarrenr		return 0;
969145516Sdarrenr	return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
970145516Sdarrenr}
971145516Sdarrenr
972145516Sdarrenr
973145516Sdarrenr/*
974145516Sdarrenr * return the first IP Address associated with an interface
975145516Sdarrenr */
976255332Scyint
977255332Scyipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
978255332Scy	ipf_main_softc_t *softc;
979255332Scy	int v, atype;
980255332Scy	void *ifptr;
981255332Scy	i6addr_t *inp, *inpmask;
982145516Sdarrenr{
983145516Sdarrenr#ifdef USE_INET6
984145516Sdarrenr	struct in6_addr *inp6 = NULL;
985145516Sdarrenr#endif
986145516Sdarrenr	struct sockaddr *sock, *mask;
987145516Sdarrenr	struct sockaddr_in *sin;
988145516Sdarrenr	struct ifaddr *ifa;
989145516Sdarrenr	struct ifnet *ifp;
990145516Sdarrenr
991145516Sdarrenr	if ((ifptr == NULL) || (ifptr == (void *)-1))
992145516Sdarrenr		return -1;
993145516Sdarrenr
994145516Sdarrenr	sin = NULL;
995145516Sdarrenr	ifp = ifptr;
996145516Sdarrenr
997145516Sdarrenr	if (v == 4)
998255332Scy		inp->in4.s_addr = 0;
999145516Sdarrenr#ifdef USE_INET6
1000145516Sdarrenr	else if (v == 6)
1001255332Scy		bzero((char *)inp, sizeof(*inp));
1002145516Sdarrenr#endif
1003145516Sdarrenr	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1004145516Sdarrenr
1005145516Sdarrenr	sock = ifa->ifa_addr;
1006145516Sdarrenr	while (sock != NULL && ifa != NULL) {
1007145516Sdarrenr		sin = (struct sockaddr_in *)sock;
1008145516Sdarrenr		if ((v == 4) && (sin->sin_family == AF_INET))
1009145516Sdarrenr			break;
1010145516Sdarrenr#ifdef USE_INET6
1011145516Sdarrenr		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1012145516Sdarrenr			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1013145516Sdarrenr			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1014145516Sdarrenr			    !IN6_IS_ADDR_LOOPBACK(inp6))
1015145516Sdarrenr				break;
1016145516Sdarrenr		}
1017145516Sdarrenr#endif
1018145516Sdarrenr		ifa = TAILQ_NEXT(ifa, ifa_link);
1019145516Sdarrenr		if (ifa != NULL)
1020145516Sdarrenr			sock = ifa->ifa_addr;
1021145516Sdarrenr	}
1022145516Sdarrenr
1023145516Sdarrenr	if (ifa == NULL || sin == NULL)
1024145516Sdarrenr		return -1;
1025145516Sdarrenr
1026145516Sdarrenr	mask = ifa->ifa_netmask;
1027145516Sdarrenr	if (atype == FRI_BROADCAST)
1028145516Sdarrenr		sock = ifa->ifa_broadaddr;
1029145516Sdarrenr	else if (atype == FRI_PEERADDR)
1030145516Sdarrenr		sock = ifa->ifa_dstaddr;
1031145516Sdarrenr
1032161356Sguido	if (sock == NULL)
1033161356Sguido		return -1;
1034161356Sguido
1035145516Sdarrenr#ifdef USE_INET6
1036145516Sdarrenr	if (v == 6) {
1037255332Scy		return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1038255332Scy					 (struct sockaddr_in6 *)mask,
1039255332Scy					 inp, inpmask);
1040145516Sdarrenr	}
1041145516Sdarrenr#endif
1042255332Scy	return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1043255332Scy				 (struct sockaddr_in *)mask,
1044255332Scy				 &inp->in4, &inpmask->in4);
1045145516Sdarrenr}
1046145516Sdarrenr
1047145516Sdarrenr
1048255332Scyu_32_t
1049255332Scyipf_newisn(fin)
1050255332Scy	fr_info_t *fin;
1051145516Sdarrenr{
1052145516Sdarrenr	u_32_t newiss;
1053145516Sdarrenr	newiss = arc4random();
1054145516Sdarrenr	return newiss;
1055145516Sdarrenr}
1056145516Sdarrenr
1057145516Sdarrenr
1058145516Sdarrenr/* ------------------------------------------------------------------------ */
1059255332Scy/* Function:    ipf_nextipid                                                */
1060145516Sdarrenr/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1061145516Sdarrenr/* Parameters:  fin(I) - pointer to packet information                      */
1062145516Sdarrenr/*                                                                          */
1063145516Sdarrenr/* Returns the next IPv4 ID to use for this packet.                         */
1064145516Sdarrenr/* ------------------------------------------------------------------------ */
1065255332Scyu_short
1066255332Scyipf_nextipid(fin)
1067255332Scy	fr_info_t *fin;
1068145516Sdarrenr{
1069145516Sdarrenr	u_short id;
1070145516Sdarrenr
1071255332Scy#ifndef	RANDOM_IP_ID
1072255332Scy	MUTEX_ENTER(&ipfmain.ipf_rw);
1073145516Sdarrenr	id = ipid++;
1074255332Scy	MUTEX_EXIT(&ipfmain.ipf_rw);
1075145516Sdarrenr#else
1076145516Sdarrenr	id = ip_randomid();
1077145516Sdarrenr#endif
1078145516Sdarrenr
1079145516Sdarrenr	return id;
1080145516Sdarrenr}
1081145516Sdarrenr
1082145516Sdarrenr
1083255332ScyINLINE int
1084255332Scyipf_checkv4sum(fin)
1085255332Scy	fr_info_t *fin;
1086145516Sdarrenr{
1087145516Sdarrenr#ifdef CSUM_DATA_VALID
1088145516Sdarrenr	int manual = 0;
1089145516Sdarrenr	u_short sum;
1090145516Sdarrenr	ip_t *ip;
1091145516Sdarrenr	mb_t *m;
1092145516Sdarrenr
1093145516Sdarrenr	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1094255332Scy		return 0;
1095145516Sdarrenr
1096255332Scy	if ((fin->fin_flx & FI_SHORT) != 0)
1097255332Scy		return 1;
1098172776Sdarrenr
1099255332Scy	if (fin->fin_cksum != FI_CK_NEEDED)
1100255332Scy		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1101255332Scy
1102145516Sdarrenr	m = fin->fin_m;
1103145516Sdarrenr	if (m == NULL) {
1104145516Sdarrenr		manual = 1;
1105145516Sdarrenr		goto skipauto;
1106145516Sdarrenr	}
1107145516Sdarrenr	ip = fin->fin_ip;
1108145516Sdarrenr
1109255332Scy	if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
1110255332Scy	    CSUM_IP_CHECKED) {
1111255332Scy		fin->fin_cksum = FI_CK_BAD;
1112255332Scy		fin->fin_flx |= FI_BAD;
1113255332Scy		return -1;
1114255332Scy	}
1115145516Sdarrenr	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1116145516Sdarrenr		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1117145516Sdarrenr			sum = m->m_pkthdr.csum_data;
1118145516Sdarrenr		else
1119145516Sdarrenr			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1120145516Sdarrenr					htonl(m->m_pkthdr.csum_data +
1121255332Scy					fin->fin_dlen + fin->fin_p));
1122145516Sdarrenr		sum ^= 0xffff;
1123172776Sdarrenr		if (sum != 0) {
1124255332Scy			fin->fin_cksum = FI_CK_BAD;
1125145516Sdarrenr			fin->fin_flx |= FI_BAD;
1126172776Sdarrenr		} else {
1127255332Scy			fin->fin_cksum = FI_CK_SUMOK;
1128255332Scy			return 0;
1129172776Sdarrenr		}
1130255332Scy	} else {
1131255332Scy		if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
1132255332Scy			fin->fin_cksum = FI_CK_L4FULL;
1133255332Scy			return 0;
1134255332Scy		} else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
1135255332Scy			   m->m_pkthdr.csum_flags == CSUM_UDP) {
1136255332Scy			fin->fin_cksum = FI_CK_L4PART;
1137255332Scy			return 0;
1138255332Scy		} else if (m->m_pkthdr.csum_flags == CSUM_IP) {
1139255332Scy			fin->fin_cksum = FI_CK_L4PART;
1140255332Scy			return 0;
1141255332Scy		} else {
1142255332Scy			manual = 1;
1143255332Scy		}
1144255332Scy	}
1145145516Sdarrenrskipauto:
1146255332Scy	if (manual != 0) {
1147255332Scy		if (ipf_checkl4sum(fin) == -1) {
1148145516Sdarrenr			fin->fin_flx |= FI_BAD;
1149255332Scy			return -1;
1150255332Scy		}
1151255332Scy	}
1152145516Sdarrenr#else
1153255332Scy	if (ipf_checkl4sum(fin) == -1) {
1154145516Sdarrenr		fin->fin_flx |= FI_BAD;
1155255332Scy		return -1;
1156255332Scy	}
1157145516Sdarrenr#endif
1158255332Scy	return 0;
1159145516Sdarrenr}
1160145516Sdarrenr
1161145516Sdarrenr
1162145516Sdarrenr#ifdef USE_INET6
1163255332ScyINLINE int
1164255332Scyipf_checkv6sum(fin)
1165255332Scy	fr_info_t *fin;
1166145516Sdarrenr{
1167255332Scy	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1168255332Scy		return 0;
1169255332Scy
1170255332Scy	if ((fin->fin_flx & FI_SHORT) != 0)
1171255332Scy		return 1;
1172255332Scy
1173255332Scy	if (fin->fin_cksum != FI_CK_NEEDED)
1174255332Scy		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1175255332Scy
1176255332Scy	if (ipf_checkl4sum(fin) == -1) {
1177145516Sdarrenr		fin->fin_flx |= FI_BAD;
1178255332Scy		return -1;
1179255332Scy	}
1180255332Scy	return 0;
1181145516Sdarrenr}
1182145516Sdarrenr#endif /* USE_INET6 */
1183145516Sdarrenr
1184145516Sdarrenr
1185255332Scysize_t
1186255332Scymbufchainlen(m0)
1187255332Scy	struct mbuf *m0;
1188255332Scy	{
1189145516Sdarrenr	size_t len;
1190145516Sdarrenr
1191145516Sdarrenr	if ((m0->m_flags & M_PKTHDR) != 0) {
1192145516Sdarrenr		len = m0->m_pkthdr.len;
1193145516Sdarrenr	} else {
1194145516Sdarrenr		struct mbuf *m;
1195145516Sdarrenr
1196145516Sdarrenr		for (m = m0, len = 0; m != NULL; m = m->m_next)
1197145516Sdarrenr			len += m->m_len;
1198145516Sdarrenr	}
1199145516Sdarrenr	return len;
1200145516Sdarrenr}
1201145516Sdarrenr
1202145516Sdarrenr
1203145516Sdarrenr/* ------------------------------------------------------------------------ */
1204255332Scy/* Function:    ipf_pullup                                                  */
1205145516Sdarrenr/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1206255332Scy/* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
1207145516Sdarrenr/*              fin(I) - pointer to packet information                      */
1208145516Sdarrenr/*              len(I) - number of bytes to pullup                          */
1209145516Sdarrenr/*                                                                          */
1210145516Sdarrenr/* Attempt to move at least len bytes (from the start of the buffer) into a */
1211145516Sdarrenr/* single buffer for ease of access.  Operating system native functions are */
1212145516Sdarrenr/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1213255332Scy/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
1214145516Sdarrenr/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1215145516Sdarrenr/* and ONLY if the pullup succeeds.                                         */
1216145516Sdarrenr/*                                                                          */
1217255332Scy/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
1218145516Sdarrenr/* of buffers that starts at *fin->fin_mp.                                  */
1219145516Sdarrenr/* ------------------------------------------------------------------------ */
1220255332Scyvoid *
1221255332Scyipf_pullup(xmin, fin, len)
1222255332Scy	mb_t *xmin;
1223255332Scy	fr_info_t *fin;
1224255332Scy	int len;
1225145516Sdarrenr{
1226255332Scy	int dpoff, ipoff;
1227255332Scy	mb_t *m = xmin;
1228145516Sdarrenr	char *ip;
1229145516Sdarrenr
1230145516Sdarrenr	if (m == NULL)
1231145516Sdarrenr		return NULL;
1232145516Sdarrenr
1233145516Sdarrenr	ip = (char *)fin->fin_ip;
1234145516Sdarrenr	if ((fin->fin_flx & FI_COALESCE) != 0)
1235145516Sdarrenr		return ip;
1236145516Sdarrenr
1237145516Sdarrenr	ipoff = fin->fin_ipoff;
1238145516Sdarrenr	if (fin->fin_dp != NULL)
1239145516Sdarrenr		dpoff = (char *)fin->fin_dp - (char *)ip;
1240145516Sdarrenr	else
1241145516Sdarrenr		dpoff = 0;
1242145516Sdarrenr
1243145516Sdarrenr	if (M_LEN(m) < len) {
1244255332Scy		mb_t *n = *fin->fin_mp;
1245145516Sdarrenr		/*
1246145516Sdarrenr		 * Assume that M_PKTHDR is set and just work with what is left
1247145516Sdarrenr		 * rather than check..
1248145516Sdarrenr		 * Should not make any real difference, anyway.
1249145516Sdarrenr		 */
1250255332Scy		if (m != n) {
1251255332Scy			/*
1252255332Scy			 * Record the mbuf that points to the mbuf that we're
1253255332Scy			 * about to go to work on so that we can update the
1254255332Scy			 * m_next appropriately later.
1255255332Scy			 */
1256255332Scy			for (; n->m_next != m; n = n->m_next)
1257255332Scy				;
1258255332Scy		} else {
1259255332Scy			n = NULL;
1260255332Scy		}
1261255332Scy
1262255332Scy#ifdef MHLEN
1263145516Sdarrenr		if (len > MHLEN)
1264145516Sdarrenr#else
1265145516Sdarrenr		if (len > MLEN)
1266145516Sdarrenr#endif
1267145516Sdarrenr		{
1268145516Sdarrenr#ifdef HAVE_M_PULLDOWN
1269145516Sdarrenr			if (m_pulldown(m, 0, len, NULL) == NULL)
1270145516Sdarrenr				m = NULL;
1271145516Sdarrenr#else
1272145516Sdarrenr			FREE_MB_T(*fin->fin_mp);
1273145516Sdarrenr			m = NULL;
1274255332Scy			n = NULL;
1275145516Sdarrenr#endif
1276145516Sdarrenr		} else
1277145516Sdarrenr		{
1278145516Sdarrenr			m = m_pullup(m, len);
1279145516Sdarrenr		}
1280255332Scy		if (n != NULL)
1281255332Scy			n->m_next = m;
1282145516Sdarrenr		if (m == NULL) {
1283255332Scy			/*
1284255332Scy			 * When n is non-NULL, it indicates that m pointed to
1285255332Scy			 * a sub-chain (tail) of the mbuf and that the head
1286255332Scy			 * of this chain has not yet been free'd.
1287255332Scy			 */
1288255332Scy			if (n != NULL) {
1289255332Scy				FREE_MB_T(*fin->fin_mp);
1290255332Scy			}
1291255332Scy
1292255332Scy			*fin->fin_mp = NULL;
1293172776Sdarrenr			fin->fin_m = NULL;
1294145516Sdarrenr			return NULL;
1295145516Sdarrenr		}
1296172776Sdarrenr
1297255332Scy		if (n == NULL)
1298255332Scy			*fin->fin_mp = m;
1299255332Scy
1300172776Sdarrenr		while (M_LEN(m) == 0) {
1301172776Sdarrenr			m = m->m_next;
1302172776Sdarrenr		}
1303172776Sdarrenr		fin->fin_m = m;
1304145516Sdarrenr		ip = MTOD(m, char *) + ipoff;
1305255332Scy
1306255332Scy		fin->fin_ip = (ip_t *)ip;
1307255332Scy		if (fin->fin_dp != NULL)
1308255332Scy			fin->fin_dp = (char *)fin->fin_ip + dpoff;
1309255332Scy		if (fin->fin_fraghdr != NULL)
1310255332Scy			fin->fin_fraghdr = (char *)ip +
1311255332Scy					   ((char *)fin->fin_fraghdr -
1312255332Scy					    (char *)fin->fin_ip);
1313145516Sdarrenr	}
1314145516Sdarrenr
1315145516Sdarrenr	if (len == fin->fin_plen)
1316145516Sdarrenr		fin->fin_flx |= FI_COALESCE;
1317145516Sdarrenr	return ip;
1318145516Sdarrenr}
1319170268Sdarrenr
1320170268Sdarrenr
1321255332Scyint
1322255332Scyipf_inject(fin, m)
1323255332Scy	fr_info_t *fin;
1324255332Scy	mb_t *m;
1325170268Sdarrenr{
1326170268Sdarrenr	int error = 0;
1327170268Sdarrenr
1328170268Sdarrenr	if (fin->fin_out == 0) {
1329170268Sdarrenr		netisr_dispatch(NETISR_IP, m);
1330170268Sdarrenr	} else {
1331173931Sdarrenr		fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1332173931Sdarrenr		fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1333170268Sdarrenr		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1334170268Sdarrenr	}
1335170268Sdarrenr
1336170268Sdarrenr	return error;
1337170268Sdarrenr}
1338172776Sdarrenr
1339172776Sdarrenrint ipf_pfil_unhook(void) {
1340172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1341172776Sdarrenr	struct pfil_head *ph_inet;
1342172776Sdarrenr#  ifdef USE_INET6
1343172776Sdarrenr	struct pfil_head *ph_inet6;
1344172776Sdarrenr#  endif
1345172776Sdarrenr#endif
1346172776Sdarrenr
1347172776Sdarrenr#ifdef NETBSD_PF
1348172776Sdarrenr	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1349172776Sdarrenr	if (ph_inet != NULL)
1350255332Scy		pfil_remove_hook((void *)ipf_check_wrapper, NULL,
1351172776Sdarrenr		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1352172776Sdarrenr# ifdef USE_INET6
1353172776Sdarrenr	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1354172776Sdarrenr	if (ph_inet6 != NULL)
1355255332Scy		pfil_remove_hook((void *)ipf_check_wrapper6, NULL,
1356172776Sdarrenr		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1357172776Sdarrenr# endif
1358172776Sdarrenr#endif
1359172776Sdarrenr
1360172776Sdarrenr	return (0);
1361172776Sdarrenr}
1362172776Sdarrenr
1363172776Sdarrenrint ipf_pfil_hook(void) {
1364172776Sdarrenr#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1365172776Sdarrenr	struct pfil_head *ph_inet;
1366172776Sdarrenr#  ifdef USE_INET6
1367172776Sdarrenr	struct pfil_head *ph_inet6;
1368172776Sdarrenr#  endif
1369172776Sdarrenr#endif
1370172776Sdarrenr
1371172776Sdarrenr# ifdef NETBSD_PF
1372172776Sdarrenr	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1373172776Sdarrenr#    ifdef USE_INET6
1374172776Sdarrenr	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1375172776Sdarrenr#    endif
1376172776Sdarrenr	if (ph_inet == NULL
1377172776Sdarrenr#    ifdef USE_INET6
1378172776Sdarrenr	    && ph_inet6 == NULL
1379172776Sdarrenr#    endif
1380255332Scy	   ) {
1381172776Sdarrenr		return ENODEV;
1382255332Scy	}
1383172776Sdarrenr
1384172776Sdarrenr	if (ph_inet != NULL)
1385255332Scy		pfil_add_hook((void *)ipf_check_wrapper, NULL,
1386172776Sdarrenr		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1387172776Sdarrenr#  ifdef USE_INET6
1388172776Sdarrenr	if (ph_inet6 != NULL)
1389255332Scy		pfil_add_hook((void *)ipf_check_wrapper6, NULL,
1390172776Sdarrenr				      PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1391172776Sdarrenr#  endif
1392172776Sdarrenr# endif
1393172776Sdarrenr	return (0);
1394172776Sdarrenr}
1395172776Sdarrenr
1396172776Sdarrenrvoid
1397172776Sdarrenripf_event_reg(void)
1398172776Sdarrenr{
1399255332Scy	ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1400255332Scy					       ipf_ifevent, &ipfmain, \
1401172776Sdarrenr					       EVENTHANDLER_PRI_ANY);
1402255332Scy	ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
1403255332Scy					       ipf_ifevent, &ipfmain, \
1404172776Sdarrenr					       EVENTHANDLER_PRI_ANY);
1405255332Scy	ipf_clonetag  = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1406255332Scy					       &ipfmain, EVENTHANDLER_PRI_ANY);
1407172776Sdarrenr}
1408172776Sdarrenr
1409172776Sdarrenrvoid
1410172776Sdarrenripf_event_dereg(void)
1411172776Sdarrenr{
1412172776Sdarrenr	if (ipf_arrivetag != NULL) {
1413172776Sdarrenr		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1414172776Sdarrenr	}
1415172776Sdarrenr	if (ipf_departtag != NULL) {
1416172776Sdarrenr		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1417172776Sdarrenr	}
1418172776Sdarrenr	if (ipf_clonetag != NULL) {
1419172776Sdarrenr		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1420172776Sdarrenr	}
1421172776Sdarrenr}
1422255332Scy
1423255332Scy
1424255332Scyu_32_t
1425255332Scyipf_random()
1426255332Scy{
1427255332Scy	return arc4random();
1428255332Scy}
1429255332Scy
1430255332Scy
1431255332Scyu_int
1432255332Scyipf_pcksum(fin, hlen, sum)
1433255332Scy	fr_info_t *fin;
1434255332Scy	int hlen;
1435255332Scy	u_int sum;
1436255332Scy{
1437255332Scy	struct mbuf *m;
1438255332Scy	u_int sum2;
1439255332Scy	int off;
1440255332Scy
1441255332Scy	m = fin->fin_m;
1442255332Scy	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
1443255332Scy	m->m_data += hlen;
1444255332Scy	m->m_len -= hlen;
1445255332Scy	sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
1446255332Scy	m->m_len += hlen;
1447255332Scy	m->m_data -= hlen;
1448255332Scy
1449255332Scy	/*
1450255332Scy	 * Both sum and sum2 are partial sums, so combine them together.
1451255332Scy	 */
1452255332Scy	sum += ~sum2 & 0xffff;
1453255332Scy	while (sum > 0xffff)
1454255332Scy		sum = (sum & 0xffff) + (sum >> 16);
1455255332Scy	sum2 = ~sum & 0xffff;
1456255332Scy	return sum2;
1457255332Scy}
1458