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