ip_fil_freebsd.c revision 341378
192108Sphk/*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c 341378 2018-12-01 18:09:17Z cy $	*/
292108Sphk
392108Sphk/*
492108Sphk * Copyright (C) 2012 by Darren Reed.
592108Sphk *
692108Sphk * See the IPFILTER.LICENCE file for details on licencing.
792108Sphk */
892108Sphk#if !defined(lint)
992108Sphkstatic const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
1092108Sphkstatic const char rcsid[] = "@(#)$Id$";
1192108Sphk#endif
1292108Sphk
1392108Sphk#if defined(KERNEL) || defined(_KERNEL)
1492108Sphk# undef KERNEL
1592108Sphk# undef _KERNEL
1692108Sphk# define	KERNEL	1
1792108Sphk# define	_KERNEL	1
1892108Sphk#endif
1992108Sphk#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
2092108Sphk    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
2192108Sphk# include "opt_inet6.h"
2292108Sphk#endif
2392108Sphk#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \
2492108Sphk    !defined(KLD_MODULE) && !defined(IPFILTER_LKM)
2592108Sphk# include "opt_random_ip_id.h"
2692108Sphk#endif
2792108Sphk#include <sys/param.h>
2892108Sphk#include <sys/errno.h>
2992108Sphk#include <sys/types.h>
3092108Sphk#include <sys/file.h>
3192108Sphk# include <sys/fcntl.h>
3292108Sphk# include <sys/filio.h>
3392108Sphk#include <sys/time.h>
3492108Sphk#include <sys/systm.h>
3592108Sphk# include <sys/dirent.h>
36116196Sobrien#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000)
37116196Sobrien#include <sys/jail.h>
3892108Sphk#endif
3992108Sphk# include <sys/mbuf.h>
4092108Sphk# include <sys/sockopt.h>
4192108Sphk#if !defined(__hpux)
4292108Sphk# include <sys/mbuf.h>
4392108Sphk#endif
4492108Sphk#include <sys/socket.h>
4592108Sphk# include <sys/selinfo.h>
4693250Sphk# include <netinet/tcp_var.h>
47249507Sivoras
4892108Sphk#include <net/if.h>
4992108Sphk# include <net/if_var.h>
5092108Sphk#  include <net/netisr.h>
5192108Sphk#include <net/route.h>
5292108Sphk#include <netinet/in.h>
5392108Sphk#include <netinet/in_var.h>
54110523Sphk#include <netinet/in_systm.h>
55110523Sphk#include <netinet/ip.h>
5692108Sphk#include <netinet/ip_var.h>
5792108Sphk#include <netinet/tcp.h>
5892108Sphk#if defined(__FreeBSD_version) && (__FreeBSD_version >= 800000)
5992108Sphk#include <net/vnet.h>
6092108Sphk#else
6192108Sphk#define CURVNET_SET(arg)
6292108Sphk#define CURVNET_RESTORE()
6392108Sphk#endif
6492108Sphk#if defined(__osf__)
6592108Sphk# include <netinet/tcp_timer.h>
6692108Sphk#endif
6792108Sphk#include <netinet/udp.h>
6892108Sphk#include <netinet/tcpip.h>
6992108Sphk#include <netinet/ip_icmp.h>
7092108Sphk#include "netinet/ip_compat.h"
7192108Sphk#ifdef USE_INET6
7292108Sphk# include <netinet/icmp6.h>
7392108Sphk#endif
7492108Sphk#include "netinet/ip_fil.h"
7593248Sphk#include "netinet/ip_nat.h"
7692108Sphk#include "netinet/ip_frag.h"
7792108Sphk#include "netinet/ip_state.h"
7892108Sphk#include "netinet/ip_proxy.h"
7992108Sphk#include "netinet/ip_auth.h"
8092108Sphk#include "netinet/ip_sync.h"
8192108Sphk#include "netinet/ip_lookup.h"
8292108Sphk#include "netinet/ip_dstlist.h"
8392108Sphk#ifdef	IPFILTER_SCAN
8492108Sphk#include "netinet/ip_scan.h"
8592108Sphk#endif
8692108Sphk#include "netinet/ip_pool.h"
8792108Sphk# include <sys/malloc.h>
8893248Sphk#include <sys/kernel.h>
8992108Sphk#ifdef CSUM_DATA_VALID
9092108Sphk#include <machine/in_cksum.h>
9192108Sphk#endif
9292108Sphkextern	int	ip_optcopy __P((struct ip *, struct ip *));
9392108Sphk
9492108Sphk
9592108Sphk# ifdef IPFILTER_M_IPFILTER
96104452SphkMALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
97112989Sphk# endif
9892108Sphk
9993248Sphk
10092108Sphkstatic	u_short	ipid = 0;
10192108Sphkstatic	int	(*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **));
102112989Sphkstatic	int	ipf_send_ip __P((fr_info_t *, mb_t *));
103104452Sphkstatic void	ipf_timer_func __P((void *arg));
104104452Sphkint		ipf_locks_done = 0;
10592108Sphk
10693774Sphkipf_main_softc_t ipfmain;
10793248Sphk
108250868Sjh# include <sys/conf.h>
10992108Sphk# if defined(NETBSD_PF)
11092108Sphk#  include <net/pfil.h>
11192108Sphk# endif /* NETBSD_PF */
112106101Sphk/*
113106101Sphk * We provide the ipf_checkp name just to minimize changes later.
114106101Sphk */
115106101Sphkint (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
116106101Sphk
11792108Sphk
118117342Sphkstatic eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
119117342Sphk
120106101Sphkstatic void ipf_ifevent(void *arg);
121106101Sphk
122106101Sphkstatic void ipf_ifevent(arg)
123107111Sphk	void *arg;
124107111Sphk{
125106101Sphk        ipf_sync(arg, NULL);
126106101Sphk}
127106101Sphk
128106101Sphk
129106101Sphk
130106101Sphkstatic int
13192108Sphkipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
132106101Sphk{
133106101Sphk	struct ip *ip = mtod(*mp, struct ip *);
134106101Sphk	int rv;
135106101Sphk
136106101Sphk	/*
137106101Sphk	 * IPFilter expects evreything in network byte order
138106101Sphk	 */
139106101Sphk#if (__FreeBSD_version < 1000019)
140106101Sphk	ip->ip_len = htons(ip->ip_len);
141112989Sphk	ip->ip_off = htons(ip->ip_off);
142106101Sphk#endif
143106101Sphk	rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT),
144106101Sphk		       mp);
145106101Sphk#if (__FreeBSD_version < 1000019)
146112989Sphk	if ((rv == 0) && (*mp != NULL)) {
147106101Sphk		ip = mtod(*mp, struct ip *);
148106101Sphk		ip->ip_len = ntohs(ip->ip_len);
149152342Smarcel		ip->ip_off = ntohs(ip->ip_off);
150249507Sivoras	}
151152342Smarcel#endif
152152342Smarcel	return rv;
153106101Sphk}
154106101Sphk
155106101Sphk# ifdef USE_INET6
156106101Sphk#  include <netinet/ip6.h>
157260479Smav
158260479Smavstatic int
159205385Sjhipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
160205385Sjh{
161205385Sjh	return (ipf_check(&ipfmain, mtod(*mp, struct ip *),
162260479Smav			  sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp));
163205385Sjh}
164205385Sjh# endif
165260479Smav#if	defined(IPFILTER_LKM)
166260479Smavint ipf_identify(s)
167260479Smav	char *s;
168260479Smav{
169205385Sjh	if (strcmp(s, "ipl") == 0)
170260479Smav		return 1;
171205385Sjh	return 0;
172205385Sjh}
173260479Smav#endif /* IPFILTER_LKM */
174205385Sjh
175260479Smav
176205385Sjhstatic void
177260479Smavipf_timer_func(arg)
178205385Sjh	void *arg;
179205385Sjh{
180205385Sjh	ipf_main_softc_t *softc = arg;
181205385Sjh	SPL_INT(s);
182205385Sjh
18392108Sphk	SPL_NET(s);
18492108Sphk	READ_ENTER(&softc->ipf_global);
18592108Sphk
18695405Sphk        if (softc->ipf_running > 0)
18795405Sphk		ipf_slowtimer(softc);
18895405Sphk
18995405Sphk	if (softc->ipf_running == -1 || softc->ipf_running == 1) {
19092108Sphk#if 0
19192108Sphk		softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
192117342Sphk#endif
193117342Sphk		callout_init(&softc->ipf_slow_ch, 1);
194117342Sphk		callout_reset(&softc->ipf_slow_ch,
19592108Sphk			(hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
19692108Sphk			ipf_timer_func, softc);
19792108Sphk	}
19892108Sphk	RWLOCK_EXIT(&softc->ipf_global);
19992108Sphk	SPL_X(s);
20092108Sphk}
20192108Sphk
20292108Sphk
20392108Sphkint
20492108Sphkipfattach(softc)
20592108Sphk	ipf_main_softc_t *softc;
20695405Sphk{
20795405Sphk#ifdef USE_SPL
20892108Sphk	int s;
20992108Sphk#endif
210260479Smav
211260479Smav	SPL_NET(s);
212260479Smav	if (softc->ipf_running > 0) {
213105540Sphk		SPL_X(s);
214105540Sphk		return EBUSY;
215105542Sphk	}
216222603Sae
217222603Sae	if (ipf_init_all(softc) < 0) {
218281301Smav		SPL_X(s);
219281301Smav		return EIO;
220281301Smav	}
221117342Sphk
222117342Sphk
22392108Sphk	if (ipf_checkp != ipf_check) {
22492108Sphk		ipf_savep = ipf_checkp;
22592108Sphk		ipf_checkp = ipf_check;
22692108Sphk	}
22792108Sphk
22892108Sphk	bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait));
22992108Sphk	softc->ipf_running = 1;
23092108Sphk
23192108Sphk	if (softc->ipf_control_forwarding & 1)
23292108Sphk		V_ipforwarding = 1;
23392108Sphk
23492108Sphk	ipid = 0;
23592108Sphk
23692108Sphk	SPL_X(s);
23795405Sphk#if 0
23895405Sphk	softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
239260479Smav				     (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
240260479Smav#endif
241260479Smav	callout_init(&softc->ipf_slow_ch, 1);
24292108Sphk	callout_reset(&softc->ipf_slow_ch, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT,
243117342Sphk		ipf_timer_func, softc);
244117342Sphk	return 0;
245117342Sphk}
24692108Sphk
24792108Sphk
24892108Sphk/*
24992108Sphk * Disable the filter by removing the hooks from the IP input/output
25092108Sphk * stream.
25192108Sphk */
25292108Sphkint
25392108Sphkipfdetach(softc)
25492108Sphk	ipf_main_softc_t *softc;
25592108Sphk{
25692108Sphk#ifdef USE_SPL
25792108Sphk	int s;
25892108Sphk#endif
25992108Sphk
26092108Sphk	if (softc->ipf_control_forwarding & 2)
26192108Sphk		V_ipforwarding = 0;
26292108Sphk
26392108Sphk	SPL_NET(s);
26492108Sphk
26593248Sphk#if 0
26692108Sphk	if (softc->ipf_slow_ch.callout != NULL)
26792108Sphk		untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
26892108Sphk	bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
26995405Sphk#endif
270260479Smav	callout_drain(&softc->ipf_slow_ch);
271260479Smav
272260479Smav#ifndef NETBSD_PF
27392108Sphk	if (ipf_checkp != NULL)
27492108Sphk		ipf_checkp = ipf_savep;
27592108Sphk	ipf_savep = NULL;
27692108Sphk#endif
27792108Sphk
27893248Sphk	ipf_fini_all(softc);
27992108Sphk
28092108Sphk	softc->ipf_running = -2;
281104452Sphk
282104452Sphk	SPL_X(s);
28392108Sphk
28493248Sphk	return 0;
28592108Sphk}
286104452Sphk
28792108Sphk
28893774Sphk/*
28992108Sphk * Filter ioctl interface.
29092108Sphk */
29193248Sphkint
29292108Sphkipfioctl(dev, cmd, data, mode, p)
29392108Sphk	struct thread *p;
29492108Sphk#    define	p_cred	td_ucred
29592108Sphk#    define	p_uid	td_ucred->cr_ruid
29692108Sphk	struct cdev *dev;
297104452Sphk	ioctlcmd_t cmd;
298112989Sphk	caddr_t data;
29992108Sphk	int mode;
30092108Sphk{
301112989Sphk	int error = 0, unit = 0;
302105091Sphk	SPL_INT(s);
303104452Sphk
30492108Sphk#if (BSD >= 199306)
30592108Sphk        if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
30692108Sphk	{
307107953Sphk		ipfmain.ipf_interror = 130001;
30892108Sphk		return EPERM;
30992108Sphk	}
31092108Sphk#endif
31192108Sphk
31292108Sphk	unit = GET_MINOR(dev);
31392108Sphk	if ((IPL_LOGMAX < unit) || (unit < 0)) {
314104195Sphk		ipfmain.ipf_interror = 130002;
315115949Sphk		return ENXIO;
316104195Sphk	}
31792108Sphk
318	if (ipfmain.ipf_running <= 0) {
319		if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
320			ipfmain.ipf_interror = 130003;
321			return EIO;
322		}
323		if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
324		    cmd != SIOCIPFSET && cmd != SIOCFRENB &&
325		    cmd != SIOCGETFS && cmd != SIOCGETFF &&
326		    cmd != SIOCIPFINTERROR) {
327			ipfmain.ipf_interror = 130004;
328			return EIO;
329		}
330	}
331
332	SPL_NET(s);
333
334	CURVNET_SET(TD_TO_VNET(p));
335	error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p);
336	CURVNET_RESTORE();
337	if (error != -1) {
338		SPL_X(s);
339		return error;
340	}
341
342	SPL_X(s);
343
344	return error;
345}
346
347
348/*
349 * ipf_send_reset - this could conceivably be a call to tcp_respond(), but that
350 * requires a large amount of setting up and isn't any more efficient.
351 */
352int
353ipf_send_reset(fin)
354	fr_info_t *fin;
355{
356	struct tcphdr *tcp, *tcp2;
357	int tlen = 0, hlen;
358	struct mbuf *m;
359#ifdef USE_INET6
360	ip6_t *ip6;
361#endif
362	ip_t *ip;
363
364	tcp = fin->fin_dp;
365	if (tcp->th_flags & TH_RST)
366		return -1;		/* feedback loop */
367
368	if (ipf_checkl4sum(fin) == -1)
369		return -1;
370
371	tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
372			((tcp->th_flags & TH_SYN) ? 1 : 0) +
373			((tcp->th_flags & TH_FIN) ? 1 : 0);
374
375#ifdef USE_INET6
376	hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t);
377#else
378	hlen = sizeof(ip_t);
379#endif
380#ifdef MGETHDR
381	MGETHDR(m, M_DONTWAIT, MT_HEADER);
382#else
383	MGET(m, M_DONTWAIT, MT_HEADER);
384#endif
385	if (m == NULL)
386		return -1;
387	if (sizeof(*tcp2) + hlen > MLEN) {
388		MCLGET(m, M_DONTWAIT);
389		if ((m->m_flags & M_EXT) == 0) {
390			FREE_MB_T(m);
391			return -1;
392		}
393	}
394
395	m->m_len = sizeof(*tcp2) + hlen;
396#if (BSD >= 199103)
397	m->m_data += max_linkhdr;
398	m->m_pkthdr.len = m->m_len;
399	m->m_pkthdr.rcvif = (struct ifnet *)0;
400#endif
401	ip = mtod(m, struct ip *);
402	bzero((char *)ip, hlen);
403#ifdef USE_INET6
404	ip6 = (ip6_t *)ip;
405#endif
406	tcp2 = (struct tcphdr *)((char *)ip + hlen);
407	tcp2->th_sport = tcp->th_dport;
408	tcp2->th_dport = tcp->th_sport;
409
410	if (tcp->th_flags & TH_ACK) {
411		tcp2->th_seq = tcp->th_ack;
412		tcp2->th_flags = TH_RST;
413		tcp2->th_ack = 0;
414	} else {
415		tcp2->th_seq = 0;
416		tcp2->th_ack = ntohl(tcp->th_seq);
417		tcp2->th_ack += tlen;
418		tcp2->th_ack = htonl(tcp2->th_ack);
419		tcp2->th_flags = TH_RST|TH_ACK;
420	}
421	TCP_X2_A(tcp2, 0);
422	TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2);
423	tcp2->th_win = tcp->th_win;
424	tcp2->th_sum = 0;
425	tcp2->th_urp = 0;
426
427#ifdef USE_INET6
428	if (fin->fin_v == 6) {
429		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
430		ip6->ip6_plen = htons(sizeof(struct tcphdr));
431		ip6->ip6_nxt = IPPROTO_TCP;
432		ip6->ip6_hlim = 0;
433		ip6->ip6_src = fin->fin_dst6.in6;
434		ip6->ip6_dst = fin->fin_src6.in6;
435		tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
436					 sizeof(*ip6), sizeof(*tcp2));
437		return ipf_send_ip(fin, m);
438	}
439#endif
440	ip->ip_p = IPPROTO_TCP;
441	ip->ip_len = htons(sizeof(struct tcphdr));
442	ip->ip_src.s_addr = fin->fin_daddr;
443	ip->ip_dst.s_addr = fin->fin_saddr;
444	tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
445	ip->ip_len = htons(hlen + sizeof(*tcp2));
446	return ipf_send_ip(fin, m);
447}
448
449
450/*
451 * ip_len must be in network byte order when called.
452 */
453static int
454ipf_send_ip(fin, m)
455	fr_info_t *fin;
456	mb_t *m;
457{
458	fr_info_t fnew;
459	ip_t *ip, *oip;
460	int hlen;
461
462	ip = mtod(m, ip_t *);
463	bzero((char *)&fnew, sizeof(fnew));
464	fnew.fin_main_soft = fin->fin_main_soft;
465
466	IP_V_A(ip, fin->fin_v);
467	switch (fin->fin_v)
468	{
469	case 4 :
470		oip = fin->fin_ip;
471		hlen = sizeof(*oip);
472		fnew.fin_v = 4;
473		fnew.fin_p = ip->ip_p;
474		fnew.fin_plen = ntohs(ip->ip_len);
475		IP_HL_A(ip, sizeof(*oip) >> 2);
476		ip->ip_tos = oip->ip_tos;
477		ip->ip_id = fin->fin_ip->ip_id;
478#if defined(FreeBSD) && (__FreeBSD_version > 460000)
479		ip->ip_off = htons(path_mtu_discovery ? IP_DF : 0);
480#else
481		ip->ip_off = 0;
482#endif
483		ip->ip_ttl = V_ip_defttl;
484		ip->ip_sum = 0;
485		break;
486#ifdef USE_INET6
487	case 6 :
488	{
489		ip6_t *ip6 = (ip6_t *)ip;
490
491		ip6->ip6_vfc = 0x60;
492		ip6->ip6_hlim = IPDEFTTL;
493
494		hlen = sizeof(*ip6);
495		fnew.fin_p = ip6->ip6_nxt;
496		fnew.fin_v = 6;
497		fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
498		break;
499	}
500#endif
501	default :
502		return EINVAL;
503	}
504#ifdef IPSEC
505	m->m_pkthdr.rcvif = NULL;
506#endif
507
508	fnew.fin_ifp = fin->fin_ifp;
509	fnew.fin_flx = FI_NOCKSUM;
510	fnew.fin_m = m;
511	fnew.fin_ip = ip;
512	fnew.fin_mp = &m;
513	fnew.fin_hlen = hlen;
514	fnew.fin_dp = (char *)ip + hlen;
515	(void) ipf_makefrip(hlen, ip, &fnew);
516
517	return ipf_fastroute(m, &m, &fnew, NULL);
518}
519
520
521int
522ipf_send_icmp_err(type, fin, dst)
523	int type;
524	fr_info_t *fin;
525	int dst;
526{
527	int err, hlen, xtra, iclen, ohlen, avail, code;
528	struct in_addr dst4;
529	struct icmp *icmp;
530	struct mbuf *m;
531	i6addr_t dst6;
532	void *ifp;
533#ifdef USE_INET6
534	ip6_t *ip6;
535#endif
536	ip_t *ip, *ip2;
537
538	if ((type < 0) || (type >= ICMP_MAXTYPE))
539		return -1;
540
541	code = fin->fin_icode;
542#ifdef USE_INET6
543#if 0
544	/* XXX Fix an off by one error: s/>/>=/
545	 was:
546	 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
547	 Fix obtained from NetBSD ip_fil_netbsd.c r1.4: */
548#endif
549	if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
550		return -1;
551#endif
552
553	if (ipf_checkl4sum(fin) == -1)
554		return -1;
555#ifdef MGETHDR
556	MGETHDR(m, M_DONTWAIT, MT_HEADER);
557#else
558	MGET(m, M_DONTWAIT, MT_HEADER);
559#endif
560	if (m == NULL)
561		return -1;
562	avail = MHLEN;
563
564	xtra = 0;
565	hlen = 0;
566	ohlen = 0;
567	dst4.s_addr = 0;
568	ifp = fin->fin_ifp;
569	if (fin->fin_v == 4) {
570		if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
571			switch (ntohs(fin->fin_data[0]) >> 8)
572			{
573			case ICMP_ECHO :
574			case ICMP_TSTAMP :
575			case ICMP_IREQ :
576			case ICMP_MASKREQ :
577				break;
578			default :
579				FREE_MB_T(m);
580				return 0;
581			}
582
583		if (dst == 0) {
584			if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp,
585					&dst6, NULL) == -1) {
586				FREE_MB_T(m);
587				return -1;
588			}
589			dst4 = dst6.in4;
590		} else
591			dst4.s_addr = fin->fin_daddr;
592
593		hlen = sizeof(ip_t);
594		ohlen = fin->fin_hlen;
595		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
596		if (fin->fin_hlen < fin->fin_plen)
597			xtra = MIN(fin->fin_dlen, 8);
598		else
599			xtra = 0;
600	}
601
602#ifdef USE_INET6
603	else if (fin->fin_v == 6) {
604		hlen = sizeof(ip6_t);
605		ohlen = sizeof(ip6_t);
606		iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
607		type = icmptoicmp6types[type];
608		if (type == ICMP6_DST_UNREACH)
609			code = icmptoicmp6unreach[code];
610
611		if (iclen + max_linkhdr + fin->fin_plen > avail) {
612			MCLGET(m, M_DONTWAIT);
613			if ((m->m_flags & M_EXT) == 0) {
614				FREE_MB_T(m);
615				return -1;
616			}
617			avail = MCLBYTES;
618		}
619		xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
620		xtra = MIN(xtra, IPV6_MMTU - iclen);
621		if (dst == 0) {
622			if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp,
623					&dst6, NULL) == -1) {
624				FREE_MB_T(m);
625				return -1;
626			}
627		} else
628			dst6 = fin->fin_dst6;
629	}
630#endif
631	else {
632		FREE_MB_T(m);
633		return -1;
634	}
635
636	avail -= (max_linkhdr + iclen);
637	if (avail < 0) {
638		FREE_MB_T(m);
639		return -1;
640	}
641	if (xtra > avail)
642		xtra = avail;
643	iclen += xtra;
644	m->m_data += max_linkhdr;
645	m->m_pkthdr.rcvif = (struct ifnet *)0;
646	m->m_pkthdr.len = iclen;
647	m->m_len = iclen;
648	ip = mtod(m, ip_t *);
649	icmp = (struct icmp *)((char *)ip + hlen);
650	ip2 = (ip_t *)&icmp->icmp_ip;
651
652	icmp->icmp_type = type;
653	icmp->icmp_code = fin->fin_icode;
654	icmp->icmp_cksum = 0;
655#ifdef icmp_nextmtu
656	if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
657		if (fin->fin_mtu != 0) {
658			icmp->icmp_nextmtu = htons(fin->fin_mtu);
659
660		} else if (ifp != NULL) {
661			icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
662
663		} else {	/* make up a number... */
664			icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
665		}
666	}
667#endif
668
669	bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
670
671#ifdef USE_INET6
672	ip6 = (ip6_t *)ip;
673	if (fin->fin_v == 6) {
674		ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow;
675		ip6->ip6_plen = htons(iclen - hlen);
676		ip6->ip6_nxt = IPPROTO_ICMPV6;
677		ip6->ip6_hlim = 0;
678		ip6->ip6_src = dst6.in6;
679		ip6->ip6_dst = fin->fin_src6.in6;
680		if (xtra > 0)
681			bcopy((char *)fin->fin_ip + ohlen,
682			      (char *)&icmp->icmp_ip + ohlen, xtra);
683		icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6,
684					     sizeof(*ip6), iclen - hlen);
685	} else
686#endif
687	{
688		ip->ip_p = IPPROTO_ICMP;
689		ip->ip_src.s_addr = dst4.s_addr;
690		ip->ip_dst.s_addr = fin->fin_saddr;
691
692		if (xtra > 0)
693			bcopy((char *)fin->fin_ip + ohlen,
694			      (char *)&icmp->icmp_ip + ohlen, xtra);
695		icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
696					     sizeof(*icmp) + 8);
697		ip->ip_len = htons(iclen);
698		ip->ip_p = IPPROTO_ICMP;
699	}
700	err = ipf_send_ip(fin, m);
701	return err;
702}
703
704
705
706
707/*
708 * m0 - pointer to mbuf where the IP packet starts
709 * mpp - pointer to the mbuf pointer that is the start of the mbuf chain
710 */
711int
712ipf_fastroute(m0, mpp, fin, fdp)
713	mb_t *m0, **mpp;
714	fr_info_t *fin;
715	frdest_t *fdp;
716{
717	register struct ip *ip, *mhip;
718	register struct mbuf *m = *mpp;
719	register struct route *ro;
720	int len, off, error = 0, hlen, code;
721	struct ifnet *ifp, *sifp;
722	struct sockaddr_in *dst;
723	struct route iproute;
724	u_short ip_off;
725	frdest_t node;
726	frentry_t *fr;
727
728	ro = NULL;
729
730#ifdef M_WRITABLE
731	/*
732	* HOT FIX/KLUDGE:
733	*
734	* If the mbuf we're about to send is not writable (because of
735	* a cluster reference, for example) we'll need to make a copy
736	* of it since this routine modifies the contents.
737	*
738	* If you have non-crappy network hardware that can transmit data
739	* from the mbuf, rather than making a copy, this is gonna be a
740	* problem.
741	*/
742	if (M_WRITABLE(m) == 0) {
743		m0 = m_dup(m, M_DONTWAIT);
744		if (m0 != NULL) {
745			FREE_MB_T(m);
746			m = m0;
747			*mpp = m;
748		} else {
749			error = ENOBUFS;
750			FREE_MB_T(m);
751			goto done;
752		}
753	}
754#endif
755
756#ifdef USE_INET6
757	if (fin->fin_v == 6) {
758		/*
759		 * currently "to <if>" and "to <if>:ip#" are not supported
760		 * for IPv6
761		 */
762		return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
763	}
764#endif
765
766	hlen = fin->fin_hlen;
767	ip = mtod(m0, struct ip *);
768	ifp = NULL;
769
770	/*
771	 * Route packet.
772	 */
773	ro = &iproute;
774	bzero(ro, sizeof (*ro));
775	dst = (struct sockaddr_in *)&ro->ro_dst;
776	dst->sin_family = AF_INET;
777	dst->sin_addr = ip->ip_dst;
778
779	fr = fin->fin_fr;
780	if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
781	    (fdp->fd_type == FRD_DSTLIST)) {
782		if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
783			fdp = &node;
784	}
785
786	if (fdp != NULL)
787		ifp = fdp->fd_ptr;
788	else
789		ifp = fin->fin_ifp;
790
791	if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
792		error = -2;
793		goto bad;
794	}
795
796	if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
797		dst->sin_addr = fdp->fd_ip;
798
799	dst->sin_len = sizeof(*dst);
800	in_rtalloc(ro, M_GETFIB(m0));
801
802	if ((ifp == NULL) && (ro->ro_rt != NULL))
803		ifp = ro->ro_rt->rt_ifp;
804
805	if ((ro->ro_rt == NULL) || (ifp == NULL)) {
806		if (in_localaddr(ip->ip_dst))
807			error = EHOSTUNREACH;
808		else
809			error = ENETUNREACH;
810		goto bad;
811	}
812	if (ro->ro_rt->rt_flags & RTF_GATEWAY)
813		dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
814	if (ro->ro_rt)
815		counter_u64_add(ro->ro_rt->rt_pksent, 1);
816
817	/*
818	 * For input packets which are being "fastrouted", they won't
819	 * go back through output filtering and miss their chance to get
820	 * NAT'd and counted.  Duplicated packets aren't considered to be
821	 * part of the normal packet stream, so do not NAT them or pass
822	 * them through stateful checking, etc.
823	 */
824	if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) {
825		sifp = fin->fin_ifp;
826		fin->fin_ifp = ifp;
827		fin->fin_out = 1;
828		(void) ipf_acctpkt(fin, NULL);
829		fin->fin_fr = NULL;
830		if (!fr || !(fr->fr_flags & FR_RETMASK)) {
831			u_32_t pass;
832
833			(void) ipf_state_check(fin, &pass);
834		}
835
836		switch (ipf_nat_checkout(fin, NULL))
837		{
838		case 0 :
839			break;
840		case 1 :
841			ip->ip_sum = 0;
842			break;
843		case -1 :
844			error = -1;
845			goto bad;
846			break;
847		}
848
849		fin->fin_ifp = sifp;
850		fin->fin_out = 0;
851	} else
852		ip->ip_sum = 0;
853	/*
854	 * If small enough for interface, can just send directly.
855	 */
856	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
857		if (!ip->ip_sum)
858			ip->ip_sum = in_cksum(m, hlen);
859		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
860			    ro
861			);
862		goto done;
863	}
864	/*
865	 * Too large for interface; fragment if possible.
866	 * Must be able to put at least 8 bytes per fragment.
867	 */
868	ip_off = ntohs(ip->ip_off);
869	if (ip_off & IP_DF) {
870		error = EMSGSIZE;
871		goto bad;
872	}
873	len = (ifp->if_mtu - hlen) &~ 7;
874	if (len < 8) {
875		error = EMSGSIZE;
876		goto bad;
877	}
878
879    {
880	int mhlen, firstlen = len;
881	struct mbuf **mnext = &m->m_act;
882
883	/*
884	 * Loop through length of segment after first fragment,
885	 * make new header and copy data of each part and link onto chain.
886	 */
887	m0 = m;
888	mhlen = sizeof (struct ip);
889	for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
890#ifdef MGETHDR
891		MGETHDR(m, M_DONTWAIT, MT_HEADER);
892#else
893		MGET(m, M_DONTWAIT, MT_HEADER);
894#endif
895		if (m == NULL) {
896			m = m0;
897			error = ENOBUFS;
898			goto bad;
899		}
900		m->m_data += max_linkhdr;
901		mhip = mtod(m, struct ip *);
902		bcopy((char *)ip, (char *)mhip, sizeof(*ip));
903		if (hlen > sizeof (struct ip)) {
904			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
905			IP_HL_A(mhip, mhlen >> 2);
906		}
907		m->m_len = mhlen;
908		mhip->ip_off = ((off - hlen) >> 3) + ip_off;
909		if (off + len >= ntohs(ip->ip_len))
910			len = ntohs(ip->ip_len) - off;
911		else
912			mhip->ip_off |= IP_MF;
913		mhip->ip_len = htons((u_short)(len + mhlen));
914		*mnext = m;
915		m->m_next = m_copy(m0, off, len);
916		if (m->m_next == 0) {
917			error = ENOBUFS;	/* ??? */
918			goto sendorfree;
919		}
920		m->m_pkthdr.len = mhlen + len;
921		m->m_pkthdr.rcvif = NULL;
922		mhip->ip_off = htons((u_short)mhip->ip_off);
923		mhip->ip_sum = 0;
924		mhip->ip_sum = in_cksum(m, mhlen);
925		mnext = &m->m_act;
926	}
927	/*
928	 * Update first fragment by trimming what's been copied out
929	 * and updating header, then send each fragment (in order).
930	 */
931	m_adj(m0, hlen + firstlen - ip->ip_len);
932	ip->ip_len = htons((u_short)(hlen + firstlen));
933	ip->ip_off = htons((u_short)IP_MF);
934	ip->ip_sum = 0;
935	ip->ip_sum = in_cksum(m0, hlen);
936sendorfree:
937	for (m = m0; m; m = m0) {
938		m0 = m->m_act;
939		m->m_act = 0;
940		if (error == 0)
941			error = (*ifp->if_output)(ifp, m,
942			    (struct sockaddr *)dst,
943			    ro
944			    );
945		else
946			FREE_MB_T(m);
947	}
948    }
949done:
950	if (!error)
951		ipfmain.ipf_frouteok[0]++;
952	else
953		ipfmain.ipf_frouteok[1]++;
954
955	if ((ro != NULL) && (ro->ro_rt != NULL)) {
956		RTFREE(ro->ro_rt);
957	}
958	return 0;
959bad:
960	if (error == EMSGSIZE) {
961		sifp = fin->fin_ifp;
962		code = fin->fin_icode;
963		fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
964		fin->fin_ifp = ifp;
965		(void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
966		fin->fin_ifp = sifp;
967		fin->fin_icode = code;
968	}
969	FREE_MB_T(m);
970	goto done;
971}
972
973
974int
975ipf_verifysrc(fin)
976	fr_info_t *fin;
977{
978	struct sockaddr_in *dst;
979	struct route iproute;
980
981	bzero((char *)&iproute, sizeof(iproute));
982	dst = (struct sockaddr_in *)&iproute.ro_dst;
983	dst->sin_len = sizeof(*dst);
984	dst->sin_family = AF_INET;
985	dst->sin_addr = fin->fin_src;
986	in_rtalloc(&iproute, 0);
987	if (iproute.ro_rt == NULL)
988		return 0;
989	return (fin->fin_ifp == iproute.ro_rt->rt_ifp);
990}
991
992
993/*
994 * return the first IP Address associated with an interface
995 */
996int
997ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
998	ipf_main_softc_t *softc;
999	int v, atype;
1000	void *ifptr;
1001	i6addr_t *inp, *inpmask;
1002{
1003#ifdef USE_INET6
1004	struct in6_addr *inp6 = NULL;
1005#endif
1006	struct sockaddr *sock, *mask;
1007	struct sockaddr_in *sin;
1008	struct ifaddr *ifa;
1009	struct ifnet *ifp;
1010
1011	if ((ifptr == NULL) || (ifptr == (void *)-1))
1012		return -1;
1013
1014	sin = NULL;
1015	ifp = ifptr;
1016
1017	if (v == 4)
1018		inp->in4.s_addr = 0;
1019#ifdef USE_INET6
1020	else if (v == 6)
1021		bzero((char *)inp, sizeof(*inp));
1022#endif
1023	ifa = TAILQ_FIRST(&ifp->if_addrhead);
1024
1025	sock = ifa->ifa_addr;
1026	while (sock != NULL && ifa != NULL) {
1027		sin = (struct sockaddr_in *)sock;
1028		if ((v == 4) && (sin->sin_family == AF_INET))
1029			break;
1030#ifdef USE_INET6
1031		if ((v == 6) && (sin->sin_family == AF_INET6)) {
1032			inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
1033			if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
1034			    !IN6_IS_ADDR_LOOPBACK(inp6))
1035				break;
1036		}
1037#endif
1038		ifa = TAILQ_NEXT(ifa, ifa_link);
1039		if (ifa != NULL)
1040			sock = ifa->ifa_addr;
1041	}
1042
1043	if (ifa == NULL || sin == NULL)
1044		return -1;
1045
1046	mask = ifa->ifa_netmask;
1047	if (atype == FRI_BROADCAST)
1048		sock = ifa->ifa_broadaddr;
1049	else if (atype == FRI_PEERADDR)
1050		sock = ifa->ifa_dstaddr;
1051
1052	if (sock == NULL)
1053		return -1;
1054
1055#ifdef USE_INET6
1056	if (v == 6) {
1057		return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
1058					 (struct sockaddr_in6 *)mask,
1059					 inp, inpmask);
1060	}
1061#endif
1062	return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
1063				 (struct sockaddr_in *)mask,
1064				 &inp->in4, &inpmask->in4);
1065}
1066
1067
1068u_32_t
1069ipf_newisn(fin)
1070	fr_info_t *fin;
1071{
1072	u_32_t newiss;
1073	newiss = arc4random();
1074	return newiss;
1075}
1076
1077
1078/* ------------------------------------------------------------------------ */
1079/* Function:    ipf_nextipid                                                */
1080/* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
1081/* Parameters:  fin(I) - pointer to packet information                      */
1082/*                                                                          */
1083/* Returns the next IPv4 ID to use for this packet.                         */
1084/* ------------------------------------------------------------------------ */
1085u_short
1086ipf_nextipid(fin)
1087	fr_info_t *fin;
1088{
1089	u_short id;
1090
1091#ifndef	RANDOM_IP_ID
1092	MUTEX_ENTER(&ipfmain.ipf_rw);
1093	id = ipid++;
1094	MUTEX_EXIT(&ipfmain.ipf_rw);
1095#else
1096	id = ip_randomid();
1097#endif
1098
1099	return id;
1100}
1101
1102
1103INLINE int
1104ipf_checkv4sum(fin)
1105	fr_info_t *fin;
1106{
1107#ifdef CSUM_DATA_VALID
1108	int manual = 0;
1109	u_short sum;
1110	ip_t *ip;
1111	mb_t *m;
1112
1113	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1114		return 0;
1115
1116	if ((fin->fin_flx & FI_SHORT) != 0)
1117		return 1;
1118
1119	if (fin->fin_cksum != FI_CK_NEEDED)
1120		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1121
1122	m = fin->fin_m;
1123	if (m == NULL) {
1124		manual = 1;
1125		goto skipauto;
1126	}
1127	ip = fin->fin_ip;
1128
1129	if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
1130	    CSUM_IP_CHECKED) {
1131		fin->fin_cksum = FI_CK_BAD;
1132		fin->fin_flx |= FI_BAD;
1133		return -1;
1134	}
1135	if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
1136		/* Depending on the driver, UDP may have zero checksum */
1137		if (fin->fin_p == IPPROTO_UDP && (fin->fin_flx &
1138		    (FI_FRAG|FI_SHORT|FI_BAD)) == 0) {
1139			udphdr_t *udp = fin->fin_dp;
1140			if (udp->uh_sum == 0) {
1141				/*
1142				 * we're good no matter what the hardware
1143				 * checksum flags and csum_data say (handling
1144				 * of csum_data for zero UDP checksum is not
1145				 * consistent across all drivers)
1146				 */
1147				fin->fin_cksum = 1;
1148				return 0;
1149			}
1150		}
1151
1152		if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
1153			sum = m->m_pkthdr.csum_data;
1154		else
1155			sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
1156					htonl(m->m_pkthdr.csum_data +
1157					fin->fin_dlen + fin->fin_p));
1158		sum ^= 0xffff;
1159		if (sum != 0) {
1160			fin->fin_cksum = FI_CK_BAD;
1161			fin->fin_flx |= FI_BAD;
1162		} else {
1163			fin->fin_cksum = FI_CK_SUMOK;
1164			return 0;
1165		}
1166	} else {
1167		if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
1168			fin->fin_cksum = FI_CK_L4FULL;
1169			return 0;
1170		} else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
1171			   m->m_pkthdr.csum_flags == CSUM_UDP) {
1172			fin->fin_cksum = FI_CK_L4PART;
1173			return 0;
1174		} else if (m->m_pkthdr.csum_flags == CSUM_IP) {
1175			fin->fin_cksum = FI_CK_L4PART;
1176			return 0;
1177		} else {
1178			manual = 1;
1179		}
1180	}
1181skipauto:
1182	if (manual != 0) {
1183		if (ipf_checkl4sum(fin) == -1) {
1184			fin->fin_flx |= FI_BAD;
1185			return -1;
1186		}
1187	}
1188#else
1189	if (ipf_checkl4sum(fin) == -1) {
1190		fin->fin_flx |= FI_BAD;
1191		return -1;
1192	}
1193#endif
1194	return 0;
1195}
1196
1197
1198#ifdef USE_INET6
1199INLINE int
1200ipf_checkv6sum(fin)
1201	fr_info_t *fin;
1202{
1203	if ((fin->fin_flx & FI_NOCKSUM) != 0)
1204		return 0;
1205
1206	if ((fin->fin_flx & FI_SHORT) != 0)
1207		return 1;
1208
1209	if (fin->fin_cksum != FI_CK_NEEDED)
1210		return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
1211
1212	if (ipf_checkl4sum(fin) == -1) {
1213		fin->fin_flx |= FI_BAD;
1214		return -1;
1215	}
1216	return 0;
1217}
1218#endif /* USE_INET6 */
1219
1220
1221size_t
1222mbufchainlen(m0)
1223	struct mbuf *m0;
1224	{
1225	size_t len;
1226
1227	if ((m0->m_flags & M_PKTHDR) != 0) {
1228		len = m0->m_pkthdr.len;
1229	} else {
1230		struct mbuf *m;
1231
1232		for (m = m0, len = 0; m != NULL; m = m->m_next)
1233			len += m->m_len;
1234	}
1235	return len;
1236}
1237
1238
1239/* ------------------------------------------------------------------------ */
1240/* Function:    ipf_pullup                                                  */
1241/* Returns:     NULL == pullup failed, else pointer to protocol header      */
1242/* Parameters:  xmin(I)- pointer to buffer where data packet starts         */
1243/*              fin(I) - pointer to packet information                      */
1244/*              len(I) - number of bytes to pullup                          */
1245/*                                                                          */
1246/* Attempt to move at least len bytes (from the start of the buffer) into a */
1247/* single buffer for ease of access.  Operating system native functions are */
1248/* used to manage buffers - if necessary.  If the entire packet ends up in  */
1249/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
1250/* not been called.  Both fin_ip and fin_dp are updated before exiting _IF_ */
1251/* and ONLY if the pullup succeeds.                                         */
1252/*                                                                          */
1253/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
1254/* of buffers that starts at *fin->fin_mp.                                  */
1255/* ------------------------------------------------------------------------ */
1256void *
1257ipf_pullup(xmin, fin, len)
1258	mb_t *xmin;
1259	fr_info_t *fin;
1260	int len;
1261{
1262	int dpoff, ipoff;
1263	mb_t *m = xmin;
1264	char *ip;
1265
1266	if (m == NULL)
1267		return NULL;
1268
1269	ip = (char *)fin->fin_ip;
1270	if ((fin->fin_flx & FI_COALESCE) != 0)
1271		return ip;
1272
1273	ipoff = fin->fin_ipoff;
1274	if (fin->fin_dp != NULL)
1275		dpoff = (char *)fin->fin_dp - (char *)ip;
1276	else
1277		dpoff = 0;
1278
1279	if (M_LEN(m) < len) {
1280		mb_t *n = *fin->fin_mp;
1281		/*
1282		 * Assume that M_PKTHDR is set and just work with what is left
1283		 * rather than check..
1284		 * Should not make any real difference, anyway.
1285		 */
1286		if (m != n) {
1287			/*
1288			 * Record the mbuf that points to the mbuf that we're
1289			 * about to go to work on so that we can update the
1290			 * m_next appropriately later.
1291			 */
1292			for (; n->m_next != m; n = n->m_next)
1293				;
1294		} else {
1295			n = NULL;
1296		}
1297
1298#ifdef MHLEN
1299		if (len > MHLEN)
1300#else
1301		if (len > MLEN)
1302#endif
1303		{
1304#ifdef HAVE_M_PULLDOWN
1305			if (m_pulldown(m, 0, len, NULL) == NULL)
1306				m = NULL;
1307#else
1308			FREE_MB_T(*fin->fin_mp);
1309			m = NULL;
1310			n = NULL;
1311#endif
1312		} else
1313		{
1314			m = m_pullup(m, len);
1315		}
1316		if (n != NULL)
1317			n->m_next = m;
1318		if (m == NULL) {
1319			/*
1320			 * When n is non-NULL, it indicates that m pointed to
1321			 * a sub-chain (tail) of the mbuf and that the head
1322			 * of this chain has not yet been free'd.
1323			 */
1324			if (n != NULL) {
1325				FREE_MB_T(*fin->fin_mp);
1326			}
1327
1328			*fin->fin_mp = NULL;
1329			fin->fin_m = NULL;
1330			return NULL;
1331		}
1332
1333		if (n == NULL)
1334			*fin->fin_mp = m;
1335
1336		while (M_LEN(m) == 0) {
1337			m = m->m_next;
1338		}
1339		fin->fin_m = m;
1340		ip = MTOD(m, char *) + ipoff;
1341
1342		fin->fin_ip = (ip_t *)ip;
1343		if (fin->fin_dp != NULL)
1344			fin->fin_dp = (char *)fin->fin_ip + dpoff;
1345		if (fin->fin_fraghdr != NULL)
1346			fin->fin_fraghdr = (char *)ip +
1347					   ((char *)fin->fin_fraghdr -
1348					    (char *)fin->fin_ip);
1349	}
1350
1351	if (len == fin->fin_plen)
1352		fin->fin_flx |= FI_COALESCE;
1353	return ip;
1354}
1355
1356
1357int
1358ipf_inject(fin, m)
1359	fr_info_t *fin;
1360	mb_t *m;
1361{
1362	int error = 0;
1363
1364	if (fin->fin_out == 0) {
1365		netisr_dispatch(NETISR_IP, m);
1366	} else {
1367		fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
1368		fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
1369		error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1370	}
1371
1372	return error;
1373}
1374
1375int ipf_pfil_unhook(void) {
1376#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1377	struct pfil_head *ph_inet;
1378#  ifdef USE_INET6
1379	struct pfil_head *ph_inet6;
1380#  endif
1381#endif
1382
1383#ifdef NETBSD_PF
1384	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1385	if (ph_inet != NULL)
1386		pfil_remove_hook((void *)ipf_check_wrapper, NULL,
1387		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1388# ifdef USE_INET6
1389	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1390	if (ph_inet6 != NULL)
1391		pfil_remove_hook((void *)ipf_check_wrapper6, NULL,
1392		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1393# endif
1394#endif
1395
1396	return (0);
1397}
1398
1399int ipf_pfil_hook(void) {
1400#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
1401	struct pfil_head *ph_inet;
1402#  ifdef USE_INET6
1403	struct pfil_head *ph_inet6;
1404#  endif
1405#endif
1406
1407# ifdef NETBSD_PF
1408	ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
1409#    ifdef USE_INET6
1410	ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
1411#    endif
1412	if (ph_inet == NULL
1413#    ifdef USE_INET6
1414	    && ph_inet6 == NULL
1415#    endif
1416	   ) {
1417		return ENODEV;
1418	}
1419
1420	if (ph_inet != NULL)
1421		pfil_add_hook((void *)ipf_check_wrapper, NULL,
1422		    PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
1423#  ifdef USE_INET6
1424	if (ph_inet6 != NULL)
1425		pfil_add_hook((void *)ipf_check_wrapper6, NULL,
1426				      PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
1427#  endif
1428# endif
1429	return (0);
1430}
1431
1432void
1433ipf_event_reg(void)
1434{
1435	ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
1436					       ipf_ifevent, &ipfmain, \
1437					       EVENTHANDLER_PRI_ANY);
1438	ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
1439					       ipf_ifevent, &ipfmain, \
1440					       EVENTHANDLER_PRI_ANY);
1441	ipf_clonetag  = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
1442					       &ipfmain, EVENTHANDLER_PRI_ANY);
1443}
1444
1445void
1446ipf_event_dereg(void)
1447{
1448	if (ipf_arrivetag != NULL) {
1449		EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
1450	}
1451	if (ipf_departtag != NULL) {
1452		EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag);
1453	}
1454	if (ipf_clonetag != NULL) {
1455		EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
1456	}
1457}
1458
1459
1460u_32_t
1461ipf_random()
1462{
1463	return arc4random();
1464}
1465
1466
1467u_int
1468ipf_pcksum(fin, hlen, sum)
1469	fr_info_t *fin;
1470	int hlen;
1471	u_int sum;
1472{
1473	struct mbuf *m;
1474	u_int sum2;
1475	int off;
1476
1477	m = fin->fin_m;
1478	off = (char *)fin->fin_dp - (char *)fin->fin_ip;
1479	m->m_data += hlen;
1480	m->m_len -= hlen;
1481	sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
1482	m->m_len += hlen;
1483	m->m_data -= hlen;
1484
1485	/*
1486	 * Both sum and sum2 are partial sums, so combine them together.
1487	 */
1488	sum += ~sum2 & 0xffff;
1489	while (sum > 0xffff)
1490		sum = (sum & 0xffff) + (sum >> 16);
1491	sum2 = ~sum & 0xffff;
1492	return sum2;
1493}
1494