/* Copyright 1984 by the Massachusetts Institute of Technology */

#include	<types.h>
#include	<sys.h>
#include	"../src/const.h"
#include	"../src/param.h"
#include	"../src/defs.h"
#include	"../src/macs.h"
#include	"../src/net.h"
#include	"../src/ext.h"
#include	"in.h"

#define INHDLEN(pkt)	(((pkt)->i_ihlver & INHLENM) * INBPHW)

static char	innfrg[] = "IN can't fragment from %d.%d.%d.%d\n";

in_frg(iob, netp)
reg	iorb	*iob;
xreg	net	*netp;
{
	xreg	inpkt	*pkt;
	reg	inpkt	*fpkt;
	reg	iorb	*fiob;
		byte	*ptr;
		int	hdlen;
		int	morefrags;
		int	frgsiz;
		int	nfrags;

	pkt = mkin(iob->i_addr);
	if (swab(pkt->i_fofflg) & INDNTF) {
		niflog(L_ERRU)
			dolog(innfrg, mksina(&pkt->i_src));
		freebuf(iob);
		return;
	}
	if (swab(pkt->i_fofflg) & INMFRG) morefrags = 1;
	else morefrags = 0;
	hdlen = INHDLEN(pkt);
	nfrags = 1 + ((swab(pkt->i_len) - hdlen) /
		      (netp->n_max - hdlen) & ~(INFRGQ - 1) );
	frgsiz = (((swab(pkt->i_len) - hdlen) / nfrags) + (INFRGQ - 1))
		 & ~(INFRGQ - 1);

	ptr = iob->i_addr + hdlen + frgsiz;
	while (ptr + frgsiz < iob->i_addr + iob->i_breq) {
		fiob = mkiorb(getbuf(bufsiz));
		fiob->i_addr = (byte *)iob + pktoff;
		fpkt = mkin(fiob->i_addr);
		copy(pkt, fpkt, hdlen);
		fiob->i_breq = hdlen;
		copy(ptr, fpkt + hdlen, frgsiz);
		fiob->i_breq += frgsiz;
		fpkt->i_fofflg = swab((ptr - iob->i_addr) / INFRGQ);
		fpkt->i_fofflg |= INMFRG;
		fpkt->i_len = hdlen + frgsiz;
		fpkt->i_cksum = 0;
		fpkt->i_cksum = ~cksum(pkt, INMINH * INWPHW, 0);
		dolog ("IN frag plen = %d, breq %d, off = %d\n", 
		       ip2s (fpkt->i_len), fiob->i_breq, ip2s (fpkt->i_fofflg) & INFOFFM);
		inaddq(fiob);
		ptr += frgsiz;
	}

	fiob = mkiorb(getbuf(bufsiz));
	fiob->i_addr = (byte *)iob + pktoff;
	fpkt = mkin(fiob->i_addr);
	copy(pkt, fpkt, hdlen);
	fiob->i_breq = hdlen;
	copy(ptr, fpkt + hdlen, iob->i_addr + iob->i_breq - ptr);
	fiob->i_breq += iob->i_addr + iob->i_breq - ptr;
	fpkt->i_fofflg = swab((ptr - iob->i_addr) / INFRGQ);
	fpkt->i_len = hdlen + iob->i_addr + iob->i_breq - ptr;
	fpkt->i_cksum = 0;
	fpkt->i_cksum = ~cksum(pkt, INMINH * INWPHW, 0);
	dolog ("IN frag (2) plen = %d, breq %d, off = %d\n", 
	       ip2s (fpkt->i_len), fiob->i_breq, ip2s (fpkt->i_fofflg) & INFOFFM);
	inaddq(fiob);

	pkt->i_fofflg = INMFRG;
	pkt->i_len = hdlen + frgsiz;
	pkt->i_cksum = 0;
	pkt->i_cksum = ~cksum(pkt, INMINH * INWPHW, 0);
	dolog ("IN frag (3) plen = %d, breq %d, off = %d\n", 
		       ip2s (pkt->i_len), iob->i_breq, ip2s (pkt->i_fofflg) & INFOFFM);
	inaddq(iob);
}
