149267Sbostic /*-
2*63222Sbostic * Copyright (c) 1991, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
449267Sbostic *
549267Sbostic * %sccs.include.redist.c%
649267Sbostic *
7*63222Sbostic * @(#)clnp_frag.c 8.1 (Berkeley) 06/10/93
849267Sbostic */
949267Sbostic
1036369Ssklower /***********************************************************
1136369Ssklower Copyright IBM Corporation 1987
1236369Ssklower
1336369Ssklower All Rights Reserved
1436369Ssklower
1536369Ssklower Permission to use, copy, modify, and distribute this software and its
1636369Ssklower documentation for any purpose and without fee is hereby granted,
1736369Ssklower provided that the above copyright notice appear in all copies and that
1836369Ssklower both that copyright notice and this permission notice appear in
1936369Ssklower supporting documentation, and that the name of IBM not be
2036369Ssklower used in advertising or publicity pertaining to distribution of the
2136369Ssklower software without specific, written prior permission.
2236369Ssklower
2336369Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436369Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536369Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636369Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736369Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836369Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936369Ssklower SOFTWARE.
3036369Ssklower
3136369Ssklower ******************************************************************/
3236369Ssklower
3336369Ssklower /*
3436369Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536369Ssklower */
3636764Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */
3736764Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */
3836369Ssklower
3956533Sbostic #include <sys/param.h>
4056533Sbostic #include <sys/systm.h>
4156533Sbostic #include <sys/mbuf.h>
4256533Sbostic #include <sys/domain.h>
4356533Sbostic #include <sys/protosw.h>
4456533Sbostic #include <sys/socket.h>
4556533Sbostic #include <sys/socketvar.h>
4656533Sbostic #include <sys/errno.h>
4736369Ssklower
4856533Sbostic #include <net/if.h>
4956533Sbostic #include <net/route.h>
5036369Ssklower
5156533Sbostic #include <netiso/iso.h>
5256533Sbostic #include <netiso/iso_var.h>
5356533Sbostic #include <netiso/clnp.h>
5456533Sbostic #include <netiso/clnp_stat.h>
5556533Sbostic #include <netiso/argo_debug.h>
5636369Ssklower
5736369Ssklower /* all fragments are hung off this list */
5836369Ssklower struct clnp_fragl *clnp_frags = NULL;
5936369Ssklower
6036369Ssklower struct mbuf *clnp_comp_pdu();
6136369Ssklower
6236369Ssklower
6336369Ssklower /*
6436369Ssklower * FUNCTION: clnp_fragment
6536369Ssklower *
6636369Ssklower * PURPOSE: Fragment a datagram, and send the itty bitty pieces
6736369Ssklower * out over an interface.
6836369Ssklower *
6936369Ssklower * RETURNS: success - 0
7036369Ssklower * failure - unix error code
7136369Ssklower *
7236369Ssklower * SIDE EFFECTS:
7336369Ssklower *
7436369Ssklower * NOTES: If there is an error sending the packet, clnp_discard
7536369Ssklower * is called to discard the packet and send an ER. If
7636369Ssklower * clnp_fragment was called from clnp_output, then
7736369Ssklower * we generated the packet, and should not send an
7836369Ssklower * ER -- clnp_emit_er will check for this. Otherwise,
7936369Ssklower * the packet was fragmented during forwarding. In this
8036369Ssklower * case, we ought to send an ER back.
8136369Ssklower */
8240776Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt)
8336369Ssklower struct ifnet *ifp; /* ptr to outgoing interface */
8436369Ssklower struct mbuf *m; /* ptr to packet */
8536369Ssklower struct sockaddr *first_hop; /* ptr to first hop */
8636369Ssklower int total_len; /* length of datagram */
8736369Ssklower int segoff; /* offset of segpart in hdr */
8836369Ssklower int flags; /* flags passed to clnp_output */
8940776Ssklower struct rtentry *rt; /* route if direct ether */
9036369Ssklower {
9139232Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
9239232Ssklower int hdr_len = (int)clnp->cnf_hdr_len;
9348730Ssklower int frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7;
9436369Ssklower
9539232Ssklower total_len -= hdr_len;
9639232Ssklower if ((clnp->cnf_type & CNF_SEG_OK) &&
9739232Ssklower (total_len >= 8) &&
9839232Ssklower (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) {
9936369Ssklower
10036369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */
10136369Ssklower struct mbuf *frag_hdr = NULL;
10236369Ssklower struct mbuf *frag_data = NULL;
10342865Ssklower struct clnp_segment seg_part; /* segmentation header */
10447598Ssklower int frag_base;
10536369Ssklower int error = 0;
10636369Ssklower
10739232Ssklower
10839195Ssklower INCSTAT(cns_fragmented);
10942865Ssklower (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part,
11042865Ssklower sizeof(seg_part));
11142865Ssklower frag_base = ntohs(seg_part.cng_off);
11236369Ssklower /*
11336369Ssklower * Duplicate header, and remove from packet
11436369Ssklower */
11539232Ssklower if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
11636369Ssklower clnp_discard(m, GEN_CONGEST);
11736369Ssklower return(ENOBUFS);
11836369Ssklower }
11939232Ssklower m_adj(m, hdr_len);
12039232Ssklower
12136369Ssklower while (total_len > 0) {
12239232Ssklower int remaining, last_frag;
12336764Ssklower
12436764Ssklower IFDEBUG(D_FRAG)
12536764Ssklower struct mbuf *mdump = frag_hdr;
12636764Ssklower int tot_mlen = 0;
12736764Ssklower printf("clnp_fragment: total_len %d:\n", total_len);
12836764Ssklower while (mdump != NULL) {
12936764Ssklower printf("\tmbuf x%x, m_len %d\n",
13036764Ssklower mdump, mdump->m_len);
13136764Ssklower tot_mlen += mdump->m_len;
13236764Ssklower mdump = mdump->m_next;
13336764Ssklower }
13436764Ssklower printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen);
13536764Ssklower ENDDEBUG
13636369Ssklower
13739232Ssklower frag_size = min(total_len, frag_size);
13839232Ssklower if ((remaining = total_len - frag_size) == 0)
13939232Ssklower last_frag = 1;
14039232Ssklower else {
14139232Ssklower /*
14239232Ssklower * If this fragment will cause the last one to
14339232Ssklower * be less than 8 bytes, shorten this fragment a bit.
14439232Ssklower * The obscure test on frag_size above ensures that
14539232Ssklower * frag_size will be positive.
14639232Ssklower */
14739232Ssklower last_frag = 0;
14839232Ssklower if (remaining < 8)
14939232Ssklower frag_size -= 8;
15039232Ssklower }
15136369Ssklower
15236369Ssklower
15336369Ssklower IFDEBUG(D_FRAG)
15436369Ssklower printf("clnp_fragment: seg off %d, size %d, remaining %d\n",
15542865Ssklower ntohs(seg_part.cng_off), frag_size, total_len-frag_size);
15636369Ssklower if (last_frag)
15736369Ssklower printf("clnp_fragment: last fragment\n");
15836369Ssklower ENDDEBUG
15936369Ssklower
16036369Ssklower if (last_frag) {
16136369Ssklower /*
16236369Ssklower * this is the last fragment; we don't need to get any other
16336369Ssklower * mbufs.
16436369Ssklower */
16536369Ssklower frag_hdr = hdr;
16636369Ssklower frag_data = m;
16736369Ssklower } else {
16836369Ssklower /* duplicate header and data mbufs */
16937469Ssklower if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) {
17039232Ssklower clnp_discard(hdr, GEN_CONGEST);
17139232Ssklower m_freem(m);
17236369Ssklower return(ENOBUFS);
17336369Ssklower }
17436369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
17539232Ssklower clnp_discard(hdr, GEN_CONGEST);
17639232Ssklower m_freem(m);
17736369Ssklower m_freem(frag_hdr);
17836369Ssklower return(ENOBUFS);
17936369Ssklower }
18039195Ssklower INCSTAT(cns_fragments);
18136369Ssklower }
18236369Ssklower clnp = mtod(frag_hdr, struct clnp_fixed *);
18336369Ssklower
18436369Ssklower if (!last_frag)
18537469Ssklower clnp->cnf_type |= CNF_MORE_SEGS;
18636369Ssklower
18736369Ssklower /* link together */
18836369Ssklower m_cat(frag_hdr, frag_data);
18936369Ssklower
19042865Ssklower /* insert segmentation part; updated below */
19142865Ssklower bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff,
19236369Ssklower sizeof(struct clnp_segment));
19336369Ssklower
19436369Ssklower {
19539232Ssklower int derived_len = hdr_len + frag_size;
19636369Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
19737469Ssklower if ((frag_hdr->m_flags & M_PKTHDR) == 0)
19837469Ssklower panic("clnp_frag:lost header");
19937469Ssklower frag_hdr->m_pkthdr.len = derived_len;
20036369Ssklower }
20136369Ssklower /* compute clnp checksum (on header only) */
20236369Ssklower if (flags & CLNP_NO_CKSUM) {
20336369Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
20436369Ssklower } else {
20539232Ssklower iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len);
20636369Ssklower }
20736369Ssklower
20836369Ssklower IFDEBUG(D_DUMPOUT)
20936369Ssklower struct mbuf *mdump = frag_hdr;
21036369Ssklower printf("clnp_fragment: sending dg:\n");
21136369Ssklower while (mdump != NULL) {
21236764Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
21336369Ssklower mdump = mdump->m_next;
21436369Ssklower }
21536369Ssklower ENDDEBUG
21636369Ssklower
21736369Ssklower #ifdef TROLL
21840776Ssklower error = troll_output(ifp, frag_hdr, first_hop, rt);
21936369Ssklower #else
22040776Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt);
22161286Ssklower #endif /* TROLL */
22236369Ssklower
22336369Ssklower /*
22436369Ssklower * Tough situation: if the error occured on the last
22536369Ssklower * fragment, we can not send an ER, as the if_output
22636369Ssklower * routine consumed the packet. If the error occured
22736369Ssklower * on any intermediate packets, we can send an ER
22836369Ssklower * because we still have the original header in (m).
22936369Ssklower */
23036369Ssklower if (error) {
23136369Ssklower if (frag_hdr != hdr) {
23236369Ssklower /*
23336369Ssklower * The error was not on the last fragment. We must
23436369Ssklower * free hdr and m before returning
23536369Ssklower */
23639232Ssklower clnp_discard(hdr, GEN_NOREAS);
23739232Ssklower m_freem(m);
23836369Ssklower }
23936369Ssklower return(error);
24036369Ssklower }
24136369Ssklower
24236369Ssklower /* bump segment offset, trim data mbuf, and decrement count left */
24336369Ssklower #ifdef TROLL
24436369Ssklower /*
24536369Ssklower * Decrement frag_size by some fraction. This will cause the
24636369Ssklower * next fragment to start 'early', thus duplicating the end
24736369Ssklower * of the current fragment. troll.tr_dup_size controls
24836369Ssklower * the fraction. If positive, it specifies the fraction. If
24936369Ssklower * negative, a random fraction is used.
25036369Ssklower */
25136369Ssklower if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
25236369Ssklower int num_bytes = frag_size;
25336369Ssklower
25436369Ssklower if (trollctl.tr_dup_size > 0)
25536369Ssklower num_bytes *= trollctl.tr_dup_size;
25636369Ssklower else
25736369Ssklower num_bytes *= troll_random();
25836369Ssklower frag_size -= num_bytes;
25936369Ssklower }
26061286Ssklower #endif /* TROLL */
26136369Ssklower total_len -= frag_size;
26236369Ssklower if (!last_frag) {
26342865Ssklower frag_base += frag_size;
26442865Ssklower seg_part.cng_off = htons(frag_base);
26536369Ssklower m_adj(m, frag_size);
26636369Ssklower }
26736369Ssklower }
26836369Ssklower return(0);
26936369Ssklower } else {
27039232Ssklower cantfrag:
27139195Ssklower INCSTAT(cns_cantfrag);
27236369Ssklower clnp_discard(m, GEN_SEGNEEDED);
27336369Ssklower return(EMSGSIZE);
27436369Ssklower }
27536369Ssklower }
27636369Ssklower
27736369Ssklower /*
27836369Ssklower * FUNCTION: clnp_reass
27936369Ssklower *
28036369Ssklower * PURPOSE: Attempt to reassemble a clnp packet given the current
28136369Ssklower * fragment. If reassembly succeeds (all the fragments
28236369Ssklower * are present), then return a pointer to an mbuf chain
28336369Ssklower * containing the reassembled packet. This packet will
28436369Ssklower * appear in the mbufs as if it had just arrived in
28536369Ssklower * one piece.
28636369Ssklower *
28736369Ssklower * If reassembly fails, then save this fragment and
28836369Ssklower * return 0.
28936369Ssklower *
29036369Ssklower * RETURNS: Ptr to assembled packet, or 0
29136369Ssklower *
29236369Ssklower * SIDE EFFECTS:
29336369Ssklower *
29436369Ssklower * NOTES:
29536369Ssklower * clnp_slowtimo can not affect this code because clnpintr, and thus
29636369Ssklower * this code, is called at a higher priority than clnp_slowtimo.
29736369Ssklower */
29836369Ssklower struct mbuf *
clnp_reass(m,src,dst,seg)29936369Ssklower clnp_reass(m, src, dst, seg)
30036369Ssklower struct mbuf *m; /* new fragment */
30136369Ssklower struct iso_addr *src; /* src of new fragment */
30236369Ssklower struct iso_addr *dst; /* dst of new fragment */
30336369Ssklower struct clnp_segment *seg; /* segment part of fragment header */
30436369Ssklower {
30536369Ssklower register struct clnp_fragl *cfh;
30636369Ssklower
30736369Ssklower /* look for other fragments of this datagram */
30836369Ssklower for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
30942865Ssklower if (seg->cng_id == cfh->cfl_id &&
31042865Ssklower iso_addrmatch1(src, &cfh->cfl_src) &&
31142865Ssklower iso_addrmatch1(dst, &cfh->cfl_dst)) {
31236369Ssklower IFDEBUG(D_REASS)
31336369Ssklower printf("clnp_reass: found packet\n");
31436369Ssklower ENDDEBUG
31536369Ssklower /*
31636369Ssklower * There are other fragments here already. Lets see if
31736369Ssklower * this fragment is of any help
31836369Ssklower */
31936369Ssklower clnp_insert_frag(cfh, m, seg);
32042865Ssklower if (m = clnp_comp_pdu(cfh)) {
32142865Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
32242865Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb,
32342865Ssklower seg->cng_tot_len);
32442865Ssklower }
32542865Ssklower return (m);
32636369Ssklower }
32736369Ssklower }
32836369Ssklower
32936369Ssklower IFDEBUG(D_REASS)
33036369Ssklower printf("clnp_reass: new packet!\n");
33136369Ssklower ENDDEBUG
33236369Ssklower
33336369Ssklower /*
33436369Ssklower * This is the first fragment. If src is not consuming too many
33536369Ssklower * resources, then create a new fragment list and add
33636369Ssklower * this fragment to the list.
33736369Ssklower */
33836369Ssklower /* TODO: don't let one src hog all the reassembly buffers */
33936369Ssklower if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) {
34039195Ssklower INCSTAT(cns_fragdropped);
34136369Ssklower clnp_discard(m, GEN_CONGEST);
34236369Ssklower }
34336369Ssklower
34436369Ssklower return(NULL);
34536369Ssklower }
34636369Ssklower
34736369Ssklower /*
34836369Ssklower * FUNCTION: clnp_newpkt
34936369Ssklower *
35036369Ssklower * PURPOSE: Create the necessary structures to handle a new
35136369Ssklower * fragmented clnp packet.
35236369Ssklower *
35336369Ssklower * RETURNS: non-zero if it succeeds, zero if fails.
35436369Ssklower *
35536369Ssklower * SIDE EFFECTS:
35636369Ssklower *
35736369Ssklower * NOTES: Failure is only due to insufficient resources.
35836369Ssklower */
35936369Ssklower clnp_newpkt(m, src, dst, seg)
36036369Ssklower struct mbuf *m; /* new fragment */
36136369Ssklower struct iso_addr *src; /* src of new fragment */
36236369Ssklower struct iso_addr *dst; /* dst of new fragment */
36336369Ssklower struct clnp_segment *seg; /* segment part of fragment header */
36436369Ssklower {
36536369Ssklower register struct clnp_fragl *cfh;
36636369Ssklower register struct clnp_fixed *clnp;
36736369Ssklower struct mbuf *m0;
36836369Ssklower
36936369Ssklower clnp = mtod(m, struct clnp_fixed *);
37036369Ssklower
37136369Ssklower /*
37236369Ssklower * Allocate new clnp fragl structure to act as header of all fragments
37336369Ssklower * for this datagram.
37436369Ssklower */
37536369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE);
37636369Ssklower if (m0 == NULL) {
37736369Ssklower return (0);
37836369Ssklower }
37936369Ssklower cfh = mtod(m0, struct clnp_fragl *);
38036369Ssklower
38136369Ssklower /*
38236369Ssklower * Duplicate the header of this fragment, and save in cfh.
38336369Ssklower * Free m0 and return if m_copy does not succeed.
38436369Ssklower */
38537469Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) {
38636369Ssklower m_freem(m0);
38736369Ssklower return (0);
38836369Ssklower }
38936369Ssklower
39036369Ssklower /* Fill in rest of fragl structure */
39136369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr));
39236369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr));
39336369Ssklower cfh->cfl_id = seg->cng_id;
39436369Ssklower cfh->cfl_ttl = clnp->cnf_ttl;
39536369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
39636369Ssklower cfh->cfl_frags = NULL;
39736369Ssklower cfh->cfl_next = NULL;
39836369Ssklower
39936369Ssklower /* Insert into list of packets */
40036369Ssklower cfh->cfl_next = clnp_frags;
40136369Ssklower clnp_frags = cfh;
40236369Ssklower
40336369Ssklower /* Insert this fragment into list headed by cfh */
40436369Ssklower clnp_insert_frag(cfh, m, seg);
40536369Ssklower return(1);
40636369Ssklower }
40736369Ssklower
40836369Ssklower /*
40936369Ssklower * FUNCTION: clnp_insert_frag
41036369Ssklower *
41136369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'.
41236369Ssklower *
41336369Ssklower * RETURNS: nothing
41436369Ssklower *
41536369Ssklower * SIDE EFFECTS:
41636369Ssklower *
41736369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm.
41836369Ssklower * Each fragment in this list contains a clnp_frag
41936369Ssklower * structure followed by the data of the fragment.
42036369Ssklower * The clnp_frag structure actually lies on top of
42136369Ssklower * part of the old clnp header.
42236369Ssklower */
42336369Ssklower clnp_insert_frag(cfh, m, seg)
42436369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */
42536369Ssklower struct mbuf *m; /* new fragment */
42636369Ssklower struct clnp_segment *seg; /* segment part of fragment header */
42736369Ssklower {
42836369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */
42936369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */
43036369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */
43136369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */
43236369Ssklower u_short first; /* offset of first byte of initial pdu*/
43336369Ssklower u_short last; /* offset of last byte of initial pdu */
43436369Ssklower u_short fraglen;/* length of fragment */
43536369Ssklower
43636369Ssklower clnp = mtod(m, struct clnp_fixed *);
43736369Ssklower first = seg->cng_off;
43836369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
43936369Ssklower fraglen -= clnp->cnf_hdr_len;
44036369Ssklower last = (first + fraglen) - 1;
44136369Ssklower
44236369Ssklower IFDEBUG(D_REASS)
44336369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n",
44436369Ssklower first, last, fraglen);
44536369Ssklower printf("clnp_insert_frag: current fragments:\n");
44636369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
44736369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last);
44836369Ssklower }
44936369Ssklower ENDDEBUG
45036369Ssklower
45136369Ssklower if (cfh->cfl_frags != NULL) {
45236369Ssklower /*
45336369Ssklower * Find fragment which begins after the new one
45436369Ssklower */
45536369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) {
45636369Ssklower if (cf->cfr_first > first) {
45736369Ssklower cf_sub = cf;
45836369Ssklower break;
45936369Ssklower }
46036369Ssklower }
46136369Ssklower
46236369Ssklower IFDEBUG(D_REASS)
46336369Ssklower printf("clnp_insert_frag: Previous frag is ");
46436369Ssklower if (cf_prev == NULL)
46536369Ssklower printf("NULL\n");
46636369Ssklower else
46736369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last);
46836369Ssklower printf("clnp_insert_frag: Subsequent frag is ");
46936369Ssklower if (cf_sub == NULL)
47036369Ssklower printf("NULL\n");
47136369Ssklower else
47236369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last);
47336369Ssklower ENDDEBUG
47436369Ssklower
47536369Ssklower /*
47636369Ssklower * If there is a fragment before the new one, check if it
47736369Ssklower * overlaps the new one. If so, then trim the end of the
47836369Ssklower * previous one.
47936369Ssklower */
48036369Ssklower if (cf_prev != NULL) {
48136369Ssklower if (cf_prev->cfr_last > first) {
48236369Ssklower u_short overlap = cf_prev->cfr_last - first;
48336369Ssklower
48436369Ssklower IFDEBUG(D_REASS)
48536369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n",
48636369Ssklower overlap);
48736369Ssklower ENDDEBUG
48836369Ssklower
48936369Ssklower if (overlap > fraglen) {
49036369Ssklower /*
49136369Ssklower * The new fragment is entirely contained in the
49236369Ssklower * preceeding one. We can punt on the new frag
49336369Ssklower * completely.
49436369Ssklower */
49536369Ssklower m_freem(m);
49636369Ssklower return;
49736369Ssklower } else {
49836369Ssklower /* Trim data off of end of previous fragment */
49936369Ssklower /* inc overlap to prevent duplication of last byte */
50036369Ssklower overlap++;
50137469Ssklower m_adj(cf_prev->cfr_data, -(int)overlap);
50236369Ssklower cf_prev->cfr_last -= overlap;
50336369Ssklower }
50436369Ssklower }
50536369Ssklower }
50636369Ssklower
50736369Ssklower /*
50836369Ssklower * For all fragments past the new one, check if any data on
50936369Ssklower * the new one overlaps data on existing fragments. If so,
51036369Ssklower * then trim the extra data off the end of the new one.
51136369Ssklower */
51236369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
51336369Ssklower if (cf->cfr_first < last) {
51436369Ssklower u_short overlap = last - cf->cfr_first;
51536369Ssklower
51636369Ssklower IFDEBUG(D_REASS)
51736369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n",
51836369Ssklower overlap);
51936369Ssklower ENDDEBUG
52036369Ssklower
52136369Ssklower if (overlap > fraglen) {
52236369Ssklower /*
52336369Ssklower * The new fragment is entirely contained in the
52436369Ssklower * succeeding one. This should not happen, because
52536369Ssklower * early on in this code we scanned for the fragment
52636369Ssklower * which started after the new one!
52736369Ssklower */
52836369Ssklower m_freem(m);
52936369Ssklower printf("clnp_insert_frag: internal error!\n");
53036369Ssklower return;
53136369Ssklower } else {
53236369Ssklower /* Trim data off of end of new fragment */
53336369Ssklower /* inc overlap to prevent duplication of last byte */
53436369Ssklower overlap++;
53537469Ssklower m_adj(m, -(int)overlap);
53636369Ssklower last -= overlap;
53736369Ssklower }
53836369Ssklower }
53936369Ssklower }
54036369Ssklower }
54136369Ssklower
54236369Ssklower /*
54336369Ssklower * Insert the new fragment beween cf_prev and cf_sub
54436369Ssklower *
54536369Ssklower * Note: the clnp hdr is still in the mbuf.
54636369Ssklower * If the data of the mbuf is not word aligned, shave off enough
54736369Ssklower * so that it is. Then, cast the clnp_frag structure on top
54836369Ssklower * of the clnp header.
54936369Ssklower * The clnp_hdr will not be used again (as we already have
55036369Ssklower * saved a copy of it).
55136369Ssklower *
55236369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to
55336369Ssklower * the data of the packet. This is used when we coalesce fragments;
55436369Ssklower * the clnp_frag structure must be removed before joining mbufs.
55536369Ssklower */
55636369Ssklower {
55736369Ssklower int pad;
55836369Ssklower u_int bytes;
55936369Ssklower
56036369Ssklower /* determine if header is not word aligned */
56136369Ssklower pad = (int)clnp % 4;
56236369Ssklower if (pad < 0)
56336369Ssklower pad = -pad;
56436369Ssklower
56536369Ssklower /* bytes is number of bytes left in front of data */
56636369Ssklower bytes = clnp->cnf_hdr_len - pad;
56736369Ssklower
56836764Ssklower IFDEBUG(D_REASS)
56936764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n",
57036764Ssklower clnp, pad);
57136764Ssklower ENDDEBUG
57236764Ssklower
57336369Ssklower /* make it word aligned if necessary */
57436369Ssklower if (pad)
57536369Ssklower m_adj(m, pad);
57636369Ssklower
57736369Ssklower cf = mtod(m, struct clnp_frag *);
57836369Ssklower cf->cfr_bytes = bytes;
57936764Ssklower
58036764Ssklower IFDEBUG(D_REASS)
58136764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf,
58236764Ssklower cf->cfr_bytes);
58336764Ssklower ENDDEBUG
58436369Ssklower }
58536369Ssklower cf->cfr_first = first;
58636369Ssklower cf->cfr_last = last;
58736369Ssklower
58836369Ssklower
58936369Ssklower /*
59036369Ssklower * The data is the mbuf itself, although we must remember that the
59136369Ssklower * first few bytes are actually a clnp_frag structure
59236369Ssklower */
59336369Ssklower cf->cfr_data = m;
59436369Ssklower
59536369Ssklower /* link into place */
59636369Ssklower cf->cfr_next = cf_sub;
59736369Ssklower if (cf_prev == NULL)
59836369Ssklower cfh->cfl_frags = cf;
59936369Ssklower else
60036369Ssklower cf_prev->cfr_next = cf;
60136369Ssklower }
60236369Ssklower
60336369Ssklower /*
60436369Ssklower * FUNCTION: clnp_comp_pdu
60536369Ssklower *
60636369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge
60736369Ssklower * any contigious fragments into one. If, after
60836369Ssklower * traversing all the fragments, it is determined that
60936369Ssklower * the packet is complete, then return a pointer to
61036369Ssklower * the packet (with header prepended). Otherwise,
61136369Ssklower * return NULL.
61236369Ssklower *
61336369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain.
61436369Ssklower *
61536369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one.
61636369Ssklower *
61736369Ssklower * NOTES: This code assumes that there are no overlaps of
61836369Ssklower * fragment pdus.
61936369Ssklower */
62036369Ssklower struct mbuf *
clnp_comp_pdu(cfh)62136369Ssklower clnp_comp_pdu(cfh)
62236369Ssklower struct clnp_fragl *cfh; /* fragment header */
62336369Ssklower {
62436369Ssklower register struct clnp_frag *cf = cfh->cfl_frags;
62536369Ssklower
62636369Ssklower while (cf->cfr_next != NULL) {
62736369Ssklower register struct clnp_frag *cf_next = cf->cfr_next;
62836369Ssklower
62936369Ssklower IFDEBUG(D_REASS)
63036369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n",
63136369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
63236369Ssklower cf_next->cfr_last);
63336369Ssklower ENDDEBUG
63436369Ssklower
63536369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) {
63636369Ssklower /*
63736369Ssklower * Merge fragment cf and cf_next
63836369Ssklower *
63936369Ssklower * - update cf header
64036369Ssklower * - trim clnp_frag structure off of cf_next
64136369Ssklower * - append cf_next to cf
64236369Ssklower */
64336369Ssklower struct clnp_frag cf_next_hdr;
64436369Ssklower struct clnp_frag *next_frag;
64536369Ssklower
64636369Ssklower cf_next_hdr = *cf_next;
64736369Ssklower next_frag = cf_next->cfr_next;
64836369Ssklower
64936369Ssklower IFDEBUG(D_REASS)
65036369Ssklower struct mbuf *mdump;
65136764Ssklower int l;
65236369Ssklower printf("clnp_comp_pdu: merging fragments\n");
65336764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n",
65436764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes);
65536369Ssklower mdump = cf->cfr_data;
65636764Ssklower l = 0;
65736369Ssklower while (mdump != NULL) {
65836369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
65936764Ssklower l += mdump->m_len;
66036369Ssklower mdump = mdump->m_next;
66136369Ssklower }
66236764Ssklower printf("\ttotal len: %d\n", l);
66336764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n",
66436764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes);
66536369Ssklower mdump = cf_next->cfr_data;
66636764Ssklower l = 0;
66736369Ssklower while (mdump != NULL) {
66836369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len);
66936764Ssklower l += mdump->m_len;
67036369Ssklower mdump = mdump->m_next;
67136369Ssklower }
67236764Ssklower printf("\ttotal len: %d\n", l);
67336369Ssklower ENDDEBUG
67436369Ssklower
67536369Ssklower cf->cfr_last = cf_next->cfr_last;
67636369Ssklower /*
67736369Ssklower * After this m_adj, the cf_next ptr is useless because we
67836369Ssklower * have adjusted the clnp_frag structure away...
67936369Ssklower */
68036764Ssklower IFDEBUG(D_REASS)
68136764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n",
68236764Ssklower cf_next_hdr.cfr_bytes);
68336764Ssklower ENDDEBUG
68437469Ssklower m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes);
68536369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
68636369Ssklower cf->cfr_next = next_frag;
68736369Ssklower } else {
68836369Ssklower cf = cf->cfr_next;
68936369Ssklower }
69036369Ssklower }
69136369Ssklower
69236369Ssklower cf = cfh->cfl_frags;
69336369Ssklower
69436369Ssklower IFDEBUG(D_REASS)
69536369Ssklower struct mbuf *mdump = cf->cfr_data;
69636369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first,
69736369Ssklower cf->cfr_last);
69836369Ssklower printf("clnp_comp_pdu: data for frag:\n");
69936369Ssklower while (mdump != NULL) {
70036369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
70136369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
70236369Ssklower mdump = mdump->m_next;
70336369Ssklower }
70436369Ssklower ENDDEBUG
70536369Ssklower
70636369Ssklower /* Check if datagram is complete */
70736369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
70836369Ssklower /*
70936369Ssklower * We have a complete pdu!
71036369Ssklower * - Remove the frag header from (only) remaining fragment
71136369Ssklower * (which is not really a fragment anymore, as the datagram is
71236369Ssklower * complete).
71336369Ssklower * - Prepend a clnp header
71436369Ssklower */
71536369Ssklower struct mbuf *data = cf->cfr_data;
71636369Ssklower struct mbuf *hdr = cfh->cfl_orighdr;
71736369Ssklower struct clnp_fragl *scan;
71836369Ssklower
71936369Ssklower IFDEBUG(D_REASS)
72036369Ssklower printf("clnp_comp_pdu: complete pdu!\n");
72136369Ssklower ENDDEBUG
72236369Ssklower
72337469Ssklower m_adj(data, (int)cf->cfr_bytes);
72436369Ssklower m_cat(hdr, data);
72536369Ssklower
72636369Ssklower IFDEBUG(D_DUMPIN)
72736369Ssklower struct mbuf *mdump = hdr;
72836369Ssklower printf("clnp_comp_pdu: pdu is:\n");
72936369Ssklower while (mdump != NULL) {
73036369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len);
73136369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/
73236369Ssklower mdump = mdump->m_next;
73336369Ssklower }
73436369Ssklower ENDDEBUG
73536369Ssklower
73636369Ssklower /*
73736369Ssklower * Remove cfh from the list of fragmented pdus
73836369Ssklower */
73936369Ssklower if (clnp_frags == cfh) {
74036369Ssklower clnp_frags = cfh->cfl_next;
74136369Ssklower } else {
74236369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) {
74336369Ssklower if (scan->cfl_next == cfh) {
74436369Ssklower scan->cfl_next = cfh->cfl_next;
74536369Ssklower break;
74636369Ssklower }
74736369Ssklower }
74836369Ssklower }
74936369Ssklower
75036369Ssklower /* free cfh */
75136369Ssklower m_freem(dtom(cfh));
75236369Ssklower
75336369Ssklower return(hdr);
75436369Ssklower }
75536369Ssklower
75636369Ssklower return(NULL);
75736369Ssklower }
75836369Ssklower #ifdef TROLL
75937469Ssklower static int troll_cnt;
76056533Sbostic #include <sys/time.h>
76136369Ssklower /*
76236369Ssklower * FUNCTION: troll_random
76336369Ssklower *
76436369Ssklower * PURPOSE: generate a pseudo-random number between 0 and 1
76536369Ssklower *
76636369Ssklower * RETURNS: the random number
76736369Ssklower *
76836369Ssklower * SIDE EFFECTS:
76936369Ssklower *
77036369Ssklower * NOTES: This is based on the clock.
77136369Ssklower */
troll_random()77236369Ssklower float troll_random()
77336369Ssklower {
77436369Ssklower extern struct timeval time;
77536369Ssklower long t = time.tv_usec % 100;
77636369Ssklower
77736369Ssklower return((float)t / (float) 100);
77836369Ssklower }
77936369Ssklower
78036369Ssklower /*
78136369Ssklower * FUNCTION: troll_output
78236369Ssklower *
78336369Ssklower * PURPOSE: Do something sneaky with the datagram passed. Possible
78436369Ssklower * operations are:
78536369Ssklower * Duplicate the packet
78636369Ssklower * Drop the packet
78736369Ssklower * Trim some number of bytes from the packet
78836369Ssklower * Munge some byte in the packet
78936369Ssklower *
79036369Ssklower * RETURNS: 0, or unix error code
79136369Ssklower *
79236369Ssklower * SIDE EFFECTS:
79336369Ssklower *
79436369Ssklower * NOTES: The operation of this procedure is regulated by the
79536369Ssklower * troll control structure (Troll).
79636369Ssklower */
79740776Ssklower troll_output(ifp, m, dst, rt)
79836369Ssklower struct ifnet *ifp;
79936369Ssklower struct mbuf *m;
80036369Ssklower struct sockaddr *dst;
80140776Ssklower struct rtentry *rt;
80236369Ssklower {
80336369Ssklower int err = 0;
80436369Ssklower troll_cnt++;
80536369Ssklower
80636369Ssklower if (trollctl.tr_ops & TR_DUPPKT) {
80736369Ssklower /*
80836369Ssklower * Duplicate every Nth packet
80936369Ssklower * TODO: random?
81036369Ssklower */
81136369Ssklower float f_freq = troll_cnt * trollctl.tr_dup_freq;
81236369Ssklower int i_freq = troll_cnt * trollctl.tr_dup_freq;
81336369Ssklower if (i_freq == f_freq) {
81437469Ssklower struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL);
81536369Ssklower if (dup != NULL)
81640776Ssklower err = (*ifp->if_output)(ifp, dup, dst, rt);
81736369Ssklower }
81836369Ssklower if (!err)
81940776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt);
82036369Ssklower return(err);
82136369Ssklower } else if (trollctl.tr_ops & TR_DROPPKT) {
82236369Ssklower } else if (trollctl.tr_ops & TR_CHANGE) {
82336369Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
82436369Ssklower clnp->cnf_cksum_msb = 0;
82540776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt);
82636369Ssklower return(err);
82736369Ssklower } else {
82840776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt);
82936369Ssklower return(err);
83036369Ssklower }
83136369Ssklower }
83236369Ssklower
83361286Ssklower #endif /* TROLL */
834