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