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