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