int len, off, error = 0, s;
int len, off, error = 0;
void ipfr_fastroute(m0, fin, fdp)struct mbuf *m0;fr_info_t *fin;frdest_t *fdp;{	register struct ip *ip, *mhip;	register struct mbuf *m = m0;	register struct route *ro;	struct ifnet *ifp = fdp->fd_ifp;	int len, off, error = 0, s;	int hlen = fin->fin_hlen;	struct route iproute;	struct sockaddr_in *dst;	ip = mtod(m0, struct ip *);	/*	 * Route packet.	 */	ro = &iproute;	bzero((caddr_t)ro, sizeof (*ro));	dst = (struct sockaddr_in *)&ro->ro_dst;	dst->sin_family = AF_INET;	dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst;#if	BSD >= 199306 && !(defined(__NetBSD__) || defined(__OpenBSD__))# ifdef	RTF_CLONING	rtalloc_ign(ro, RTF_CLONING);# else	rtalloc_ign(ro, RTF_PRCLONING);# endif#else	rtalloc(ro);#endif	if (!ifp) {		if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) {			error = -2;			goto bad;		}		if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {			if (in_localaddr(ip->ip_dst))				error = EHOSTUNREACH;			else				error = ENETUNREACH;			goto bad;		}		if (ro->ro_rt->rt_flags & RTF_GATEWAY)			dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;	}	ro->ro_rt->rt_use++;	/*		 * If small enough for interface, can just send directly.	 */	if (ip->ip_len <= ifp->if_mtu) {#ifndef sparc		ip->ip_id = htons(ip->ip_id);		ip->ip_len = htons(ip->ip_len);		ip->ip_off = htons(ip->ip_off);#endif		if (!ip->ip_sum)			ip->ip_sum = in_cksum(m, hlen);#if	BSD >= 199306		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,					  ro->ro_rt);#else		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);#endif		goto done;	}	/*	 * Too large for interface; fragment if possible.	 * Must be able to put at least 8 bytes per fragment.	 */	if (ip->ip_off & IP_DF) {		error = EMSGSIZE;		goto bad;	}	len = (ifp->if_mtu - hlen) &~ 7;	if (len < 8) {		error = EMSGSIZE;		goto bad;	}    {	int mhlen, firstlen = len;	struct mbuf **mnext = &m->m_act;	/*	 * Loop through length of segment after first fragment,	 * make new header and copy data of each part and link onto chain.	 */	m0 = m;	mhlen = sizeof (struct ip);	for (off = hlen + len; off < ip->ip_len; off += len) {		MGET(m, M_DONTWAIT, MT_HEADER);		if (m == 0) {			error = ENOBUFS;			goto bad;		}#if BSD >= 199306		m->m_data += max_linkhdr;#else		m->m_off = MMAXOFF - hlen;#endif		mhip = mtod(m, struct ip *);		bcopy((char *)ip, (char *)mhip, sizeof(*ip));		if (hlen > sizeof (struct ip)) {			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);			mhip->ip_hl = mhlen >> 2;		}		m->m_len = mhlen;		mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);		if (ip->ip_off & IP_MF)			mhip->ip_off |= IP_MF;		if (off + len >= ip->ip_len)			len = ip->ip_len - off;		else			mhip->ip_off |= IP_MF;		mhip->ip_len = htons((u_short)(len + mhlen));		m->m_next = m_copy(m0, off, len);		if (m->m_next == 0) {			error = ENOBUFS;	/* ??? */			goto sendorfree;		}#ifndef sparc		mhip->ip_off = htons((u_short)mhip->ip_off);#endif		mhip->ip_sum = 0;		mhip->ip_sum = in_cksum(m, mhlen);		*mnext = m;		mnext = &m->m_act;	}	/*	 * Update first fragment by trimming what's been copied out	 * and updating header, then send each fragment (in order).	 */	m_adj(m0, hlen + firstlen - ip->ip_len);	ip->ip_len = htons((u_short)(hlen + firstlen));	ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));	ip->ip_sum = 0;	ip->ip_sum = in_cksum(m0, hlen);sendorfree:	for (m = m0; m; m = m0) {		m0 = m->m_act;		m->m_act = 0;		if (error == 0)#if BSD >= 199306			error = (*ifp->if_output)(ifp, m,			    (struct sockaddr *)dst, ro->ro_rt);#else			error = (*ifp->if_output)(ifp, m,			    (struct sockaddr *)dst);#endif		else			m_freem(m);	}    }	done:	if (ro->ro_rt) {		RTFREE(ro->ro_rt);	}	return;bad:	m_freem(m);	goto done;}