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