xref: /csrg-svn/sys/netiso/clnp_frag.c (revision 36369)
1*36369Ssklower /***********************************************************
2*36369Ssklower 		Copyright IBM Corporation 1987
3*36369Ssklower 
4*36369Ssklower                       All Rights Reserved
5*36369Ssklower 
6*36369Ssklower Permission to use, copy, modify, and distribute this software and its
7*36369Ssklower documentation for any purpose and without fee is hereby granted,
8*36369Ssklower provided that the above copyright notice appear in all copies and that
9*36369Ssklower both that copyright notice and this permission notice appear in
10*36369Ssklower supporting documentation, and that the name of IBM not be
11*36369Ssklower used in advertising or publicity pertaining to distribution of the
12*36369Ssklower software without specific, written prior permission.
13*36369Ssklower 
14*36369Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36369Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36369Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36369Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36369Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36369Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36369Ssklower SOFTWARE.
21*36369Ssklower 
22*36369Ssklower ******************************************************************/
23*36369Ssklower 
24*36369Ssklower /*
25*36369Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36369Ssklower  */
27*36369Ssklower /* $Header: clnp_frag.c,v 4.2 88/06/29 14:58:40 hagens Exp $ */
28*36369Ssklower /* $Source: /usr/argo/sys/netiso/RCS/clnp_frag.c,v $ */
29*36369Ssklower 
30*36369Ssklower #ifndef lint
31*36369Ssklower static char *rcsid = "$Header: clnp_frag.c,v 4.2 88/06/29 14:58:40 hagens Exp $";
32*36369Ssklower #endif lint
33*36369Ssklower 
34*36369Ssklower #ifdef ISO
35*36369Ssklower 
36*36369Ssklower #include "../h/types.h"
37*36369Ssklower #include "../h/param.h"
38*36369Ssklower #include "../h/mbuf.h"
39*36369Ssklower #include "../h/domain.h"
40*36369Ssklower #include "../h/protosw.h"
41*36369Ssklower #include "../h/socket.h"
42*36369Ssklower #include "../h/socketvar.h"
43*36369Ssklower #include "../h/errno.h"
44*36369Ssklower 
45*36369Ssklower #include "../net/if.h"
46*36369Ssklower #include "../net/route.h"
47*36369Ssklower 
48*36369Ssklower #include "../netiso/iso.h"
49*36369Ssklower #include "../netiso/iso_var.h"
50*36369Ssklower #include "../netiso/clnp.h"
51*36369Ssklower #include "../netiso/clnp_stat.h"
52*36369Ssklower #include "../netiso/argo_debug.h"
53*36369Ssklower 
54*36369Ssklower /* all fragments are hung off this list */
55*36369Ssklower struct clnp_fragl	*clnp_frags = NULL;
56*36369Ssklower 
57*36369Ssklower struct mbuf	*clnp_comp_pdu();
58*36369Ssklower 
59*36369Ssklower #ifdef	TROLL
60*36369Ssklower float troll_random();
61*36369Ssklower static int troll_cnt = 0;
62*36369Ssklower #endif	TROLL
63*36369Ssklower 
64*36369Ssklower 
65*36369Ssklower /*
66*36369Ssklower  * FUNCTION:		clnp_fragment
67*36369Ssklower  *
68*36369Ssklower  * PURPOSE:			Fragment a datagram, and send the itty bitty pieces
69*36369Ssklower  *					out over an interface.
70*36369Ssklower  *
71*36369Ssklower  * RETURNS:			success - 0
72*36369Ssklower  *					failure - unix error code
73*36369Ssklower  *
74*36369Ssklower  * SIDE EFFECTS:
75*36369Ssklower  *
76*36369Ssklower  * NOTES:			If there is an error sending the packet, clnp_discard
77*36369Ssklower  *					is called to discard the packet and send an ER. If
78*36369Ssklower  *					clnp_fragment was called from clnp_output, then
79*36369Ssklower  *					we generated the packet, and should not send an
80*36369Ssklower  *					ER -- clnp_emit_er will check for this. Otherwise,
81*36369Ssklower  *					the packet was fragmented during forwarding. In this
82*36369Ssklower  *					case, we ought to send an ER back.
83*36369Ssklower  */
84*36369Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags)
85*36369Ssklower struct ifnet	*ifp;		/* ptr to outgoing interface */
86*36369Ssklower struct mbuf		*m;			/* ptr to packet */
87*36369Ssklower struct sockaddr	*first_hop;	/* ptr to first hop */
88*36369Ssklower int				total_len;	/* length of datagram */
89*36369Ssklower int				segoff;		/* offset of segpart in hdr */
90*36369Ssklower int				flags;		/* flags passed to clnp_output */
91*36369Ssklower {
92*36369Ssklower 	struct clnp_fixed	*clnp;		/* ptr to fixed part of header */
93*36369Ssklower 
94*36369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
95*36369Ssklower 
96*36369Ssklower 	if (clnp->cnf_seg_ok) {
97*36369Ssklower 		struct mbuf			*hdr = NULL;		/* save copy of clnp hdr */
98*36369Ssklower 		struct mbuf			*frag_hdr = NULL;
99*36369Ssklower 		struct mbuf			*frag_data = NULL;
100*36369Ssklower 		struct clnp_segment	seg_part, tmp_seg;	/* segmentation header */
101*36369Ssklower 		extern int 			clnp_id;			/* id of datagram */
102*36369Ssklower 		int					error = 0;
103*36369Ssklower 
104*36369Ssklower 		INCSTAT(cns_frag);
105*36369Ssklower 
106*36369Ssklower 		seg_part.cng_id = clnp_id++;
107*36369Ssklower 		seg_part.cng_off = 0;
108*36369Ssklower 		seg_part.cng_tot_len = total_len;
109*36369Ssklower 
110*36369Ssklower 		/*
111*36369Ssklower 		 *	Duplicate header, and remove from packet
112*36369Ssklower 		 */
113*36369Ssklower 		if ((hdr = m_copy(m, 0, clnp->cnf_hdr_len)) == NULL) {
114*36369Ssklower 			clnp_discard(m, GEN_CONGEST);
115*36369Ssklower 			return(ENOBUFS);
116*36369Ssklower 		}
117*36369Ssklower 		m_adj(m, clnp->cnf_hdr_len);
118*36369Ssklower 		total_len -= clnp->cnf_hdr_len;
119*36369Ssklower 
120*36369Ssklower 		while (total_len > 0) {
121*36369Ssklower 			int		frag_size;
122*36369Ssklower 			int		last_frag = 0;		/* true if this is the last fragment */
123*36369Ssklower 
124*36369Ssklower 			frag_size = min(total_len, ifp->if_mtu - clnp->cnf_hdr_len);
125*36369Ssklower 
126*36369Ssklower 			/*
127*36369Ssklower 			 *	For some stupid reason, fragments must be at least 8 bytes
128*36369Ssklower 			 *	in length. If this fragment will cause the last one to
129*36369Ssklower 			 *	be less than 8 bytes, shorten this fragment a bit.
130*36369Ssklower 			 */
131*36369Ssklower 			if (((total_len - frag_size) > 0) && ((total_len - frag_size) < 8))
132*36369Ssklower 				frag_size -= (8 - (total_len - frag_size));
133*36369Ssklower 
134*36369Ssklower 			last_frag = ((total_len - frag_size) == 0);
135*36369Ssklower 
136*36369Ssklower 			IFDEBUG(D_FRAG)
137*36369Ssklower 				printf("clnp_fragment: seg off %d, size %d, remaining %d\n",
138*36369Ssklower 					seg_part.cng_off, frag_size, total_len-frag_size);
139*36369Ssklower 				if (last_frag)
140*36369Ssklower 					printf("clnp_fragment: last fragment\n");
141*36369Ssklower 			ENDDEBUG
142*36369Ssklower 
143*36369Ssklower 			if (last_frag) {
144*36369Ssklower 				/*
145*36369Ssklower 				 *	this is the last fragment; we don't need to get any other
146*36369Ssklower 				 *	mbufs.
147*36369Ssklower 				 */
148*36369Ssklower 				frag_hdr = hdr;
149*36369Ssklower 				frag_data = m;
150*36369Ssklower 			} else {
151*36369Ssklower 				/* duplicate header and data mbufs */
152*36369Ssklower 				if ((frag_hdr = m_copy(hdr, 0, M_COPYALL)) == NULL) {
153*36369Ssklower 					clnp_discard(m, GEN_CONGEST);
154*36369Ssklower 					m_freem(hdr);
155*36369Ssklower 					return(ENOBUFS);
156*36369Ssklower 				}
157*36369Ssklower 				if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
158*36369Ssklower 					clnp_discard(m, GEN_CONGEST);
159*36369Ssklower 					m_freem(hdr);
160*36369Ssklower 					m_freem(frag_hdr);
161*36369Ssklower 					return(ENOBUFS);
162*36369Ssklower 				}
163*36369Ssklower 			}
164*36369Ssklower 			clnp = mtod(frag_hdr, struct clnp_fixed *);
165*36369Ssklower 
166*36369Ssklower 			if (!last_frag)
167*36369Ssklower 				clnp->cnf_more_segs = 1;
168*36369Ssklower 
169*36369Ssklower 			/* link together */
170*36369Ssklower 			m_cat(frag_hdr, frag_data);
171*36369Ssklower 
172*36369Ssklower 			/* make sure segmentation fields are in network order */
173*36369Ssklower 			tmp_seg.cng_id = htons(seg_part.cng_id);
174*36369Ssklower 			tmp_seg.cng_off = htons(seg_part.cng_off);
175*36369Ssklower 			tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len);
176*36369Ssklower 
177*36369Ssklower 			/* insert segmentation part */
178*36369Ssklower 			bcopy((caddr_t)&tmp_seg, mtod(frag_hdr, caddr_t) + segoff,
179*36369Ssklower 				sizeof(struct clnp_segment));
180*36369Ssklower 
181*36369Ssklower 			{
182*36369Ssklower 				int	derived_len = clnp->cnf_hdr_len + frag_size;
183*36369Ssklower 				HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
184*36369Ssklower 			}
185*36369Ssklower 			/* compute clnp checksum (on header only) */
186*36369Ssklower 			if (flags & CLNP_NO_CKSUM) {
187*36369Ssklower 				HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
188*36369Ssklower 			} else {
189*36369Ssklower 				iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
190*36369Ssklower 			}
191*36369Ssklower 
192*36369Ssklower 			IFDEBUG(D_DUMPOUT)
193*36369Ssklower 				struct mbuf *mdump = frag_hdr;
194*36369Ssklower 				printf("clnp_fragment: sending dg:\n");
195*36369Ssklower /* 				dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
196*36369Ssklower 				while (mdump != NULL) {
197*36369Ssklower 					printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
198*36369Ssklower /*  					dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
199*36369Ssklower 					mdump = mdump->m_next;
200*36369Ssklower 				}
201*36369Ssklower 			ENDDEBUG
202*36369Ssklower 
203*36369Ssklower #ifdef	TROLL
204*36369Ssklower 			error = troll_output(ifp, frag_hdr, first_hop);
205*36369Ssklower #else
206*36369Ssklower 			error = (*ifp->if_output)(ifp, frag_hdr, first_hop);
207*36369Ssklower #endif	TROLL
208*36369Ssklower 
209*36369Ssklower 			/*
210*36369Ssklower 			 *	Tough situation: if the error occured on the last
211*36369Ssklower 			 *	fragment, we can not send an ER, as the if_output
212*36369Ssklower 			 *	routine consumed the packet. If the error occured
213*36369Ssklower 			 *	on any intermediate packets, we can send an ER
214*36369Ssklower 			 *	because we still have the original header in (m).
215*36369Ssklower 			 */
216*36369Ssklower 			if (error) {
217*36369Ssklower 				if (frag_hdr != hdr) {
218*36369Ssklower 					/*
219*36369Ssklower 					 *	The error was not on the last fragment. We must
220*36369Ssklower 					 *	free hdr and m before returning
221*36369Ssklower 					 */
222*36369Ssklower 					clnp_discard(m, GEN_NOREAS);
223*36369Ssklower 					m_freem(hdr);
224*36369Ssklower 				}
225*36369Ssklower 				return(error);
226*36369Ssklower 			}
227*36369Ssklower 
228*36369Ssklower 			/* bump segment offset, trim data mbuf, and decrement count left */
229*36369Ssklower #ifdef	TROLL
230*36369Ssklower 			/*
231*36369Ssklower 			 *	Decrement frag_size by some fraction. This will cause the
232*36369Ssklower 			 *	next fragment to start 'early', thus duplicating the end
233*36369Ssklower 			 *	of the current fragment.  troll.tr_dup_size controls
234*36369Ssklower 			 *	the fraction. If positive, it specifies the fraction. If
235*36369Ssklower 			 *	negative, a random fraction is used.
236*36369Ssklower 			 */
237*36369Ssklower 			if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
238*36369Ssklower 				int num_bytes = frag_size;
239*36369Ssklower 
240*36369Ssklower 				if (trollctl.tr_dup_size > 0)
241*36369Ssklower 					num_bytes *= trollctl.tr_dup_size;
242*36369Ssklower 				else
243*36369Ssklower 					num_bytes *= troll_random();
244*36369Ssklower 				frag_size -= num_bytes;
245*36369Ssklower 			}
246*36369Ssklower #endif	TROLL
247*36369Ssklower 			total_len -= frag_size;
248*36369Ssklower 			if (!last_frag) {
249*36369Ssklower 				seg_part.cng_off += frag_size;
250*36369Ssklower 				m_adj(m, frag_size);
251*36369Ssklower 			}
252*36369Ssklower 		}
253*36369Ssklower 		return(0);
254*36369Ssklower 	} else {
255*36369Ssklower 		clnp_discard(m, GEN_SEGNEEDED);
256*36369Ssklower 		return(EMSGSIZE);
257*36369Ssklower 	}
258*36369Ssklower }
259*36369Ssklower 
260*36369Ssklower /*
261*36369Ssklower  * FUNCTION:		clnp_reass
262*36369Ssklower  *
263*36369Ssklower  * PURPOSE:			Attempt to reassemble a clnp packet given the current
264*36369Ssklower  *					fragment. If reassembly succeeds (all the fragments
265*36369Ssklower  *					are present), then return a pointer to an mbuf chain
266*36369Ssklower  *					containing the reassembled packet. This packet will
267*36369Ssklower  *					appear in the mbufs as if it had just arrived in
268*36369Ssklower  *					one piece.
269*36369Ssklower  *
270*36369Ssklower  *					If reassembly fails, then save this fragment and
271*36369Ssklower  *					return 0.
272*36369Ssklower  *
273*36369Ssklower  * RETURNS:			Ptr to assembled packet, or 0
274*36369Ssklower  *
275*36369Ssklower  * SIDE EFFECTS:
276*36369Ssklower  *
277*36369Ssklower  * NOTES:
278*36369Ssklower  *		clnp_slowtimo can not affect this code because clnpintr, and thus
279*36369Ssklower  *		this code, is called at a higher priority than clnp_slowtimo.
280*36369Ssklower  */
281*36369Ssklower struct mbuf *
282*36369Ssklower clnp_reass(m, src, dst, seg)
283*36369Ssklower struct mbuf 		*m;		/* new fragment */
284*36369Ssklower struct iso_addr		*src;	/* src of new fragment */
285*36369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
286*36369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
287*36369Ssklower {
288*36369Ssklower 	register struct clnp_fragl		*cfh;
289*36369Ssklower 
290*36369Ssklower 	/* look for other fragments of this datagram */
291*36369Ssklower 	for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
292*36369Ssklower 		if (iso_addrmatch1(src, &cfh->cfl_src) &&
293*36369Ssklower 			iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) {
294*36369Ssklower 			IFDEBUG(D_REASS)
295*36369Ssklower 				printf("clnp_reass: found packet\n");
296*36369Ssklower 			ENDDEBUG
297*36369Ssklower 			/*
298*36369Ssklower 			 *	There are other fragments here already. Lets see if
299*36369Ssklower 			 *	this fragment is of any help
300*36369Ssklower 			 */
301*36369Ssklower 			clnp_insert_frag(cfh, m, seg);
302*36369Ssklower 			return (clnp_comp_pdu(cfh));
303*36369Ssklower 		}
304*36369Ssklower 	}
305*36369Ssklower 
306*36369Ssklower 	IFDEBUG(D_REASS)
307*36369Ssklower 		printf("clnp_reass: new packet!\n");
308*36369Ssklower 	ENDDEBUG
309*36369Ssklower 
310*36369Ssklower 	/*
311*36369Ssklower 	 *	This is the first fragment. If src is not consuming too many
312*36369Ssklower 	 *	resources, then create a new fragment list and add
313*36369Ssklower 	 *	this fragment to the list.
314*36369Ssklower 	 */
315*36369Ssklower 	/* TODO: don't let one src hog all the reassembly buffers */
316*36369Ssklower 	if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) {
317*36369Ssklower 		clnp_discard(m, GEN_CONGEST);
318*36369Ssklower 	}
319*36369Ssklower 
320*36369Ssklower 	return(NULL);
321*36369Ssklower }
322*36369Ssklower 
323*36369Ssklower /*
324*36369Ssklower  * FUNCTION:		clnp_newpkt
325*36369Ssklower  *
326*36369Ssklower  * PURPOSE:			Create the necessary structures to handle a new
327*36369Ssklower  *					fragmented clnp packet.
328*36369Ssklower  *
329*36369Ssklower  * RETURNS:			non-zero if it succeeds, zero if fails.
330*36369Ssklower  *
331*36369Ssklower  * SIDE EFFECTS:
332*36369Ssklower  *
333*36369Ssklower  * NOTES:			Failure is only due to insufficient resources.
334*36369Ssklower  */
335*36369Ssklower clnp_newpkt(m, src, dst, seg)
336*36369Ssklower struct mbuf 		*m;		/* new fragment */
337*36369Ssklower struct iso_addr		*src;	/* src of new fragment */
338*36369Ssklower struct iso_addr		*dst; 	/* dst of new fragment */
339*36369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
340*36369Ssklower {
341*36369Ssklower 	register struct clnp_fragl		*cfh;
342*36369Ssklower 	register struct clnp_fixed		*clnp;
343*36369Ssklower 	struct mbuf 					*m0;
344*36369Ssklower 
345*36369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
346*36369Ssklower 
347*36369Ssklower 	/*
348*36369Ssklower 	 *	Allocate new clnp fragl structure to act as header of all fragments
349*36369Ssklower 	 *	for this datagram.
350*36369Ssklower 	 */
351*36369Ssklower 	MGET(m0, M_DONTWAIT, MT_FTABLE);
352*36369Ssklower 	if (m0 == NULL) {
353*36369Ssklower 		return (0);
354*36369Ssklower 	}
355*36369Ssklower 	cfh = mtod(m0, struct clnp_fragl *);
356*36369Ssklower 
357*36369Ssklower 	/*
358*36369Ssklower 	 *	Duplicate the header of this fragment, and save in cfh.
359*36369Ssklower 	 *	Free m0 and return if m_copy does not succeed.
360*36369Ssklower 	 */
361*36369Ssklower 	if ((cfh->cfl_orighdr = m_copy(m, 0, clnp->cnf_hdr_len)) == NULL) {
362*36369Ssklower 		m_freem(m0);
363*36369Ssklower 		return (0);
364*36369Ssklower 	}
365*36369Ssklower 
366*36369Ssklower 	/* Fill in rest of fragl structure */
367*36369Ssklower 	bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr));
368*36369Ssklower 	bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr));
369*36369Ssklower 	cfh->cfl_id = seg->cng_id;
370*36369Ssklower 	cfh->cfl_ttl = clnp->cnf_ttl;
371*36369Ssklower 	cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
372*36369Ssklower 	cfh->cfl_frags = NULL;
373*36369Ssklower 	cfh->cfl_next = NULL;
374*36369Ssklower 
375*36369Ssklower 	/* Insert into list of packets */
376*36369Ssklower 	cfh->cfl_next = clnp_frags;
377*36369Ssklower 	clnp_frags = cfh;
378*36369Ssklower 
379*36369Ssklower 	/* Insert this fragment into list headed by cfh */
380*36369Ssklower 	clnp_insert_frag(cfh, m, seg);
381*36369Ssklower 	return(1);
382*36369Ssklower }
383*36369Ssklower 
384*36369Ssklower /*
385*36369Ssklower  * FUNCTION:		clnp_insert_frag
386*36369Ssklower  *
387*36369Ssklower  * PURPOSE:			Insert fragment into list headed by 'cf'.
388*36369Ssklower  *
389*36369Ssklower  * RETURNS:			nothing
390*36369Ssklower  *
391*36369Ssklower  * SIDE EFFECTS:
392*36369Ssklower  *
393*36369Ssklower  * NOTES:			This is the 'guts' of the reassembly algorithm.
394*36369Ssklower  *					Each fragment in this list contains a clnp_frag
395*36369Ssklower  *					structure followed by the data of the fragment.
396*36369Ssklower  *					The clnp_frag structure actually lies on top of
397*36369Ssklower  *					part of the old clnp header.
398*36369Ssklower  */
399*36369Ssklower clnp_insert_frag(cfh, m, seg)
400*36369Ssklower struct clnp_fragl	*cfh;	/* header of list of packet fragments */
401*36369Ssklower struct mbuf 		*m;		/* new fragment */
402*36369Ssklower struct clnp_segment	*seg;	/* segment part of fragment header */
403*36369Ssklower {
404*36369Ssklower 	register struct clnp_fixed	*clnp;	/* clnp hdr of fragment */
405*36369Ssklower 	register struct clnp_frag	*cf;	/* generic fragment ptr */
406*36369Ssklower 	register struct clnp_frag 	*cf_sub = NULL;	/* frag subsequent to new one */
407*36369Ssklower 	register struct clnp_frag 	*cf_prev = NULL; /* frag previous to new one */
408*36369Ssklower 	u_short						first;	/* offset of first byte of initial pdu*/
409*36369Ssklower 	u_short						last;	/* offset of last byte of initial pdu */
410*36369Ssklower 	u_short						fraglen;/* length of fragment */
411*36369Ssklower 
412*36369Ssklower 	clnp = mtod(m, struct clnp_fixed *);
413*36369Ssklower 	first = seg->cng_off;
414*36369Ssklower 	CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
415*36369Ssklower 	fraglen -= clnp->cnf_hdr_len;
416*36369Ssklower 	last = (first + fraglen) - 1;
417*36369Ssklower 
418*36369Ssklower 	IFDEBUG(D_REASS)
419*36369Ssklower 		printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n",
420*36369Ssklower 			first, last, fraglen);
421*36369Ssklower 		printf("clnp_insert_frag: current fragments:\n");
422*36369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
423*36369Ssklower 			printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last);
424*36369Ssklower 		}
425*36369Ssklower 	ENDDEBUG
426*36369Ssklower 
427*36369Ssklower 	if (cfh->cfl_frags != NULL) {
428*36369Ssklower 		/*
429*36369Ssklower 		 *	Find fragment which begins after the new one
430*36369Ssklower 		 */
431*36369Ssklower 		for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) {
432*36369Ssklower 			if (cf->cfr_first > first) {
433*36369Ssklower 				cf_sub = cf;
434*36369Ssklower 				break;
435*36369Ssklower 			}
436*36369Ssklower 		}
437*36369Ssklower 
438*36369Ssklower 		IFDEBUG(D_REASS)
439*36369Ssklower 			printf("clnp_insert_frag: Previous frag is ");
440*36369Ssklower 			if (cf_prev == NULL)
441*36369Ssklower 				printf("NULL\n");
442*36369Ssklower 			else
443*36369Ssklower 				printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last);
444*36369Ssklower 			printf("clnp_insert_frag: Subsequent frag is ");
445*36369Ssklower 			if (cf_sub == NULL)
446*36369Ssklower 				printf("NULL\n");
447*36369Ssklower 			else
448*36369Ssklower 				printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last);
449*36369Ssklower 		ENDDEBUG
450*36369Ssklower 
451*36369Ssklower 		/*
452*36369Ssklower 		 *	If there is a fragment before the new one, check if it
453*36369Ssklower 		 *	overlaps the new one. If so, then trim the end of the
454*36369Ssklower 		 *	previous one.
455*36369Ssklower 		 */
456*36369Ssklower 		if (cf_prev != NULL) {
457*36369Ssklower 			if (cf_prev->cfr_last > first) {
458*36369Ssklower 				u_short overlap = cf_prev->cfr_last - first;
459*36369Ssklower 
460*36369Ssklower 				IFDEBUG(D_REASS)
461*36369Ssklower 					printf("clnp_insert_frag: previous overlaps by %d\n",
462*36369Ssklower 						overlap);
463*36369Ssklower 				ENDDEBUG
464*36369Ssklower 
465*36369Ssklower 				if (overlap > fraglen) {
466*36369Ssklower 					/*
467*36369Ssklower 					 *	The new fragment is entirely contained in the
468*36369Ssklower 					 *	preceeding one. We can punt on the new frag
469*36369Ssklower 					 *	completely.
470*36369Ssklower 					 */
471*36369Ssklower 					m_freem(m);
472*36369Ssklower 					return;
473*36369Ssklower 				} else {
474*36369Ssklower 					/* Trim data off of end of previous fragment */
475*36369Ssklower 					/* inc overlap to prevent duplication of last byte */
476*36369Ssklower 					overlap++;
477*36369Ssklower 					m_adj(cf_prev->cfr_data, -overlap);
478*36369Ssklower 					cf_prev->cfr_last -= overlap;
479*36369Ssklower 				}
480*36369Ssklower 			}
481*36369Ssklower 		}
482*36369Ssklower 
483*36369Ssklower 		/*
484*36369Ssklower 		 *	For all fragments past the new one, check if any data on
485*36369Ssklower 		 *	the new one overlaps data on existing fragments. If so,
486*36369Ssklower 		 *	then trim the extra data off the end of the new one.
487*36369Ssklower 		 */
488*36369Ssklower 		for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
489*36369Ssklower 			if (cf->cfr_first < last) {
490*36369Ssklower 				u_short overlap = last - cf->cfr_first;
491*36369Ssklower 
492*36369Ssklower 				IFDEBUG(D_REASS)
493*36369Ssklower 					printf("clnp_insert_frag: subsequent overlaps by %d\n",
494*36369Ssklower 						overlap);
495*36369Ssklower 				ENDDEBUG
496*36369Ssklower 
497*36369Ssklower 				if (overlap > fraglen) {
498*36369Ssklower 					/*
499*36369Ssklower 					 *	The new fragment is entirely contained in the
500*36369Ssklower 					 *	succeeding one. This should not happen, because
501*36369Ssklower 					 *	early on in this code we scanned for the fragment
502*36369Ssklower 					 *	which started after the new one!
503*36369Ssklower 					 */
504*36369Ssklower 					m_freem(m);
505*36369Ssklower 					printf("clnp_insert_frag: internal error!\n");
506*36369Ssklower 					return;
507*36369Ssklower 				} else {
508*36369Ssklower 					/* Trim data off of end of new fragment */
509*36369Ssklower 					/* inc overlap to prevent duplication of last byte */
510*36369Ssklower 					overlap++;
511*36369Ssklower 					m_adj(m, -overlap);
512*36369Ssklower 					last -= overlap;
513*36369Ssklower 				}
514*36369Ssklower 			}
515*36369Ssklower 		}
516*36369Ssklower 	}
517*36369Ssklower 
518*36369Ssklower 	/*
519*36369Ssklower 	 *	Insert the new fragment beween cf_prev and cf_sub
520*36369Ssklower 	 *
521*36369Ssklower 	 *	Note: the clnp hdr is still in the mbuf.
522*36369Ssklower 	 *	If the data of the mbuf is not word aligned, shave off enough
523*36369Ssklower 	 *	so that it is. Then, cast the clnp_frag structure on top
524*36369Ssklower 	 *	of the clnp header.
525*36369Ssklower 	 *	The clnp_hdr will not be used again (as we already have
526*36369Ssklower 	 *	saved a copy of it).
527*36369Ssklower 	 *
528*36369Ssklower 	 *	Save in cfr_bytes the number of bytes to shave off to get to
529*36369Ssklower 	 *	the data of the packet. This is used when we coalesce fragments;
530*36369Ssklower 	 *	the clnp_frag structure must be removed before joining mbufs.
531*36369Ssklower 	 */
532*36369Ssklower 	{
533*36369Ssklower 		int	pad;
534*36369Ssklower 		u_int	bytes;
535*36369Ssklower 
536*36369Ssklower 		/* determine if header is not word aligned */
537*36369Ssklower 		pad = (int)clnp % 4;
538*36369Ssklower 		if (pad < 0)
539*36369Ssklower 			pad = -pad;
540*36369Ssklower 
541*36369Ssklower 		/* bytes is number of bytes left in front of data */
542*36369Ssklower 		bytes = clnp->cnf_hdr_len - pad;
543*36369Ssklower 
544*36369Ssklower 		/* make it word aligned if necessary */
545*36369Ssklower 		if (pad)
546*36369Ssklower 			m_adj(m, pad);
547*36369Ssklower 
548*36369Ssklower 		cf = mtod(m, struct clnp_frag *);
549*36369Ssklower 		cf->cfr_bytes = bytes;
550*36369Ssklower 	}
551*36369Ssklower 	cf->cfr_first = first;
552*36369Ssklower 	cf->cfr_last = last;
553*36369Ssklower 
554*36369Ssklower 
555*36369Ssklower 	/*
556*36369Ssklower 	 *	The data is the mbuf itself, although we must remember that the
557*36369Ssklower 	 *	first few bytes are actually a clnp_frag structure
558*36369Ssklower 	 */
559*36369Ssklower 	cf->cfr_data = m;
560*36369Ssklower 
561*36369Ssklower 	/* link into place */
562*36369Ssklower 	cf->cfr_next = cf_sub;
563*36369Ssklower 	if (cf_prev == NULL)
564*36369Ssklower 		cfh->cfl_frags = cf;
565*36369Ssklower 	else
566*36369Ssklower 		cf_prev->cfr_next = cf;
567*36369Ssklower }
568*36369Ssklower 
569*36369Ssklower /*
570*36369Ssklower  * FUNCTION:		clnp_comp_pdu
571*36369Ssklower  *
572*36369Ssklower  * PURPOSE:			Scan the list of fragments headed by cfh. Merge
573*36369Ssklower  *					any contigious fragments into one. If, after
574*36369Ssklower  *					traversing all the fragments, it is determined that
575*36369Ssklower  *					the packet is complete, then return a pointer to
576*36369Ssklower  *					the packet (with header prepended). Otherwise,
577*36369Ssklower  *					return NULL.
578*36369Ssklower  *
579*36369Ssklower  * RETURNS:			NULL, or a pointer to the assembled pdu in an mbuf chain.
580*36369Ssklower  *
581*36369Ssklower  * SIDE EFFECTS:	Will colapse contigious fragments into one.
582*36369Ssklower  *
583*36369Ssklower  * NOTES:			This code assumes that there are no overlaps of
584*36369Ssklower  *					fragment pdus.
585*36369Ssklower  */
586*36369Ssklower struct mbuf *
587*36369Ssklower clnp_comp_pdu(cfh)
588*36369Ssklower struct clnp_fragl	*cfh;		/* fragment header */
589*36369Ssklower {
590*36369Ssklower 	register struct clnp_frag	*cf = cfh->cfl_frags;
591*36369Ssklower 
592*36369Ssklower 	while (cf->cfr_next != NULL) {
593*36369Ssklower 		register struct clnp_frag	*cf_next = cf->cfr_next;
594*36369Ssklower 
595*36369Ssklower 		IFDEBUG(D_REASS)
596*36369Ssklower 			printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n",
597*36369Ssklower 				cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
598*36369Ssklower 				cf_next->cfr_last);
599*36369Ssklower 		ENDDEBUG
600*36369Ssklower 
601*36369Ssklower 		if (cf->cfr_last == (cf_next->cfr_first - 1)) {
602*36369Ssklower 			/*
603*36369Ssklower 			 *	Merge fragment cf and cf_next
604*36369Ssklower 			 *
605*36369Ssklower 			 *	- update cf header
606*36369Ssklower 			 *	- trim clnp_frag structure off of cf_next
607*36369Ssklower 			 *	- append cf_next to cf
608*36369Ssklower 			 */
609*36369Ssklower 			struct clnp_frag	cf_next_hdr;
610*36369Ssklower 			struct clnp_frag	*next_frag;
611*36369Ssklower 
612*36369Ssklower 			cf_next_hdr = *cf_next;
613*36369Ssklower 			next_frag = cf_next->cfr_next;
614*36369Ssklower 
615*36369Ssklower 			IFDEBUG(D_REASS)
616*36369Ssklower 				struct mbuf *mdump;
617*36369Ssklower 				printf("clnp_comp_pdu: merging fragments\n");
618*36369Ssklower 				printf("clnp_comp_pdu: 1st: [%d ... %d]\n", cf->cfr_first,
619*36369Ssklower 					cf->cfr_last);
620*36369Ssklower 				mdump = cf->cfr_data;
621*36369Ssklower 				while (mdump != NULL) {
622*36369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
623*36369Ssklower 					mdump = mdump->m_next;
624*36369Ssklower 				}
625*36369Ssklower 				printf("clnp_comp_pdu: 2nd: [%d ... %d]\n", cf_next->cfr_first,
626*36369Ssklower 					cf_next->cfr_last);
627*36369Ssklower 				mdump = cf_next->cfr_data;
628*36369Ssklower 				while (mdump != NULL) {
629*36369Ssklower 					printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
630*36369Ssklower 					mdump = mdump->m_next;
631*36369Ssklower 				}
632*36369Ssklower 			ENDDEBUG
633*36369Ssklower 
634*36369Ssklower 			cf->cfr_last = cf_next->cfr_last;
635*36369Ssklower 			/*
636*36369Ssklower 			 *	After this m_adj, the cf_next ptr is useless because we
637*36369Ssklower 			 *	have adjusted the clnp_frag structure away...
638*36369Ssklower 			 */
639*36369Ssklower 			m_adj(cf_next_hdr.cfr_data, cf_next_hdr.cfr_bytes);
640*36369Ssklower 			m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
641*36369Ssklower 			cf->cfr_next = next_frag;
642*36369Ssklower 		} else {
643*36369Ssklower 			cf = cf->cfr_next;
644*36369Ssklower 		}
645*36369Ssklower 	}
646*36369Ssklower 
647*36369Ssklower 	cf = cfh->cfl_frags;
648*36369Ssklower 
649*36369Ssklower 	IFDEBUG(D_REASS)
650*36369Ssklower 		struct mbuf *mdump = cf->cfr_data;
651*36369Ssklower 		printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first,
652*36369Ssklower 			cf->cfr_last);
653*36369Ssklower 		printf("clnp_comp_pdu: data for frag:\n");
654*36369Ssklower 		while (mdump != NULL) {
655*36369Ssklower 			printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
656*36369Ssklower /* 			dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
657*36369Ssklower 			mdump = mdump->m_next;
658*36369Ssklower 		}
659*36369Ssklower 	ENDDEBUG
660*36369Ssklower 
661*36369Ssklower 	/* Check if datagram is complete */
662*36369Ssklower 	if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
663*36369Ssklower 		/*
664*36369Ssklower 		 *	We have a complete pdu!
665*36369Ssklower 		 *	- Remove the frag header from (only) remaining fragment
666*36369Ssklower 		 *		(which is not really a fragment anymore, as the datagram is
667*36369Ssklower 		 *		complete).
668*36369Ssklower 		 *	- Prepend a clnp header
669*36369Ssklower 		 */
670*36369Ssklower 		struct mbuf	*data = cf->cfr_data;
671*36369Ssklower 		struct mbuf	*hdr = cfh->cfl_orighdr;
672*36369Ssklower 		struct clnp_fragl *scan;
673*36369Ssklower 
674*36369Ssklower 		IFDEBUG(D_REASS)
675*36369Ssklower 			printf("clnp_comp_pdu: complete pdu!\n");
676*36369Ssklower 		ENDDEBUG
677*36369Ssklower 
678*36369Ssklower 		m_adj(data, cf->cfr_bytes);
679*36369Ssklower 		m_cat(hdr, data);
680*36369Ssklower 
681*36369Ssklower 		IFDEBUG(D_DUMPIN)
682*36369Ssklower 			struct mbuf *mdump = hdr;
683*36369Ssklower 			printf("clnp_comp_pdu: pdu is:\n");
684*36369Ssklower 			while (mdump != NULL) {
685*36369Ssklower 				printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
686*36369Ssklower /* 				dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
687*36369Ssklower 				mdump = mdump->m_next;
688*36369Ssklower 			}
689*36369Ssklower 		ENDDEBUG
690*36369Ssklower 
691*36369Ssklower 		/*
692*36369Ssklower 		 *	Remove cfh from the list of fragmented pdus
693*36369Ssklower 		 */
694*36369Ssklower 		if (clnp_frags == cfh) {
695*36369Ssklower 			clnp_frags = cfh->cfl_next;
696*36369Ssklower 		} else {
697*36369Ssklower 			for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) {
698*36369Ssklower 				if (scan->cfl_next == cfh) {
699*36369Ssklower 					scan->cfl_next = cfh->cfl_next;
700*36369Ssklower 					break;
701*36369Ssklower 				}
702*36369Ssklower 			}
703*36369Ssklower 		}
704*36369Ssklower 
705*36369Ssklower 		/* free cfh */
706*36369Ssklower 		m_freem(dtom(cfh));
707*36369Ssklower 
708*36369Ssklower 		return(hdr);
709*36369Ssklower 	}
710*36369Ssklower 
711*36369Ssklower 	return(NULL);
712*36369Ssklower }
713*36369Ssklower #ifdef	TROLL
714*36369Ssklower #include "../h/time.h"
715*36369Ssklower /*
716*36369Ssklower  * FUNCTION:		troll_random
717*36369Ssklower  *
718*36369Ssklower  * PURPOSE:			generate a pseudo-random number between 0 and 1
719*36369Ssklower  *
720*36369Ssklower  * RETURNS:			the random number
721*36369Ssklower  *
722*36369Ssklower  * SIDE EFFECTS:
723*36369Ssklower  *
724*36369Ssklower  * NOTES:			This is based on the clock.
725*36369Ssklower  */
726*36369Ssklower float troll_random()
727*36369Ssklower {
728*36369Ssklower 	extern struct timeval time;
729*36369Ssklower 	long	t = time.tv_usec % 100;
730*36369Ssklower 
731*36369Ssklower 	return((float)t / (float) 100);
732*36369Ssklower }
733*36369Ssklower 
734*36369Ssklower /*
735*36369Ssklower  * FUNCTION:		troll_output
736*36369Ssklower  *
737*36369Ssklower  * PURPOSE:			Do something sneaky with the datagram passed. Possible
738*36369Ssklower  *					operations are:
739*36369Ssklower  *						Duplicate the packet
740*36369Ssklower  *						Drop the packet
741*36369Ssklower  *						Trim some number of bytes from the packet
742*36369Ssklower  *						Munge some byte in the packet
743*36369Ssklower  *
744*36369Ssklower  * RETURNS:			0, or unix error code
745*36369Ssklower  *
746*36369Ssklower  * SIDE EFFECTS:
747*36369Ssklower  *
748*36369Ssklower  * NOTES:			The operation of this procedure is regulated by the
749*36369Ssklower  *					troll control structure (Troll).
750*36369Ssklower  */
751*36369Ssklower troll_output(ifp, m, dst)
752*36369Ssklower struct ifnet	*ifp;
753*36369Ssklower struct mbuf		*m;
754*36369Ssklower struct sockaddr	*dst;
755*36369Ssklower {
756*36369Ssklower 	int	err = 0;
757*36369Ssklower 	troll_cnt++;
758*36369Ssklower 
759*36369Ssklower 	if (trollctl.tr_ops & TR_DUPPKT) {
760*36369Ssklower 		/*
761*36369Ssklower 		 *	Duplicate every Nth packet
762*36369Ssklower 		 *	TODO: random?
763*36369Ssklower 		 */
764*36369Ssklower 		float	f_freq = troll_cnt * trollctl.tr_dup_freq;
765*36369Ssklower 		int		i_freq = troll_cnt * trollctl.tr_dup_freq;
766*36369Ssklower 		if (i_freq == f_freq) {
767*36369Ssklower 			struct mbuf *dup = m_copy(m, 0, M_COPYALL);
768*36369Ssklower 			if (dup != NULL)
769*36369Ssklower 				err = (*ifp->if_output)(ifp, dup, dst);
770*36369Ssklower 		}
771*36369Ssklower 		if (!err)
772*36369Ssklower 			err = (*ifp->if_output)(ifp, m, dst);
773*36369Ssklower 		return(err);
774*36369Ssklower 	} else if (trollctl.tr_ops & TR_DROPPKT) {
775*36369Ssklower 	} else if (trollctl.tr_ops & TR_CHANGE) {
776*36369Ssklower 		struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
777*36369Ssklower 		clnp->cnf_cksum_msb = 0;
778*36369Ssklower 		err = (*ifp->if_output)(ifp, m, dst);
779*36369Ssklower 		return(err);
780*36369Ssklower 	} else {
781*36369Ssklower 		err = (*ifp->if_output)(ifp, m, dst);
782*36369Ssklower 		return(err);
783*36369Ssklower 	}
784*36369Ssklower }
785*36369Ssklower 
786*36369Ssklower #endif	TROLL
787*36369Ssklower #endif	ISO
788