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