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