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