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