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