xref: /csrg-svn/sys/netiso/clnp_frag.c (revision 63222)
149267Sbostic /*-
2*63222Sbostic  * Copyright (c) 1991, 1993
3*63222Sbostic  *	The Regents of the University of California.  All rights reserved.
449267Sbostic  *
549267Sbostic  * %sccs.include.redist.c%
649267Sbostic  *
7*63222Sbostic  *	@(#)clnp_frag.c	8.1 (Berkeley) 06/10/93
849267Sbostic  */
949267Sbostic 
1036369Ssklower /***********************************************************
1136369Ssklower 		Copyright IBM Corporation 1987
1236369Ssklower 
1336369Ssklower                       All Rights Reserved
1436369Ssklower 
1536369Ssklower Permission to use, copy, modify, and distribute this software and its
1636369Ssklower documentation for any purpose and without fee is hereby granted,
1736369Ssklower provided that the above copyright notice appear in all copies and that
1836369Ssklower both that copyright notice and this permission notice appear in
1936369Ssklower supporting documentation, and that the name of IBM not be
2036369Ssklower used in advertising or publicity pertaining to distribution of the
2136369Ssklower software without specific, written prior permission.
2236369Ssklower 
2336369Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436369Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536369Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636369Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736369Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836369Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936369Ssklower SOFTWARE.
3036369Ssklower 
3136369Ssklower ******************************************************************/
3236369Ssklower 
3336369Ssklower /*
3436369Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536369Ssklower  */
3636764Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */
3736764Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */
3836369Ssklower 
3956533Sbostic #include <sys/param.h>
4056533Sbostic #include <sys/systm.h>
4156533Sbostic #include <sys/mbuf.h>
4256533Sbostic #include <sys/domain.h>
4356533Sbostic #include <sys/protosw.h>
4456533Sbostic #include <sys/socket.h>
4556533Sbostic #include <sys/socketvar.h>
4656533Sbostic #include <sys/errno.h>
4736369Ssklower 
4856533Sbostic #include <net/if.h>
4956533Sbostic #include <net/route.h>
5036369Ssklower 
5156533Sbostic #include <netiso/iso.h>
5256533Sbostic #include <netiso/iso_var.h>
5356533Sbostic #include <netiso/clnp.h>
5456533Sbostic #include <netiso/clnp_stat.h>
5556533Sbostic #include <netiso/argo_debug.h>
5636369Ssklower 
5736369Ssklower /* all fragments are hung off this list */
5836369Ssklower struct clnp_fragl	*clnp_frags = NULL;
5936369Ssklower 
6036369Ssklower struct mbuf	*clnp_comp_pdu();
6136369Ssklower 
6236369Ssklower 
6336369Ssklower /*
6436369Ssklower  * FUNCTION:		clnp_fragment
6536369Ssklower  *
6636369Ssklower  * PURPOSE:			Fragment a datagram, and send the itty bitty pieces
6736369Ssklower  *					out over an interface.
6836369Ssklower  *
6936369Ssklower  * RETURNS:			success - 0
7036369Ssklower  *					failure - unix error code
7136369Ssklower  *
7236369Ssklower  * SIDE EFFECTS:
7336369Ssklower  *
7436369Ssklower  * NOTES:			If there is an error sending the packet, clnp_discard
7536369Ssklower  *					is called to discard the packet and send an ER. If
7636369Ssklower  *					clnp_fragment was called from clnp_output, then
7736369Ssklower  *					we generated the packet, and should not send an
7836369Ssklower  *					ER -- clnp_emit_er will check for this. Otherwise,
7936369Ssklower  *					the packet was fragmented during forwarding. In this
8036369Ssklower  *					case, we ought to send an ER back.
8136369Ssklower  */
8240776Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt)
8336369Ssklower struct ifnet	*ifp;		/* ptr to outgoing interface */
8436369Ssklower struct mbuf		*m;			/* ptr to packet */
8536369Ssklower struct sockaddr	*first_hop;	/* ptr to first hop */
8636369Ssklower int				total_len;	/* length of datagram */
8736369Ssklower int				segoff;		/* offset of segpart in hdr */
8836369Ssklower int				flags;		/* flags passed to clnp_output */
8940776Ssklower struct rtentry *rt;			/* route if direct ether */
9036369Ssklower {
9139232Ssklower 	struct clnp_fixed		*clnp = mtod(m, struct clnp_fixed *);
9239232Ssklower 	int						hdr_len = (int)clnp->cnf_hdr_len;
9348730Ssklower 	int						frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7;
9436369Ssklower 
9539232Ssklower 	total_len -= hdr_len;
9639232Ssklower 	if ((clnp->cnf_type & CNF_SEG_OK) &&
9739232Ssklower 		(total_len >= 8) &&
9839232Ssklower 		(frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) {
9936369Ssklower 
10036369Ssklower 		struct mbuf			*hdr = NULL;		/* save copy of clnp hdr */
10136369Ssklower 		struct mbuf			*frag_hdr = NULL;
10236369Ssklower 		struct mbuf			*frag_data = NULL;
10342865Ssklower 		struct clnp_segment	seg_part;			/* segmentation header */
10447598Ssklower 		int					frag_base;
10536369Ssklower 		int					error = 0;
10636369Ssklower 
10739232Ssklower 
10839195Ssklower 		INCSTAT(cns_fragmented);
10942865Ssklower         (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part,
11042865Ssklower             sizeof(seg_part));
11142865Ssklower 		frag_base = ntohs(seg_part.cng_off);
11236369Ssklower 		/*
11336369Ssklower 		 *	Duplicate header, and remove from packet
11436369Ssklower 		 */
11539232Ssklower 		if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
11636369Ssklower 			clnp_discard(m, GEN_CONGEST);
11736369Ssklower 			return(ENOBUFS);
11836369Ssklower 		}
11939232Ssklower 		m_adj(m, hdr_len);
12039232Ssklower 
12136369Ssklower 		while (total_len > 0) {
12239232Ssklower 			int		remaining, last_frag;
12336764Ssklower 
12436764Ssklower 			IFDEBUG(D_FRAG)
12536764Ssklower 				struct mbuf *mdump = frag_hdr;
12636764Ssklower 				int tot_mlen = 0;
12736764Ssklower 				printf("clnp_fragment: total_len %d:\n", total_len);
12836764Ssklower 				while (mdump != NULL) {
12936764Ssklower 					printf("\tmbuf x%x, m_len %d\n",
13036764Ssklower 						mdump, mdump->m_len);
13136764Ssklower 					tot_mlen += mdump->m_len;
13236764Ssklower 					mdump = mdump->m_next;
13336764Ssklower 				}
13436764Ssklower 				printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen);
13536764Ssklower 			ENDDEBUG
13636369Ssklower 
13739232Ssklower 			frag_size = min(total_len, frag_size);
13839232Ssklower 			if ((remaining = total_len - frag_size) == 0)
13939232Ssklower 				last_frag = 1;
14039232Ssklower 			else {
14139232Ssklower 				/*
14239232Ssklower 				 *  If this fragment will cause the last one to
14339232Ssklower 				 *	be less than 8 bytes, shorten this fragment a bit.
14439232Ssklower 				 *  The obscure test on frag_size above ensures that
14539232Ssklower 				 *  frag_size will be positive.
14639232Ssklower 				 */
14739232Ssklower 				last_frag = 0;
14839232Ssklower 				if (remaining < 8)
14939232Ssklower 						frag_size -= 8;
15039232Ssklower 			}
15136369Ssklower 
15236369Ssklower 
15336369Ssklower 			IFDEBUG(D_FRAG)
15436369Ssklower 				printf("clnp_fragment: seg off %d, size %d, remaining %d\n",
15542865Ssklower 					ntohs(seg_part.cng_off), frag_size, total_len-frag_size);
15636369Ssklower 				if (last_frag)
15736369Ssklower 					printf("clnp_fragment: last fragment\n");
15836369Ssklower 			ENDDEBUG
15936369Ssklower 
16036369Ssklower 			if (last_frag) {
16136369Ssklower 				/*
16236369Ssklower 				 *	this is the last fragment; we don't need to get any other
16336369Ssklower 				 *	mbufs.
16436369Ssklower 				 */
16536369Ssklower 				frag_hdr = hdr;
16636369Ssklower 				frag_data = m;
16736369Ssklower 			} else {
16836369Ssklower 				/* duplicate header and data mbufs */
16937469Ssklower 				if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) {
17039232Ssklower 					clnp_discard(hdr, GEN_CONGEST);
17139232Ssklower 					m_freem(m);
17236369Ssklower 					return(ENOBUFS);
17336369Ssklower 				}
17436369Ssklower 				if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
17539232Ssklower 					clnp_discard(hdr, GEN_CONGEST);
17639232Ssklower 					m_freem(m);
17736369Ssklower 					m_freem(frag_hdr);
17836369Ssklower 					return(ENOBUFS);
17936369Ssklower 				}
18039195Ssklower 				INCSTAT(cns_fragments);
18136369Ssklower 			}
18236369Ssklower 			clnp = mtod(frag_hdr, struct clnp_fixed *);
18336369Ssklower 
18436369Ssklower 			if (!last_frag)
18537469Ssklower 				clnp->cnf_type |= CNF_MORE_SEGS;
18636369Ssklower 
18736369Ssklower 			/* link together */
18836369Ssklower 			m_cat(frag_hdr, frag_data);
18936369Ssklower 
19042865Ssklower 			/* insert segmentation part; updated below */
19142865Ssklower 			bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff,
19236369Ssklower 				sizeof(struct clnp_segment));
19336369Ssklower 
19436369Ssklower 			{
19539232Ssklower 				int	derived_len = hdr_len + frag_size;
19636369Ssklower 				HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
19737469Ssklower 				if ((frag_hdr->m_flags & M_PKTHDR) == 0)
19837469Ssklower 					panic("clnp_frag:lost header");
19937469Ssklower 				frag_hdr->m_pkthdr.len = derived_len;
20036369Ssklower 			}
20136369Ssklower 			/* compute clnp checksum (on header only) */
20236369Ssklower 			if (flags & CLNP_NO_CKSUM) {
20336369Ssklower 				HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
20436369Ssklower 			} else {
20539232Ssklower 				iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len);
20636369Ssklower 			}
20736369Ssklower 
20836369Ssklower 			IFDEBUG(D_DUMPOUT)
20936369Ssklower 				struct mbuf *mdump = frag_hdr;
21036369Ssklower 				printf("clnp_fragment: sending dg:\n");
21136369Ssklower 				while (mdump != NULL) {
21236764Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
21336369Ssklower 					mdump = mdump->m_next;
21436369Ssklower 				}
21536369Ssklower 			ENDDEBUG
21636369Ssklower 
21736369Ssklower #ifdef	TROLL
21840776Ssklower 			error = troll_output(ifp, frag_hdr, first_hop, rt);
21936369Ssklower #else
22040776Ssklower 			error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt);
22161286Ssklower #endif	/* TROLL */
22236369Ssklower 
22336369Ssklower 			/*
22436369Ssklower 			 *	Tough situation: if the error occured on the last
22536369Ssklower 			 *	fragment, we can not send an ER, as the if_output
22636369Ssklower 			 *	routine consumed the packet. If the error occured
22736369Ssklower 			 *	on any intermediate packets, we can send an ER
22836369Ssklower 			 *	because we still have the original header in (m).
22936369Ssklower 			 */
23036369Ssklower 			if (error) {
23136369Ssklower 				if (frag_hdr != hdr) {
23236369Ssklower 					/*
23336369Ssklower 					 *	The error was not on the last fragment. We must
23436369Ssklower 					 *	free hdr and m before returning
23536369Ssklower 					 */
23639232Ssklower 					clnp_discard(hdr, GEN_NOREAS);
23739232Ssklower 					m_freem(m);
23836369Ssklower 				}
23936369Ssklower 				return(error);
24036369Ssklower 			}
24136369Ssklower 
24236369Ssklower 			/* bump segment offset, trim data mbuf, and decrement count left */
24336369Ssklower #ifdef	TROLL
24436369Ssklower 			/*
24536369Ssklower 			 *	Decrement frag_size by some fraction. This will cause the
24636369Ssklower 			 *	next fragment to start 'early', thus duplicating the end
24736369Ssklower 			 *	of the current fragment.  troll.tr_dup_size controls
24836369Ssklower 			 *	the fraction. If positive, it specifies the fraction. If
24936369Ssklower 			 *	negative, a random fraction is used.
25036369Ssklower 			 */
25136369Ssklower 			if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
25236369Ssklower 				int num_bytes = frag_size;
25336369Ssklower 
25436369Ssklower 				if (trollctl.tr_dup_size > 0)
25536369Ssklower 					num_bytes *= trollctl.tr_dup_size;
25636369Ssklower 				else
25736369Ssklower 					num_bytes *= troll_random();
25836369Ssklower 				frag_size -= num_bytes;
25936369Ssklower 			}
26061286Ssklower #endif	/* TROLL */
26136369Ssklower 			total_len -= frag_size;
26236369Ssklower 			if (!last_frag) {
26342865Ssklower 				frag_base += frag_size;
26442865Ssklower 				seg_part.cng_off = htons(frag_base);
26536369Ssklower 				m_adj(m, frag_size);
26636369Ssklower 			}
26736369Ssklower 		}
26836369Ssklower 		return(0);
26936369Ssklower 	} else {
27039232Ssklower 	cantfrag:
27139195Ssklower 		INCSTAT(cns_cantfrag);
27236369Ssklower 		clnp_discard(m, GEN_SEGNEEDED);
27336369Ssklower 		return(EMSGSIZE);
27436369Ssklower 	}
27536369Ssklower }
27636369Ssklower 
27736369Ssklower /*
27836369Ssklower  * FUNCTION:		clnp_reass
27936369Ssklower  *
28036369Ssklower  * PURPOSE:			Attempt to reassemble a clnp packet given the current
28136369Ssklower  *					fragment. If reassembly succeeds (all the fragments
28236369Ssklower  *					are present), then return a pointer to an mbuf chain
28336369Ssklower  *					containing the reassembled packet. This packet will
28436369Ssklower  *					appear in the mbufs as if it had just arrived in
28536369Ssklower  *					one piece.
28636369Ssklower  *
28736369Ssklower  *					If reassembly fails, then save this fragment and
28836369Ssklower  *					return 0.
28936369Ssklower  *
29036369Ssklower  * RETURNS:			Ptr to assembled packet, or 0
29136369Ssklower  *
29236369Ssklower  * SIDE EFFECTS:
29336369Ssklower  *
29436369Ssklower  * NOTES:
29536369Ssklower  *		clnp_slowtimo can not affect this code because clnpintr, and thus
29636369Ssklower  *		this code, is called at a higher priority than clnp_slowtimo.
29736369Ssklower  */
29836369Ssklower struct mbuf *
clnp_reass(m,src,dst,seg)29936369Ssklower clnp_reass(m, src, dst, seg)
30036369Ssklower struct mbuf 		*m;		/* new fragment */
30136369Ssklower struct iso_addr		*src;	/* src of new fragment */
30236369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
30336369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
30436369Ssklower {
30536369Ssklower 	register struct clnp_fragl		*cfh;
30636369Ssklower 
30736369Ssklower 	/* look for other fragments of this datagram */
30836369Ssklower 	for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
30942865Ssklower 		if (seg->cng_id == cfh->cfl_id &&
31042865Ssklower 		    iso_addrmatch1(src, &cfh->cfl_src) &&
31142865Ssklower 			iso_addrmatch1(dst, &cfh->cfl_dst)) {
31236369Ssklower 			IFDEBUG(D_REASS)
31336369Ssklower 				printf("clnp_reass: found packet\n");
31436369Ssklower 			ENDDEBUG
31536369Ssklower 			/*
31636369Ssklower 			 *	There are other fragments here already. Lets see if
31736369Ssklower 			 *	this fragment is of any help
31836369Ssklower 			 */
31936369Ssklower 			clnp_insert_frag(cfh, m, seg);
32042865Ssklower 			if (m = clnp_comp_pdu(cfh)) {
32142865Ssklower 				register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
32242865Ssklower 				HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb,
32342865Ssklower 					 seg->cng_tot_len);
32442865Ssklower 			}
32542865Ssklower 			return (m);
32636369Ssklower 		}
32736369Ssklower 	}
32836369Ssklower 
32936369Ssklower 	IFDEBUG(D_REASS)
33036369Ssklower 		printf("clnp_reass: new packet!\n");
33136369Ssklower 	ENDDEBUG
33236369Ssklower 
33336369Ssklower 	/*
33436369Ssklower 	 *	This is the first fragment. If src is not consuming too many
33536369Ssklower 	 *	resources, then create a new fragment list and add
33636369Ssklower 	 *	this fragment to the list.
33736369Ssklower 	 */
33836369Ssklower 	/* TODO: don't let one src hog all the reassembly buffers */
33936369Ssklower 	if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) {
34039195Ssklower 		INCSTAT(cns_fragdropped);
34136369Ssklower 		clnp_discard(m, GEN_CONGEST);
34236369Ssklower 	}
34336369Ssklower 
34436369Ssklower 	return(NULL);
34536369Ssklower }
34636369Ssklower 
34736369Ssklower /*
34836369Ssklower  * FUNCTION:		clnp_newpkt
34936369Ssklower  *
35036369Ssklower  * PURPOSE:			Create the necessary structures to handle a new
35136369Ssklower  *					fragmented clnp packet.
35236369Ssklower  *
35336369Ssklower  * RETURNS:			non-zero if it succeeds, zero if fails.
35436369Ssklower  *
35536369Ssklower  * SIDE EFFECTS:
35636369Ssklower  *
35736369Ssklower  * NOTES:			Failure is only due to insufficient resources.
35836369Ssklower  */
35936369Ssklower clnp_newpkt(m, src, dst, seg)
36036369Ssklower struct mbuf 		*m;		/* new fragment */
36136369Ssklower struct iso_addr		*src;	/* src of new fragment */
36236369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
36336369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
36436369Ssklower {
36536369Ssklower 	register struct clnp_fragl		*cfh;
36636369Ssklower 	register struct clnp_fixed		*clnp;
36736369Ssklower 	struct mbuf 					*m0;
36836369Ssklower 
36936369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
37036369Ssklower 
37136369Ssklower 	/*
37236369Ssklower 	 *	Allocate new clnp fragl structure to act as header of all fragments
37336369Ssklower 	 *	for this datagram.
37436369Ssklower 	 */
37536369Ssklower 	MGET(m0, M_DONTWAIT, MT_FTABLE);
37636369Ssklower 	if (m0 == NULL) {
37736369Ssklower 		return (0);
37836369Ssklower 	}
37936369Ssklower 	cfh = mtod(m0, struct clnp_fragl *);
38036369Ssklower 
38136369Ssklower 	/*
38236369Ssklower 	 *	Duplicate the header of this fragment, and save in cfh.
38336369Ssklower 	 *	Free m0 and return if m_copy does not succeed.
38436369Ssklower 	 */
38537469Ssklower 	if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) {
38636369Ssklower 		m_freem(m0);
38736369Ssklower 		return (0);
38836369Ssklower 	}
38936369Ssklower 
39036369Ssklower 	/* Fill in rest of fragl structure */
39136369Ssklower 	bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr));
39236369Ssklower 	bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr));
39336369Ssklower 	cfh->cfl_id = seg->cng_id;
39436369Ssklower 	cfh->cfl_ttl = clnp->cnf_ttl;
39536369Ssklower 	cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
39636369Ssklower 	cfh->cfl_frags = NULL;
39736369Ssklower 	cfh->cfl_next = NULL;
39836369Ssklower 
39936369Ssklower 	/* Insert into list of packets */
40036369Ssklower 	cfh->cfl_next = clnp_frags;
40136369Ssklower 	clnp_frags = cfh;
40236369Ssklower 
40336369Ssklower 	/* Insert this fragment into list headed by cfh */
40436369Ssklower 	clnp_insert_frag(cfh, m, seg);
40536369Ssklower 	return(1);
40636369Ssklower }
40736369Ssklower 
40836369Ssklower /*
40936369Ssklower  * FUNCTION:		clnp_insert_frag
41036369Ssklower  *
41136369Ssklower  * PURPOSE:			Insert fragment into list headed by 'cf'.
41236369Ssklower  *
41336369Ssklower  * RETURNS:			nothing
41436369Ssklower  *
41536369Ssklower  * SIDE EFFECTS:
41636369Ssklower  *
41736369Ssklower  * NOTES:			This is the 'guts' of the reassembly algorithm.
41836369Ssklower  *					Each fragment in this list contains a clnp_frag
41936369Ssklower  *					structure followed by the data of the fragment.
42036369Ssklower  *					The clnp_frag structure actually lies on top of
42136369Ssklower  *					part of the old clnp header.
42236369Ssklower  */
42336369Ssklower clnp_insert_frag(cfh, m, seg)
42436369Ssklower struct clnp_fragl	*cfh;	/* header of list of packet fragments */
42536369Ssklower struct mbuf 		*m;		/* new fragment */
42636369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
42736369Ssklower {
42836369Ssklower 	register struct clnp_fixed	*clnp;	/* clnp hdr of fragment */
42936369Ssklower 	register struct clnp_frag	*cf;	/* generic fragment ptr */
43036369Ssklower 	register struct clnp_frag 	*cf_sub = NULL;	/* frag subsequent to new one */
43136369Ssklower 	register struct clnp_frag 	*cf_prev = NULL; /* frag previous to new one */
43236369Ssklower 	u_short						first;	/* offset of first byte of initial pdu*/
43336369Ssklower 	u_short						last;	/* offset of last byte of initial pdu */
43436369Ssklower 	u_short						fraglen;/* length of fragment */
43536369Ssklower 
43636369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
43736369Ssklower 	first = seg->cng_off;
43836369Ssklower 	CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
43936369Ssklower 	fraglen -= clnp->cnf_hdr_len;
44036369Ssklower 	last = (first + fraglen) - 1;
44136369Ssklower 
44236369Ssklower 	IFDEBUG(D_REASS)
44336369Ssklower 		printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n",
44436369Ssklower 			first, last, fraglen);
44536369Ssklower 		printf("clnp_insert_frag: current fragments:\n");
44636369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
44736369Ssklower 			printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last);
44836369Ssklower 		}
44936369Ssklower 	ENDDEBUG
45036369Ssklower 
45136369Ssklower 	if (cfh->cfl_frags != NULL) {
45236369Ssklower 		/*
45336369Ssklower 		 *	Find fragment which begins after the new one
45436369Ssklower 		 */
45536369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) {
45636369Ssklower 			if (cf->cfr_first > first) {
45736369Ssklower 				cf_sub = cf;
45836369Ssklower 				break;
45936369Ssklower 			}
46036369Ssklower 		}
46136369Ssklower 
46236369Ssklower 		IFDEBUG(D_REASS)
46336369Ssklower 			printf("clnp_insert_frag: Previous frag is ");
46436369Ssklower 			if (cf_prev == NULL)
46536369Ssklower 				printf("NULL\n");
46636369Ssklower 			else
46736369Ssklower 				printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last);
46836369Ssklower 			printf("clnp_insert_frag: Subsequent frag is ");
46936369Ssklower 			if (cf_sub == NULL)
47036369Ssklower 				printf("NULL\n");
47136369Ssklower 			else
47236369Ssklower 				printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last);
47336369Ssklower 		ENDDEBUG
47436369Ssklower 
47536369Ssklower 		/*
47636369Ssklower 		 *	If there is a fragment before the new one, check if it
47736369Ssklower 		 *	overlaps the new one. If so, then trim the end of the
47836369Ssklower 		 *	previous one.
47936369Ssklower 		 */
48036369Ssklower 		if (cf_prev != NULL) {
48136369Ssklower 			if (cf_prev->cfr_last > first) {
48236369Ssklower 				u_short overlap = cf_prev->cfr_last - first;
48336369Ssklower 
48436369Ssklower 				IFDEBUG(D_REASS)
48536369Ssklower 					printf("clnp_insert_frag: previous overlaps by %d\n",
48636369Ssklower 						overlap);
48736369Ssklower 				ENDDEBUG
48836369Ssklower 
48936369Ssklower 				if (overlap > fraglen) {
49036369Ssklower 					/*
49136369Ssklower 					 *	The new fragment is entirely contained in the
49236369Ssklower 					 *	preceeding one. We can punt on the new frag
49336369Ssklower 					 *	completely.
49436369Ssklower 					 */
49536369Ssklower 					m_freem(m);
49636369Ssklower 					return;
49736369Ssklower 				} else {
49836369Ssklower 					/* Trim data off of end of previous fragment */
49936369Ssklower 					/* inc overlap to prevent duplication of last byte */
50036369Ssklower 					overlap++;
50137469Ssklower 					m_adj(cf_prev->cfr_data, -(int)overlap);
50236369Ssklower 					cf_prev->cfr_last -= overlap;
50336369Ssklower 				}
50436369Ssklower 			}
50536369Ssklower 		}
50636369Ssklower 
50736369Ssklower 		/*
50836369Ssklower 		 *	For all fragments past the new one, check if any data on
50936369Ssklower 		 *	the new one overlaps data on existing fragments. If so,
51036369Ssklower 		 *	then trim the extra data off the end of the new one.
51136369Ssklower 		 */
51236369Ssklower 		for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
51336369Ssklower 			if (cf->cfr_first < last) {
51436369Ssklower 				u_short overlap = last - cf->cfr_first;
51536369Ssklower 
51636369Ssklower 				IFDEBUG(D_REASS)
51736369Ssklower 					printf("clnp_insert_frag: subsequent overlaps by %d\n",
51836369Ssklower 						overlap);
51936369Ssklower 				ENDDEBUG
52036369Ssklower 
52136369Ssklower 				if (overlap > fraglen) {
52236369Ssklower 					/*
52336369Ssklower 					 *	The new fragment is entirely contained in the
52436369Ssklower 					 *	succeeding one. This should not happen, because
52536369Ssklower 					 *	early on in this code we scanned for the fragment
52636369Ssklower 					 *	which started after the new one!
52736369Ssklower 					 */
52836369Ssklower 					m_freem(m);
52936369Ssklower 					printf("clnp_insert_frag: internal error!\n");
53036369Ssklower 					return;
53136369Ssklower 				} else {
53236369Ssklower 					/* Trim data off of end of new fragment */
53336369Ssklower 					/* inc overlap to prevent duplication of last byte */
53436369Ssklower 					overlap++;
53537469Ssklower 					m_adj(m, -(int)overlap);
53636369Ssklower 					last -= overlap;
53736369Ssklower 				}
53836369Ssklower 			}
53936369Ssklower 		}
54036369Ssklower 	}
54136369Ssklower 
54236369Ssklower 	/*
54336369Ssklower 	 *	Insert the new fragment beween cf_prev and cf_sub
54436369Ssklower 	 *
54536369Ssklower 	 *	Note: the clnp hdr is still in the mbuf.
54636369Ssklower 	 *	If the data of the mbuf is not word aligned, shave off enough
54736369Ssklower 	 *	so that it is. Then, cast the clnp_frag structure on top
54836369Ssklower 	 *	of the clnp header.
54936369Ssklower 	 *	The clnp_hdr will not be used again (as we already have
55036369Ssklower 	 *	saved a copy of it).
55136369Ssklower 	 *
55236369Ssklower 	 *	Save in cfr_bytes the number of bytes to shave off to get to
55336369Ssklower 	 *	the data of the packet. This is used when we coalesce fragments;
55436369Ssklower 	 *	the clnp_frag structure must be removed before joining mbufs.
55536369Ssklower 	 */
55636369Ssklower 	{
55736369Ssklower 		int	pad;
55836369Ssklower 		u_int	bytes;
55936369Ssklower 
56036369Ssklower 		/* determine if header is not word aligned */
56136369Ssklower 		pad = (int)clnp % 4;
56236369Ssklower 		if (pad < 0)
56336369Ssklower 			pad = -pad;
56436369Ssklower 
56536369Ssklower 		/* bytes is number of bytes left in front of data */
56636369Ssklower 		bytes = clnp->cnf_hdr_len - pad;
56736369Ssklower 
56836764Ssklower 		IFDEBUG(D_REASS)
56936764Ssklower 			printf("clnp_insert_frag: clnp x%x requires %d alignment\n",
57036764Ssklower 				clnp, pad);
57136764Ssklower 		ENDDEBUG
57236764Ssklower 
57336369Ssklower 		/* make it word aligned if necessary */
57436369Ssklower 		if (pad)
57536369Ssklower 			m_adj(m, pad);
57636369Ssklower 
57736369Ssklower 		cf = mtod(m, struct clnp_frag *);
57836369Ssklower 		cf->cfr_bytes = bytes;
57936764Ssklower 
58036764Ssklower 		IFDEBUG(D_REASS)
58136764Ssklower 			printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf,
58236764Ssklower 				cf->cfr_bytes);
58336764Ssklower 		ENDDEBUG
58436369Ssklower 	}
58536369Ssklower 	cf->cfr_first = first;
58636369Ssklower 	cf->cfr_last = last;
58736369Ssklower 
58836369Ssklower 
58936369Ssklower 	/*
59036369Ssklower 	 *	The data is the mbuf itself, although we must remember that the
59136369Ssklower 	 *	first few bytes are actually a clnp_frag structure
59236369Ssklower 	 */
59336369Ssklower 	cf->cfr_data = m;
59436369Ssklower 
59536369Ssklower 	/* link into place */
59636369Ssklower 	cf->cfr_next = cf_sub;
59736369Ssklower 	if (cf_prev == NULL)
59836369Ssklower 		cfh->cfl_frags = cf;
59936369Ssklower 	else
60036369Ssklower 		cf_prev->cfr_next = cf;
60136369Ssklower }
60236369Ssklower 
60336369Ssklower /*
60436369Ssklower  * FUNCTION:		clnp_comp_pdu
60536369Ssklower  *
60636369Ssklower  * PURPOSE:			Scan the list of fragments headed by cfh. Merge
60736369Ssklower  *					any contigious fragments into one. If, after
60836369Ssklower  *					traversing all the fragments, it is determined that
60936369Ssklower  *					the packet is complete, then return a pointer to
61036369Ssklower  *					the packet (with header prepended). Otherwise,
61136369Ssklower  *					return NULL.
61236369Ssklower  *
61336369Ssklower  * RETURNS:			NULL, or a pointer to the assembled pdu in an mbuf chain.
61436369Ssklower  *
61536369Ssklower  * SIDE EFFECTS:	Will colapse contigious fragments into one.
61636369Ssklower  *
61736369Ssklower  * NOTES:			This code assumes that there are no overlaps of
61836369Ssklower  *					fragment pdus.
61936369Ssklower  */
62036369Ssklower struct mbuf *
clnp_comp_pdu(cfh)62136369Ssklower clnp_comp_pdu(cfh)
62236369Ssklower struct clnp_fragl	*cfh;		/* fragment header */
62336369Ssklower {
62436369Ssklower 	register struct clnp_frag	*cf = cfh->cfl_frags;
62536369Ssklower 
62636369Ssklower 	while (cf->cfr_next != NULL) {
62736369Ssklower 		register struct clnp_frag	*cf_next = cf->cfr_next;
62836369Ssklower 
62936369Ssklower 		IFDEBUG(D_REASS)
63036369Ssklower 			printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n",
63136369Ssklower 				cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
63236369Ssklower 				cf_next->cfr_last);
63336369Ssklower 		ENDDEBUG
63436369Ssklower 
63536369Ssklower 		if (cf->cfr_last == (cf_next->cfr_first - 1)) {
63636369Ssklower 			/*
63736369Ssklower 			 *	Merge fragment cf and cf_next
63836369Ssklower 			 *
63936369Ssklower 			 *	- update cf header
64036369Ssklower 			 *	- trim clnp_frag structure off of cf_next
64136369Ssklower 			 *	- append cf_next to cf
64236369Ssklower 			 */
64336369Ssklower 			struct clnp_frag	cf_next_hdr;
64436369Ssklower 			struct clnp_frag	*next_frag;
64536369Ssklower 
64636369Ssklower 			cf_next_hdr = *cf_next;
64736369Ssklower 			next_frag = cf_next->cfr_next;
64836369Ssklower 
64936369Ssklower 			IFDEBUG(D_REASS)
65036369Ssklower 				struct mbuf *mdump;
65136764Ssklower 				int l;
65236369Ssklower 				printf("clnp_comp_pdu: merging fragments\n");
65336764Ssklower 				printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n",
65436764Ssklower 					cf->cfr_first, cf->cfr_last, cf->cfr_bytes);
65536369Ssklower 				mdump = cf->cfr_data;
65636764Ssklower 				l = 0;
65736369Ssklower 				while (mdump != NULL) {
65836369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
65936764Ssklower 					l += mdump->m_len;
66036369Ssklower 					mdump = mdump->m_next;
66136369Ssklower 				}
66236764Ssklower 				printf("\ttotal len: %d\n", l);
66336764Ssklower 				printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n",
66436764Ssklower 					cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes);
66536369Ssklower 				mdump = cf_next->cfr_data;
66636764Ssklower 				l = 0;
66736369Ssklower 				while (mdump != NULL) {
66836369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
66936764Ssklower 					l += mdump->m_len;
67036369Ssklower 					mdump = mdump->m_next;
67136369Ssklower 				}
67236764Ssklower 				printf("\ttotal len: %d\n", l);
67336369Ssklower 			ENDDEBUG
67436369Ssklower 
67536369Ssklower 			cf->cfr_last = cf_next->cfr_last;
67636369Ssklower 			/*
67736369Ssklower 			 *	After this m_adj, the cf_next ptr is useless because we
67836369Ssklower 			 *	have adjusted the clnp_frag structure away...
67936369Ssklower 			 */
68036764Ssklower 			IFDEBUG(D_REASS)
68136764Ssklower 				printf("clnp_comp_pdu: shaving off %d bytes\n",
68236764Ssklower 					cf_next_hdr.cfr_bytes);
68336764Ssklower 			ENDDEBUG
68437469Ssklower 			m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes);
68536369Ssklower 			m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
68636369Ssklower 			cf->cfr_next = next_frag;
68736369Ssklower 		} else {
68836369Ssklower 			cf = cf->cfr_next;
68936369Ssklower 		}
69036369Ssklower 	}
69136369Ssklower 
69236369Ssklower 	cf = cfh->cfl_frags;
69336369Ssklower 
69436369Ssklower 	IFDEBUG(D_REASS)
69536369Ssklower 		struct mbuf *mdump = cf->cfr_data;
69636369Ssklower 		printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first,
69736369Ssklower 			cf->cfr_last);
69836369Ssklower 		printf("clnp_comp_pdu: data for frag:\n");
69936369Ssklower 		while (mdump != NULL) {
70036369Ssklower 			printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
70136369Ssklower /* 			dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
70236369Ssklower 			mdump = mdump->m_next;
70336369Ssklower 		}
70436369Ssklower 	ENDDEBUG
70536369Ssklower 
70636369Ssklower 	/* Check if datagram is complete */
70736369Ssklower 	if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
70836369Ssklower 		/*
70936369Ssklower 		 *	We have a complete pdu!
71036369Ssklower 		 *	- Remove the frag header from (only) remaining fragment
71136369Ssklower 		 *		(which is not really a fragment anymore, as the datagram is
71236369Ssklower 		 *		complete).
71336369Ssklower 		 *	- Prepend a clnp header
71436369Ssklower 		 */
71536369Ssklower 		struct mbuf	*data = cf->cfr_data;
71636369Ssklower 		struct mbuf	*hdr = cfh->cfl_orighdr;
71736369Ssklower 		struct clnp_fragl *scan;
71836369Ssklower 
71936369Ssklower 		IFDEBUG(D_REASS)
72036369Ssklower 			printf("clnp_comp_pdu: complete pdu!\n");
72136369Ssklower 		ENDDEBUG
72236369Ssklower 
72337469Ssklower 		m_adj(data, (int)cf->cfr_bytes);
72436369Ssklower 		m_cat(hdr, data);
72536369Ssklower 
72636369Ssklower 		IFDEBUG(D_DUMPIN)
72736369Ssklower 			struct mbuf *mdump = hdr;
72836369Ssklower 			printf("clnp_comp_pdu: pdu is:\n");
72936369Ssklower 			while (mdump != NULL) {
73036369Ssklower 				printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
73136369Ssklower /* 				dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
73236369Ssklower 				mdump = mdump->m_next;
73336369Ssklower 			}
73436369Ssklower 		ENDDEBUG
73536369Ssklower 
73636369Ssklower 		/*
73736369Ssklower 		 *	Remove cfh from the list of fragmented pdus
73836369Ssklower 		 */
73936369Ssklower 		if (clnp_frags == cfh) {
74036369Ssklower 			clnp_frags = cfh->cfl_next;
74136369Ssklower 		} else {
74236369Ssklower 			for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) {
74336369Ssklower 				if (scan->cfl_next == cfh) {
74436369Ssklower 					scan->cfl_next = cfh->cfl_next;
74536369Ssklower 					break;
74636369Ssklower 				}
74736369Ssklower 			}
74836369Ssklower 		}
74936369Ssklower 
75036369Ssklower 		/* free cfh */
75136369Ssklower 		m_freem(dtom(cfh));
75236369Ssklower 
75336369Ssklower 		return(hdr);
75436369Ssklower 	}
75536369Ssklower 
75636369Ssklower 	return(NULL);
75736369Ssklower }
75836369Ssklower #ifdef	TROLL
75937469Ssklower static int troll_cnt;
76056533Sbostic #include <sys/time.h>
76136369Ssklower /*
76236369Ssklower  * FUNCTION:		troll_random
76336369Ssklower  *
76436369Ssklower  * PURPOSE:			generate a pseudo-random number between 0 and 1
76536369Ssklower  *
76636369Ssklower  * RETURNS:			the random number
76736369Ssklower  *
76836369Ssklower  * SIDE EFFECTS:
76936369Ssklower  *
77036369Ssklower  * NOTES:			This is based on the clock.
77136369Ssklower  */
troll_random()77236369Ssklower float troll_random()
77336369Ssklower {
77436369Ssklower 	extern struct timeval time;
77536369Ssklower 	long	t = time.tv_usec % 100;
77636369Ssklower 
77736369Ssklower 	return((float)t / (float) 100);
77836369Ssklower }
77936369Ssklower 
78036369Ssklower /*
78136369Ssklower  * FUNCTION:		troll_output
78236369Ssklower  *
78336369Ssklower  * PURPOSE:			Do something sneaky with the datagram passed. Possible
78436369Ssklower  *					operations are:
78536369Ssklower  *						Duplicate the packet
78636369Ssklower  *						Drop the packet
78736369Ssklower  *						Trim some number of bytes from the packet
78836369Ssklower  *						Munge some byte in the packet
78936369Ssklower  *
79036369Ssklower  * RETURNS:			0, or unix error code
79136369Ssklower  *
79236369Ssklower  * SIDE EFFECTS:
79336369Ssklower  *
79436369Ssklower  * NOTES:			The operation of this procedure is regulated by the
79536369Ssklower  *					troll control structure (Troll).
79636369Ssklower  */
79740776Ssklower troll_output(ifp, m, dst, rt)
79836369Ssklower struct ifnet	*ifp;
79936369Ssklower struct mbuf		*m;
80036369Ssklower struct sockaddr	*dst;
80140776Ssklower struct rtentry *rt;
80236369Ssklower {
80336369Ssklower 	int	err = 0;
80436369Ssklower 	troll_cnt++;
80536369Ssklower 
80636369Ssklower 	if (trollctl.tr_ops & TR_DUPPKT) {
80736369Ssklower 		/*
80836369Ssklower 		 *	Duplicate every Nth packet
80936369Ssklower 		 *	TODO: random?
81036369Ssklower 		 */
81136369Ssklower 		float	f_freq = troll_cnt * trollctl.tr_dup_freq;
81236369Ssklower 		int		i_freq = troll_cnt * trollctl.tr_dup_freq;
81336369Ssklower 		if (i_freq == f_freq) {
81437469Ssklower 			struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL);
81536369Ssklower 			if (dup != NULL)
81640776Ssklower 				err = (*ifp->if_output)(ifp, dup, dst, rt);
81736369Ssklower 		}
81836369Ssklower 		if (!err)
81940776Ssklower 			err = (*ifp->if_output)(ifp, m, dst, rt);
82036369Ssklower 		return(err);
82136369Ssklower 	} else if (trollctl.tr_ops & TR_DROPPKT) {
82236369Ssklower 	} else if (trollctl.tr_ops & TR_CHANGE) {
82336369Ssklower 		struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
82436369Ssklower 		clnp->cnf_cksum_msb = 0;
82540776Ssklower 		err = (*ifp->if_output)(ifp, m, dst, rt);
82636369Ssklower 		return(err);
82736369Ssklower 	} else {
82840776Ssklower 		err = (*ifp->if_output)(ifp, m, dst, rt);
82936369Ssklower 		return(err);
83036369Ssklower 	}
83136369Ssklower }
83236369Ssklower 
83361286Ssklower #endif	/* TROLL */
834