No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netiso / clnp_frag.c
blob3102a7070a0c5d926a69ed526af34b66ce6c4f8a
1 /* $NetBSD: clnp_frag.c,v 1.24 2009/03/18 17:06:52 cegger Exp $ */
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
31 * @(#)clnp_frag.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
37 All Rights Reserved
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: clnp_frag.c,v 1.24 2009/03/18 17:06:52 cegger Exp $");
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>
73 #include <net/if.h>
74 #include <net/route.h>
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>
82 /* all fragments are hung off this list */
83 struct clnp_fragl *clnp_frags = NULL;
86 * FUNCTION: clnp_fragment
88 * PURPOSE: Fragment a datagram, and send the itty bitty pieces
89 * out over an interface.
91 * RETURNS: success - 0
92 * failure - unix error code
94 * SIDE EFFECTS:
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.
105 clnp_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 */
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;
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;
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);
135 * Duplicate header, and remove from packet
137 if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
138 clnp_discard(m, GEN_CONGEST);
139 return (ENOBUFS);
141 m_adj(m, hdr_len);
143 while (total_len > 0) {
144 int remaining, last_frag;
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;
158 printf("clnp_fragment: sum of mbuf chain %d:\n",
159 tot_mlen);
161 #endif
163 frag_size = min(total_len, frag_size);
164 if ((remaining = total_len - frag_size) == 0)
165 last_frag = 1;
166 else {
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.
173 last_frag = 0;
174 if (remaining < 8)
175 frag_size -= 8;
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");
189 #endif
191 if (last_frag) {
193 * this is the last fragment; we don't need
194 * to get any other mbufs.
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);
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);
213 INCSTAT(cns_fragments);
215 clnp = mtod(frag_hdr, struct clnp_fixed *);
217 if (!last_frag)
218 clnp->cnf_type |= CNF_MORE_SEGS;
220 /* link together */
221 m_cat(frag_hdr, frag_data);
223 /* insert segmentation part; updated below */
224 (void)memmove(mtod(frag_hdr, char *) + segoff,
225 &seg_part,
226 sizeof(struct clnp_segment));
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;
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);
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;
255 #endif
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 */
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).
270 if (error) {
271 if (frag_hdr != hdr) {
273 * The error was not on the last
274 * fragment. We must free hdr and m
275 * before returning
277 clnp_discard(hdr, GEN_NOREAS);
278 m_freem(m);
280 return (error);
283 * bump segment offset, trim data mbuf, and decrement
284 * count left
286 #ifdef TROLL
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.
295 if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
296 int num_bytes = frag_size;
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;
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);
312 return (0);
313 } else {
314 INCSTAT(cns_cantfrag);
315 clnp_discard(m, GEN_SEGNEEDED);
316 return (EMSGSIZE);
321 * FUNCTION: clnp_reass
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.
330 * If reassembly fails, then save this fragment and
331 * return 0.
333 * RETURNS: Ptr to assembled packet, or 0
335 * SIDE EFFECTS:
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.
341 struct mbuf *
342 clnp_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 */
348 struct clnp_fragl *cfh;
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");
359 #endif
361 * There are other fragments here already. Lets see if
362 * this fragment is of any help
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);
372 return (m);
376 #ifdef ARGO_DEBUG
377 if (argo_debug[D_REASS]) {
378 printf("clnp_reass: new packet!\n");
380 #endif
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.
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);
392 return (NULL);
396 * FUNCTION: clnp_newpkt
398 * PURPOSE: Create the necessary structures to handle a new
399 * fragmented clnp packet.
401 * RETURNS: non-zero if it succeeds, zero if fails.
403 * SIDE EFFECTS:
405 * NOTES: Failure is only due to insufficient resources.
408 clnp_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 */
414 struct clnp_fragl *cfh;
415 struct clnp_fixed *clnp;
417 clnp = mtod(m, struct clnp_fixed *);
420 * Allocate new clnp fragl structure to act as header of all
421 * fragments for this datagram.
423 cfh = malloc(sizeof (struct clnp_fragl), M_FTABLE, M_NOWAIT);
424 if (cfh == NULL) {
425 return (0);
429 * Duplicate the header of this fragment, and save in cfh. Free m0
430 * and return if m_copy does not succeed.
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);
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;
446 /* Insert into list of packets */
447 cfh->cfl_next = clnp_frags;
448 clnp_frags = cfh;
450 /* Insert this fragment into list headed by cfh */
451 clnp_insert_frag(cfh, m, seg);
452 return (1);
456 * FUNCTION: clnp_insert_frag
458 * PURPOSE: Insert fragment into list headed by 'cf'.
460 * RETURNS: nothing
462 * SIDE EFFECTS:
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.
470 void
471 clnp_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 */
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 */
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;
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);
501 #endif
503 if (cfh->cfl_frags != NULL) {
505 * Find fragment which begins after the new one
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;
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);
530 #endif
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.
537 if (cf_prev != NULL) {
538 if (cf_prev->cfr_last > first) {
539 u_short overlap = cf_prev->cfr_last - first;
541 #ifdef ARGO_DEBUG
542 if (argo_debug[D_REASS]) {
543 printf(
544 "clnp_insert_frag: previous overlaps by %d\n",
545 overlap);
547 #endif
549 if (overlap > fraglen) {
551 * The new fragment is entirely
552 * contained in the preceding one.
553 * We can punt on the new frag
554 * completely.
556 m_freem(m);
557 return;
558 } else {
560 * Trim data off of end of previous
561 * fragment
564 * inc overlap to prevent duplication
565 * of last byte
567 overlap++;
568 m_adj(cf_prev->cfr_data, -(int) overlap);
569 cf_prev->cfr_last -= overlap;
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.
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;
582 #ifdef ARGO_DEBUG
583 if (argo_debug[D_REASS]) {
584 printf(
585 "clnp_insert_frag: subsequent overlaps by %d\n",
586 overlap);
588 #endif
590 if (overlap > fraglen) {
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!
599 m_freem(m);
600 printf(
601 "clnp_insert_frag: internal error!\n");
602 return;
603 } else {
605 * Trim data off of end of new fragment
606 * inc overlap to prevent duplication
607 * of last byte
609 overlap++;
610 m_adj(m, -(int) overlap);
611 last -= overlap;
617 * Insert the new fragment beween cf_prev and cf_sub
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).
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.
631 int pad;
632 u_int bytes;
634 /* determine if header is not word aligned */
635 pad = (long) clnp % 4;
636 if (pad < 0)
637 pad = -pad;
639 /* bytes is number of bytes left in front of data */
640 bytes = clnp->cnf_hdr_len - pad;
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);
648 #endif
650 /* make it word aligned if necessary */
651 if (pad)
652 m_adj(m, pad);
654 cf = mtod(m, struct clnp_frag *);
655 cf->cfr_bytes = bytes;
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);
662 #endif
664 cf->cfr_first = first;
665 cf->cfr_last = last;
669 * The data is the mbuf itself, although we must remember that the
670 * first few bytes are actually a clnp_frag structure
672 cf->cfr_data = m;
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;
683 * FUNCTION: clnp_comp_pdu
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.
692 * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf
693 * chain.
695 * SIDE EFFECTS: Will colapse contigious fragments into one.
697 * NOTES: This code assumes that there are no overlaps of
698 * fragment pdus.
700 struct mbuf *
701 clnp_comp_pdu(
702 struct clnp_fragl *cfh) /* fragment header */
704 struct clnp_frag *cf = cfh->cfl_frags;
706 while (cf->cfr_next != NULL) {
707 struct clnp_frag *cf_next = cf->cfr_next;
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);
715 #endif
717 if (cf->cfr_last == (cf_next->cfr_first - 1)) {
719 * Merge fragment cf and cf_next
721 * - update cf header
722 * - trim clnp_frag structure off of cf_next
723 * - append cf_next to cf
725 struct clnp_frag cf_next_hdr;
726 struct clnp_frag *next_frag;
728 cf_next_hdr = *cf_next;
729 next_frag = cf_next->cfr_next;
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;
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;
761 printf("\ttotal len: %d\n", l);
763 #endif
765 cf->cfr_last = cf_next->cfr_last;
767 * After this m_adj, the cf_next ptr is useless
768 * because we have adjusted the clnp_frag structure
769 * away...
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);
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;
786 cf = cfh->cfl_frags;
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;
800 #endif
802 /* Check if datagram is complete */
803 if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
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
811 struct mbuf *data = cf->cfr_data;
812 struct mbuf *hdr = cfh->cfl_orighdr;
813 struct clnp_fragl *scan;
815 #ifdef ARGO_DEBUG
816 if (argo_debug[D_REASS]) {
817 printf("clnp_comp_pdu: complete pdu!\n");
819 #endif
821 m_adj(data, (int) cf->cfr_bytes);
822 m_cat(hdr, data);
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;
837 #endif
840 * Remove cfh from the list of fragmented pdus
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;
854 /* free cfh */
855 free(cfh, M_FTABLE);
857 return (hdr);
859 return (NULL);
861 #ifdef TROLL
862 static int troll_cnt;
863 #include <sys/time.h>
865 * FUNCTION: troll_random
867 * PURPOSE: generate a pseudo-random number between 0 and 1
869 * RETURNS: the random number
871 * SIDE EFFECTS:
873 * NOTES: This is based on the clock.
875 float
876 troll_random(void)
878 extern struct timeval time;
879 long t = time.tv_usec % 100;
881 return ((float) t / (float) 100);
885 * FUNCTION: troll_output
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
894 * RETURNS: 0, or unix error code
896 * SIDE EFFECTS:
898 * NOTES: The operation of this procedure is regulated by the
899 * troll control structure (Troll).
902 troll_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct rtentry *rt)
904 int err = 0;
905 troll_cnt++;
907 if (trollctl.tr_ops & TR_DUPPKT) {
909 * Duplicate every Nth packet
910 * TODO: random?
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);
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);
934 #endif /* TROLL */