ip_fil_freebsd.c revision 342588
1/*	$FreeBSD: stable/11/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 342588 2018-12-29 03:18:16Z cy $	*/
2
3/*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8#if !defined(lint)
9static const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10static const char rcsid[] = "@(#)$Id$";
11#endif
12
13#if defined(KERNEL) || defined(_KERNEL)
14# undef KERNEL
15# undef _KERNEL
16# define	KERNEL	1
17# define	_KERNEL	1
18#endif
19#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
20    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
21# include "opt_inet6.h"
22#endif
23#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
24    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
25# include "opt_random_ip_id.h"
26#endif
27#include <sys/param.h>
28#include <sys/errno.h>
29#include <sys/types.h>
30#include <sys/file.h>
31# include <sys/fcntl.h>
32# include <sys/filio.h>
33#include <sys/time.h>
34#include <sys/systm.h>
35# include <sys/dirent.h>
36#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000)
37#include <sys/jail.h>
38#endif
39# include <sys/malloc.h>
40# include <sys/mbuf.h>
41# include <sys/sockopt.h>
42# include <sys/mbuf.h>
43#include <sys/socket.h>
44# include <sys/selinfo.h>
45# include <netinet/tcp_var.h>
46
47#include <net/if.h>
48# include <net/if_var.h>
49#  include <net/netisr.h>
50#include <net/route.h>
51#include <netinet/in.h>
52#include <netinet/in_fib.h>
53#include <netinet/in_var.h>
54#include <netinet/in_systm.h>
55#include <netinet/ip.h>
56#include <netinet/ip_var.h>
57#include <netinet/tcp.h>
58#include <net/vnet.h>
59#include <netinet/udp.h>
60#include <netinet/tcpip.h>
61#include <netinet/ip_icmp.h>
62#include "netinet/ip_compat.h"
63#ifdef USE_INET6
64# include <netinet/icmp6.h>
65#endif
66#include "netinet/ip_fil.h"
67#include "netinet/ip_nat.h"
68#include "netinet/ip_frag.h"
69#include "netinet/ip_state.h"
70#include "netinet/ip_proxy.h"
71#include "netinet/ip_auth.h"
72#include "netinet/ip_sync.h"
73#include "netinet/ip_lookup.h"
74#include "netinet/ip_dstlist.h"
75#ifdef	IPFILTER_SCAN
76#include "netinet/ip_scan.h"
77#endif
78#include "netinet/ip_pool.h"
79# include <sys/malloc.h>
80#include <sys/kernel.h>
81#ifdef CSUM_DATA_VALID
82#include <machine/in_cksum.h>
83#endif
84extern	int	ip_optcopy __P((struct ip *, struct ip *));
85
86# ifdef IPFILTER_M_IPFILTER
87MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
88# endif
89
90
91static	int	ipf_send_ip __P((fr_info_t *, mb_t *));
92static void	ipf_timer_func __P((void *arg));
93
94VNET_DEFINE(ipf_main_softc_t, ipfmain) = {
95	.ipf_running		= -2,
96};
97#define	V_ipfmain		VNET(ipfmain)
98
99# include <sys/conf.h>
100# if defined(NETBSD_PF)
101#  include <net/pfil.h>
102# endif /* NETBSD_PF */
103
104static eventhandler_tag ipf_arrivetag, ipf_departtag;
105#if 0
106/*
107 * Disable the "cloner" event handler;  we are getting interface
108 * events before the firewall is fully initiallized and also no vnet
109 * information thus leading to uninitialised memory accesses.
110 * In addition it is unclear why we need it in first place.
111 * If it turns out to be needed, well need a dedicated event handler
112 * for it to deal with the ifc and the correct vnet.
113 */
114static eventhandler_tag ipf_clonetag;
115#endif
116
117static void ipf_ifevent(void *arg, struct ifnet *ifp);
118
119static void ipf_ifevent(arg, ifp)
120	void *arg;
121	struct ifnet *ifp;
122{
123
124	CURVNET_SET(ifp->if_vnet);
125	if (V_ipfmain.ipf_running > 0)
126		ipf_sync(&V_ipfmain, NULL);
127	CURVNET_RESTORE();
128}
129
130
131
132static int
133ipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
134{
135	struct ip *ip = mtod(*mp, struct ip *);
136	int rv;
137
138	/*
139	 * IPFilter expects evreything in network byte order
140	 */
141#if (__FreeBSD_version < 1000019)
142	ip->ip_len = htons(ip->ip_len);
143	ip->ip_off = htons(ip->ip_off);
144#endif
145	CURVNET_SET(ifp->if_vnet);
146	rv = ipf_check(&V_ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT),
147		       mp);
148	CURVNET_RESTORE();
149#if (__FreeBSD_version < 1000019)
150	if ((rv == 0) && (*mp != NULL)) {
151		ip = mtod(*mp, struct ip *);
152		ip->ip_len = ntohs(ip->ip_len);
153		ip->ip_off = ntohs(ip->ip_off);
154	}
155#endif
156	return rv;
157}
158
159# ifdef USE_INET6
160#  include <netinet/ip6.h>
161
162static int
163ipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
164{
165	int error;
166
167	CURVNET_SET(ifp->if_vnet);
168	error = ipf_check(&V_ipfmain, mtod(*mp, struct ip *),
169			  sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp);
170	CURVNET_RESTORE();
171	return (error);
172}
173# endif
174#if	defined(IPFILTER_LKM)
175int ipf_identify(s)
176	char *s;
177{
178	if (strcmp(s, "ipl") == 0)
179		return 1;
180	return 0;
181}
182#endif /* IPFILTER_LKM */
183
184
185static void
186ipf_timer_func(arg)
187	void *arg;
188{
189	ipf_main_softc_t *softc = arg;
190	SPL_INT(s);
191
192	SPL_NET(s);
193	READ_ENTER(&softc->ipf_global);
194
195        if (softc->ipf_running > 0)
196		ipf_slowtimer(softc);
197
198	if (softc->ipf_running == -1 || softc->ipf_running == 1) {
199#if 0
200		softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
201#endif
202		callout_init(&softc->ipf_slow_ch, 1);
203		callout_reset(&softc->ipf_slow_ch,
204			(hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
205			ipf_timer_func, softc);
206	}
207	RWLOCK_EXIT(&softc->ipf_global);
208	SPL_X(s);
209}
210
211
212int
213ipfattach(softc)
214	ipf_main_softc_t *softc;
215{
216#ifdef USE_SPL
217	int s;
218#endif
219
220	SPL_NET(s);
221	if (softc->ipf_running > 0) {
222		SPL_X(s);
223		return EBUSY;
224	}
225
226	if (ipf_init_all(softc) < 0) {
227		SPL_X(s);
228		return EIO;
229	}
230
231
232	bzero((char *)V_ipfmain.ipf_selwait, sizeof(V_ipfmain.ipf_selwait));
233	softc->ipf_running = 1;
234
235	if (softc->ipf_control_forwarding & 1)
236		V_ipforwarding = 1;
237
238	SPL_X(s);
239#if 0
240	softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
241				     (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
242#endif
243	callout_init(&softc->ipf_slow_ch, 1);
244	callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
245		ipf_timer_func, softc);
246	return 0;
247}
248
249
250/*
251 * Disable the filter by removing the hooks from the IP input/output
252 * stream.
253 */
254int
255ipfdetach(softc)
256	ipf_main_softc_t *softc;
257{
258#ifdef USE_SPL
259	int s;
260#endif
261
262	if (softc->ipf_control_forwarding & 2)
263		V_ipforwarding = 0;
264
265	SPL_NET(s);
266
267#if 0
268	if (softc->ipf_slow_ch.callout != NULL)
269		untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
270	bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
271#endif
272	callout_drain(&softc->ipf_slow_ch);
273
274	ipf_fini_all(softc);
275
276	softc->ipf_running = -2;
277
278	SPL_X(s);
279
280	return 0;
281}
282
283
284/*
285 * Filter ioctl interface.
286 */
287int
288ipfioctl(dev, cmd, data, mode, p)
289	struct thread *p;
290#    define	p_cred	td_ucred
291#    define	p_uid	td_ucred->cr_ruid
292	struct cdev *dev;
293	ioctlcmd_t cmd;
294	caddr_t data;
295	int mode;
296{
297	int error = 0, unit = 0;
298	SPL_INT(s);
299
300	CURVNET_SET(TD_TO_VNET(p));
301#if (BSD >= 199306)
302        if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
303	{
304		V_ipfmain.ipf_interror = 130001;
305		CURVNET_RESTORE();
306		return EPERM;
307	}
308#endif
309
310	unit = GET_MINOR(dev);
311	if ((IPL_LOGMAX < unit) || (unit < 0)) {
312		V_ipfmain.ipf_interror = 130002;
313		CURVNET_RESTORE();
314		return ENXIO;
315	}
316
317	if (V_ipfmain.ipf_running <= 0) {
318		if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
319			V_ipfmain.ipf_interror = 130003;
320			CURVNET_RESTORE();
321			return EIO;
322		}
323		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
324		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
325		    cmd != SIOCGETFS && cmd != SIOCGETFF &&
326		    cmd != SIOCIPFINTERROR) {
327			V_ipfmain.ipf_interror = 130004;
328			CURVNET_RESTORE();
329			return EIO;
330		}
331	}
332
333	SPL_NET(s);
334
335	error = ipf_ioctlswitch(&V_ipfmain, unit, data, cmd, mode, p->p_uid, p);
336	CURVNET_RESTORE();
337	if (error != -1) {
338		SPL_X(s);
339		return error;
340	}
341
342	SPL_X(s);
343
344	return error;
345}
346
347
348/*
349 * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
350 * requires a large amount of setting up and isn't any more efficient.
351 */
352int
353ipf_send_reset(fin)
354	fr_info_t *fin;
355{
356	struct tcphdr *tcp, *tcp2;
357	int tlen = 0, hlen;
358	struct mbuf *m;
359#ifdef USE_INET6
360	ip6_t *ip6;
361#endif
362	ip_t *ip;
363
364	tcp = fin->fin_dp;
365	if (tcp->th_flags & TH_RST)
366		return -1;		/* feedback loop */
367
368	if (ipf_checkl4sum(fin) == -1)
369		return -1;
370
371	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
372			((tcp->th_flags & TH_SYN) ? 1 : 0) +
373			((tcp->th_flags & TH_FIN) ? 1 : 0);
374
375#ifdef USE_INET6
376	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
377#else
378	hlen = sizeof(ip_t);
379#endif
380#ifdef MGETHDR
381	MGETHDR(m, M_NOWAIT, MT_HEADER);
382#else
383	MGET(m, M_NOWAIT, MT_HEADER);
384#endif
385	if (m == NULL)
386		return -1;
387	if (sizeof(*tcp2) + hlen > MLEN) {
388		if (!(MCLGET(m, M_NOWAIT))) {
389			FREE_MB_T(m);
390			return -1;
391		}
392	}
393
394	m->m_len = sizeof(*tcp2) + hlen;
395#if (BSD >= 199103)
396	m->m_data += max_linkhdr;
397	m->m_pkthdr.len = m->m_len;
398	m->m_pkthdr.rcvif = (struct ifnet *)0;
399#endif
400	ip = mtod(m, struct ip *);
401	bzero((char *)ip, hlen);
402#ifdef USE_INET6
403	ip6 = (ip6_t *)ip;
404#endif
405	tcp2 = (struct tcphdr *)((char *)ip + hlen);
406	tcp2->th_sport = tcp->th_dport;
407	tcp2->th_dport = tcp->th_sport;
408
409	if (tcp->th_flags & TH_ACK) {
410		tcp2->th_seq = tcp->th_ack;
411		tcp2->th_flags = TH_RST;
412		tcp2->th_ack = 0;
413	} else {
414		tcp2->th_seq = 0;
415		tcp2->th_ack = ntohl(tcp->th_seq);
416		tcp2->th_ack += tlen;
417		tcp2->th_ack = htonl(tcp2->th_ack);
418		tcp2->th_flags = TH_RST|TH_ACK;
419	}
420	TCP_X2_A(tcp2, 0);
421	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
422	tcp2->th_win = tcp->th_win;
423	tcp2->th_sum = 0;
424	tcp2->th_urp = 0;
425
426#ifdef USE_INET6
427	if (fin->fin_v == 6) {
428		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
429		ip6->ip6_plen = htons(sizeof(struct tcphdr));
430		ip6->ip6_nxt = IPPROTO_TCP;
431		ip6->ip6_hlim = 0;
432		ip6->ip6_src = fin->fin_dst6.in6;
433		ip6->ip6_dst = fin->fin_src6.in6;
434		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
435					 sizeof(*ip6), sizeof(*tcp2));
436		return ipf_send_ip(fin, m);
437	}
438#endif
439	ip->ip_p = IPPROTO_TCP;
440	ip->ip_len = htons(sizeof(struct tcphdr));
441	ip->ip_src.s_addr = fin->fin_daddr;
442	ip->ip_dst.s_addr = fin->fin_saddr;
443	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
444	ip->ip_len = htons(hlen + sizeof(*tcp2));
445	return ipf_send_ip(fin, m);
446}
447
448
449/*
450 * ip_len must be in network byte order when called.
451 */
452static int
453ipf_send_ip(fin, m)
454	fr_info_t *fin;
455	mb_t *m;
456{
457	fr_info_t fnew;
458	ip_t *ip, *oip;
459	int hlen;
460
461	ip = mtod(m, ip_t *);
462	bzero((char *)&fnew, sizeof(fnew));
463	fnew.fin_main_soft = fin->fin_main_soft;
464
465	IP_V_A(ip, fin->fin_v);
466	switch (fin->fin_v)
467	{
468	case 4 :
469		oip = fin->fin_ip;
470		hlen = sizeof(*oip);
471		fnew.fin_v = 4;
472		fnew.fin_p = ip->ip_p;
473		fnew.fin_plen = ntohs(ip->ip_len);
474		IP_HL_A(ip, sizeof(*oip) >> 2);
475		ip->ip_tos = oip->ip_tos;
476		ip->ip_id = fin->fin_ip->ip_id;
477		ip->ip_off = htons(V_path_mtu_discovery ? IP_DF : 0);
478		ip->ip_ttl = V_ip_defttl;
479		ip->ip_sum = 0;
480		break;
481#ifdef USE_INET6
482	case 6 :
483	{
484		ip6_t *ip6 = (ip6_t *)ip;
485
486		ip6->ip6_vfc = 0x60;
487		ip6->ip6_hlim = IPDEFTTL;
488
489		hlen = sizeof(*ip6);
490		fnew.fin_p = ip6->ip6_nxt;
491		fnew.fin_v = 6;
492		fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
493		break;
494	}
495#endif
496	default :
497		return EINVAL;
498	}
499#ifdef IPSEC
500	m->m_pkthdr.rcvif = NULL;
501#endif
502
503	fnew.fin_ifp = fin->fin_ifp;
504	fnew.fin_flx = FI_NOCKSUM;
505	fnew.fin_m = m;
506	fnew.fin_ip = ip;
507	fnew.fin_mp = &m;
508	fnew.fin_hlen = hlen;
509	fnew.fin_dp = (char *)ip + hlen;
510	(void) ipf_makefrip(hlen, ip, &fnew);
511
512	return ipf_fastroute(m, &m, &fnew, NULL);
513}
514
515
516int
517ipf_send_icmp_err(type, fin, dst)
518	int type;
519	fr_info_t *fin;
520	int dst;
521{
522	int err, hlen, xtra, iclen, ohlen, avail, code;
523	struct in_addr dst4;
524	struct icmp *icmp;
525	struct mbuf *m;
526	i6addr_t dst6;
527	void *ifp;
528#ifdef USE_INET6
529	ip6_t *ip6;
530#endif
531	ip_t *ip, *ip2;
532
533	if ((type < 0) || (type >= ICMP_MAXTYPE))
534		return -1;
535
536	code = fin->fin_icode;
537#ifdef USE_INET6
538	/* See NetBSD ip_fil_netbsd.c r1.4: */
539	if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
540		return -1;
541#endif
542
543	if (ipf_checkl4sum(fin) == -1)
544		return -1;
545#ifdef MGETHDR
546	MGETHDR(m, M_NOWAIT, MT_HEADER);
547#else
548	MGET(m, M_NOWAIT, MT_HEADER);
549#endif
550	if (m == NULL)
551		return -1;
552	avail = MHLEN;
553
554	xtra = 0;
555	hlen = 0;
556	ohlen = 0;
557	dst4.s_addr = 0;
558	ifp = fin->fin_ifp;
559	if (fin->fin_v == 4) {
560		if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
561			switch (ntohs(fin->fin_data[0]) >> 8)
562			{
563			case ICMP_ECHO :
564			case ICMP_TSTAMP :
565			case ICMP_IREQ :
566			case ICMP_MASKREQ :
567				break;
568			default :
569				FREE_MB_T(m);
570				return 0;
571			}
572
573		if (dst == 0) {
574			if (ipf_ifpaddr(&V_ipfmain, 4, FRI_NORMAL, ifp,
575					&dst6, NULL) == -1) {
576				FREE_MB_T(m);
577				return -1;
578			}
579			dst4 = dst6.in4;
580		} else
581			dst4.s_addr = fin->fin_daddr;
582
583		hlen = sizeof(ip_t);
584		ohlen = fin->fin_hlen;
585		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
586		if (fin->fin_hlen < fin->fin_plen)
587			xtra = MIN(fin->fin_dlen, 8);
588		else
589			xtra = 0;
590	}
591
592#ifdef USE_INET6
593	else if (fin->fin_v == 6) {
594		hlen = sizeof(ip6_t);
595		ohlen = sizeof(ip6_t);
596		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
597		type = icmptoicmp6types[type];
598		if (type == ICMP6_DST_UNREACH)
599			code = icmptoicmp6unreach[code];
600
601		if (iclen + max_linkhdr + fin->fin_plen > avail) {
602			if (!(MCLGET(m, M_NOWAIT))) {
603				FREE_MB_T(m);
604				return -1;
605			}
606			avail = MCLBYTES;
607		}
608		xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
609		xtra = MIN(xtra, IPV6_MMTU - iclen);
610		if (dst == 0) {
611			if (ipf_ifpaddr(&V_ipfmain, 6, FRI_NORMAL, ifp,
612					&dst6, NULL) == -1) {
613				FREE_MB_T(m);
614				return -1;
615			}
616		} else
617			dst6 = fin->fin_dst6;
618	}
619#endif
620	else {
621		FREE_MB_T(m);
622		return -1;
623	}
624
625	avail -= (max_linkhdr + iclen);
626	if (avail < 0) {
627		FREE_MB_T(m);
628		return -1;
629	}
630	if (xtra > avail)
631		xtra = avail;
632	iclen += xtra;
633	m->m_data += max_linkhdr;
634	m->m_pkthdr.rcvif = (struct ifnet *)0;
635	m->m_pkthdr.len = iclen;
636	m->m_len = iclen;
637	ip = mtod(m, ip_t *);
638	icmp = (struct icmp *)((char *)ip + hlen);
639	ip2 = (ip_t *)&icmp->icmp_ip;
640
641	icmp->icmp_type = type;
642	icmp->icmp_code = fin->fin_icode;
643	icmp->icmp_cksum = 0;
644#ifdef icmp_nextmtu
645	if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
646		if (fin->fin_mtu != 0) {
647			icmp->icmp_nextmtu = htons(fin->fin_mtu);
648
649		} else if (ifp != NULL) {
650			icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
651
652		} else {	/* make up a number... */
653			icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
654		}
655	}
656#endif
657
658	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
659
660#ifdef USE_INET6
661	ip6 = (ip6_t *)ip;
662	if (fin->fin_v == 6) {
663		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
664		ip6->ip6_plen = htons(iclen - hlen);
665		ip6->ip6_nxt = IPPROTO_ICMPV6;
666		ip6->ip6_hlim = 0;
667		ip6->ip6_src = dst6.in6;
668		ip6->ip6_dst = fin->fin_src6.in6;
669		if (xtra > 0)
670			bcopy((char *)fin->fin_ip + ohlen,
671			      (char *)&icmp->icmp_ip + ohlen, xtra);
672		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
673					     sizeof(*ip6), iclen - hlen);
674	} else
675#endif
676	{
677		ip->ip_p = IPPROTO_ICMP;
678		ip->ip_src.s_addr = dst4.s_addr;
679		ip->ip_dst.s_addr = fin->fin_saddr;
680
681		if (xtra > 0)
682			bcopy((char *)fin->fin_ip + ohlen,
683			      (char *)&icmp->icmp_ip + ohlen, xtra);
684		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
685					     sizeof(*icmp) + 8);
686		ip->ip_len = htons(iclen);
687		ip->ip_p = IPPROTO_ICMP;
688	}
689	err = ipf_send_ip(fin, m);
690	return err;
691}
692
693
694
695
696/*
697 * m0 - pointer to mbuf where the IP packet starts
698 * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
699 */
700int
701ipf_fastroute(m0, mpp, fin, fdp)
702	mb_t *m0, **mpp;
703	fr_info_t *fin;
704	frdest_t *fdp;
705{
706	register struct ip *ip, *mhip;
707	register struct mbuf *m = *mpp;
708	int len, off, error = 0, hlen, code;
709	struct ifnet *ifp, *sifp;
710	struct sockaddr_in dst;
711	struct nhop4_extended nh4;
712	int has_nhop = 0;
713	u_long fibnum = 0;
714	u_short ip_off;
715	frdest_t node;
716	frentry_t *fr;
717
718#ifdef M_WRITABLE
719	/*
720	* HOT FIX/KLUDGE:
721	*
722	* If the mbuf we're about to send is not writable (because of
723	* a cluster reference, for example) we'll need to make a copy
724	* of it since this routine modifies the contents.
725	*
726	* If you have non-crappy network hardware that can transmit data
727	* from the mbuf, rather than making a copy, this is gonna be a
728	* problem.
729	*/
730	if (M_WRITABLE(m) == 0) {
731		m0 = m_dup(m, M_NOWAIT);
732		if (m0 != NULL) {
733			FREE_MB_T(m);
734			m = m0;
735			*mpp = m;
736		} else {
737			error = ENOBUFS;
738			FREE_MB_T(m);
739			goto done;
740		}
741	}
742#endif
743
744#ifdef USE_INET6
745	if (fin->fin_v == 6) {
746		/*
747		 * currently "to <if>" and "to <if>:ip#" are not supported
748		 * for IPv6
749		 */
750		return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
751	}
752#endif
753
754	hlen = fin->fin_hlen;
755	ip = mtod(m0, struct ip *);
756	ifp = NULL;
757
758	/*
759	 * Route packet.
760	 */
761	bzero(&dst, sizeof (dst));
762	dst.sin_family = AF_INET;
763	dst.sin_addr = ip->ip_dst;
764	dst.sin_len = sizeof(dst);
765
766	fr = fin->fin_fr;
767	if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
768	    (fdp->fd_type == FRD_DSTLIST)) {
769		if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
770			fdp = &node;
771	}
772
773	if (fdp != NULL)
774		ifp = fdp->fd_ptr;
775	else
776		ifp = fin->fin_ifp;
777
778	if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
779		error = -2;
780		goto bad;
781	}
782
783	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
784		dst.sin_addr = fdp->fd_ip;
785
786	fibnum = M_GETFIB(m0);
787	if (fib4_lookup_nh_ext(fibnum, dst.sin_addr, NHR_REF, 0, &nh4) != 0) {
788		if (in_localaddr(ip->ip_dst))
789			error = EHOSTUNREACH;
790		else
791			error = ENETUNREACH;
792		goto bad;
793	}
794
795	has_nhop = 1;
796	if (ifp == NULL)
797		ifp = nh4.nh_ifp;
798	if (nh4.nh_flags & NHF_GATEWAY)
799		dst.sin_addr = nh4.nh_addr;
800
801	/*
802	 * For input packets which are being "fastrouted", they won't
803	 * go back through output filtering and miss their chance to get
804	 * NAT'd and counted.  Duplicated packets aren't considered to be
805	 * part of the normal packet stream, so do not NAT them or pass
806	 * them through stateful checking, etc.
807	 */
808	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
809		sifp = fin->fin_ifp;
810		fin->fin_ifp = ifp;
811		fin->fin_out = 1;
812		(void) ipf_acctpkt(fin, NULL);
813		fin->fin_fr = NULL;
814		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
815			u_32_t pass;
816
817			(void) ipf_state_check(fin, &pass);
818		}
819
820		switch (ipf_nat_checkout(fin, NULL))
821		{
822		case 0 :
823			break;
824		case 1 :
825			ip->ip_sum = 0;
826			break;
827		case -1 :
828			error = -1;
829			goto bad;
830			break;
831		}
832
833		fin->fin_ifp = sifp;
834		fin->fin_out = 0;
835	} else
836		ip->ip_sum = 0;
837	/*
838	 * If small enough for interface, can just send directly.
839	 */
840	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
841		if (!ip->ip_sum)
842			ip->ip_sum = in_cksum(m, hlen);
843		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
844			    NULL
845			);
846		goto done;
847	}
848	/*
849	 * Too large for interface; fragment if possible.
850	 * Must be able to put at least 8 bytes per fragment.
851	 */
852	ip_off = ntohs(ip->ip_off);
853	if (ip_off & IP_DF) {
854		error = EMSGSIZE;
855		goto bad;
856	}
857	len = (ifp->if_mtu - hlen) &~ 7;
858	if (len < 8) {
859		error = EMSGSIZE;
860		goto bad;
861	}
862
863    {
864	int mhlen, firstlen = len;
865	struct mbuf **mnext = &m->m_act;
866
867	/*
868	 * Loop through length of segment after first fragment,
869	 * make new header and copy data of each part and link onto chain.
870	 */
871	m0 = m;
872	mhlen = sizeof (struct ip);
873	for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
874#ifdef MGETHDR
875		MGETHDR(m, M_NOWAIT, MT_HEADER);
876#else
877		MGET(m, M_NOWAIT, MT_HEADER);
878#endif
879		if (m == NULL) {
880			m = m0;
881			error = ENOBUFS;
882			goto bad;
883		}
884		m->m_data += max_linkhdr;
885		mhip = mtod(m, struct ip *);
886		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
887		if (hlen > sizeof (struct ip)) {
888			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
889			IP_HL_A(mhip, mhlen >> 2);
890		}
891		m->m_len = mhlen;
892		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
893		if (off + len >= ntohs(ip->ip_len))
894			len = ntohs(ip->ip_len) - off;
895		else
896			mhip->ip_off |= IP_MF;
897		mhip->ip_len = htons((u_short)(len + mhlen));
898		*mnext = m;
899		m->m_next = m_copy(m0, off, len);
900		if (m->m_next == 0) {
901			error = ENOBUFS;	/* ??? */
902			goto sendorfree;
903		}
904		m->m_pkthdr.len = mhlen + len;
905		m->m_pkthdr.rcvif = NULL;
906		mhip->ip_off = htons((u_short)mhip->ip_off);
907		mhip->ip_sum = 0;
908		mhip->ip_sum = in_cksum(m, mhlen);
909		mnext = &m->m_act;
910	}
911	/*
912	 * Update first fragment by trimming what's been copied out
913	 * and updating header, then send each fragment (in order).
914	 */
915	m_adj(m0, hlen + firstlen - ip->ip_len);
916	ip->ip_len = htons((u_short)(hlen + firstlen));
917	ip->ip_off = htons((u_short)IP_MF);
918	ip->ip_sum = 0;
919	ip->ip_sum = in_cksum(m0, hlen);
920sendorfree:
921	for (m = m0; m; m = m0) {
922		m0 = m->m_act;
923		m->m_act = 0;
924		if (error == 0)
925			error = (*ifp->if_output)(ifp, m,
926			    (struct sockaddr *)&dst,
927			    NULL
928			    );
929		else
930			FREE_MB_T(m);
931	}
932    }
933done:
934	if (!error)
935		V_ipfmain.ipf_frouteok[0]++;
936	else
937		V_ipfmain.ipf_frouteok[1]++;
938
939	if (has_nhop)
940		fib4_free_nh_ext(fibnum, &nh4);
941
942	return 0;
943bad:
944	if (error == EMSGSIZE) {
945		sifp = fin->fin_ifp;
946		code = fin->fin_icode;
947		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
948		fin->fin_ifp = ifp;
949		(void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
950		fin->fin_ifp = sifp;
951		fin->fin_icode = code;
952	}
953	FREE_MB_T(m);
954	goto done;
955}
956
957
958int
959ipf_verifysrc(fin)
960	fr_info_t *fin;
961{
962	struct nhop4_basic nh4;
963
964	if (fib4_lookup_nh_basic(0, fin->fin_src, 0, 0, &nh4) != 0)
965		return (0);
966	return (fin->fin_ifp == nh4.nh_ifp);
967}
968
969
970/*
971 * return the first IP Address associated with an interface
972 */
973int
974ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
975	ipf_main_softc_t *softc;
976	int v, atype;
977	void *ifptr;
978	i6addr_t *inp, *inpmask;
979{
980#ifdef USE_INET6
981	struct in6_addr *inp6 = NULL;
982#endif
983	struct sockaddr *sock, *mask;
984	struct sockaddr_in *sin;
985	struct ifaddr *ifa;
986	struct ifnet *ifp;
987
988	if ((ifptr == NULL) || (ifptr == (void *)-1))
989		return -1;
990
991	sin = NULL;
992	ifp = ifptr;
993
994	if (v == 4)
995		inp->in4.s_addr = 0;
996#ifdef USE_INET6
997	else if (v == 6)
998		bzero((char *)inp, sizeof(*inp));
999#endif
1000	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1001
1002	sock = ifa->ifa_addr;
1003	while (sock != NULL && ifa != NULL) {
1004		sin = (struct sockaddr_in *)sock;
1005		if ((v == 4) && (sin->sin_family == AF_INET))
1006			break;
1007#ifdef USE_INET6
1008		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1009			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1010			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1011			    !IN6_IS_ADDR_LOOPBACK(inp6))
1012				break;
1013		}
1014#endif
1015		ifa = TAILQ_NEXT(ifa, ifa_link);
1016		if (ifa != NULL)
1017			sock = ifa->ifa_addr;
1018	}
1019
1020	if (ifa == NULL || sin == NULL)
1021		return -1;
1022
1023	mask = ifa->ifa_netmask;
1024	if (atype == FRI_BROADCAST)
1025		sock = ifa->ifa_broadaddr;
1026	else if (atype == FRI_PEERADDR)
1027		sock = ifa->ifa_dstaddr;
1028
1029	if (sock == NULL)
1030		return -1;
1031
1032#ifdef USE_INET6
1033	if (v == 6) {
1034		return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1035					 (struct sockaddr_in6 *)mask,
1036					 inp, inpmask);
1037	}
1038#endif
1039	return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1040				 (struct sockaddr_in *)mask,
1041				 &inp->in4, &inpmask->in4);
1042}
1043
1044
1045u_32_t
1046ipf_newisn(fin)
1047	fr_info_t *fin;
1048{
1049	u_32_t newiss;
1050	newiss = arc4random();
1051	return newiss;
1052}
1053
1054
1055INLINE int
1056ipf_checkv4sum(fin)
1057	fr_info_t *fin;
1058{
1059#ifdef CSUM_DATA_VALID
1060	int manual = 0;
1061	u_short sum;
1062	ip_t *ip;
1063	mb_t *m;
1064
1065	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1066		return 0;
1067
1068	if ((fin->fin_flx & FI_SHORT) != 0)
1069		return 1;
1070
1071	if (fin->fin_cksum != FI_CK_NEEDED)
1072		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1073
1074	m = fin->fin_m;
1075	if (m == NULL) {
1076		manual = 1;
1077		goto skipauto;
1078	}
1079	ip = fin->fin_ip;
1080
1081	if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
1082	    CSUM_IP_CHECKED) {
1083		fin->fin_cksum = FI_CK_BAD;
1084		fin->fin_flx |= FI_BAD;
1085		DT2(ipf_fi_bad_checkv4sum_csum_ip_checked, fr_info_t *, fin, u_int, m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID));
1086		return -1;
1087	}
1088	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1089		/* Depending on the driver, UDP may have zero checksum */
1090		if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx &
1091		    (FI_FRAG|FI_SHORT|FI_BAD)) == 0) {
1092			udphdr_t *udp = fin->fin_dp;
1093			if (udp->uh_sum == 0) {
1094				/*
1095				 * we're good no matter what the hardware
1096				 * checksum flags and csum_data say (handling
1097				 * of csum_data for zero UDP checksum is not
1098				 * consistent across all drivers)
1099				 */
1100				fin->fin_cksum = 1;
1101				return 0;
1102			}
1103		}
1104
1105		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1106			sum = m->m_pkthdr.csum_data;
1107		else
1108			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1109					htonl(m->m_pkthdr.csum_data +
1110					fin->fin_dlen + fin->fin_p));
1111		sum ^= 0xffff;
1112		if (sum != 0) {
1113			fin->fin_cksum = FI_CK_BAD;
1114			fin->fin_flx |= FI_BAD;
1115			DT2(ipf_fi_bad_checkv4sum_sum, fr_info_t *, fin, u_int, sum);
1116		} else {
1117			fin->fin_cksum = FI_CK_SUMOK;
1118			return 0;
1119		}
1120	} else {
1121		if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
1122			fin->fin_cksum = FI_CK_L4FULL;
1123			return 0;
1124		} else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
1125			   m->m_pkthdr.csum_flags == CSUM_UDP) {
1126			fin->fin_cksum = FI_CK_L4PART;
1127			return 0;
1128		} else if (m->m_pkthdr.csum_flags == CSUM_IP) {
1129			fin->fin_cksum = FI_CK_L4PART;
1130			return 0;
1131		} else {
1132			manual = 1;
1133		}
1134	}
1135skipauto:
1136	if (manual != 0) {
1137		if (ipf_checkl4sum(fin) == -1) {
1138			fin->fin_flx |= FI_BAD;
1139			DT2(ipf_fi_bad_checkv4sum_manual, fr_info_t *, fin, u_int, manual);
1140			return -1;
1141		}
1142	}
1143#else
1144	if (ipf_checkl4sum(fin) == -1) {
1145		fin->fin_flx |= FI_BAD;
1146		DT2(ipf_fi_bad_checkv4sum_checkl4sum, fr_info_t *, fin, u_int, -1);
1147		return -1;
1148	}
1149#endif
1150	return 0;
1151}
1152
1153
1154#ifdef USE_INET6
1155INLINE int
1156ipf_checkv6sum(fin)
1157	fr_info_t *fin;
1158{
1159	if ((fin->fin_flx & FI_NOCKSUM) != 0) {
1160		DT(ipf_checkv6sum_fi_nocksum);
1161		return 0;
1162	}
1163
1164	if ((fin->fin_flx & FI_SHORT) != 0) {
1165		DT(ipf_checkv6sum_fi_short);
1166		return 1;
1167	}
1168
1169	if (fin->fin_cksum != FI_CK_NEEDED) {
1170		DT(ipf_checkv6sum_fi_ck_needed);
1171		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1172	}
1173
1174	if (ipf_checkl4sum(fin) == -1) {
1175		fin->fin_flx |= FI_BAD;
1176		DT2(ipf_fi_bad_checkv6sum_checkl4sum, fr_info_t *, fin, u_int, -1);
1177		return -1;
1178	}
1179	return 0;
1180}
1181#endif /* USE_INET6 */
1182
1183
1184size_t
1185mbufchainlen(m0)
1186	struct mbuf *m0;
1187	{
1188	size_t len;
1189
1190	if ((m0->m_flags & M_PKTHDR) != 0) {
1191		len = m0->m_pkthdr.len;
1192	} else {
1193		struct mbuf *m;
1194
1195		for (m = m0, len = 0; m != NULL; m = m->m_next)
1196			len += m->m_len;
1197	}
1198	return len;
1199}
1200
1201
1202/* ------------------------------------------------------------------------ */
1203/* Function:    ipf_pullup                                                  */
1204/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1205/* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
1206/*              fin(I) - pointer to packet information                      */
1207/*              len(I) - number of bytes to pullup                          */
1208/*                                                                          */
1209/* Attempt to move at least len bytes (from the start of the buffer) into a */
1210/* single buffer for ease of access.  Operating system native functions are */
1211/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1212/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
1213/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1214/* and ONLY if the pullup succeeds.                                         */
1215/*                                                                          */
1216/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
1217/* of buffers that starts at *fin->fin_mp.                                  */
1218/* ------------------------------------------------------------------------ */
1219void *
1220ipf_pullup(xmin, fin, len)
1221	mb_t *xmin;
1222	fr_info_t *fin;
1223	int len;
1224{
1225	int dpoff, ipoff;
1226	mb_t *m = xmin;
1227	char *ip;
1228
1229	if (m == NULL)
1230		return NULL;
1231
1232	ip = (char *)fin->fin_ip;
1233	if ((fin->fin_flx & FI_COALESCE) != 0)
1234		return ip;
1235
1236	ipoff = fin->fin_ipoff;
1237	if (fin->fin_dp != NULL)
1238		dpoff = (char *)fin->fin_dp - (char *)ip;
1239	else
1240		dpoff = 0;
1241
1242	if (M_LEN(m) < len) {
1243		mb_t *n = *fin->fin_mp;
1244		/*
1245		 * Assume that M_PKTHDR is set and just work with what is left
1246		 * rather than check..
1247		 * Should not make any real difference, anyway.
1248		 */
1249		if (m != n) {
1250			/*
1251			 * Record the mbuf that points to the mbuf that we're
1252			 * about to go to work on so that we can update the
1253			 * m_next appropriately later.
1254			 */
1255			for (; n->m_next != m; n = n->m_next)
1256				;
1257		} else {
1258			n = NULL;
1259		}
1260
1261#ifdef MHLEN
1262		if (len > MHLEN)
1263#else
1264		if (len > MLEN)
1265#endif
1266		{
1267#ifdef HAVE_M_PULLDOWN
1268			if (m_pulldown(m, 0, len, NULL) == NULL)
1269				m = NULL;
1270#else
1271			FREE_MB_T(*fin->fin_mp);
1272			m = NULL;
1273			n = NULL;
1274#endif
1275		} else
1276		{
1277			m = m_pullup(m, len);
1278		}
1279		if (n != NULL)
1280			n->m_next = m;
1281		if (m == NULL) {
1282			/*
1283			 * When n is non-NULL, it indicates that m pointed to
1284			 * a sub-chain (tail) of the mbuf and that the head
1285			 * of this chain has not yet been free'd.
1286			 */
1287			if (n != NULL) {
1288				FREE_MB_T(*fin->fin_mp);
1289			}
1290
1291			*fin->fin_mp = NULL;
1292			fin->fin_m = NULL;
1293			return NULL;
1294		}
1295
1296		if (n == NULL)
1297			*fin->fin_mp = m;
1298
1299		while (M_LEN(m) == 0) {
1300			m = m->m_next;
1301		}
1302		fin->fin_m = m;
1303		ip = MTOD(m, char *) + ipoff;
1304
1305		fin->fin_ip = (ip_t *)ip;
1306		if (fin->fin_dp != NULL)
1307			fin->fin_dp = (char *)fin->fin_ip + dpoff;
1308		if (fin->fin_fraghdr != NULL)
1309			fin->fin_fraghdr = (char *)ip +
1310					   ((char *)fin->fin_fraghdr -
1311					    (char *)fin->fin_ip);
1312	}
1313
1314	if (len == fin->fin_plen)
1315		fin->fin_flx |= FI_COALESCE;
1316	return ip;
1317}
1318
1319
1320int
1321ipf_inject(fin, m)
1322	fr_info_t *fin;
1323	mb_t *m;
1324{
1325	int error = 0;
1326
1327	if (fin->fin_out == 0) {
1328		netisr_dispatch(NETISR_IP, m);
1329	} else {
1330		fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1331		fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1332		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1333	}
1334
1335	return error;
1336}
1337
1338int ipf_pfil_unhook(void) {
1339#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1340	struct pfil_head *ph_inet;
1341#  ifdef USE_INET6
1342	struct pfil_head *ph_inet6;
1343#  endif
1344#endif
1345
1346#ifdef NETBSD_PF
1347	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1348	if (ph_inet != NULL)
1349		pfil_remove_hook((void *)ipf_check_wrapper, NULL,
1350		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1351# ifdef USE_INET6
1352	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1353	if (ph_inet6 != NULL)
1354		pfil_remove_hook((void *)ipf_check_wrapper6, NULL,
1355		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1356# endif
1357#endif
1358
1359	return (0);
1360}
1361
1362int ipf_pfil_hook(void) {
1363#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1364	struct pfil_head *ph_inet;
1365#  ifdef USE_INET6
1366	struct pfil_head *ph_inet6;
1367#  endif
1368#endif
1369
1370# ifdef NETBSD_PF
1371	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1372#    ifdef USE_INET6
1373	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1374#    endif
1375	if (ph_inet == NULL
1376#    ifdef USE_INET6
1377	    && ph_inet6 == NULL
1378#    endif
1379	   ) {
1380		return ENODEV;
1381	}
1382
1383	if (ph_inet != NULL)
1384		pfil_add_hook((void *)ipf_check_wrapper, NULL,
1385		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1386#  ifdef USE_INET6
1387	if (ph_inet6 != NULL)
1388		pfil_add_hook((void *)ipf_check_wrapper6, NULL,
1389				      PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1390#  endif
1391# endif
1392	return (0);
1393}
1394
1395void
1396ipf_event_reg(void)
1397{
1398	ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1399					       ipf_ifevent, NULL, \
1400					       EVENTHANDLER_PRI_ANY);
1401	ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
1402					       ipf_ifevent, NULL, \
1403					       EVENTHANDLER_PRI_ANY);
1404#if 0
1405	ipf_clonetag  = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1406					       NULL, EVENTHANDLER_PRI_ANY);
1407#endif
1408}
1409
1410void
1411ipf_event_dereg(void)
1412{
1413	if (ipf_arrivetag != NULL) {
1414		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1415	}
1416	if (ipf_departtag != NULL) {
1417		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1418	}
1419#if 0
1420	if (ipf_clonetag != NULL) {
1421		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1422	}
1423#endif
1424}
1425
1426
1427u_32_t
1428ipf_random()
1429{
1430	return arc4random();
1431}
1432
1433
1434u_int
1435ipf_pcksum(fin, hlen, sum)
1436	fr_info_t *fin;
1437	int hlen;
1438	u_int sum;
1439{
1440	struct mbuf *m;
1441	u_int sum2;
1442	int off;
1443
1444	m = fin->fin_m;
1445	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
1446	m->m_data += hlen;
1447	m->m_len -= hlen;
1448	sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
1449	m->m_len += hlen;
1450	m->m_data -= hlen;
1451
1452	/*
1453	 * Both sum and sum2 are partial sums, so combine them together.
1454	 */
1455	sum += ~sum2 & 0xffff;
1456	while (sum > 0xffff)
1457		sum = (sum & 0xffff) + (sum >> 16);
1458	sum2 = ~sum & 0xffff;
1459	return sum2;
1460}
1461