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