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