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