xref: /csrg-svn/sys/netiso/clnp_frag.c (revision 39195)
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*39195Ssklower /*	@(#)clnp_frag.c	7.6 (Berkeley) 09/22/89 */
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  */
7736369Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags)
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 */
8436369Ssklower {
8536369Ssklower 	struct clnp_fixed	*clnp;		/* ptr to fixed part of header */
8636369Ssklower 
8736369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
8836369Ssklower 
8937469Ssklower 	if (clnp->cnf_type & CNF_SEG_OK) {
9036369Ssklower 		struct mbuf			*hdr = NULL;		/* save copy of clnp hdr */
9136369Ssklower 		struct mbuf			*frag_hdr = NULL;
9236369Ssklower 		struct mbuf			*frag_data = NULL;
9336369Ssklower 		struct clnp_segment	seg_part, tmp_seg;	/* segmentation header */
9436369Ssklower 		extern int 			clnp_id;			/* id of datagram */
9536369Ssklower 		int					error = 0;
9636369Ssklower 
97*39195Ssklower 		INCSTAT(cns_fragmented);
9836369Ssklower 
9936369Ssklower 		seg_part.cng_id = clnp_id++;
10036369Ssklower 		seg_part.cng_off = 0;
10136369Ssklower 		seg_part.cng_tot_len = total_len;
10236369Ssklower 
10336369Ssklower 		/*
10436369Ssklower 		 *	Duplicate header, and remove from packet
10536369Ssklower 		 */
10637469Ssklower 		if ((hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) {
10736369Ssklower 			clnp_discard(m, GEN_CONGEST);
10836369Ssklower 			return(ENOBUFS);
10936369Ssklower 		}
11037469Ssklower 		m_adj(m, (int)clnp->cnf_hdr_len);
11136369Ssklower 		total_len -= clnp->cnf_hdr_len;
11236369Ssklower 
11336369Ssklower 		while (total_len > 0) {
11436369Ssklower 			int		frag_size;
11536369Ssklower 			int		last_frag = 0;		/* true if this is the last fragment */
11636764Ssklower 
11736764Ssklower 			IFDEBUG(D_FRAG)
11836764Ssklower 				struct mbuf *mdump = frag_hdr;
11936764Ssklower 				int tot_mlen = 0;
12036764Ssklower 				printf("clnp_fragment: total_len %d:\n", total_len);
12136764Ssklower 				while (mdump != NULL) {
12236764Ssklower 					printf("\tmbuf x%x, m_len %d\n",
12336764Ssklower 						mdump, mdump->m_len);
12436764Ssklower 					tot_mlen += mdump->m_len;
12536764Ssklower 					mdump = mdump->m_next;
12636764Ssklower 				}
12736764Ssklower 				printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen);
12836764Ssklower 			ENDDEBUG
12936369Ssklower 
13036369Ssklower 			frag_size = min(total_len, ifp->if_mtu - clnp->cnf_hdr_len);
13136369Ssklower 
13236369Ssklower 			/*
13336369Ssklower 			 *	For some stupid reason, fragments must be at least 8 bytes
13436369Ssklower 			 *	in length. If this fragment will cause the last one to
13536369Ssklower 			 *	be less than 8 bytes, shorten this fragment a bit.
13636369Ssklower 			 */
13736369Ssklower 			if (((total_len - frag_size) > 0) && ((total_len - frag_size) < 8))
13836369Ssklower 				frag_size -= (8 - (total_len - frag_size));
13936369Ssklower 
14036369Ssklower 			last_frag = ((total_len - frag_size) == 0);
14136369Ssklower 
14236369Ssklower 			IFDEBUG(D_FRAG)
14336369Ssklower 				printf("clnp_fragment: seg off %d, size %d, remaining %d\n",
14436369Ssklower 					seg_part.cng_off, frag_size, total_len-frag_size);
14536369Ssklower 				if (last_frag)
14636369Ssklower 					printf("clnp_fragment: last fragment\n");
14736369Ssklower 			ENDDEBUG
14836369Ssklower 
14936369Ssklower 			if (last_frag) {
15036369Ssklower 				/*
15136369Ssklower 				 *	this is the last fragment; we don't need to get any other
15236369Ssklower 				 *	mbufs.
15336369Ssklower 				 */
15436369Ssklower 				frag_hdr = hdr;
15536369Ssklower 				frag_data = m;
15636369Ssklower 			} else {
15736369Ssklower 				/* duplicate header and data mbufs */
15837469Ssklower 				if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) {
15936369Ssklower 					clnp_discard(m, GEN_CONGEST);
16036369Ssklower 					m_freem(hdr);
16136369Ssklower 					return(ENOBUFS);
16236369Ssklower 				}
16336369Ssklower 				if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
16436369Ssklower 					clnp_discard(m, GEN_CONGEST);
16536369Ssklower 					m_freem(hdr);
16636369Ssklower 					m_freem(frag_hdr);
16736369Ssklower 					return(ENOBUFS);
16836369Ssklower 				}
169*39195Ssklower 				INCSTAT(cns_fragments);
17036369Ssklower 			}
17136369Ssklower 			clnp = mtod(frag_hdr, struct clnp_fixed *);
17236369Ssklower 
17336369Ssklower 			if (!last_frag)
17437469Ssklower 				clnp->cnf_type |= CNF_MORE_SEGS;
17536369Ssklower 
17636369Ssklower 			/* link together */
17736369Ssklower 			m_cat(frag_hdr, frag_data);
17836369Ssklower 
17936369Ssklower 			/* make sure segmentation fields are in network order */
18036369Ssklower 			tmp_seg.cng_id = htons(seg_part.cng_id);
18136369Ssklower 			tmp_seg.cng_off = htons(seg_part.cng_off);
18236369Ssklower 			tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len);
18336369Ssklower 
18436369Ssklower 			/* insert segmentation part */
18536369Ssklower 			bcopy((caddr_t)&tmp_seg, mtod(frag_hdr, caddr_t) + segoff,
18636369Ssklower 				sizeof(struct clnp_segment));
18736369Ssklower 
18836369Ssklower 			{
18936369Ssklower 				int	derived_len = clnp->cnf_hdr_len + frag_size;
19036369Ssklower 				HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
19137469Ssklower 				if ((frag_hdr->m_flags & M_PKTHDR) == 0)
19237469Ssklower 					panic("clnp_frag:lost header");
19337469Ssklower 				frag_hdr->m_pkthdr.len = derived_len;
19436369Ssklower 			}
19536369Ssklower 			/* compute clnp checksum (on header only) */
19636369Ssklower 			if (flags & CLNP_NO_CKSUM) {
19736369Ssklower 				HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
19836369Ssklower 			} else {
19936369Ssklower 				iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
20036369Ssklower 			}
20136369Ssklower 
20236369Ssklower 			IFDEBUG(D_DUMPOUT)
20336369Ssklower 				struct mbuf *mdump = frag_hdr;
20436369Ssklower 				printf("clnp_fragment: sending dg:\n");
20536369Ssklower 				while (mdump != NULL) {
20636764Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
20736369Ssklower 					mdump = mdump->m_next;
20836369Ssklower 				}
20936369Ssklower 			ENDDEBUG
21036369Ssklower 
21136369Ssklower #ifdef	TROLL
21236369Ssklower 			error = troll_output(ifp, frag_hdr, first_hop);
21336369Ssklower #else
21436369Ssklower 			error = (*ifp->if_output)(ifp, frag_hdr, first_hop);
21536369Ssklower #endif	TROLL
21636369Ssklower 
21736369Ssklower 			/*
21836369Ssklower 			 *	Tough situation: if the error occured on the last
21936369Ssklower 			 *	fragment, we can not send an ER, as the if_output
22036369Ssklower 			 *	routine consumed the packet. If the error occured
22136369Ssklower 			 *	on any intermediate packets, we can send an ER
22236369Ssklower 			 *	because we still have the original header in (m).
22336369Ssklower 			 */
22436369Ssklower 			if (error) {
22536369Ssklower 				if (frag_hdr != hdr) {
22636369Ssklower 					/*
22736369Ssklower 					 *	The error was not on the last fragment. We must
22836369Ssklower 					 *	free hdr and m before returning
22936369Ssklower 					 */
23036369Ssklower 					clnp_discard(m, GEN_NOREAS);
23136369Ssklower 					m_freem(hdr);
23236369Ssklower 				}
23336369Ssklower 				return(error);
23436369Ssklower 			}
23536369Ssklower 
23636369Ssklower 			/* bump segment offset, trim data mbuf, and decrement count left */
23736369Ssklower #ifdef	TROLL
23836369Ssklower 			/*
23936369Ssklower 			 *	Decrement frag_size by some fraction. This will cause the
24036369Ssklower 			 *	next fragment to start 'early', thus duplicating the end
24136369Ssklower 			 *	of the current fragment.  troll.tr_dup_size controls
24236369Ssklower 			 *	the fraction. If positive, it specifies the fraction. If
24336369Ssklower 			 *	negative, a random fraction is used.
24436369Ssklower 			 */
24536369Ssklower 			if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
24636369Ssklower 				int num_bytes = frag_size;
24736369Ssklower 
24836369Ssklower 				if (trollctl.tr_dup_size > 0)
24936369Ssklower 					num_bytes *= trollctl.tr_dup_size;
25036369Ssklower 				else
25136369Ssklower 					num_bytes *= troll_random();
25236369Ssklower 				frag_size -= num_bytes;
25336369Ssklower 			}
25436369Ssklower #endif	TROLL
25536369Ssklower 			total_len -= frag_size;
25636369Ssklower 			if (!last_frag) {
25736369Ssklower 				seg_part.cng_off += frag_size;
25836369Ssklower 				m_adj(m, frag_size);
25936369Ssklower 			}
26036369Ssklower 		}
26136369Ssklower 		return(0);
26236369Ssklower 	} else {
263*39195Ssklower 		INCSTAT(cns_cantfrag);
26436369Ssklower 		clnp_discard(m, GEN_SEGNEEDED);
26536369Ssklower 		return(EMSGSIZE);
26636369Ssklower 	}
26736369Ssklower }
26836369Ssklower 
26936369Ssklower /*
27036369Ssklower  * FUNCTION:		clnp_reass
27136369Ssklower  *
27236369Ssklower  * PURPOSE:			Attempt to reassemble a clnp packet given the current
27336369Ssklower  *					fragment. If reassembly succeeds (all the fragments
27436369Ssklower  *					are present), then return a pointer to an mbuf chain
27536369Ssklower  *					containing the reassembled packet. This packet will
27636369Ssklower  *					appear in the mbufs as if it had just arrived in
27736369Ssklower  *					one piece.
27836369Ssklower  *
27936369Ssklower  *					If reassembly fails, then save this fragment and
28036369Ssklower  *					return 0.
28136369Ssklower  *
28236369Ssklower  * RETURNS:			Ptr to assembled packet, or 0
28336369Ssklower  *
28436369Ssklower  * SIDE EFFECTS:
28536369Ssklower  *
28636369Ssklower  * NOTES:
28736369Ssklower  *		clnp_slowtimo can not affect this code because clnpintr, and thus
28836369Ssklower  *		this code, is called at a higher priority than clnp_slowtimo.
28936369Ssklower  */
29036369Ssklower struct mbuf *
29136369Ssklower clnp_reass(m, src, dst, seg)
29236369Ssklower struct mbuf 		*m;		/* new fragment */
29336369Ssklower struct iso_addr		*src;	/* src of new fragment */
29436369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
29536369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
29636369Ssklower {
29736369Ssklower 	register struct clnp_fragl		*cfh;
29836369Ssklower 
29936369Ssklower 	/* look for other fragments of this datagram */
30036369Ssklower 	for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
30136369Ssklower 		if (iso_addrmatch1(src, &cfh->cfl_src) &&
30236369Ssklower 			iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) {
30336369Ssklower 			IFDEBUG(D_REASS)
30436369Ssklower 				printf("clnp_reass: found packet\n");
30536369Ssklower 			ENDDEBUG
30636369Ssklower 			/*
30736369Ssklower 			 *	There are other fragments here already. Lets see if
30836369Ssklower 			 *	this fragment is of any help
30936369Ssklower 			 */
31036369Ssklower 			clnp_insert_frag(cfh, m, seg);
31136369Ssklower 			return (clnp_comp_pdu(cfh));
31236369Ssklower 		}
31336369Ssklower 	}
31436369Ssklower 
31536369Ssklower 	IFDEBUG(D_REASS)
31636369Ssklower 		printf("clnp_reass: new packet!\n");
31736369Ssklower 	ENDDEBUG
31836369Ssklower 
31936369Ssklower 	/*
32036369Ssklower 	 *	This is the first fragment. If src is not consuming too many
32136369Ssklower 	 *	resources, then create a new fragment list and add
32236369Ssklower 	 *	this fragment to the list.
32336369Ssklower 	 */
32436369Ssklower 	/* TODO: don't let one src hog all the reassembly buffers */
32536369Ssklower 	if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) {
326*39195Ssklower 		INCSTAT(cns_fragdropped);
32736369Ssklower 		clnp_discard(m, GEN_CONGEST);
32836369Ssklower 	}
32936369Ssklower 
33036369Ssklower 	return(NULL);
33136369Ssklower }
33236369Ssklower 
33336369Ssklower /*
33436369Ssklower  * FUNCTION:		clnp_newpkt
33536369Ssklower  *
33636369Ssklower  * PURPOSE:			Create the necessary structures to handle a new
33736369Ssklower  *					fragmented clnp packet.
33836369Ssklower  *
33936369Ssklower  * RETURNS:			non-zero if it succeeds, zero if fails.
34036369Ssklower  *
34136369Ssklower  * SIDE EFFECTS:
34236369Ssklower  *
34336369Ssklower  * NOTES:			Failure is only due to insufficient resources.
34436369Ssklower  */
34536369Ssklower clnp_newpkt(m, src, dst, seg)
34636369Ssklower struct mbuf 		*m;		/* new fragment */
34736369Ssklower struct iso_addr		*src;	/* src of new fragment */
34836369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
34936369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
35036369Ssklower {
35136369Ssklower 	register struct clnp_fragl		*cfh;
35236369Ssklower 	register struct clnp_fixed		*clnp;
35336369Ssklower 	struct mbuf 					*m0;
35436369Ssklower 
35536369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
35636369Ssklower 
35736369Ssklower 	/*
35836369Ssklower 	 *	Allocate new clnp fragl structure to act as header of all fragments
35936369Ssklower 	 *	for this datagram.
36036369Ssklower 	 */
36136369Ssklower 	MGET(m0, M_DONTWAIT, MT_FTABLE);
36236369Ssklower 	if (m0 == NULL) {
36336369Ssklower 		return (0);
36436369Ssklower 	}
36536369Ssklower 	cfh = mtod(m0, struct clnp_fragl *);
36636369Ssklower 
36736369Ssklower 	/*
36836369Ssklower 	 *	Duplicate the header of this fragment, and save in cfh.
36936369Ssklower 	 *	Free m0 and return if m_copy does not succeed.
37036369Ssklower 	 */
37137469Ssklower 	if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) {
37236369Ssklower 		m_freem(m0);
37336369Ssklower 		return (0);
37436369Ssklower 	}
37536369Ssklower 
37636369Ssklower 	/* Fill in rest of fragl structure */
37736369Ssklower 	bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr));
37836369Ssklower 	bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr));
37936369Ssklower 	cfh->cfl_id = seg->cng_id;
38036369Ssklower 	cfh->cfl_ttl = clnp->cnf_ttl;
38136369Ssklower 	cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
38236369Ssklower 	cfh->cfl_frags = NULL;
38336369Ssklower 	cfh->cfl_next = NULL;
38436369Ssklower 
38536369Ssklower 	/* Insert into list of packets */
38636369Ssklower 	cfh->cfl_next = clnp_frags;
38736369Ssklower 	clnp_frags = cfh;
38836369Ssklower 
38936369Ssklower 	/* Insert this fragment into list headed by cfh */
39036369Ssklower 	clnp_insert_frag(cfh, m, seg);
39136369Ssklower 	return(1);
39236369Ssklower }
39336369Ssklower 
39436369Ssklower /*
39536369Ssklower  * FUNCTION:		clnp_insert_frag
39636369Ssklower  *
39736369Ssklower  * PURPOSE:			Insert fragment into list headed by 'cf'.
39836369Ssklower  *
39936369Ssklower  * RETURNS:			nothing
40036369Ssklower  *
40136369Ssklower  * SIDE EFFECTS:
40236369Ssklower  *
40336369Ssklower  * NOTES:			This is the 'guts' of the reassembly algorithm.
40436369Ssklower  *					Each fragment in this list contains a clnp_frag
40536369Ssklower  *					structure followed by the data of the fragment.
40636369Ssklower  *					The clnp_frag structure actually lies on top of
40736369Ssklower  *					part of the old clnp header.
40836369Ssklower  */
40936369Ssklower clnp_insert_frag(cfh, m, seg)
41036369Ssklower struct clnp_fragl	*cfh;	/* header of list of packet fragments */
41136369Ssklower struct mbuf 		*m;		/* new fragment */
41236369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
41336369Ssklower {
41436369Ssklower 	register struct clnp_fixed	*clnp;	/* clnp hdr of fragment */
41536369Ssklower 	register struct clnp_frag	*cf;	/* generic fragment ptr */
41636369Ssklower 	register struct clnp_frag 	*cf_sub = NULL;	/* frag subsequent to new one */
41736369Ssklower 	register struct clnp_frag 	*cf_prev = NULL; /* frag previous to new one */
41836369Ssklower 	u_short						first;	/* offset of first byte of initial pdu*/
41936369Ssklower 	u_short						last;	/* offset of last byte of initial pdu */
42036369Ssklower 	u_short						fraglen;/* length of fragment */
42136369Ssklower 
42236369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
42336369Ssklower 	first = seg->cng_off;
42436369Ssklower 	CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
42536369Ssklower 	fraglen -= clnp->cnf_hdr_len;
42636369Ssklower 	last = (first + fraglen) - 1;
42736369Ssklower 
42836369Ssklower 	IFDEBUG(D_REASS)
42936369Ssklower 		printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n",
43036369Ssklower 			first, last, fraglen);
43136369Ssklower 		printf("clnp_insert_frag: current fragments:\n");
43236369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
43336369Ssklower 			printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last);
43436369Ssklower 		}
43536369Ssklower 	ENDDEBUG
43636369Ssklower 
43736369Ssklower 	if (cfh->cfl_frags != NULL) {
43836369Ssklower 		/*
43936369Ssklower 		 *	Find fragment which begins after the new one
44036369Ssklower 		 */
44136369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) {
44236369Ssklower 			if (cf->cfr_first > first) {
44336369Ssklower 				cf_sub = cf;
44436369Ssklower 				break;
44536369Ssklower 			}
44636369Ssklower 		}
44736369Ssklower 
44836369Ssklower 		IFDEBUG(D_REASS)
44936369Ssklower 			printf("clnp_insert_frag: Previous frag is ");
45036369Ssklower 			if (cf_prev == NULL)
45136369Ssklower 				printf("NULL\n");
45236369Ssklower 			else
45336369Ssklower 				printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last);
45436369Ssklower 			printf("clnp_insert_frag: Subsequent frag is ");
45536369Ssklower 			if (cf_sub == NULL)
45636369Ssklower 				printf("NULL\n");
45736369Ssklower 			else
45836369Ssklower 				printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last);
45936369Ssklower 		ENDDEBUG
46036369Ssklower 
46136369Ssklower 		/*
46236369Ssklower 		 *	If there is a fragment before the new one, check if it
46336369Ssklower 		 *	overlaps the new one. If so, then trim the end of the
46436369Ssklower 		 *	previous one.
46536369Ssklower 		 */
46636369Ssklower 		if (cf_prev != NULL) {
46736369Ssklower 			if (cf_prev->cfr_last > first) {
46836369Ssklower 				u_short overlap = cf_prev->cfr_last - first;
46936369Ssklower 
47036369Ssklower 				IFDEBUG(D_REASS)
47136369Ssklower 					printf("clnp_insert_frag: previous overlaps by %d\n",
47236369Ssklower 						overlap);
47336369Ssklower 				ENDDEBUG
47436369Ssklower 
47536369Ssklower 				if (overlap > fraglen) {
47636369Ssklower 					/*
47736369Ssklower 					 *	The new fragment is entirely contained in the
47836369Ssklower 					 *	preceeding one. We can punt on the new frag
47936369Ssklower 					 *	completely.
48036369Ssklower 					 */
48136369Ssklower 					m_freem(m);
48236369Ssklower 					return;
48336369Ssklower 				} else {
48436369Ssklower 					/* Trim data off of end of previous fragment */
48536369Ssklower 					/* inc overlap to prevent duplication of last byte */
48636369Ssklower 					overlap++;
48737469Ssklower 					m_adj(cf_prev->cfr_data, -(int)overlap);
48836369Ssklower 					cf_prev->cfr_last -= overlap;
48936369Ssklower 				}
49036369Ssklower 			}
49136369Ssklower 		}
49236369Ssklower 
49336369Ssklower 		/*
49436369Ssklower 		 *	For all fragments past the new one, check if any data on
49536369Ssklower 		 *	the new one overlaps data on existing fragments. If so,
49636369Ssklower 		 *	then trim the extra data off the end of the new one.
49736369Ssklower 		 */
49836369Ssklower 		for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
49936369Ssklower 			if (cf->cfr_first < last) {
50036369Ssklower 				u_short overlap = last - cf->cfr_first;
50136369Ssklower 
50236369Ssklower 				IFDEBUG(D_REASS)
50336369Ssklower 					printf("clnp_insert_frag: subsequent overlaps by %d\n",
50436369Ssklower 						overlap);
50536369Ssklower 				ENDDEBUG
50636369Ssklower 
50736369Ssklower 				if (overlap > fraglen) {
50836369Ssklower 					/*
50936369Ssklower 					 *	The new fragment is entirely contained in the
51036369Ssklower 					 *	succeeding one. This should not happen, because
51136369Ssklower 					 *	early on in this code we scanned for the fragment
51236369Ssklower 					 *	which started after the new one!
51336369Ssklower 					 */
51436369Ssklower 					m_freem(m);
51536369Ssklower 					printf("clnp_insert_frag: internal error!\n");
51636369Ssklower 					return;
51736369Ssklower 				} else {
51836369Ssklower 					/* Trim data off of end of new fragment */
51936369Ssklower 					/* inc overlap to prevent duplication of last byte */
52036369Ssklower 					overlap++;
52137469Ssklower 					m_adj(m, -(int)overlap);
52236369Ssklower 					last -= overlap;
52336369Ssklower 				}
52436369Ssklower 			}
52536369Ssklower 		}
52636369Ssklower 	}
52736369Ssklower 
52836369Ssklower 	/*
52936369Ssklower 	 *	Insert the new fragment beween cf_prev and cf_sub
53036369Ssklower 	 *
53136369Ssklower 	 *	Note: the clnp hdr is still in the mbuf.
53236369Ssklower 	 *	If the data of the mbuf is not word aligned, shave off enough
53336369Ssklower 	 *	so that it is. Then, cast the clnp_frag structure on top
53436369Ssklower 	 *	of the clnp header.
53536369Ssklower 	 *	The clnp_hdr will not be used again (as we already have
53636369Ssklower 	 *	saved a copy of it).
53736369Ssklower 	 *
53836369Ssklower 	 *	Save in cfr_bytes the number of bytes to shave off to get to
53936369Ssklower 	 *	the data of the packet. This is used when we coalesce fragments;
54036369Ssklower 	 *	the clnp_frag structure must be removed before joining mbufs.
54136369Ssklower 	 */
54236369Ssklower 	{
54336369Ssklower 		int	pad;
54436369Ssklower 		u_int	bytes;
54536369Ssklower 
54636369Ssklower 		/* determine if header is not word aligned */
54736369Ssklower 		pad = (int)clnp % 4;
54836369Ssklower 		if (pad < 0)
54936369Ssklower 			pad = -pad;
55036369Ssklower 
55136369Ssklower 		/* bytes is number of bytes left in front of data */
55236369Ssklower 		bytes = clnp->cnf_hdr_len - pad;
55336369Ssklower 
55436764Ssklower 		IFDEBUG(D_REASS)
55536764Ssklower 			printf("clnp_insert_frag: clnp x%x requires %d alignment\n",
55636764Ssklower 				clnp, pad);
55736764Ssklower 		ENDDEBUG
55836764Ssklower 
55936369Ssklower 		/* make it word aligned if necessary */
56036369Ssklower 		if (pad)
56136369Ssklower 			m_adj(m, pad);
56236369Ssklower 
56336369Ssklower 		cf = mtod(m, struct clnp_frag *);
56436369Ssklower 		cf->cfr_bytes = bytes;
56536764Ssklower 
56636764Ssklower 		IFDEBUG(D_REASS)
56736764Ssklower 			printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf,
56836764Ssklower 				cf->cfr_bytes);
56936764Ssklower 		ENDDEBUG
57036369Ssklower 	}
57136369Ssklower 	cf->cfr_first = first;
57236369Ssklower 	cf->cfr_last = last;
57336369Ssklower 
57436369Ssklower 
57536369Ssklower 	/*
57636369Ssklower 	 *	The data is the mbuf itself, although we must remember that the
57736369Ssklower 	 *	first few bytes are actually a clnp_frag structure
57836369Ssklower 	 */
57936369Ssklower 	cf->cfr_data = m;
58036369Ssklower 
58136369Ssklower 	/* link into place */
58236369Ssklower 	cf->cfr_next = cf_sub;
58336369Ssklower 	if (cf_prev == NULL)
58436369Ssklower 		cfh->cfl_frags = cf;
58536369Ssklower 	else
58636369Ssklower 		cf_prev->cfr_next = cf;
58736369Ssklower }
58836369Ssklower 
58936369Ssklower /*
59036369Ssklower  * FUNCTION:		clnp_comp_pdu
59136369Ssklower  *
59236369Ssklower  * PURPOSE:			Scan the list of fragments headed by cfh. Merge
59336369Ssklower  *					any contigious fragments into one. If, after
59436369Ssklower  *					traversing all the fragments, it is determined that
59536369Ssklower  *					the packet is complete, then return a pointer to
59636369Ssklower  *					the packet (with header prepended). Otherwise,
59736369Ssklower  *					return NULL.
59836369Ssklower  *
59936369Ssklower  * RETURNS:			NULL, or a pointer to the assembled pdu in an mbuf chain.
60036369Ssklower  *
60136369Ssklower  * SIDE EFFECTS:	Will colapse contigious fragments into one.
60236369Ssklower  *
60336369Ssklower  * NOTES:			This code assumes that there are no overlaps of
60436369Ssklower  *					fragment pdus.
60536369Ssklower  */
60636369Ssklower struct mbuf *
60736369Ssklower clnp_comp_pdu(cfh)
60836369Ssklower struct clnp_fragl	*cfh;		/* fragment header */
60936369Ssklower {
61036369Ssklower 	register struct clnp_frag	*cf = cfh->cfl_frags;
61136369Ssklower 
61236369Ssklower 	while (cf->cfr_next != NULL) {
61336369Ssklower 		register struct clnp_frag	*cf_next = cf->cfr_next;
61436369Ssklower 
61536369Ssklower 		IFDEBUG(D_REASS)
61636369Ssklower 			printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n",
61736369Ssklower 				cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
61836369Ssklower 				cf_next->cfr_last);
61936369Ssklower 		ENDDEBUG
62036369Ssklower 
62136369Ssklower 		if (cf->cfr_last == (cf_next->cfr_first - 1)) {
62236369Ssklower 			/*
62336369Ssklower 			 *	Merge fragment cf and cf_next
62436369Ssklower 			 *
62536369Ssklower 			 *	- update cf header
62636369Ssklower 			 *	- trim clnp_frag structure off of cf_next
62736369Ssklower 			 *	- append cf_next to cf
62836369Ssklower 			 */
62936369Ssklower 			struct clnp_frag	cf_next_hdr;
63036369Ssklower 			struct clnp_frag	*next_frag;
63136369Ssklower 
63236369Ssklower 			cf_next_hdr = *cf_next;
63336369Ssklower 			next_frag = cf_next->cfr_next;
63436369Ssklower 
63536369Ssklower 			IFDEBUG(D_REASS)
63636369Ssklower 				struct mbuf *mdump;
63736764Ssklower 				int l;
63836369Ssklower 				printf("clnp_comp_pdu: merging fragments\n");
63936764Ssklower 				printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n",
64036764Ssklower 					cf->cfr_first, cf->cfr_last, cf->cfr_bytes);
64136369Ssklower 				mdump = cf->cfr_data;
64236764Ssklower 				l = 0;
64336369Ssklower 				while (mdump != NULL) {
64436369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
64536764Ssklower 					l += mdump->m_len;
64636369Ssklower 					mdump = mdump->m_next;
64736369Ssklower 				}
64836764Ssklower 				printf("\ttotal len: %d\n", l);
64936764Ssklower 				printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n",
65036764Ssklower 					cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes);
65136369Ssklower 				mdump = cf_next->cfr_data;
65236764Ssklower 				l = 0;
65336369Ssklower 				while (mdump != NULL) {
65436369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
65536764Ssklower 					l += mdump->m_len;
65636369Ssklower 					mdump = mdump->m_next;
65736369Ssklower 				}
65836764Ssklower 				printf("\ttotal len: %d\n", l);
65936369Ssklower 			ENDDEBUG
66036369Ssklower 
66136369Ssklower 			cf->cfr_last = cf_next->cfr_last;
66236369Ssklower 			/*
66336369Ssklower 			 *	After this m_adj, the cf_next ptr is useless because we
66436369Ssklower 			 *	have adjusted the clnp_frag structure away...
66536369Ssklower 			 */
66636764Ssklower 			IFDEBUG(D_REASS)
66736764Ssklower 				printf("clnp_comp_pdu: shaving off %d bytes\n",
66836764Ssklower 					cf_next_hdr.cfr_bytes);
66936764Ssklower 			ENDDEBUG
67037469Ssklower 			m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes);
67136369Ssklower 			m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
67236369Ssklower 			cf->cfr_next = next_frag;
67336369Ssklower 		} else {
67436369Ssklower 			cf = cf->cfr_next;
67536369Ssklower 		}
67636369Ssklower 	}
67736369Ssklower 
67836369Ssklower 	cf = cfh->cfl_frags;
67936369Ssklower 
68036369Ssklower 	IFDEBUG(D_REASS)
68136369Ssklower 		struct mbuf *mdump = cf->cfr_data;
68236369Ssklower 		printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first,
68336369Ssklower 			cf->cfr_last);
68436369Ssklower 		printf("clnp_comp_pdu: data for frag:\n");
68536369Ssklower 		while (mdump != NULL) {
68636369Ssklower 			printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
68736369Ssklower /* 			dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
68836369Ssklower 			mdump = mdump->m_next;
68936369Ssklower 		}
69036369Ssklower 	ENDDEBUG
69136369Ssklower 
69236369Ssklower 	/* Check if datagram is complete */
69336369Ssklower 	if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
69436369Ssklower 		/*
69536369Ssklower 		 *	We have a complete pdu!
69636369Ssklower 		 *	- Remove the frag header from (only) remaining fragment
69736369Ssklower 		 *		(which is not really a fragment anymore, as the datagram is
69836369Ssklower 		 *		complete).
69936369Ssklower 		 *	- Prepend a clnp header
70036369Ssklower 		 */
70136369Ssklower 		struct mbuf	*data = cf->cfr_data;
70236369Ssklower 		struct mbuf	*hdr = cfh->cfl_orighdr;
70336369Ssklower 		struct clnp_fragl *scan;
70436369Ssklower 
70536369Ssklower 		IFDEBUG(D_REASS)
70636369Ssklower 			printf("clnp_comp_pdu: complete pdu!\n");
70736369Ssklower 		ENDDEBUG
70836369Ssklower 
70937469Ssklower 		m_adj(data, (int)cf->cfr_bytes);
71036369Ssklower 		m_cat(hdr, data);
71136369Ssklower 
71236369Ssklower 		IFDEBUG(D_DUMPIN)
71336369Ssklower 			struct mbuf *mdump = hdr;
71436369Ssklower 			printf("clnp_comp_pdu: pdu is:\n");
71536369Ssklower 			while (mdump != NULL) {
71636369Ssklower 				printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
71736369Ssklower /* 				dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
71836369Ssklower 				mdump = mdump->m_next;
71936369Ssklower 			}
72036369Ssklower 		ENDDEBUG
72136369Ssklower 
72236369Ssklower 		/*
72336369Ssklower 		 *	Remove cfh from the list of fragmented pdus
72436369Ssklower 		 */
72536369Ssklower 		if (clnp_frags == cfh) {
72636369Ssklower 			clnp_frags = cfh->cfl_next;
72736369Ssklower 		} else {
72836369Ssklower 			for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) {
72936369Ssklower 				if (scan->cfl_next == cfh) {
73036369Ssklower 					scan->cfl_next = cfh->cfl_next;
73136369Ssklower 					break;
73236369Ssklower 				}
73336369Ssklower 			}
73436369Ssklower 		}
73536369Ssklower 
73636369Ssklower 		/* free cfh */
73736369Ssklower 		m_freem(dtom(cfh));
73836369Ssklower 
73936369Ssklower 		return(hdr);
74036369Ssklower 	}
74136369Ssklower 
74236369Ssklower 	return(NULL);
74336369Ssklower }
74436369Ssklower #ifdef	TROLL
74537469Ssklower static int troll_cnt;
74637536Smckusick #include "time.h"
74736369Ssklower /*
74836369Ssklower  * FUNCTION:		troll_random
74936369Ssklower  *
75036369Ssklower  * PURPOSE:			generate a pseudo-random number between 0 and 1
75136369Ssklower  *
75236369Ssklower  * RETURNS:			the random number
75336369Ssklower  *
75436369Ssklower  * SIDE EFFECTS:
75536369Ssklower  *
75636369Ssklower  * NOTES:			This is based on the clock.
75736369Ssklower  */
75836369Ssklower float troll_random()
75936369Ssklower {
76036369Ssklower 	extern struct timeval time;
76136369Ssklower 	long	t = time.tv_usec % 100;
76236369Ssklower 
76336369Ssklower 	return((float)t / (float) 100);
76436369Ssklower }
76536369Ssklower 
76636369Ssklower /*
76736369Ssklower  * FUNCTION:		troll_output
76836369Ssklower  *
76936369Ssklower  * PURPOSE:			Do something sneaky with the datagram passed. Possible
77036369Ssklower  *					operations are:
77136369Ssklower  *						Duplicate the packet
77236369Ssklower  *						Drop the packet
77336369Ssklower  *						Trim some number of bytes from the packet
77436369Ssklower  *						Munge some byte in the packet
77536369Ssklower  *
77636369Ssklower  * RETURNS:			0, or unix error code
77736369Ssklower  *
77836369Ssklower  * SIDE EFFECTS:
77936369Ssklower  *
78036369Ssklower  * NOTES:			The operation of this procedure is regulated by the
78136369Ssklower  *					troll control structure (Troll).
78236369Ssklower  */
78336369Ssklower troll_output(ifp, m, dst)
78436369Ssklower struct ifnet	*ifp;
78536369Ssklower struct mbuf		*m;
78636369Ssklower struct sockaddr	*dst;
78736369Ssklower {
78836369Ssklower 	int	err = 0;
78936369Ssklower 	troll_cnt++;
79036369Ssklower 
79136369Ssklower 	if (trollctl.tr_ops & TR_DUPPKT) {
79236369Ssklower 		/*
79336369Ssklower 		 *	Duplicate every Nth packet
79436369Ssklower 		 *	TODO: random?
79536369Ssklower 		 */
79636369Ssklower 		float	f_freq = troll_cnt * trollctl.tr_dup_freq;
79736369Ssklower 		int		i_freq = troll_cnt * trollctl.tr_dup_freq;
79836369Ssklower 		if (i_freq == f_freq) {
79937469Ssklower 			struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL);
80036369Ssklower 			if (dup != NULL)
80136369Ssklower 				err = (*ifp->if_output)(ifp, dup, dst);
80236369Ssklower 		}
80336369Ssklower 		if (!err)
80436369Ssklower 			err = (*ifp->if_output)(ifp, m, dst);
80536369Ssklower 		return(err);
80636369Ssklower 	} else if (trollctl.tr_ops & TR_DROPPKT) {
80736369Ssklower 	} else if (trollctl.tr_ops & TR_CHANGE) {
80836369Ssklower 		struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
80936369Ssklower 		clnp->cnf_cksum_msb = 0;
81036369Ssklower 		err = (*ifp->if_output)(ifp, m, dst);
81136369Ssklower 		return(err);
81236369Ssklower 	} else {
81336369Ssklower 		err = (*ifp->if_output)(ifp, m, dst);
81436369Ssklower 		return(err);
81536369Ssklower 	}
81636369Ssklower }
81736369Ssklower 
81836369Ssklower #endif	TROLL
819