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