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