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