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