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