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