1 /* $NetBSD: clnp_frag.c,v 1.18 2005/12/11 12:25:12 christos 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
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.
46
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.
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.18 2005/12/11 12:25:12 christos 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 */
83 struct 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 */
104 int
105 clnp_fragment(
106 struct ifnet *ifp, /* ptr to outgoing interface */
107 struct mbuf *m, /* ptr to packet */
108 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) bcopy(segoff + mtod(m, caddr_t), (caddr_t) & seg_part,
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 bcopy((caddr_t) & seg_part,
225 mtod(frag_hdr, caddr_t) + segoff,
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 */
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 */
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 */
407 int
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 */
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 MALLOC(cfh, struct clnp_fragl *, sizeof (struct clnp_fragl),
424 M_FTABLE, M_NOWAIT);
425 if (cfh == NULL) {
426 return (0);
427 }
428
429 /*
430 * Duplicate the header of this fragment, and save in cfh. Free m0
431 * and return if m_copy does not succeed.
432 */
433 cfh->cfl_orighdr = m_copy(m, 0, (int) clnp->cnf_hdr_len);
434 if (cfh->cfl_orighdr == NULL) {
435 FREE(cfh, M_FTABLE);
436 return (0);
437 }
438 /* Fill in rest of fragl structure */
439 bcopy((caddr_t) src, (caddr_t) & cfh->cfl_src, sizeof(struct iso_addr));
440 bcopy((caddr_t) dst, (caddr_t) & cfh->cfl_dst, sizeof(struct iso_addr));
441 cfh->cfl_id = seg->cng_id;
442 cfh->cfl_ttl = clnp->cnf_ttl;
443 cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
444 cfh->cfl_frags = NULL;
445 cfh->cfl_next = NULL;
446
447 /* Insert into list of packets */
448 cfh->cfl_next = clnp_frags;
449 clnp_frags = cfh;
450
451 /* Insert this fragment into list headed by cfh */
452 clnp_insert_frag(cfh, m, seg);
453 return (1);
454 }
455
456 /*
457 * FUNCTION: clnp_insert_frag
458 *
459 * PURPOSE: Insert fragment into list headed by 'cf'.
460 *
461 * RETURNS: nothing
462 *
463 * SIDE EFFECTS:
464 *
465 * NOTES: This is the 'guts' of the reassembly algorithm.
466 * Each fragment in this list contains a clnp_frag
467 * structure followed by the data of the fragment.
468 * The clnp_frag structure actually lies on top of
469 * part of the old clnp header.
470 */
471 void
472 clnp_insert_frag(
473 struct clnp_fragl *cfh, /* header of list of packet fragments */
474 struct mbuf *m, /* new fragment */
475 struct clnp_segment *seg) /* segment part of fragment header */
476 {
477 struct clnp_fixed *clnp; /* clnp hdr of fragment */
478 struct clnp_frag *cf; /* generic fragment ptr */
479 struct clnp_frag *cf_sub = NULL; /* frag subseq to new
480 * one */
481 struct clnp_frag *cf_prev = NULL; /* frag prev to new one */
482 u_short first; /* offset of first byte of initial pdu */
483 u_short last; /* offset of last byte of initial pdu */
484 u_short fraglen;/* length of fragment */
485
486 clnp = mtod(m, struct clnp_fixed *);
487 first = seg->cng_off;
488 CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
489 fraglen -= clnp->cnf_hdr_len;
490 last = (first + fraglen) - 1;
491
492 #ifdef ARGO_DEBUG
493 if (argo_debug[D_REASS]) {
494 printf("clnp_insert_frag: New fragment: [%d-%d], len %d\n",
495 first, last, fraglen);
496 printf("clnp_insert_frag: current fragments:\n");
497 for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
498 printf("\tcf %p: [%d-%d]\n",
499 cf, cf->cfr_first, cf->cfr_last);
500 }
501 }
502 #endif
503
504 if (cfh->cfl_frags != NULL) {
505 /*
506 * Find fragment which begins after the new one
507 */
508 for (cf = cfh->cfl_frags; cf != NULL;
509 cf_prev = cf, cf = cf->cfr_next) {
510 if (cf->cfr_first > first) {
511 cf_sub = cf;
512 break;
513 }
514 }
515
516 #ifdef ARGO_DEBUG
517 if (argo_debug[D_REASS]) {
518 printf("clnp_insert_frag: Previous frag is ");
519 if (cf_prev == NULL)
520 printf("NULL\n");
521 else
522 printf("[%d-%d]\n", cf_prev->cfr_first,
523 cf_prev->cfr_last);
524 printf("clnp_insert_frag: Subsequent frag is ");
525 if (cf_sub == NULL)
526 printf("NULL\n");
527 else
528 printf("[%d-%d]\n", cf_sub->cfr_first,
529 cf_sub->cfr_last);
530 }
531 #endif
532
533 /*
534 * If there is a fragment before the new one, check if it
535 * overlaps the new one. If so, then trim the end of the
536 * previous one.
537 */
538 if (cf_prev != NULL) {
539 if (cf_prev->cfr_last > first) {
540 u_short overlap = cf_prev->cfr_last - first;
541
542 #ifdef ARGO_DEBUG
543 if (argo_debug[D_REASS]) {
544 printf(
545 "clnp_insert_frag: previous overlaps by %d\n",
546 overlap);
547 }
548 #endif
549
550 if (overlap > fraglen) {
551 /*
552 * The new fragment is entirely
553 * contained in the preceding one.
554 * We can punt on the new frag
555 * completely.
556 */
557 m_freem(m);
558 return;
559 } else {
560 /*
561 * Trim data off of end of previous
562 * fragment
563 */
564 /*
565 * inc overlap to prevent duplication
566 * of last byte
567 */
568 overlap++;
569 m_adj(cf_prev->cfr_data, -(int) overlap);
570 cf_prev->cfr_last -= overlap;
571 }
572 }
573 }
574 /*
575 * For all fragments past the new one, check if any data on
576 * the new one overlaps data on existing fragments. If so,
577 * then trim the extra data off the end of the new one.
578 */
579 for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
580 if (cf->cfr_first < last) {
581 u_short overlap = last - cf->cfr_first;
582
583 #ifdef ARGO_DEBUG
584 if (argo_debug[D_REASS]) {
585 printf(
586 "clnp_insert_frag: subsequent overlaps by %d\n",
587 overlap);
588 }
589 #endif
590
591 if (overlap > fraglen) {
592 /*
593 * The new fragment is entirely
594 * contained in the succeeding one.
595 * This should not happen, because
596 * early on in this code we scanned
597 * for the fragment which started
598 * after the new one!
599 */
600 m_freem(m);
601 printf(
602 "clnp_insert_frag: internal error!\n");
603 return;
604 } else {
605 /*
606 * Trim data off of end of new fragment
607 * inc overlap to prevent duplication
608 * of last byte
609 */
610 overlap++;
611 m_adj(m, -(int) overlap);
612 last -= overlap;
613 }
614 }
615 }
616 }
617 /*
618 * Insert the new fragment beween cf_prev and cf_sub
619 *
620 * Note: the clnp hdr is still in the mbuf.
621 * If the data of the mbuf is not word aligned, shave off enough
622 * so that it is. Then, cast the clnp_frag structure on top
623 * of the clnp header.
624 * The clnp_hdr will not be used again (as we already have
625 * saved a copy of it).
626 *
627 * Save in cfr_bytes the number of bytes to shave off to get to
628 * the data of the packet. This is used when we coalesce fragments;
629 * the clnp_frag structure must be removed before joining mbufs.
630 */
631 {
632 int pad;
633 u_int bytes;
634
635 /* determine if header is not word aligned */
636 pad = (long) clnp % 4;
637 if (pad < 0)
638 pad = -pad;
639
640 /* bytes is number of bytes left in front of data */
641 bytes = clnp->cnf_hdr_len - pad;
642
643 #ifdef ARGO_DEBUG
644 if (argo_debug[D_REASS]) {
645 printf(
646 "clnp_insert_frag: clnp %p requires %d alignment\n",
647 clnp, pad);
648 }
649 #endif
650
651 /* make it word aligned if necessary */
652 if (pad)
653 m_adj(m, pad);
654
655 cf = mtod(m, struct clnp_frag *);
656 cf->cfr_bytes = bytes;
657
658 #ifdef ARGO_DEBUG
659 if (argo_debug[D_REASS]) {
660 printf("clnp_insert_frag: cf now %p, cfr_bytes %d\n",
661 cf, cf->cfr_bytes);
662 }
663 #endif
664 }
665 cf->cfr_first = first;
666 cf->cfr_last = last;
667
668
669 /*
670 * The data is the mbuf itself, although we must remember that the
671 * first few bytes are actually a clnp_frag structure
672 */
673 cf->cfr_data = m;
674
675 /* link into place */
676 cf->cfr_next = cf_sub;
677 if (cf_prev == NULL)
678 cfh->cfl_frags = cf;
679 else
680 cf_prev->cfr_next = cf;
681 }
682
683 /*
684 * FUNCTION: clnp_comp_pdu
685 *
686 * PURPOSE: Scan the list of fragments headed by cfh. Merge
687 * any contigious fragments into one. If, after
688 * traversing all the fragments, it is determined that
689 * the packet is complete, then return a pointer to
690 * the packet (with header prepended). Otherwise,
691 * return NULL.
692 *
693 * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf
694 * chain.
695 *
696 * SIDE EFFECTS: Will colapse contigious fragments into one.
697 *
698 * NOTES: This code assumes that there are no overlaps of
699 * fragment pdus.
700 */
701 struct mbuf *
702 clnp_comp_pdu(
703 struct clnp_fragl *cfh) /* fragment header */
704 {
705 struct clnp_frag *cf = cfh->cfl_frags;
706
707 while (cf->cfr_next != NULL) {
708 struct clnp_frag *cf_next = cf->cfr_next;
709
710 #ifdef ARGO_DEBUG
711 if (argo_debug[D_REASS]) {
712 printf("clnp_comp_pdu: comparing: [%d-%d] to [%d-%d]\n",
713 cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
714 cf_next->cfr_last);
715 }
716 #endif
717
718 if (cf->cfr_last == (cf_next->cfr_first - 1)) {
719 /*
720 * Merge fragment cf and cf_next
721 *
722 * - update cf header
723 * - trim clnp_frag structure off of cf_next
724 * - append cf_next to cf
725 */
726 struct clnp_frag cf_next_hdr;
727 struct clnp_frag *next_frag;
728
729 cf_next_hdr = *cf_next;
730 next_frag = cf_next->cfr_next;
731
732 #ifdef ARGO_DEBUG
733 if (argo_debug[D_REASS]) {
734 struct mbuf *mdump;
735 int l;
736 printf("clnp_comp_pdu: merging fragments\n");
737 printf(
738 "clnp_comp_pdu: 1st: [%d-%d] (bytes %d)\n",
739 cf->cfr_first, cf->cfr_last,
740 cf->cfr_bytes);
741 mdump = cf->cfr_data;
742 l = 0;
743 while (mdump != NULL) {
744 printf("\tmbuf %p, m_len %d\n",
745 mdump, mdump->m_len);
746 l += mdump->m_len;
747 mdump = mdump->m_next;
748 }
749 printf("\ttotal len: %d\n", l);
750 printf(
751 "clnp_comp_pdu: 2nd: [%d-%d] (bytes %d)\n",
752 cf_next->cfr_first, cf_next->cfr_last,
753 cf_next->cfr_bytes);
754 mdump = cf_next->cfr_data;
755 l = 0;
756 while (mdump != NULL) {
757 printf("\tmbuf %p, m_len %d\n",
758 mdump, mdump->m_len);
759 l += mdump->m_len;
760 mdump = mdump->m_next;
761 }
762 printf("\ttotal len: %d\n", l);
763 }
764 #endif
765
766 cf->cfr_last = cf_next->cfr_last;
767 /*
768 * After this m_adj, the cf_next ptr is useless
769 * because we have adjusted the clnp_frag structure
770 * away...
771 */
772 #ifdef ARGO_DEBUG
773 if (argo_debug[D_REASS]) {
774 printf("clnp_comp_pdu: shaving off %d bytes\n",
775 cf_next_hdr.cfr_bytes);
776 }
777 #endif
778 m_adj(cf_next_hdr.cfr_data,
779 (int) cf_next_hdr.cfr_bytes);
780 m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
781 cf->cfr_next = next_frag;
782 } else {
783 cf = cf->cfr_next;
784 }
785 }
786
787 cf = cfh->cfl_frags;
788
789 #ifdef ARGO_DEBUG
790 if (argo_debug[D_REASS]) {
791 struct mbuf *mdump = cf->cfr_data;
792 printf("clnp_comp_pdu: first frag now: [%d-%d]\n",
793 cf->cfr_first, cf->cfr_last);
794 printf("clnp_comp_pdu: data for frag:\n");
795 while (mdump != NULL) {
796 printf("mbuf %p, m_len %d\n", mdump, mdump->m_len);
797 /* dump_buf(mtod(mdump, caddr_t), mdump->m_len); */
798 mdump = mdump->m_next;
799 }
800 }
801 #endif
802
803 /* Check if datagram is complete */
804 if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
805 /*
806 * We have a complete pdu!
807 * - Remove the frag header from (only) remaining fragment
808 * (which is not really a fragment anymore, as the datagram
809 * is complete).
810 * - Prepend a clnp header
811 */
812 struct mbuf *data = cf->cfr_data;
813 struct mbuf *hdr = cfh->cfl_orighdr;
814 struct clnp_fragl *scan;
815
816 #ifdef ARGO_DEBUG
817 if (argo_debug[D_REASS]) {
818 printf("clnp_comp_pdu: complete pdu!\n");
819 }
820 #endif
821
822 m_adj(data, (int) cf->cfr_bytes);
823 m_cat(hdr, data);
824
825 #ifdef ARGO_DEBUG
826 if (argo_debug[D_DUMPIN]) {
827 struct mbuf *mdump = hdr;
828 printf("clnp_comp_pdu: pdu is:\n");
829 while (mdump != NULL) {
830 printf("mbuf %p, m_len %d\n",
831 mdump, mdump->m_len);
832 #if 0
833 dump_buf(mtod(mdump, caddr_t), mdump->m_len);
834 #endif
835 mdump = mdump->m_next;
836 }
837 }
838 #endif
839
840 /*
841 * Remove cfh from the list of fragmented pdus
842 */
843 if (clnp_frags == cfh) {
844 clnp_frags = cfh->cfl_next;
845 } else {
846 for (scan = clnp_frags; scan != NULL;
847 scan = scan->cfl_next) {
848 if (scan->cfl_next == cfh) {
849 scan->cfl_next = cfh->cfl_next;
850 break;
851 }
852 }
853 }
854
855 /* free cfh */
856 FREE(cfh, M_FTABLE);
857
858 return (hdr);
859 }
860 return (NULL);
861 }
862 #ifdef TROLL
863 static int troll_cnt;
864 #include <sys/time.h>
865 /*
866 * FUNCTION: troll_random
867 *
868 * PURPOSE: generate a pseudo-random number between 0 and 1
869 *
870 * RETURNS: the random number
871 *
872 * SIDE EFFECTS:
873 *
874 * NOTES: This is based on the clock.
875 */
876 float
877 troll_random()
878 {
879 extern struct timeval time;
880 long t = time.tv_usec % 100;
881
882 return ((float) t / (float) 100);
883 }
884
885 /*
886 * FUNCTION: troll_output
887 *
888 * PURPOSE: Do something sneaky with the datagram passed. Possible
889 * operations are:
890 * Duplicate the packet
891 * Drop the packet
892 * Trim some number of bytes from the packet
893 * Munge some byte in the packet
894 *
895 * RETURNS: 0, or unix error code
896 *
897 * SIDE EFFECTS:
898 *
899 * NOTES: The operation of this procedure is regulated by the
900 * troll control structure (Troll).
901 */
902 int
903 troll_output(ifp, m, dst, rt)
904 struct ifnet *ifp;
905 struct mbuf *m;
906 struct sockaddr *dst;
907 struct rtentry *rt;
908 {
909 int err = 0;
910 troll_cnt++;
911
912 if (trollctl.tr_ops & TR_DUPPKT) {
913 /*
914 * Duplicate every Nth packet
915 * TODO: random?
916 */
917 float f_freq = troll_cnt * trollctl.tr_dup_freq;
918 int i_freq = troll_cnt * trollctl.tr_dup_freq;
919 if (i_freq == f_freq) {
920 struct mbuf *dup = m_copy(m, 0, (int) M_COPYALL);
921 if (dup != NULL)
922 err = (*ifp->if_output) (ifp, dup, dst, rt);
923 }
924 if (!err)
925 err = (*ifp->if_output) (ifp, m, dst, rt);
926 return (err);
927 } else if (trollctl.tr_ops & TR_DROPPKT) {
928 } else if (trollctl.tr_ops & TR_CHANGE) {
929 struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
930 clnp->cnf_cksum_msb = 0;
931 err = (*ifp->if_output) (ifp, m, dst, rt);
932 return (err);
933 } else {
934 err = (*ifp->if_output) (ifp, m, dst, rt);
935 return (err);
936 }
937 }
938
939 #endif /* TROLL */
Cache object: ea777fb130884f3f2e9febbf6ba86fd3
|