trailing comment after #else or #endif
[unix-history] / usr / src / sys / netiso / clnp_frag.c
CommitLineData
7bcd1bb8
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
5548a02f 7 * @(#)clnp_frag.c 7.14 (Berkeley) %G%
7bcd1bb8
KB
8 */
9
6ddcd52e
KS
10/***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15Permission to use, copy, modify, and distribute this software and its
16documentation for any purpose and without fee is hereby granted,
17provided that the above copyright notice appear in all copies and that
18both that copyright notice and this permission notice appear in
19supporting documentation, and that the name of IBM not be
20used in advertising or publicity pertaining to distribution of the
21software without specific, written prior permission.
22
23IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29SOFTWARE.
30
31******************************************************************/
32
33/*
34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35 */
87428488
KS
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 $ */
6ddcd52e 38
5548a02f
KB
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>
6ddcd52e 47
5548a02f
KB
48#include <net/if.h>
49#include <net/route.h>
6ddcd52e 50
5548a02f
KB
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>
6ddcd52e
KS
56
57/* all fragments are hung off this list */
58struct clnp_fragl *clnp_frags = NULL;
59
60struct mbuf *clnp_comp_pdu();
61
6ddcd52e
KS
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 */
a544c9af 82clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt)
6ddcd52e
KS
83struct ifnet *ifp; /* ptr to outgoing interface */
84struct mbuf *m; /* ptr to packet */
85struct sockaddr *first_hop; /* ptr to first hop */
86int total_len; /* length of datagram */
87int segoff; /* offset of segpart in hdr */
88int flags; /* flags passed to clnp_output */
a544c9af 89struct rtentry *rt; /* route if direct ether */
6ddcd52e 90{
0358170d
KS
91 struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
92 int hdr_len = (int)clnp->cnf_hdr_len;
53571a64 93 int frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7;
6ddcd52e 94
0358170d
KS
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)))) {
6ddcd52e 99
6ddcd52e
KS
100 struct mbuf *hdr = NULL; /* save copy of clnp hdr */
101 struct mbuf *frag_hdr = NULL;
102 struct mbuf *frag_data = NULL;
282ab75d 103 struct clnp_segment seg_part; /* segmentation header */
ddf6aba6 104 int frag_base;
6ddcd52e
KS
105 int error = 0;
106
6ddcd52e 107
0358170d 108 INCSTAT(cns_fragmented);
282ab75d
KS
109 (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part,
110 sizeof(seg_part));
111 frag_base = ntohs(seg_part.cng_off);
6ddcd52e
KS
112 /*
113 * Duplicate header, and remove from packet
114 */
0358170d 115 if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
6ddcd52e
KS
116 clnp_discard(m, GEN_CONGEST);
117 return(ENOBUFS);
118 }
0358170d
KS
119 m_adj(m, hdr_len);
120
6ddcd52e 121 while (total_len > 0) {
0358170d 122 int remaining, last_frag;
87428488
KS
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
6ddcd52e 136
0358170d
KS
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 }
6ddcd52e 151
6ddcd52e
KS
152
153 IFDEBUG(D_FRAG)
154 printf("clnp_fragment: seg off %d, size %d, remaining %d\n",
282ab75d 155 ntohs(seg_part.cng_off), frag_size, total_len-frag_size);
6ddcd52e
KS
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 */
a50e2bc0 169 if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) {
0358170d
KS
170 clnp_discard(hdr, GEN_CONGEST);
171 m_freem(m);
6ddcd52e
KS
172 return(ENOBUFS);
173 }
174 if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
0358170d
KS
175 clnp_discard(hdr, GEN_CONGEST);
176 m_freem(m);
6ddcd52e
KS
177 m_freem(frag_hdr);
178 return(ENOBUFS);
179 }
4f565be6 180 INCSTAT(cns_fragments);
6ddcd52e
KS
181 }
182 clnp = mtod(frag_hdr, struct clnp_fixed *);
183
184 if (!last_frag)
a50e2bc0 185 clnp->cnf_type |= CNF_MORE_SEGS;
6ddcd52e
KS
186
187 /* link together */
188 m_cat(frag_hdr, frag_data);
189
282ab75d
KS
190 /* insert segmentation part; updated below */
191 bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff,
6ddcd52e
KS
192 sizeof(struct clnp_segment));
193
194 {
0358170d 195 int derived_len = hdr_len + frag_size;
6ddcd52e 196 HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
a50e2bc0
KS
197 if ((frag_hdr->m_flags & M_PKTHDR) == 0)
198 panic("clnp_frag:lost header");
199 frag_hdr->m_pkthdr.len = derived_len;
6ddcd52e
KS
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 {
0358170d 205 iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len);
6ddcd52e
KS
206 }
207
208 IFDEBUG(D_DUMPOUT)
209 struct mbuf *mdump = frag_hdr;
210 printf("clnp_fragment: sending dg:\n");
6ddcd52e 211 while (mdump != NULL) {
87428488 212 printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
6ddcd52e
KS
213 mdump = mdump->m_next;
214 }
215 ENDDEBUG
216
217#ifdef TROLL
a544c9af 218 error = troll_output(ifp, frag_hdr, first_hop, rt);
6ddcd52e 219#else
a544c9af 220 error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt);
6ddcd52e
KS
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 */
0358170d
KS
236 clnp_discard(hdr, GEN_NOREAS);
237 m_freem(m);
6ddcd52e
KS
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) {
282ab75d
KS
263 frag_base += frag_size;
264 seg_part.cng_off = htons(frag_base);
6ddcd52e
KS
265 m_adj(m, frag_size);
266 }
267 }
268 return(0);
269 } else {
0358170d 270 cantfrag:
4f565be6 271 INCSTAT(cns_cantfrag);
6ddcd52e
KS
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 */
298struct mbuf *
299clnp_reass(m, src, dst, seg)
300struct mbuf *m; /* new fragment */
301struct iso_addr *src; /* src of new fragment */
302struct iso_addr *dst; /* dst of new fragment */
303struct 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) {
282ab75d
KS
309 if (seg->cng_id == cfh->cfl_id &&
310 iso_addrmatch1(src, &cfh->cfl_src) &&
311 iso_addrmatch1(dst, &cfh->cfl_dst)) {
6ddcd52e
KS
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);
282ab75d
KS
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);
6ddcd52e
KS
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 */) {
4f565be6 340 INCSTAT(cns_fragdropped);
6ddcd52e
KS
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 */
359clnp_newpkt(m, src, dst, seg)
360struct mbuf *m; /* new fragment */
361struct iso_addr *src; /* src of new fragment */
362struct iso_addr *dst; /* dst of new fragment */
363struct 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 */
a50e2bc0 385 if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) {
6ddcd52e
KS
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 */
423clnp_insert_frag(cfh, m, seg)
424struct clnp_fragl *cfh; /* header of list of packet fragments */
425struct mbuf *m; /* new fragment */
426struct 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++;
a50e2bc0 501 m_adj(cf_prev->cfr_data, -(int)overlap);
6ddcd52e
KS
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++;
a50e2bc0 535 m_adj(m, -(int)overlap);
6ddcd52e
KS
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
87428488
KS
568 IFDEBUG(D_REASS)
569 printf("clnp_insert_frag: clnp x%x requires %d alignment\n",
570 clnp, pad);
571 ENDDEBUG
572
6ddcd52e
KS
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;
87428488
KS
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
6ddcd52e
KS
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 */
620struct mbuf *
621clnp_comp_pdu(cfh)
622struct 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;
87428488 651 int l;
6ddcd52e 652 printf("clnp_comp_pdu: merging fragments\n");
87428488
KS
653 printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n",
654 cf->cfr_first, cf->cfr_last, cf->cfr_bytes);
6ddcd52e 655 mdump = cf->cfr_data;
87428488 656 l = 0;
6ddcd52e
KS
657 while (mdump != NULL) {
658 printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
87428488 659 l += mdump->m_len;
6ddcd52e
KS
660 mdump = mdump->m_next;
661 }
87428488
KS
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);
6ddcd52e 665 mdump = cf_next->cfr_data;
87428488 666 l = 0;
6ddcd52e
KS
667 while (mdump != NULL) {
668 printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
87428488 669 l += mdump->m_len;
6ddcd52e
KS
670 mdump = mdump->m_next;
671 }
87428488 672 printf("\ttotal len: %d\n", l);
6ddcd52e
KS
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 */
87428488
KS
680 IFDEBUG(D_REASS)
681 printf("clnp_comp_pdu: shaving off %d bytes\n",
682 cf_next_hdr.cfr_bytes);
683 ENDDEBUG
a50e2bc0 684 m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes);
6ddcd52e
KS
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
a50e2bc0 723 m_adj(data, (int)cf->cfr_bytes);
6ddcd52e
KS
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
a50e2bc0 759static int troll_cnt;
5548a02f 760#include <sys/time.h>
6ddcd52e
KS
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 */
772float 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 */
a544c9af 797troll_output(ifp, m, dst, rt)
6ddcd52e
KS
798struct ifnet *ifp;
799struct mbuf *m;
800struct sockaddr *dst;
a544c9af 801struct rtentry *rt;
6ddcd52e
KS
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) {
a50e2bc0 814 struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL);
6ddcd52e 815 if (dup != NULL)
a544c9af 816 err = (*ifp->if_output)(ifp, dup, dst, rt);
6ddcd52e
KS
817 }
818 if (!err)
a544c9af 819 err = (*ifp->if_output)(ifp, m, dst, rt);
6ddcd52e
KS
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;
a544c9af 825 err = (*ifp->if_output)(ifp, m, dst, rt);
6ddcd52e
KS
826 return(err);
827 } else {
a544c9af 828 err = (*ifp->if_output)(ifp, m, dst, rt);
6ddcd52e
KS
829 return(err);
830 }
831}
832
833#endif TROLL