xref: /csrg-svn/sys/netiso/clnp_frag.c (revision 42865)
136369Ssklower /***********************************************************
236369Ssklower 		Copyright IBM Corporation 1987
336369Ssklower 
436369Ssklower                       All Rights Reserved
536369Ssklower 
636369Ssklower Permission to use, copy, modify, and distribute this software and its
736369Ssklower documentation for any purpose and without fee is hereby granted,
836369Ssklower provided that the above copyright notice appear in all copies and that
936369Ssklower both that copyright notice and this permission notice appear in
1036369Ssklower supporting documentation, and that the name of IBM not be
1136369Ssklower used in advertising or publicity pertaining to distribution of the
1236369Ssklower software without specific, written prior permission.
1336369Ssklower 
1436369Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536369Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636369Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736369Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836369Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936369Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036369Ssklower SOFTWARE.
2136369Ssklower 
2236369Ssklower ******************************************************************/
2336369Ssklower 
2436369Ssklower /*
2536369Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636369Ssklower  */
2736764Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */
2836764Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */
29*42865Ssklower /*	@(#)clnp_frag.c	7.9 (Berkeley) 06/04/90 */
3036369Ssklower 
3136369Ssklower #ifndef lint
3236764Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $";
3336369Ssklower #endif lint
3436369Ssklower 
3537536Smckusick #include "param.h"
3637536Smckusick #include "mbuf.h"
3737536Smckusick #include "domain.h"
3837536Smckusick #include "protosw.h"
3937536Smckusick #include "socket.h"
4037536Smckusick #include "socketvar.h"
4137536Smckusick #include "errno.h"
4236369Ssklower 
4336369Ssklower #include "../net/if.h"
4436369Ssklower #include "../net/route.h"
4536369Ssklower 
4637469Ssklower #include "iso.h"
4737469Ssklower #include "iso_var.h"
4837469Ssklower #include "clnp.h"
4937469Ssklower #include "clnp_stat.h"
5037469Ssklower #include "argo_debug.h"
5136369Ssklower 
5236369Ssklower /* all fragments are hung off this list */
5336369Ssklower struct clnp_fragl	*clnp_frags = NULL;
5436369Ssklower 
5536369Ssklower struct mbuf	*clnp_comp_pdu();
5636369Ssklower 
5736369Ssklower 
5836369Ssklower /*
5936369Ssklower  * FUNCTION:		clnp_fragment
6036369Ssklower  *
6136369Ssklower  * PURPOSE:			Fragment a datagram, and send the itty bitty pieces
6236369Ssklower  *					out over an interface.
6336369Ssklower  *
6436369Ssklower  * RETURNS:			success - 0
6536369Ssklower  *					failure - unix error code
6636369Ssklower  *
6736369Ssklower  * SIDE EFFECTS:
6836369Ssklower  *
6936369Ssklower  * NOTES:			If there is an error sending the packet, clnp_discard
7036369Ssklower  *					is called to discard the packet and send an ER. If
7136369Ssklower  *					clnp_fragment was called from clnp_output, then
7236369Ssklower  *					we generated the packet, and should not send an
7336369Ssklower  *					ER -- clnp_emit_er will check for this. Otherwise,
7436369Ssklower  *					the packet was fragmented during forwarding. In this
7536369Ssklower  *					case, we ought to send an ER back.
7636369Ssklower  */
7740776Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt)
7836369Ssklower struct ifnet	*ifp;		/* ptr to outgoing interface */
7936369Ssklower struct mbuf		*m;			/* ptr to packet */
8036369Ssklower struct sockaddr	*first_hop;	/* ptr to first hop */
8136369Ssklower int				total_len;	/* length of datagram */
8236369Ssklower int				segoff;		/* offset of segpart in hdr */
8336369Ssklower int				flags;		/* flags passed to clnp_output */
8440776Ssklower struct rtentry *rt;			/* route if direct ether */
8536369Ssklower {
8639232Ssklower 	struct clnp_fixed		*clnp = mtod(m, struct clnp_fixed *);
8739232Ssklower 	int						hdr_len = (int)clnp->cnf_hdr_len;
8839232Ssklower 	int						frag_size = (ifp->if_mtu - hdr_len) & ~7;
8936369Ssklower 
9039232Ssklower 	total_len -= hdr_len;
9139232Ssklower 	if ((clnp->cnf_type & CNF_SEG_OK) &&
9239232Ssklower 		(total_len >= 8) &&
9339232Ssklower 		(frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) {
9436369Ssklower 
9536369Ssklower 		struct mbuf			*hdr = NULL;		/* save copy of clnp hdr */
9636369Ssklower 		struct mbuf			*frag_hdr = NULL;
9736369Ssklower 		struct mbuf			*frag_data = NULL;
98*42865Ssklower 		struct clnp_segment	seg_part;			/* segmentation header */
99*42865Ssklower 		int					frag_size, frag_base;
10036369Ssklower 		int					error = 0;
10136369Ssklower 
10239232Ssklower 
10339195Ssklower 		INCSTAT(cns_fragmented);
104*42865Ssklower         (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part,
105*42865Ssklower             sizeof(seg_part));
106*42865Ssklower 		frag_base = ntohs(seg_part.cng_off);
10736369Ssklower 		/*
10836369Ssklower 		 *	Duplicate header, and remove from packet
10936369Ssklower 		 */
11039232Ssklower 		if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
11136369Ssklower 			clnp_discard(m, GEN_CONGEST);
11236369Ssklower 			return(ENOBUFS);
11336369Ssklower 		}
11439232Ssklower 		m_adj(m, hdr_len);
11539232Ssklower 
11636369Ssklower 		while (total_len > 0) {
11739232Ssklower 			int		remaining, last_frag;
11836764Ssklower 
11936764Ssklower 			IFDEBUG(D_FRAG)
12036764Ssklower 				struct mbuf *mdump = frag_hdr;
12136764Ssklower 				int tot_mlen = 0;
12236764Ssklower 				printf("clnp_fragment: total_len %d:\n", total_len);
12336764Ssklower 				while (mdump != NULL) {
12436764Ssklower 					printf("\tmbuf x%x, m_len %d\n",
12536764Ssklower 						mdump, mdump->m_len);
12636764Ssklower 					tot_mlen += mdump->m_len;
12736764Ssklower 					mdump = mdump->m_next;
12836764Ssklower 				}
12936764Ssklower 				printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen);
13036764Ssklower 			ENDDEBUG
13136369Ssklower 
13239232Ssklower 			frag_size = min(total_len, frag_size);
13339232Ssklower 			if ((remaining = total_len - frag_size) == 0)
13439232Ssklower 				last_frag = 1;
13539232Ssklower 			else {
13639232Ssklower 				/*
13739232Ssklower 				 *  If this fragment will cause the last one to
13839232Ssklower 				 *	be less than 8 bytes, shorten this fragment a bit.
13939232Ssklower 				 *  The obscure test on frag_size above ensures that
14039232Ssklower 				 *  frag_size will be positive.
14139232Ssklower 				 */
14239232Ssklower 				last_frag = 0;
14339232Ssklower 				if (remaining < 8)
14439232Ssklower 						frag_size -= 8;
14539232Ssklower 			}
14636369Ssklower 
14736369Ssklower 
14836369Ssklower 			IFDEBUG(D_FRAG)
14936369Ssklower 				printf("clnp_fragment: seg off %d, size %d, remaining %d\n",
150*42865Ssklower 					ntohs(seg_part.cng_off), frag_size, total_len-frag_size);
15136369Ssklower 				if (last_frag)
15236369Ssklower 					printf("clnp_fragment: last fragment\n");
15336369Ssklower 			ENDDEBUG
15436369Ssklower 
15536369Ssklower 			if (last_frag) {
15636369Ssklower 				/*
15736369Ssklower 				 *	this is the last fragment; we don't need to get any other
15836369Ssklower 				 *	mbufs.
15936369Ssklower 				 */
16036369Ssklower 				frag_hdr = hdr;
16136369Ssklower 				frag_data = m;
16236369Ssklower 			} else {
16336369Ssklower 				/* duplicate header and data mbufs */
16437469Ssklower 				if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) {
16539232Ssklower 					clnp_discard(hdr, GEN_CONGEST);
16639232Ssklower 					m_freem(m);
16736369Ssklower 					return(ENOBUFS);
16836369Ssklower 				}
16936369Ssklower 				if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
17039232Ssklower 					clnp_discard(hdr, GEN_CONGEST);
17139232Ssklower 					m_freem(m);
17236369Ssklower 					m_freem(frag_hdr);
17336369Ssklower 					return(ENOBUFS);
17436369Ssklower 				}
17539195Ssklower 				INCSTAT(cns_fragments);
17636369Ssklower 			}
17736369Ssklower 			clnp = mtod(frag_hdr, struct clnp_fixed *);
17836369Ssklower 
17936369Ssklower 			if (!last_frag)
18037469Ssklower 				clnp->cnf_type |= CNF_MORE_SEGS;
18136369Ssklower 
18236369Ssklower 			/* link together */
18336369Ssklower 			m_cat(frag_hdr, frag_data);
18436369Ssklower 
185*42865Ssklower 			/* insert segmentation part; updated below */
186*42865Ssklower 			bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff,
18736369Ssklower 				sizeof(struct clnp_segment));
18836369Ssklower 
18936369Ssklower 			{
19039232Ssklower 				int	derived_len = hdr_len + frag_size;
19136369Ssklower 				HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
19237469Ssklower 				if ((frag_hdr->m_flags & M_PKTHDR) == 0)
19337469Ssklower 					panic("clnp_frag:lost header");
19437469Ssklower 				frag_hdr->m_pkthdr.len = derived_len;
19536369Ssklower 			}
19636369Ssklower 			/* compute clnp checksum (on header only) */
19736369Ssklower 			if (flags & CLNP_NO_CKSUM) {
19836369Ssklower 				HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
19936369Ssklower 			} else {
20039232Ssklower 				iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len);
20136369Ssklower 			}
20236369Ssklower 
20336369Ssklower 			IFDEBUG(D_DUMPOUT)
20436369Ssklower 				struct mbuf *mdump = frag_hdr;
20536369Ssklower 				printf("clnp_fragment: sending dg:\n");
20636369Ssklower 				while (mdump != NULL) {
20736764Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
20836369Ssklower 					mdump = mdump->m_next;
20936369Ssklower 				}
21036369Ssklower 			ENDDEBUG
21136369Ssklower 
21236369Ssklower #ifdef	TROLL
21340776Ssklower 			error = troll_output(ifp, frag_hdr, first_hop, rt);
21436369Ssklower #else
21540776Ssklower 			error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt);
21636369Ssklower #endif	TROLL
21736369Ssklower 
21836369Ssklower 			/*
21936369Ssklower 			 *	Tough situation: if the error occured on the last
22036369Ssklower 			 *	fragment, we can not send an ER, as the if_output
22136369Ssklower 			 *	routine consumed the packet. If the error occured
22236369Ssklower 			 *	on any intermediate packets, we can send an ER
22336369Ssklower 			 *	because we still have the original header in (m).
22436369Ssklower 			 */
22536369Ssklower 			if (error) {
22636369Ssklower 				if (frag_hdr != hdr) {
22736369Ssklower 					/*
22836369Ssklower 					 *	The error was not on the last fragment. We must
22936369Ssklower 					 *	free hdr and m before returning
23036369Ssklower 					 */
23139232Ssklower 					clnp_discard(hdr, GEN_NOREAS);
23239232Ssklower 					m_freem(m);
23336369Ssklower 				}
23436369Ssklower 				return(error);
23536369Ssklower 			}
23636369Ssklower 
23736369Ssklower 			/* bump segment offset, trim data mbuf, and decrement count left */
23836369Ssklower #ifdef	TROLL
23936369Ssklower 			/*
24036369Ssklower 			 *	Decrement frag_size by some fraction. This will cause the
24136369Ssklower 			 *	next fragment to start 'early', thus duplicating the end
24236369Ssklower 			 *	of the current fragment.  troll.tr_dup_size controls
24336369Ssklower 			 *	the fraction. If positive, it specifies the fraction. If
24436369Ssklower 			 *	negative, a random fraction is used.
24536369Ssklower 			 */
24636369Ssklower 			if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
24736369Ssklower 				int num_bytes = frag_size;
24836369Ssklower 
24936369Ssklower 				if (trollctl.tr_dup_size > 0)
25036369Ssklower 					num_bytes *= trollctl.tr_dup_size;
25136369Ssklower 				else
25236369Ssklower 					num_bytes *= troll_random();
25336369Ssklower 				frag_size -= num_bytes;
25436369Ssklower 			}
25536369Ssklower #endif	TROLL
25636369Ssklower 			total_len -= frag_size;
25736369Ssklower 			if (!last_frag) {
258*42865Ssklower 				frag_base += frag_size;
259*42865Ssklower 				seg_part.cng_off = htons(frag_base);
26036369Ssklower 				m_adj(m, frag_size);
26136369Ssklower 			}
26236369Ssklower 		}
26336369Ssklower 		return(0);
26436369Ssklower 	} else {
26539232Ssklower 	cantfrag:
26639195Ssklower 		INCSTAT(cns_cantfrag);
26736369Ssklower 		clnp_discard(m, GEN_SEGNEEDED);
26836369Ssklower 		return(EMSGSIZE);
26936369Ssklower 	}
27036369Ssklower }
27136369Ssklower 
27236369Ssklower /*
27336369Ssklower  * FUNCTION:		clnp_reass
27436369Ssklower  *
27536369Ssklower  * PURPOSE:			Attempt to reassemble a clnp packet given the current
27636369Ssklower  *					fragment. If reassembly succeeds (all the fragments
27736369Ssklower  *					are present), then return a pointer to an mbuf chain
27836369Ssklower  *					containing the reassembled packet. This packet will
27936369Ssklower  *					appear in the mbufs as if it had just arrived in
28036369Ssklower  *					one piece.
28136369Ssklower  *
28236369Ssklower  *					If reassembly fails, then save this fragment and
28336369Ssklower  *					return 0.
28436369Ssklower  *
28536369Ssklower  * RETURNS:			Ptr to assembled packet, or 0
28636369Ssklower  *
28736369Ssklower  * SIDE EFFECTS:
28836369Ssklower  *
28936369Ssklower  * NOTES:
29036369Ssklower  *		clnp_slowtimo can not affect this code because clnpintr, and thus
29136369Ssklower  *		this code, is called at a higher priority than clnp_slowtimo.
29236369Ssklower  */
29336369Ssklower struct mbuf *
29436369Ssklower clnp_reass(m, src, dst, seg)
29536369Ssklower struct mbuf 		*m;		/* new fragment */
29636369Ssklower struct iso_addr		*src;	/* src of new fragment */
29736369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
29836369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
29936369Ssklower {
30036369Ssklower 	register struct clnp_fragl		*cfh;
30136369Ssklower 
30236369Ssklower 	/* look for other fragments of this datagram */
30336369Ssklower 	for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
304*42865Ssklower 		if (seg->cng_id == cfh->cfl_id &&
305*42865Ssklower 		    iso_addrmatch1(src, &cfh->cfl_src) &&
306*42865Ssklower 			iso_addrmatch1(dst, &cfh->cfl_dst)) {
30736369Ssklower 			IFDEBUG(D_REASS)
30836369Ssklower 				printf("clnp_reass: found packet\n");
30936369Ssklower 			ENDDEBUG
31036369Ssklower 			/*
31136369Ssklower 			 *	There are other fragments here already. Lets see if
31236369Ssklower 			 *	this fragment is of any help
31336369Ssklower 			 */
31436369Ssklower 			clnp_insert_frag(cfh, m, seg);
315*42865Ssklower 			if (m = clnp_comp_pdu(cfh)) {
316*42865Ssklower 				register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
317*42865Ssklower 				HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb,
318*42865Ssklower 					 seg->cng_tot_len);
319*42865Ssklower 			}
320*42865Ssklower 			return (m);
32136369Ssklower 		}
32236369Ssklower 	}
32336369Ssklower 
32436369Ssklower 	IFDEBUG(D_REASS)
32536369Ssklower 		printf("clnp_reass: new packet!\n");
32636369Ssklower 	ENDDEBUG
32736369Ssklower 
32836369Ssklower 	/*
32936369Ssklower 	 *	This is the first fragment. If src is not consuming too many
33036369Ssklower 	 *	resources, then create a new fragment list and add
33136369Ssklower 	 *	this fragment to the list.
33236369Ssklower 	 */
33336369Ssklower 	/* TODO: don't let one src hog all the reassembly buffers */
33436369Ssklower 	if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) {
33539195Ssklower 		INCSTAT(cns_fragdropped);
33636369Ssklower 		clnp_discard(m, GEN_CONGEST);
33736369Ssklower 	}
33836369Ssklower 
33936369Ssklower 	return(NULL);
34036369Ssklower }
34136369Ssklower 
34236369Ssklower /*
34336369Ssklower  * FUNCTION:		clnp_newpkt
34436369Ssklower  *
34536369Ssklower  * PURPOSE:			Create the necessary structures to handle a new
34636369Ssklower  *					fragmented clnp packet.
34736369Ssklower  *
34836369Ssklower  * RETURNS:			non-zero if it succeeds, zero if fails.
34936369Ssklower  *
35036369Ssklower  * SIDE EFFECTS:
35136369Ssklower  *
35236369Ssklower  * NOTES:			Failure is only due to insufficient resources.
35336369Ssklower  */
35436369Ssklower clnp_newpkt(m, src, dst, seg)
35536369Ssklower struct mbuf 		*m;		/* new fragment */
35636369Ssklower struct iso_addr		*src;	/* src of new fragment */
35736369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
35836369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
35936369Ssklower {
36036369Ssklower 	register struct clnp_fragl		*cfh;
36136369Ssklower 	register struct clnp_fixed		*clnp;
36236369Ssklower 	struct mbuf 					*m0;
36336369Ssklower 
36436369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
36536369Ssklower 
36636369Ssklower 	/*
36736369Ssklower 	 *	Allocate new clnp fragl structure to act as header of all fragments
36836369Ssklower 	 *	for this datagram.
36936369Ssklower 	 */
37036369Ssklower 	MGET(m0, M_DONTWAIT, MT_FTABLE);
37136369Ssklower 	if (m0 == NULL) {
37236369Ssklower 		return (0);
37336369Ssklower 	}
37436369Ssklower 	cfh = mtod(m0, struct clnp_fragl *);
37536369Ssklower 
37636369Ssklower 	/*
37736369Ssklower 	 *	Duplicate the header of this fragment, and save in cfh.
37836369Ssklower 	 *	Free m0 and return if m_copy does not succeed.
37936369Ssklower 	 */
38037469Ssklower 	if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) {
38136369Ssklower 		m_freem(m0);
38236369Ssklower 		return (0);
38336369Ssklower 	}
38436369Ssklower 
38536369Ssklower 	/* Fill in rest of fragl structure */
38636369Ssklower 	bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr));
38736369Ssklower 	bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr));
38836369Ssklower 	cfh->cfl_id = seg->cng_id;
38936369Ssklower 	cfh->cfl_ttl = clnp->cnf_ttl;
39036369Ssklower 	cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
39136369Ssklower 	cfh->cfl_frags = NULL;
39236369Ssklower 	cfh->cfl_next = NULL;
39336369Ssklower 
39436369Ssklower 	/* Insert into list of packets */
39536369Ssklower 	cfh->cfl_next = clnp_frags;
39636369Ssklower 	clnp_frags = cfh;
39736369Ssklower 
39836369Ssklower 	/* Insert this fragment into list headed by cfh */
39936369Ssklower 	clnp_insert_frag(cfh, m, seg);
40036369Ssklower 	return(1);
40136369Ssklower }
40236369Ssklower 
40336369Ssklower /*
40436369Ssklower  * FUNCTION:		clnp_insert_frag
40536369Ssklower  *
40636369Ssklower  * PURPOSE:			Insert fragment into list headed by 'cf'.
40736369Ssklower  *
40836369Ssklower  * RETURNS:			nothing
40936369Ssklower  *
41036369Ssklower  * SIDE EFFECTS:
41136369Ssklower  *
41236369Ssklower  * NOTES:			This is the 'guts' of the reassembly algorithm.
41336369Ssklower  *					Each fragment in this list contains a clnp_frag
41436369Ssklower  *					structure followed by the data of the fragment.
41536369Ssklower  *					The clnp_frag structure actually lies on top of
41636369Ssklower  *					part of the old clnp header.
41736369Ssklower  */
41836369Ssklower clnp_insert_frag(cfh, m, seg)
41936369Ssklower struct clnp_fragl	*cfh;	/* header of list of packet fragments */
42036369Ssklower struct mbuf 		*m;		/* new fragment */
42136369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
42236369Ssklower {
42336369Ssklower 	register struct clnp_fixed	*clnp;	/* clnp hdr of fragment */
42436369Ssklower 	register struct clnp_frag	*cf;	/* generic fragment ptr */
42536369Ssklower 	register struct clnp_frag 	*cf_sub = NULL;	/* frag subsequent to new one */
42636369Ssklower 	register struct clnp_frag 	*cf_prev = NULL; /* frag previous to new one */
42736369Ssklower 	u_short						first;	/* offset of first byte of initial pdu*/
42836369Ssklower 	u_short						last;	/* offset of last byte of initial pdu */
42936369Ssklower 	u_short						fraglen;/* length of fragment */
43036369Ssklower 
43136369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
43236369Ssklower 	first = seg->cng_off;
43336369Ssklower 	CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
43436369Ssklower 	fraglen -= clnp->cnf_hdr_len;
43536369Ssklower 	last = (first + fraglen) - 1;
43636369Ssklower 
43736369Ssklower 	IFDEBUG(D_REASS)
43836369Ssklower 		printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n",
43936369Ssklower 			first, last, fraglen);
44036369Ssklower 		printf("clnp_insert_frag: current fragments:\n");
44136369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
44236369Ssklower 			printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last);
44336369Ssklower 		}
44436369Ssklower 	ENDDEBUG
44536369Ssklower 
44636369Ssklower 	if (cfh->cfl_frags != NULL) {
44736369Ssklower 		/*
44836369Ssklower 		 *	Find fragment which begins after the new one
44936369Ssklower 		 */
45036369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) {
45136369Ssklower 			if (cf->cfr_first > first) {
45236369Ssklower 				cf_sub = cf;
45336369Ssklower 				break;
45436369Ssklower 			}
45536369Ssklower 		}
45636369Ssklower 
45736369Ssklower 		IFDEBUG(D_REASS)
45836369Ssklower 			printf("clnp_insert_frag: Previous frag is ");
45936369Ssklower 			if (cf_prev == NULL)
46036369Ssklower 				printf("NULL\n");
46136369Ssklower 			else
46236369Ssklower 				printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last);
46336369Ssklower 			printf("clnp_insert_frag: Subsequent frag is ");
46436369Ssklower 			if (cf_sub == NULL)
46536369Ssklower 				printf("NULL\n");
46636369Ssklower 			else
46736369Ssklower 				printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last);
46836369Ssklower 		ENDDEBUG
46936369Ssklower 
47036369Ssklower 		/*
47136369Ssklower 		 *	If there is a fragment before the new one, check if it
47236369Ssklower 		 *	overlaps the new one. If so, then trim the end of the
47336369Ssklower 		 *	previous one.
47436369Ssklower 		 */
47536369Ssklower 		if (cf_prev != NULL) {
47636369Ssklower 			if (cf_prev->cfr_last > first) {
47736369Ssklower 				u_short overlap = cf_prev->cfr_last - first;
47836369Ssklower 
47936369Ssklower 				IFDEBUG(D_REASS)
48036369Ssklower 					printf("clnp_insert_frag: previous overlaps by %d\n",
48136369Ssklower 						overlap);
48236369Ssklower 				ENDDEBUG
48336369Ssklower 
48436369Ssklower 				if (overlap > fraglen) {
48536369Ssklower 					/*
48636369Ssklower 					 *	The new fragment is entirely contained in the
48736369Ssklower 					 *	preceeding one. We can punt on the new frag
48836369Ssklower 					 *	completely.
48936369Ssklower 					 */
49036369Ssklower 					m_freem(m);
49136369Ssklower 					return;
49236369Ssklower 				} else {
49336369Ssklower 					/* Trim data off of end of previous fragment */
49436369Ssklower 					/* inc overlap to prevent duplication of last byte */
49536369Ssklower 					overlap++;
49637469Ssklower 					m_adj(cf_prev->cfr_data, -(int)overlap);
49736369Ssklower 					cf_prev->cfr_last -= overlap;
49836369Ssklower 				}
49936369Ssklower 			}
50036369Ssklower 		}
50136369Ssklower 
50236369Ssklower 		/*
50336369Ssklower 		 *	For all fragments past the new one, check if any data on
50436369Ssklower 		 *	the new one overlaps data on existing fragments. If so,
50536369Ssklower 		 *	then trim the extra data off the end of the new one.
50636369Ssklower 		 */
50736369Ssklower 		for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
50836369Ssklower 			if (cf->cfr_first < last) {
50936369Ssklower 				u_short overlap = last - cf->cfr_first;
51036369Ssklower 
51136369Ssklower 				IFDEBUG(D_REASS)
51236369Ssklower 					printf("clnp_insert_frag: subsequent overlaps by %d\n",
51336369Ssklower 						overlap);
51436369Ssklower 				ENDDEBUG
51536369Ssklower 
51636369Ssklower 				if (overlap > fraglen) {
51736369Ssklower 					/*
51836369Ssklower 					 *	The new fragment is entirely contained in the
51936369Ssklower 					 *	succeeding one. This should not happen, because
52036369Ssklower 					 *	early on in this code we scanned for the fragment
52136369Ssklower 					 *	which started after the new one!
52236369Ssklower 					 */
52336369Ssklower 					m_freem(m);
52436369Ssklower 					printf("clnp_insert_frag: internal error!\n");
52536369Ssklower 					return;
52636369Ssklower 				} else {
52736369Ssklower 					/* Trim data off of end of new fragment */
52836369Ssklower 					/* inc overlap to prevent duplication of last byte */
52936369Ssklower 					overlap++;
53037469Ssklower 					m_adj(m, -(int)overlap);
53136369Ssklower 					last -= overlap;
53236369Ssklower 				}
53336369Ssklower 			}
53436369Ssklower 		}
53536369Ssklower 	}
53636369Ssklower 
53736369Ssklower 	/*
53836369Ssklower 	 *	Insert the new fragment beween cf_prev and cf_sub
53936369Ssklower 	 *
54036369Ssklower 	 *	Note: the clnp hdr is still in the mbuf.
54136369Ssklower 	 *	If the data of the mbuf is not word aligned, shave off enough
54236369Ssklower 	 *	so that it is. Then, cast the clnp_frag structure on top
54336369Ssklower 	 *	of the clnp header.
54436369Ssklower 	 *	The clnp_hdr will not be used again (as we already have
54536369Ssklower 	 *	saved a copy of it).
54636369Ssklower 	 *
54736369Ssklower 	 *	Save in cfr_bytes the number of bytes to shave off to get to
54836369Ssklower 	 *	the data of the packet. This is used when we coalesce fragments;
54936369Ssklower 	 *	the clnp_frag structure must be removed before joining mbufs.
55036369Ssklower 	 */
55136369Ssklower 	{
55236369Ssklower 		int	pad;
55336369Ssklower 		u_int	bytes;
55436369Ssklower 
55536369Ssklower 		/* determine if header is not word aligned */
55636369Ssklower 		pad = (int)clnp % 4;
55736369Ssklower 		if (pad < 0)
55836369Ssklower 			pad = -pad;
55936369Ssklower 
56036369Ssklower 		/* bytes is number of bytes left in front of data */
56136369Ssklower 		bytes = clnp->cnf_hdr_len - pad;
56236369Ssklower 
56336764Ssklower 		IFDEBUG(D_REASS)
56436764Ssklower 			printf("clnp_insert_frag: clnp x%x requires %d alignment\n",
56536764Ssklower 				clnp, pad);
56636764Ssklower 		ENDDEBUG
56736764Ssklower 
56836369Ssklower 		/* make it word aligned if necessary */
56936369Ssklower 		if (pad)
57036369Ssklower 			m_adj(m, pad);
57136369Ssklower 
57236369Ssklower 		cf = mtod(m, struct clnp_frag *);
57336369Ssklower 		cf->cfr_bytes = bytes;
57436764Ssklower 
57536764Ssklower 		IFDEBUG(D_REASS)
57636764Ssklower 			printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf,
57736764Ssklower 				cf->cfr_bytes);
57836764Ssklower 		ENDDEBUG
57936369Ssklower 	}
58036369Ssklower 	cf->cfr_first = first;
58136369Ssklower 	cf->cfr_last = last;
58236369Ssklower 
58336369Ssklower 
58436369Ssklower 	/*
58536369Ssklower 	 *	The data is the mbuf itself, although we must remember that the
58636369Ssklower 	 *	first few bytes are actually a clnp_frag structure
58736369Ssklower 	 */
58836369Ssklower 	cf->cfr_data = m;
58936369Ssklower 
59036369Ssklower 	/* link into place */
59136369Ssklower 	cf->cfr_next = cf_sub;
59236369Ssklower 	if (cf_prev == NULL)
59336369Ssklower 		cfh->cfl_frags = cf;
59436369Ssklower 	else
59536369Ssklower 		cf_prev->cfr_next = cf;
59636369Ssklower }
59736369Ssklower 
59836369Ssklower /*
59936369Ssklower  * FUNCTION:		clnp_comp_pdu
60036369Ssklower  *
60136369Ssklower  * PURPOSE:			Scan the list of fragments headed by cfh. Merge
60236369Ssklower  *					any contigious fragments into one. If, after
60336369Ssklower  *					traversing all the fragments, it is determined that
60436369Ssklower  *					the packet is complete, then return a pointer to
60536369Ssklower  *					the packet (with header prepended). Otherwise,
60636369Ssklower  *					return NULL.
60736369Ssklower  *
60836369Ssklower  * RETURNS:			NULL, or a pointer to the assembled pdu in an mbuf chain.
60936369Ssklower  *
61036369Ssklower  * SIDE EFFECTS:	Will colapse contigious fragments into one.
61136369Ssklower  *
61236369Ssklower  * NOTES:			This code assumes that there are no overlaps of
61336369Ssklower  *					fragment pdus.
61436369Ssklower  */
61536369Ssklower struct mbuf *
61636369Ssklower clnp_comp_pdu(cfh)
61736369Ssklower struct clnp_fragl	*cfh;		/* fragment header */
61836369Ssklower {
61936369Ssklower 	register struct clnp_frag	*cf = cfh->cfl_frags;
62036369Ssklower 
62136369Ssklower 	while (cf->cfr_next != NULL) {
62236369Ssklower 		register struct clnp_frag	*cf_next = cf->cfr_next;
62336369Ssklower 
62436369Ssklower 		IFDEBUG(D_REASS)
62536369Ssklower 			printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n",
62636369Ssklower 				cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
62736369Ssklower 				cf_next->cfr_last);
62836369Ssklower 		ENDDEBUG
62936369Ssklower 
63036369Ssklower 		if (cf->cfr_last == (cf_next->cfr_first - 1)) {
63136369Ssklower 			/*
63236369Ssklower 			 *	Merge fragment cf and cf_next
63336369Ssklower 			 *
63436369Ssklower 			 *	- update cf header
63536369Ssklower 			 *	- trim clnp_frag structure off of cf_next
63636369Ssklower 			 *	- append cf_next to cf
63736369Ssklower 			 */
63836369Ssklower 			struct clnp_frag	cf_next_hdr;
63936369Ssklower 			struct clnp_frag	*next_frag;
64036369Ssklower 
64136369Ssklower 			cf_next_hdr = *cf_next;
64236369Ssklower 			next_frag = cf_next->cfr_next;
64336369Ssklower 
64436369Ssklower 			IFDEBUG(D_REASS)
64536369Ssklower 				struct mbuf *mdump;
64636764Ssklower 				int l;
64736369Ssklower 				printf("clnp_comp_pdu: merging fragments\n");
64836764Ssklower 				printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n",
64936764Ssklower 					cf->cfr_first, cf->cfr_last, cf->cfr_bytes);
65036369Ssklower 				mdump = cf->cfr_data;
65136764Ssklower 				l = 0;
65236369Ssklower 				while (mdump != NULL) {
65336369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
65436764Ssklower 					l += mdump->m_len;
65536369Ssklower 					mdump = mdump->m_next;
65636369Ssklower 				}
65736764Ssklower 				printf("\ttotal len: %d\n", l);
65836764Ssklower 				printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n",
65936764Ssklower 					cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes);
66036369Ssklower 				mdump = cf_next->cfr_data;
66136764Ssklower 				l = 0;
66236369Ssklower 				while (mdump != NULL) {
66336369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
66436764Ssklower 					l += mdump->m_len;
66536369Ssklower 					mdump = mdump->m_next;
66636369Ssklower 				}
66736764Ssklower 				printf("\ttotal len: %d\n", l);
66836369Ssklower 			ENDDEBUG
66936369Ssklower 
67036369Ssklower 			cf->cfr_last = cf_next->cfr_last;
67136369Ssklower 			/*
67236369Ssklower 			 *	After this m_adj, the cf_next ptr is useless because we
67336369Ssklower 			 *	have adjusted the clnp_frag structure away...
67436369Ssklower 			 */
67536764Ssklower 			IFDEBUG(D_REASS)
67636764Ssklower 				printf("clnp_comp_pdu: shaving off %d bytes\n",
67736764Ssklower 					cf_next_hdr.cfr_bytes);
67836764Ssklower 			ENDDEBUG
67937469Ssklower 			m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes);
68036369Ssklower 			m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
68136369Ssklower 			cf->cfr_next = next_frag;
68236369Ssklower 		} else {
68336369Ssklower 			cf = cf->cfr_next;
68436369Ssklower 		}
68536369Ssklower 	}
68636369Ssklower 
68736369Ssklower 	cf = cfh->cfl_frags;
68836369Ssklower 
68936369Ssklower 	IFDEBUG(D_REASS)
69036369Ssklower 		struct mbuf *mdump = cf->cfr_data;
69136369Ssklower 		printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first,
69236369Ssklower 			cf->cfr_last);
69336369Ssklower 		printf("clnp_comp_pdu: data for frag:\n");
69436369Ssklower 		while (mdump != NULL) {
69536369Ssklower 			printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
69636369Ssklower /* 			dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
69736369Ssklower 			mdump = mdump->m_next;
69836369Ssklower 		}
69936369Ssklower 	ENDDEBUG
70036369Ssklower 
70136369Ssklower 	/* Check if datagram is complete */
70236369Ssklower 	if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
70336369Ssklower 		/*
70436369Ssklower 		 *	We have a complete pdu!
70536369Ssklower 		 *	- Remove the frag header from (only) remaining fragment
70636369Ssklower 		 *		(which is not really a fragment anymore, as the datagram is
70736369Ssklower 		 *		complete).
70836369Ssklower 		 *	- Prepend a clnp header
70936369Ssklower 		 */
71036369Ssklower 		struct mbuf	*data = cf->cfr_data;
71136369Ssklower 		struct mbuf	*hdr = cfh->cfl_orighdr;
71236369Ssklower 		struct clnp_fragl *scan;
71336369Ssklower 
71436369Ssklower 		IFDEBUG(D_REASS)
71536369Ssklower 			printf("clnp_comp_pdu: complete pdu!\n");
71636369Ssklower 		ENDDEBUG
71736369Ssklower 
71837469Ssklower 		m_adj(data, (int)cf->cfr_bytes);
71936369Ssklower 		m_cat(hdr, data);
72036369Ssklower 
72136369Ssklower 		IFDEBUG(D_DUMPIN)
72236369Ssklower 			struct mbuf *mdump = hdr;
72336369Ssklower 			printf("clnp_comp_pdu: pdu is:\n");
72436369Ssklower 			while (mdump != NULL) {
72536369Ssklower 				printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
72636369Ssklower /* 				dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
72736369Ssklower 				mdump = mdump->m_next;
72836369Ssklower 			}
72936369Ssklower 		ENDDEBUG
73036369Ssklower 
73136369Ssklower 		/*
73236369Ssklower 		 *	Remove cfh from the list of fragmented pdus
73336369Ssklower 		 */
73436369Ssklower 		if (clnp_frags == cfh) {
73536369Ssklower 			clnp_frags = cfh->cfl_next;
73636369Ssklower 		} else {
73736369Ssklower 			for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) {
73836369Ssklower 				if (scan->cfl_next == cfh) {
73936369Ssklower 					scan->cfl_next = cfh->cfl_next;
74036369Ssklower 					break;
74136369Ssklower 				}
74236369Ssklower 			}
74336369Ssklower 		}
74436369Ssklower 
74536369Ssklower 		/* free cfh */
74636369Ssklower 		m_freem(dtom(cfh));
74736369Ssklower 
74836369Ssklower 		return(hdr);
74936369Ssklower 	}
75036369Ssklower 
75136369Ssklower 	return(NULL);
75236369Ssklower }
75336369Ssklower #ifdef	TROLL
75437469Ssklower static int troll_cnt;
75537536Smckusick #include "time.h"
75636369Ssklower /*
75736369Ssklower  * FUNCTION:		troll_random
75836369Ssklower  *
75936369Ssklower  * PURPOSE:			generate a pseudo-random number between 0 and 1
76036369Ssklower  *
76136369Ssklower  * RETURNS:			the random number
76236369Ssklower  *
76336369Ssklower  * SIDE EFFECTS:
76436369Ssklower  *
76536369Ssklower  * NOTES:			This is based on the clock.
76636369Ssklower  */
76736369Ssklower float troll_random()
76836369Ssklower {
76936369Ssklower 	extern struct timeval time;
77036369Ssklower 	long	t = time.tv_usec % 100;
77136369Ssklower 
77236369Ssklower 	return((float)t / (float) 100);
77336369Ssklower }
77436369Ssklower 
77536369Ssklower /*
77636369Ssklower  * FUNCTION:		troll_output
77736369Ssklower  *
77836369Ssklower  * PURPOSE:			Do something sneaky with the datagram passed. Possible
77936369Ssklower  *					operations are:
78036369Ssklower  *						Duplicate the packet
78136369Ssklower  *						Drop the packet
78236369Ssklower  *						Trim some number of bytes from the packet
78336369Ssklower  *						Munge some byte in the packet
78436369Ssklower  *
78536369Ssklower  * RETURNS:			0, or unix error code
78636369Ssklower  *
78736369Ssklower  * SIDE EFFECTS:
78836369Ssklower  *
78936369Ssklower  * NOTES:			The operation of this procedure is regulated by the
79036369Ssklower  *					troll control structure (Troll).
79136369Ssklower  */
79240776Ssklower troll_output(ifp, m, dst, rt)
79336369Ssklower struct ifnet	*ifp;
79436369Ssklower struct mbuf		*m;
79536369Ssklower struct sockaddr	*dst;
79640776Ssklower struct rtentry *rt;
79736369Ssklower {
79836369Ssklower 	int	err = 0;
79936369Ssklower 	troll_cnt++;
80036369Ssklower 
80136369Ssklower 	if (trollctl.tr_ops & TR_DUPPKT) {
80236369Ssklower 		/*
80336369Ssklower 		 *	Duplicate every Nth packet
80436369Ssklower 		 *	TODO: random?
80536369Ssklower 		 */
80636369Ssklower 		float	f_freq = troll_cnt * trollctl.tr_dup_freq;
80736369Ssklower 		int		i_freq = troll_cnt * trollctl.tr_dup_freq;
80836369Ssklower 		if (i_freq == f_freq) {
80937469Ssklower 			struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL);
81036369Ssklower 			if (dup != NULL)
81140776Ssklower 				err = (*ifp->if_output)(ifp, dup, dst, rt);
81236369Ssklower 		}
81336369Ssklower 		if (!err)
81440776Ssklower 			err = (*ifp->if_output)(ifp, m, dst, rt);
81536369Ssklower 		return(err);
81636369Ssklower 	} else if (trollctl.tr_ops & TR_DROPPKT) {
81736369Ssklower 	} else if (trollctl.tr_ops & TR_CHANGE) {
81836369Ssklower 		struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
81936369Ssklower 		clnp->cnf_cksum_msb = 0;
82040776Ssklower 		err = (*ifp->if_output)(ifp, m, dst, rt);
82136369Ssklower 		return(err);
82236369Ssklower 	} else {
82340776Ssklower 		err = (*ifp->if_output)(ifp, m, dst, rt);
82436369Ssklower 		return(err);
82536369Ssklower 	}
82636369Ssklower }
82736369Ssklower 
82836369Ssklower #endif	TROLL
829