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