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