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.7 (Berkeley) 09/26/89 */ 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) 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 { 85 struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 86 int hdr_len = (int)clnp->cnf_hdr_len; 87 int frag_size = (ifp->if_mtu - hdr_len) & ~7; 88 89 total_len -= hdr_len; 90 if ((clnp->cnf_type & CNF_SEG_OK) && 91 (total_len >= 8) && 92 (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { 93 94 struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 95 struct mbuf *frag_hdr = NULL; 96 struct mbuf *frag_data = NULL; 97 struct clnp_segment seg_part, tmp_seg; /* segmentation header */ 98 extern int clnp_id; /* id of datagram */ 99 int frag_size; 100 int error = 0; 101 102 103 INCSTAT(cns_fragmented); 104 seg_part.cng_id = clnp_id++; 105 seg_part.cng_off = 0; 106 seg_part.cng_tot_len = total_len + hdr_len; 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 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 /* make sure segmentation fields are in network order */ 186 tmp_seg.cng_id = htons(seg_part.cng_id); 187 tmp_seg.cng_off = htons(seg_part.cng_off); 188 tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len); 189 190 /* insert segmentation part */ 191 bcopy((caddr_t)&tmp_seg, 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); 219 #else 220 error = (*ifp->if_output)(ifp, frag_hdr, first_hop); 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 seg_part.cng_off += frag_size; 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 (iso_addrmatch1(src, &cfh->cfl_src) && 309 iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) { 310 IFDEBUG(D_REASS) 311 printf("clnp_reass: found packet\n"); 312 ENDDEBUG 313 /* 314 * There are other fragments here already. Lets see if 315 * this fragment is of any help 316 */ 317 clnp_insert_frag(cfh, m, seg); 318 return (clnp_comp_pdu(cfh)); 319 } 320 } 321 322 IFDEBUG(D_REASS) 323 printf("clnp_reass: new packet!\n"); 324 ENDDEBUG 325 326 /* 327 * This is the first fragment. If src is not consuming too many 328 * resources, then create a new fragment list and add 329 * this fragment to the list. 330 */ 331 /* TODO: don't let one src hog all the reassembly buffers */ 332 if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { 333 INCSTAT(cns_fragdropped); 334 clnp_discard(m, GEN_CONGEST); 335 } 336 337 return(NULL); 338 } 339 340 /* 341 * FUNCTION: clnp_newpkt 342 * 343 * PURPOSE: Create the necessary structures to handle a new 344 * fragmented clnp packet. 345 * 346 * RETURNS: non-zero if it succeeds, zero if fails. 347 * 348 * SIDE EFFECTS: 349 * 350 * NOTES: Failure is only due to insufficient resources. 351 */ 352 clnp_newpkt(m, src, dst, seg) 353 struct mbuf *m; /* new fragment */ 354 struct iso_addr *src; /* src of new fragment */ 355 struct iso_addr *dst; /* dst of new fragment */ 356 struct clnp_segment *seg; /* segment part of fragment header */ 357 { 358 register struct clnp_fragl *cfh; 359 register struct clnp_fixed *clnp; 360 struct mbuf *m0; 361 362 clnp = mtod(m, struct clnp_fixed *); 363 364 /* 365 * Allocate new clnp fragl structure to act as header of all fragments 366 * for this datagram. 367 */ 368 MGET(m0, M_DONTWAIT, MT_FTABLE); 369 if (m0 == NULL) { 370 return (0); 371 } 372 cfh = mtod(m0, struct clnp_fragl *); 373 374 /* 375 * Duplicate the header of this fragment, and save in cfh. 376 * Free m0 and return if m_copy does not succeed. 377 */ 378 if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 379 m_freem(m0); 380 return (0); 381 } 382 383 /* Fill in rest of fragl structure */ 384 bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 385 bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 386 cfh->cfl_id = seg->cng_id; 387 cfh->cfl_ttl = clnp->cnf_ttl; 388 cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 389 cfh->cfl_frags = NULL; 390 cfh->cfl_next = NULL; 391 392 /* Insert into list of packets */ 393 cfh->cfl_next = clnp_frags; 394 clnp_frags = cfh; 395 396 /* Insert this fragment into list headed by cfh */ 397 clnp_insert_frag(cfh, m, seg); 398 return(1); 399 } 400 401 /* 402 * FUNCTION: clnp_insert_frag 403 * 404 * PURPOSE: Insert fragment into list headed by 'cf'. 405 * 406 * RETURNS: nothing 407 * 408 * SIDE EFFECTS: 409 * 410 * NOTES: This is the 'guts' of the reassembly algorithm. 411 * Each fragment in this list contains a clnp_frag 412 * structure followed by the data of the fragment. 413 * The clnp_frag structure actually lies on top of 414 * part of the old clnp header. 415 */ 416 clnp_insert_frag(cfh, m, seg) 417 struct clnp_fragl *cfh; /* header of list of packet fragments */ 418 struct mbuf *m; /* new fragment */ 419 struct clnp_segment *seg; /* segment part of fragment header */ 420 { 421 register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 422 register struct clnp_frag *cf; /* generic fragment ptr */ 423 register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 424 register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 425 u_short first; /* offset of first byte of initial pdu*/ 426 u_short last; /* offset of last byte of initial pdu */ 427 u_short fraglen;/* length of fragment */ 428 429 clnp = mtod(m, struct clnp_fixed *); 430 first = seg->cng_off; 431 CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 432 fraglen -= clnp->cnf_hdr_len; 433 last = (first + fraglen) - 1; 434 435 IFDEBUG(D_REASS) 436 printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 437 first, last, fraglen); 438 printf("clnp_insert_frag: current fragments:\n"); 439 for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 440 printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 441 } 442 ENDDEBUG 443 444 if (cfh->cfl_frags != NULL) { 445 /* 446 * Find fragment which begins after the new one 447 */ 448 for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 449 if (cf->cfr_first > first) { 450 cf_sub = cf; 451 break; 452 } 453 } 454 455 IFDEBUG(D_REASS) 456 printf("clnp_insert_frag: Previous frag is "); 457 if (cf_prev == NULL) 458 printf("NULL\n"); 459 else 460 printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 461 printf("clnp_insert_frag: Subsequent frag is "); 462 if (cf_sub == NULL) 463 printf("NULL\n"); 464 else 465 printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 466 ENDDEBUG 467 468 /* 469 * If there is a fragment before the new one, check if it 470 * overlaps the new one. If so, then trim the end of the 471 * previous one. 472 */ 473 if (cf_prev != NULL) { 474 if (cf_prev->cfr_last > first) { 475 u_short overlap = cf_prev->cfr_last - first; 476 477 IFDEBUG(D_REASS) 478 printf("clnp_insert_frag: previous overlaps by %d\n", 479 overlap); 480 ENDDEBUG 481 482 if (overlap > fraglen) { 483 /* 484 * The new fragment is entirely contained in the 485 * preceeding one. We can punt on the new frag 486 * completely. 487 */ 488 m_freem(m); 489 return; 490 } else { 491 /* Trim data off of end of previous fragment */ 492 /* inc overlap to prevent duplication of last byte */ 493 overlap++; 494 m_adj(cf_prev->cfr_data, -(int)overlap); 495 cf_prev->cfr_last -= overlap; 496 } 497 } 498 } 499 500 /* 501 * For all fragments past the new one, check if any data on 502 * the new one overlaps data on existing fragments. If so, 503 * then trim the extra data off the end of the new one. 504 */ 505 for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 506 if (cf->cfr_first < last) { 507 u_short overlap = last - cf->cfr_first; 508 509 IFDEBUG(D_REASS) 510 printf("clnp_insert_frag: subsequent overlaps by %d\n", 511 overlap); 512 ENDDEBUG 513 514 if (overlap > fraglen) { 515 /* 516 * The new fragment is entirely contained in the 517 * succeeding one. This should not happen, because 518 * early on in this code we scanned for the fragment 519 * which started after the new one! 520 */ 521 m_freem(m); 522 printf("clnp_insert_frag: internal error!\n"); 523 return; 524 } else { 525 /* Trim data off of end of new fragment */ 526 /* inc overlap to prevent duplication of last byte */ 527 overlap++; 528 m_adj(m, -(int)overlap); 529 last -= overlap; 530 } 531 } 532 } 533 } 534 535 /* 536 * Insert the new fragment beween cf_prev and cf_sub 537 * 538 * Note: the clnp hdr is still in the mbuf. 539 * If the data of the mbuf is not word aligned, shave off enough 540 * so that it is. Then, cast the clnp_frag structure on top 541 * of the clnp header. 542 * The clnp_hdr will not be used again (as we already have 543 * saved a copy of it). 544 * 545 * Save in cfr_bytes the number of bytes to shave off to get to 546 * the data of the packet. This is used when we coalesce fragments; 547 * the clnp_frag structure must be removed before joining mbufs. 548 */ 549 { 550 int pad; 551 u_int bytes; 552 553 /* determine if header is not word aligned */ 554 pad = (int)clnp % 4; 555 if (pad < 0) 556 pad = -pad; 557 558 /* bytes is number of bytes left in front of data */ 559 bytes = clnp->cnf_hdr_len - pad; 560 561 IFDEBUG(D_REASS) 562 printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 563 clnp, pad); 564 ENDDEBUG 565 566 /* make it word aligned if necessary */ 567 if (pad) 568 m_adj(m, pad); 569 570 cf = mtod(m, struct clnp_frag *); 571 cf->cfr_bytes = bytes; 572 573 IFDEBUG(D_REASS) 574 printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 575 cf->cfr_bytes); 576 ENDDEBUG 577 } 578 cf->cfr_first = first; 579 cf->cfr_last = last; 580 581 582 /* 583 * The data is the mbuf itself, although we must remember that the 584 * first few bytes are actually a clnp_frag structure 585 */ 586 cf->cfr_data = m; 587 588 /* link into place */ 589 cf->cfr_next = cf_sub; 590 if (cf_prev == NULL) 591 cfh->cfl_frags = cf; 592 else 593 cf_prev->cfr_next = cf; 594 } 595 596 /* 597 * FUNCTION: clnp_comp_pdu 598 * 599 * PURPOSE: Scan the list of fragments headed by cfh. Merge 600 * any contigious fragments into one. If, after 601 * traversing all the fragments, it is determined that 602 * the packet is complete, then return a pointer to 603 * the packet (with header prepended). Otherwise, 604 * return NULL. 605 * 606 * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 607 * 608 * SIDE EFFECTS: Will colapse contigious fragments into one. 609 * 610 * NOTES: This code assumes that there are no overlaps of 611 * fragment pdus. 612 */ 613 struct mbuf * 614 clnp_comp_pdu(cfh) 615 struct clnp_fragl *cfh; /* fragment header */ 616 { 617 register struct clnp_frag *cf = cfh->cfl_frags; 618 619 while (cf->cfr_next != NULL) { 620 register struct clnp_frag *cf_next = cf->cfr_next; 621 622 IFDEBUG(D_REASS) 623 printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 624 cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 625 cf_next->cfr_last); 626 ENDDEBUG 627 628 if (cf->cfr_last == (cf_next->cfr_first - 1)) { 629 /* 630 * Merge fragment cf and cf_next 631 * 632 * - update cf header 633 * - trim clnp_frag structure off of cf_next 634 * - append cf_next to cf 635 */ 636 struct clnp_frag cf_next_hdr; 637 struct clnp_frag *next_frag; 638 639 cf_next_hdr = *cf_next; 640 next_frag = cf_next->cfr_next; 641 642 IFDEBUG(D_REASS) 643 struct mbuf *mdump; 644 int l; 645 printf("clnp_comp_pdu: merging fragments\n"); 646 printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 647 cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 648 mdump = cf->cfr_data; 649 l = 0; 650 while (mdump != NULL) { 651 printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 652 l += mdump->m_len; 653 mdump = mdump->m_next; 654 } 655 printf("\ttotal len: %d\n", l); 656 printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 657 cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 658 mdump = cf_next->cfr_data; 659 l = 0; 660 while (mdump != NULL) { 661 printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 662 l += mdump->m_len; 663 mdump = mdump->m_next; 664 } 665 printf("\ttotal len: %d\n", l); 666 ENDDEBUG 667 668 cf->cfr_last = cf_next->cfr_last; 669 /* 670 * After this m_adj, the cf_next ptr is useless because we 671 * have adjusted the clnp_frag structure away... 672 */ 673 IFDEBUG(D_REASS) 674 printf("clnp_comp_pdu: shaving off %d bytes\n", 675 cf_next_hdr.cfr_bytes); 676 ENDDEBUG 677 m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); 678 m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 679 cf->cfr_next = next_frag; 680 } else { 681 cf = cf->cfr_next; 682 } 683 } 684 685 cf = cfh->cfl_frags; 686 687 IFDEBUG(D_REASS) 688 struct mbuf *mdump = cf->cfr_data; 689 printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 690 cf->cfr_last); 691 printf("clnp_comp_pdu: data for frag:\n"); 692 while (mdump != NULL) { 693 printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 694 /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 695 mdump = mdump->m_next; 696 } 697 ENDDEBUG 698 699 /* Check if datagram is complete */ 700 if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 701 /* 702 * We have a complete pdu! 703 * - Remove the frag header from (only) remaining fragment 704 * (which is not really a fragment anymore, as the datagram is 705 * complete). 706 * - Prepend a clnp header 707 */ 708 struct mbuf *data = cf->cfr_data; 709 struct mbuf *hdr = cfh->cfl_orighdr; 710 struct clnp_fragl *scan; 711 712 IFDEBUG(D_REASS) 713 printf("clnp_comp_pdu: complete pdu!\n"); 714 ENDDEBUG 715 716 m_adj(data, (int)cf->cfr_bytes); 717 m_cat(hdr, data); 718 719 IFDEBUG(D_DUMPIN) 720 struct mbuf *mdump = hdr; 721 printf("clnp_comp_pdu: pdu is:\n"); 722 while (mdump != NULL) { 723 printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 724 /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 725 mdump = mdump->m_next; 726 } 727 ENDDEBUG 728 729 /* 730 * Remove cfh from the list of fragmented pdus 731 */ 732 if (clnp_frags == cfh) { 733 clnp_frags = cfh->cfl_next; 734 } else { 735 for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 736 if (scan->cfl_next == cfh) { 737 scan->cfl_next = cfh->cfl_next; 738 break; 739 } 740 } 741 } 742 743 /* free cfh */ 744 m_freem(dtom(cfh)); 745 746 return(hdr); 747 } 748 749 return(NULL); 750 } 751 #ifdef TROLL 752 static int troll_cnt; 753 #include "time.h" 754 /* 755 * FUNCTION: troll_random 756 * 757 * PURPOSE: generate a pseudo-random number between 0 and 1 758 * 759 * RETURNS: the random number 760 * 761 * SIDE EFFECTS: 762 * 763 * NOTES: This is based on the clock. 764 */ 765 float troll_random() 766 { 767 extern struct timeval time; 768 long t = time.tv_usec % 100; 769 770 return((float)t / (float) 100); 771 } 772 773 /* 774 * FUNCTION: troll_output 775 * 776 * PURPOSE: Do something sneaky with the datagram passed. Possible 777 * operations are: 778 * Duplicate the packet 779 * Drop the packet 780 * Trim some number of bytes from the packet 781 * Munge some byte in the packet 782 * 783 * RETURNS: 0, or unix error code 784 * 785 * SIDE EFFECTS: 786 * 787 * NOTES: The operation of this procedure is regulated by the 788 * troll control structure (Troll). 789 */ 790 troll_output(ifp, m, dst) 791 struct ifnet *ifp; 792 struct mbuf *m; 793 struct sockaddr *dst; 794 { 795 int err = 0; 796 troll_cnt++; 797 798 if (trollctl.tr_ops & TR_DUPPKT) { 799 /* 800 * Duplicate every Nth packet 801 * TODO: random? 802 */ 803 float f_freq = troll_cnt * trollctl.tr_dup_freq; 804 int i_freq = troll_cnt * trollctl.tr_dup_freq; 805 if (i_freq == f_freq) { 806 struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); 807 if (dup != NULL) 808 err = (*ifp->if_output)(ifp, dup, dst); 809 } 810 if (!err) 811 err = (*ifp->if_output)(ifp, m, dst); 812 return(err); 813 } else if (trollctl.tr_ops & TR_DROPPKT) { 814 } else if (trollctl.tr_ops & TR_CHANGE) { 815 struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 816 clnp->cnf_cksum_msb = 0; 817 err = (*ifp->if_output)(ifp, m, dst); 818 return(err); 819 } else { 820 err = (*ifp->if_output)(ifp, m, dst); 821 return(err); 822 } 823 } 824 825 #endif TROLL 826