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