1/*	$NetBSD: clnp_frag.c,v 1.24 2009/03/18 17:06:52 cegger Exp $	*/
2
3/*-
4 * Copyright (c) 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	@(#)clnp_frag.c	8.1 (Berkeley) 6/10/93
32 */
33
34/***********************************************************
35		Copyright IBM Corporation 1987
36
37                      All Rights Reserved
38
39Permission to use, copy, modify, and distribute this software and its
40documentation for any purpose and without fee is hereby granted,
41provided that the above copyright notice appear in all copies and that
42both that copyright notice and this permission notice appear in
43supporting documentation, and that the name of IBM not be
44used in advertising or publicity pertaining to distribution of the
45software without specific, written prior permission.
46
47IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53SOFTWARE.
54
55******************************************************************/
56
57/*
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
59 */
60
61#include <sys/cdefs.h>
62__KERNEL_RCSID(0, "$NetBSD: clnp_frag.c,v 1.24 2009/03/18 17:06:52 cegger Exp $");
63
64#include <sys/param.h>
65#include <sys/systm.h>
66#include <sys/mbuf.h>
67#include <sys/domain.h>
68#include <sys/protosw.h>
69#include <sys/socket.h>
70#include <sys/socketvar.h>
71#include <sys/errno.h>
72
73#include <net/if.h>
74#include <net/route.h>
75
76#include <netiso/iso.h>
77#include <netiso/iso_var.h>
78#include <netiso/clnp.h>
79#include <netiso/clnp_stat.h>
80#include <netiso/argo_debug.h>
81
82/* all fragments are hung off this list */
83struct clnp_fragl *clnp_frags = NULL;
84
85/*
86 * FUNCTION:		clnp_fragment
87 *
88 * PURPOSE:		Fragment a datagram, and send the itty bitty pieces
89 *			out over an interface.
90 *
91 * RETURNS:		success - 0
92 *			failure - unix error code
93 *
94 * SIDE EFFECTS:
95 *
96 * NOTES:		If there is an error sending the packet, clnp_discard
97 *			is called to discard the packet and send an ER. If
98 *			clnp_fragment was called from clnp_output, then
99 *			we generated the packet, and should not send an
100 *			ER -- clnp_emit_er will check for this. Otherwise,
101 *			the packet was fragmented during forwarding. In this
102 *			case, we ought to send an ER back.
103 */
104int
105clnp_fragment(
106	struct ifnet   *ifp,	/* ptr to outgoing interface */
107	struct mbuf    *m,	/* ptr to packet */
108	const struct sockaddr *first_hop,	/* ptr to first hop */
109	int             total_len,	/* length of datagram */
110	int             segoff,	/* offset of segpart in hdr */
111	int             flags,	/* flags passed to clnp_output */
112	struct rtentry *rt)	/* route if direct ether */
113{
114	struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
115	int             hdr_len = (int) clnp->cnf_hdr_len;
116	int             frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7;
117
118	total_len -= hdr_len;
119	if ((clnp->cnf_type & CNF_SEG_OK) &&
120	    (total_len >= 8) &&
121	    (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) {
122		struct mbuf    *hdr = NULL;	/* save copy of clnp hdr */
123		struct mbuf    *frag_hdr = NULL;
124		struct mbuf    *frag_data = NULL;
125		struct clnp_segment seg_part;	/* segmentation header */
126		int             frag_base;
127		int             error = 0;
128
129
130		INCSTAT(cns_fragmented);
131		(void)memmove(&seg_part, segoff + mtod(m, char *),
132		    sizeof(seg_part));
133		frag_base = ntohs(seg_part.cng_off);
134		/*
135		 *	Duplicate header, and remove from packet
136		 */
137		if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
138			clnp_discard(m, GEN_CONGEST);
139			return (ENOBUFS);
140		}
141		m_adj(m, hdr_len);
142
143		while (total_len > 0) {
144			int             remaining, last_frag;
145
146#ifdef ARGO_DEBUG
147			if (argo_debug[D_FRAG]) {
148				struct mbuf    *mdump = frag_hdr;
149				int             tot_mlen = 0;
150				printf("clnp_fragment: total_len %d:\n",
151				    total_len);
152				while (mdump != NULL) {
153					printf("\tmbuf %p, m_len %d\n",
154					    mdump, mdump->m_len);
155					tot_mlen += mdump->m_len;
156					mdump = mdump->m_next;
157				}
158				printf("clnp_fragment: sum of mbuf chain %d:\n",
159				    tot_mlen);
160			}
161#endif
162
163			frag_size = min(total_len, frag_size);
164			if ((remaining = total_len - frag_size) == 0)
165				last_frag = 1;
166			else {
167				/*
168				 * If this fragment will cause the last one to
169				 * be less than 8 bytes, shorten this fragment
170				 * a bit. The obscure test on frag_size above
171				 * ensures that frag_size will be positive.
172				 */
173				last_frag = 0;
174				if (remaining < 8)
175					frag_size -= 8;
176			}
177
178
179#ifdef ARGO_DEBUG
180			if (argo_debug[D_FRAG]) {
181				printf(
182				    "clnp_fragment: seg off %d, size %d, rem %d\n",
183				    ntohs(seg_part.cng_off), frag_size,
184				       total_len - frag_size);
185				if (last_frag)
186					printf(
187					  "clnp_fragment: last fragment\n");
188			}
189#endif
190
191			if (last_frag) {
192				/*
193				 * this is the last fragment; we don't need
194				 * to get any other mbufs.
195				 */
196				frag_hdr = hdr;
197				frag_data = m;
198			} else {
199				/* duplicate header and data mbufs */
200				frag_hdr = m_copy(hdr, 0, (int) M_COPYALL);
201				if (frag_hdr == NULL) {
202					clnp_discard(hdr, GEN_CONGEST);
203					m_freem(m);
204					return (ENOBUFS);
205				}
206				frag_data = m_copy(m, 0, frag_size);
207				if (frag_data == NULL) {
208					clnp_discard(hdr, GEN_CONGEST);
209					m_freem(m);
210					m_freem(frag_hdr);
211					return (ENOBUFS);
212				}
213				INCSTAT(cns_fragments);
214			}
215			clnp = mtod(frag_hdr, struct clnp_fixed *);
216
217			if (!last_frag)
218				clnp->cnf_type |= CNF_MORE_SEGS;
219
220			/* link together */
221			m_cat(frag_hdr, frag_data);
222
223			/* insert segmentation part; updated below */
224			(void)memmove(mtod(frag_hdr, char *) + segoff,
225			    &seg_part,
226			    sizeof(struct clnp_segment));
227
228			{
229				int             derived_len = hdr_len + frag_size;
230				HTOC(clnp->cnf_seglen_msb,
231				     clnp->cnf_seglen_lsb, derived_len);
232				if ((frag_hdr->m_flags & M_PKTHDR) == 0)
233					panic("clnp_frag:lost header");
234				frag_hdr->m_pkthdr.len = derived_len;
235			}
236
237			/* compute clnp checksum (on header only) */
238			if (flags & CLNP_NO_CKSUM) {
239				HTOC(clnp->cnf_cksum_msb,
240				     clnp->cnf_cksum_lsb, 0);
241			} else {
242				iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len);
243			}
244
245#ifdef ARGO_DEBUG
246			if (argo_debug[D_DUMPOUT]) {
247				struct mbuf    *mdump = frag_hdr;
248				printf("clnp_fragment: sending dg:\n");
249				while (mdump != NULL) {
250					printf("\tmbuf %p, m_len %d\n",
251					    mdump, mdump->m_len);
252					mdump = mdump->m_next;
253				}
254			}
255#endif
256
257#ifdef	TROLL
258			error = troll_output(ifp, frag_hdr, first_hop, rt);
259#else
260			error = (*ifp->if_output) (ifp, frag_hdr, first_hop, rt);
261#endif				/* TROLL */
262
263			/*
264			 * Tough situation: if the error occurred on the last
265			 * fragment, we can not send an ER, as the if_output
266			 * routine consumed the packet. If the error occurred
267			 * on any intermediate packets, we can send an ER
268			 * because we still have the original header in (m).
269			 */
270			if (error) {
271				if (frag_hdr != hdr) {
272					/*
273					 * The error was not on the last
274					 * fragment. We must free hdr and m
275					 * before returning
276					 */
277					clnp_discard(hdr, GEN_NOREAS);
278					m_freem(m);
279				}
280				return (error);
281			}
282			/*
283			 * bump segment offset, trim data mbuf, and decrement
284			 * count left
285			 */
286#ifdef	TROLL
287			/*
288			 * Decrement frag_size by some fraction. This will
289			 * cause the next fragment to start 'early', thus
290			 * duplicating the end of the current fragment.
291			 * troll.tr_dup_size controls the fraction. If
292			 * positive, it specifies the fraction. If
293			 * negative, a random fraction is used.
294			 */
295			if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
296				int             num_bytes = frag_size;
297
298				if (trollctl.tr_dup_size > 0)
299					num_bytes *= trollctl.tr_dup_size;
300				else
301					num_bytes *= troll_random();
302				frag_size -= num_bytes;
303			}
304#endif				/* TROLL */
305			total_len -= frag_size;
306			if (!last_frag) {
307				frag_base += frag_size;
308				seg_part.cng_off = htons(frag_base);
309				m_adj(m, frag_size);
310			}
311		}
312		return (0);
313	} else {
314		INCSTAT(cns_cantfrag);
315		clnp_discard(m, GEN_SEGNEEDED);
316		return (EMSGSIZE);
317	}
318}
319
320/*
321 * FUNCTION:		clnp_reass
322 *
323 * PURPOSE:		Attempt to reassemble a clnp packet given the current
324 *			fragment. If reassembly succeeds (all the fragments
325 *			are present), then return a pointer to an mbuf chain
326 *			containing the reassembled packet. This packet will
327 *			appear in the mbufs as if it had just arrived in
328 *			one piece.
329 *
330 *			If reassembly fails, then save this fragment and
331 *			return 0.
332 *
333 * RETURNS:		Ptr to assembled packet, or 0
334 *
335 * SIDE EFFECTS:
336 *
337 * NOTES: 		clnp_slowtimo can not affect this code because
338 *			clnpintr, and thus this code, is called at a higher
339 *			priority than clnp_slowtimo.
340 */
341struct mbuf    *
342clnp_reass(
343	struct mbuf    *m,	/* new fragment */
344	struct iso_addr *src,	/* src of new fragment */
345	struct iso_addr *dst,	/* dst of new fragment */
346	struct clnp_segment *seg)	/* segment part of fragment header */
347{
348	struct clnp_fragl *cfh;
349
350	/* look for other fragments of this datagram */
351	for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
352		if (seg->cng_id == cfh->cfl_id &&
353		    iso_addrmatch1(src, &cfh->cfl_src) &&
354		    iso_addrmatch1(dst, &cfh->cfl_dst)) {
355#ifdef ARGO_DEBUG
356			if (argo_debug[D_REASS]) {
357				printf("clnp_reass: found packet\n");
358			}
359#endif
360			/*
361			 * There are other fragments here already. Lets see if
362			 * this fragment is of any help
363			 */
364			clnp_insert_frag(cfh, m, seg);
365			if ((m = clnp_comp_pdu(cfh)) != NULL) {
366				struct clnp_fixed *clnp =
367				mtod(m, struct clnp_fixed *);
368				HTOC(clnp->cnf_seglen_msb,
369				     clnp->cnf_seglen_lsb,
370				     seg->cng_tot_len);
371			}
372			return (m);
373		}
374	}
375
376#ifdef ARGO_DEBUG
377	if (argo_debug[D_REASS]) {
378		printf("clnp_reass: new packet!\n");
379	}
380#endif
381
382	/*
383	 * This is the first fragment. If src is not consuming too many
384	 * resources, then create a new fragment list and add
385	 * this fragment to the list.
386	 */
387	/* TODO: don't let one src hog all the reassembly buffers */
388	if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */ ) {
389		INCSTAT(cns_fragdropped);
390		clnp_discard(m, GEN_CONGEST);
391	}
392	return (NULL);
393}
394
395/*
396 * FUNCTION:		clnp_newpkt
397 *
398 * PURPOSE:		Create the necessary structures to handle a new
399 *			fragmented clnp packet.
400 *
401 * RETURNS:		non-zero if it succeeds, zero if fails.
402 *
403 * SIDE EFFECTS:
404 *
405 * NOTES:		Failure is only due to insufficient resources.
406 */
407int
408clnp_newpkt(
409	struct mbuf *m,		/* new fragment */
410	struct iso_addr *src,	/* src of new fragment */
411	struct iso_addr *dst,	/* dst of new fragment */
412	struct clnp_segment *seg)	/* segment part of fragment header */
413{
414	struct clnp_fragl *cfh;
415	struct clnp_fixed *clnp;
416
417	clnp = mtod(m, struct clnp_fixed *);
418
419	/*
420	 * Allocate new clnp fragl structure to act as header of all
421	 * fragments for this datagram.
422	 */
423	cfh = malloc(sizeof (struct clnp_fragl), M_FTABLE, M_NOWAIT);
424	if (cfh == NULL) {
425		return (0);
426	}
427
428	/*
429	 * Duplicate the header of this fragment, and save in cfh. Free m0
430	 * and return if m_copy does not succeed.
431	 */
432	cfh->cfl_orighdr = m_copy(m, 0, (int) clnp->cnf_hdr_len);
433	if (cfh->cfl_orighdr == NULL) {
434		free(cfh, M_FTABLE);
435		return (0);
436	}
437	/* Fill in rest of fragl structure */
438	memcpy((void *) & cfh->cfl_src, (void *) src, sizeof(struct iso_addr));
439	memcpy((void *) & cfh->cfl_dst, (void *) dst, sizeof(struct iso_addr));
440	cfh->cfl_id = seg->cng_id;
441	cfh->cfl_ttl = clnp->cnf_ttl;
442	cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
443	cfh->cfl_frags = NULL;
444	cfh->cfl_next = NULL;
445
446	/* Insert into list of packets */
447	cfh->cfl_next = clnp_frags;
448	clnp_frags = cfh;
449
450	/* Insert this fragment into list headed by cfh */
451	clnp_insert_frag(cfh, m, seg);
452	return (1);
453}
454
455/*
456 * FUNCTION:		clnp_insert_frag
457 *
458 * PURPOSE:		Insert fragment into list headed by 'cf'.
459 *
460 * RETURNS:		nothing
461 *
462 * SIDE EFFECTS:
463 *
464 * NOTES:		This is the 'guts' of the reassembly algorithm.
465 *			Each fragment in this list contains a clnp_frag
466 *			structure followed by the data of the fragment.
467 *			The clnp_frag structure actually lies on top of
468 *			part of the old clnp header.
469 */
470void
471clnp_insert_frag(
472	struct clnp_fragl *cfh,	/* header of list of packet fragments */
473	struct mbuf *m,		/* new fragment */
474	struct clnp_segment *seg)	/* segment part of fragment header */
475{
476	struct clnp_fixed *clnp;		/* clnp hdr of fragment */
477	struct clnp_frag *cf;			/* generic fragment ptr */
478	struct clnp_frag *cf_sub = NULL;	/* frag subseq to new
479							 * one */
480	struct clnp_frag *cf_prev = NULL;	/* frag prev to new one */
481	u_short         first;	/* offset of first byte of initial pdu */
482	u_short         last;	/* offset of last byte of initial pdu */
483	u_short         fraglen;/* length of fragment */
484
485	clnp = mtod(m, struct clnp_fixed *);
486	first = seg->cng_off;
487	CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
488	fraglen -= clnp->cnf_hdr_len;
489	last = (first + fraglen) - 1;
490
491#ifdef ARGO_DEBUG
492	if (argo_debug[D_REASS]) {
493		printf("clnp_insert_frag: New fragment: [%d-%d], len %d\n",
494		    first, last, fraglen);
495		printf("clnp_insert_frag: current fragments:\n");
496		for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
497			printf("\tcf %p: [%d-%d]\n",
498			    cf, cf->cfr_first, cf->cfr_last);
499		}
500	}
501#endif
502
503	if (cfh->cfl_frags != NULL) {
504		/*
505		 * Find fragment which begins after the new one
506		 */
507		for (cf = cfh->cfl_frags; cf != NULL;
508		     cf_prev = cf, cf = cf->cfr_next) {
509			if (cf->cfr_first > first) {
510				cf_sub = cf;
511				break;
512			}
513		}
514
515#ifdef ARGO_DEBUG
516		if (argo_debug[D_REASS]) {
517			printf("clnp_insert_frag: Previous frag is ");
518			if (cf_prev == NULL)
519				printf("NULL\n");
520			else
521				printf("[%d-%d]\n", cf_prev->cfr_first,
522				    cf_prev->cfr_last);
523			printf("clnp_insert_frag: Subsequent frag is ");
524			if (cf_sub == NULL)
525				printf("NULL\n");
526			else
527				printf("[%d-%d]\n", cf_sub->cfr_first,
528				    cf_sub->cfr_last);
529		}
530#endif
531
532		/*
533		 * If there is a fragment before the new one, check if it
534		 * overlaps the new one. If so, then trim the end of the
535		 * previous one.
536		 */
537		if (cf_prev != NULL) {
538			if (cf_prev->cfr_last > first) {
539				u_short         overlap = cf_prev->cfr_last - first;
540
541#ifdef ARGO_DEBUG
542				if (argo_debug[D_REASS]) {
543					printf(
544					    "clnp_insert_frag: previous overlaps by %d\n",
545					    overlap);
546				}
547#endif
548
549				if (overlap > fraglen) {
550					/*
551					 * The new fragment is entirely
552					 * contained in the preceding one.
553					 * We can punt on the new frag
554					 * completely.
555					 */
556					m_freem(m);
557					return;
558				} else {
559					/*
560					 * Trim data off of end of previous
561					 * fragment
562					 */
563					/*
564					 * inc overlap to prevent duplication
565					 * of last byte
566					 */
567					overlap++;
568					m_adj(cf_prev->cfr_data, -(int) overlap);
569					cf_prev->cfr_last -= overlap;
570				}
571			}
572		}
573		/*
574		 *	For all fragments past the new one, check if any data on
575		 *	the new one overlaps data on existing fragments. If so,
576		 *	then trim the extra data off the end of the new one.
577		 */
578		for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
579			if (cf->cfr_first < last) {
580				u_short         overlap = last - cf->cfr_first;
581
582#ifdef ARGO_DEBUG
583				if (argo_debug[D_REASS]) {
584					printf(
585					    "clnp_insert_frag: subsequent overlaps by %d\n",
586					    overlap);
587				}
588#endif
589
590				if (overlap > fraglen) {
591					/*
592					 * The new fragment is entirely
593					 * contained in the succeeding one.
594					 * This should not happen, because
595					 * early on in this code we scanned
596					 * for the fragment which started
597					 * after the new one!
598					 */
599					m_freem(m);
600					printf(
601					    "clnp_insert_frag: internal error!\n");
602					return;
603				} else {
604					/*
605					 * Trim data off of end of new fragment
606					 * inc overlap to prevent duplication
607					 * of last byte
608					 */
609					overlap++;
610					m_adj(m, -(int) overlap);
611					last -= overlap;
612				}
613			}
614		}
615	}
616	/*
617	 * Insert the new fragment beween cf_prev and cf_sub
618	 *
619	 * Note: the clnp hdr is still in the mbuf.
620	 * If the data of the mbuf is not word aligned, shave off enough
621	 * so that it is. Then, cast the clnp_frag structure on top
622	 * of the clnp header.
623	 * The clnp_hdr will not be used again (as we already have
624	 * saved a copy of it).
625	 *
626	 * Save in cfr_bytes the number of bytes to shave off to get to
627	 * the data of the packet. This is used when we coalesce fragments;
628	 * the clnp_frag structure must be removed before joining mbufs.
629	 */
630	{
631		int             pad;
632		u_int           bytes;
633
634		/* determine if header is not word aligned */
635		pad = (long) clnp % 4;
636		if (pad < 0)
637			pad = -pad;
638
639		/* bytes is number of bytes left in front of data */
640		bytes = clnp->cnf_hdr_len - pad;
641
642#ifdef ARGO_DEBUG
643		if (argo_debug[D_REASS]) {
644			printf(
645			"clnp_insert_frag: clnp %p requires %d alignment\n",
646			       clnp, pad);
647		}
648#endif
649
650		/* make it word aligned if necessary */
651		if (pad)
652			m_adj(m, pad);
653
654		cf = mtod(m, struct clnp_frag *);
655		cf->cfr_bytes = bytes;
656
657#ifdef ARGO_DEBUG
658		if (argo_debug[D_REASS]) {
659			printf("clnp_insert_frag: cf now %p, cfr_bytes %d\n",
660			       cf, cf->cfr_bytes);
661		}
662#endif
663	}
664	cf->cfr_first = first;
665	cf->cfr_last = last;
666
667
668	/*
669	 * The data is the mbuf itself, although we must remember that the
670	 * first few bytes are actually a clnp_frag structure
671	 */
672	cf->cfr_data = m;
673
674	/* link into place */
675	cf->cfr_next = cf_sub;
676	if (cf_prev == NULL)
677		cfh->cfl_frags = cf;
678	else
679		cf_prev->cfr_next = cf;
680}
681
682/*
683 * FUNCTION:		clnp_comp_pdu
684 *
685 * PURPOSE:		Scan the list of fragments headed by cfh. Merge
686 *			any contigious fragments into one. If, after
687 *			traversing all the fragments, it is determined that
688 *			the packet is complete, then return a pointer to
689 *			the packet (with header prepended). Otherwise,
690 *			return NULL.
691 *
692 * RETURNS:		NULL, or a pointer to the assembled pdu in an mbuf
693 *			chain.
694 *
695 * SIDE EFFECTS:	Will colapse contigious fragments into one.
696 *
697 * NOTES:		This code assumes that there are no overlaps of
698 *			fragment pdus.
699 */
700struct mbuf    *
701clnp_comp_pdu(
702	struct clnp_fragl *cfh)	/* fragment header */
703{
704	struct clnp_frag *cf = cfh->cfl_frags;
705
706	while (cf->cfr_next != NULL) {
707		struct clnp_frag *cf_next = cf->cfr_next;
708
709#ifdef ARGO_DEBUG
710		if (argo_debug[D_REASS]) {
711			printf("clnp_comp_pdu: comparing: [%d-%d] to [%d-%d]\n",
712			    cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
713			    cf_next->cfr_last);
714		}
715#endif
716
717		if (cf->cfr_last == (cf_next->cfr_first - 1)) {
718			/*
719			 * Merge fragment cf and cf_next
720			 *
721			 * - update cf header
722			 * - trim clnp_frag structure off of cf_next
723			 * - append cf_next to cf
724			 */
725			struct clnp_frag cf_next_hdr;
726			struct clnp_frag *next_frag;
727
728			cf_next_hdr = *cf_next;
729			next_frag = cf_next->cfr_next;
730
731#ifdef ARGO_DEBUG
732			if (argo_debug[D_REASS]) {
733				struct mbuf    *mdump;
734				int             l;
735				printf("clnp_comp_pdu: merging fragments\n");
736				printf(
737				    "clnp_comp_pdu: 1st: [%d-%d] (bytes %d)\n",
738				    cf->cfr_first, cf->cfr_last,
739				    cf->cfr_bytes);
740				mdump = cf->cfr_data;
741				l = 0;
742				while (mdump != NULL) {
743					printf("\tmbuf %p, m_len %d\n",
744					    mdump, mdump->m_len);
745					l += mdump->m_len;
746					mdump = mdump->m_next;
747				}
748				printf("\ttotal len: %d\n", l);
749				printf(
750				    "clnp_comp_pdu: 2nd: [%d-%d] (bytes %d)\n",
751				    cf_next->cfr_first, cf_next->cfr_last,
752				       cf_next->cfr_bytes);
753				mdump = cf_next->cfr_data;
754				l = 0;
755				while (mdump != NULL) {
756					printf("\tmbuf %p, m_len %d\n",
757					       mdump, mdump->m_len);
758					l += mdump->m_len;
759					mdump = mdump->m_next;
760				}
761				printf("\ttotal len: %d\n", l);
762			}
763#endif
764
765			cf->cfr_last = cf_next->cfr_last;
766			/*
767			 * After this m_adj, the cf_next ptr is useless
768			 * because we have adjusted the clnp_frag structure
769			 * away...
770			 */
771#ifdef ARGO_DEBUG
772			if (argo_debug[D_REASS]) {
773				printf("clnp_comp_pdu: shaving off %d bytes\n",
774				       cf_next_hdr.cfr_bytes);
775			}
776#endif
777			m_adj(cf_next_hdr.cfr_data,
778			      (int) cf_next_hdr.cfr_bytes);
779			m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
780			cf->cfr_next = next_frag;
781		} else {
782			cf = cf->cfr_next;
783		}
784	}
785
786	cf = cfh->cfl_frags;
787
788#ifdef ARGO_DEBUG
789	if (argo_debug[D_REASS]) {
790		struct mbuf    *mdump = cf->cfr_data;
791		printf("clnp_comp_pdu: first frag now: [%d-%d]\n",
792		    cf->cfr_first, cf->cfr_last);
793		printf("clnp_comp_pdu: data for frag:\n");
794		while (mdump != NULL) {
795			printf("mbuf %p, m_len %d\n", mdump, mdump->m_len);
796			/* dump_buf(mtod(mdump, void *), mdump->m_len); */
797			mdump = mdump->m_next;
798		}
799	}
800#endif
801
802	/* Check if datagram is complete */
803	if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
804		/*
805		 * We have a complete pdu!
806		 * - Remove the frag header from (only) remaining fragment
807		 *   (which is not really a fragment anymore, as the datagram
808		 *    is complete).
809		 * - Prepend a clnp header
810		 */
811		struct mbuf    *data = cf->cfr_data;
812		struct mbuf    *hdr = cfh->cfl_orighdr;
813		struct clnp_fragl *scan;
814
815#ifdef ARGO_DEBUG
816		if (argo_debug[D_REASS]) {
817			printf("clnp_comp_pdu: complete pdu!\n");
818		}
819#endif
820
821		m_adj(data, (int) cf->cfr_bytes);
822		m_cat(hdr, data);
823
824#ifdef ARGO_DEBUG
825		if (argo_debug[D_DUMPIN]) {
826			struct mbuf    *mdump = hdr;
827			printf("clnp_comp_pdu: pdu is:\n");
828			while (mdump != NULL) {
829				printf("mbuf %p, m_len %d\n",
830				       mdump, mdump->m_len);
831#if 0
832				dump_buf(mtod(mdump, void *), mdump->m_len);
833#endif
834				mdump = mdump->m_next;
835			}
836		}
837#endif
838
839		/*
840		 * Remove cfh from the list of fragmented pdus
841		 */
842		if (clnp_frags == cfh) {
843			clnp_frags = cfh->cfl_next;
844		} else {
845			for (scan = clnp_frags; scan != NULL;
846			     scan = scan->cfl_next) {
847				if (scan->cfl_next == cfh) {
848					scan->cfl_next = cfh->cfl_next;
849					break;
850				}
851			}
852		}
853
854		/* free cfh */
855		free(cfh, M_FTABLE);
856
857		return (hdr);
858	}
859	return (NULL);
860}
861#ifdef	TROLL
862static int      troll_cnt;
863#include <sys/time.h>
864/*
865 * FUNCTION:		troll_random
866 *
867 * PURPOSE:		generate a pseudo-random number between 0 and 1
868 *
869 * RETURNS:		the random number
870 *
871 * SIDE EFFECTS:
872 *
873 * NOTES:		This is based on the clock.
874 */
875float
876troll_random(void)
877{
878	extern struct timeval time;
879	long            t = time.tv_usec % 100;
880
881	return ((float) t / (float) 100);
882}
883
884/*
885 * FUNCTION:		troll_output
886 *
887 * PURPOSE:		Do something sneaky with the datagram passed. Possible
888 *			operations are:
889 *				Duplicate the packet
890 *				Drop the packet
891 *				Trim some number of bytes from the packet
892 *				Munge some byte in the packet
893 *
894 * RETURNS:		0, or unix error code
895 *
896 * SIDE EFFECTS:
897 *
898 * NOTES:		The operation of this procedure is regulated by the
899 *			troll control structure (Troll).
900 */
901int
902troll_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct rtentry *rt)
903{
904	int             err = 0;
905	troll_cnt++;
906
907	if (trollctl.tr_ops & TR_DUPPKT) {
908		/*
909		 *	Duplicate every Nth packet
910		 *	TODO: random?
911		 */
912		float           f_freq = troll_cnt * trollctl.tr_dup_freq;
913		int             i_freq = troll_cnt * trollctl.tr_dup_freq;
914		if (i_freq == f_freq) {
915			struct mbuf    *dup = m_copy(m, 0, (int) M_COPYALL);
916			if (dup != NULL)
917				err = (*ifp->if_output) (ifp, dup, dst, rt);
918		}
919		if (!err)
920			err = (*ifp->if_output) (ifp, m, dst, rt);
921		return (err);
922	} else if (trollctl.tr_ops & TR_DROPPKT) {
923	} else if (trollctl.tr_ops & TR_CHANGE) {
924		struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
925		clnp->cnf_cksum_msb = 0;
926		err = (*ifp->if_output) (ifp, m, dst, rt);
927		return (err);
928	} else {
929		err = (*ifp->if_output) (ifp, m, dst, rt);
930		return (err);
931	}
932}
933
934#endif				/* TROLL */
935