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