149267Sbostic /*- 249267Sbostic * Copyright (c) 1991 The Regents of the University of California. 349267Sbostic * All rights reserved. 449267Sbostic * 549267Sbostic * %sccs.include.redist.c% 649267Sbostic * 7*56533Sbostic * @(#)clnp_frag.c 7.14 (Berkeley) 10/11/92 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 39*56533Sbostic #include <sys/param.h> 40*56533Sbostic #include <sys/systm.h> 41*56533Sbostic #include <sys/mbuf.h> 42*56533Sbostic #include <sys/domain.h> 43*56533Sbostic #include <sys/protosw.h> 44*56533Sbostic #include <sys/socket.h> 45*56533Sbostic #include <sys/socketvar.h> 46*56533Sbostic #include <sys/errno.h> 4736369Ssklower 48*56533Sbostic #include <net/if.h> 49*56533Sbostic #include <net/route.h> 5036369Ssklower 51*56533Sbostic #include <netiso/iso.h> 52*56533Sbostic #include <netiso/iso_var.h> 53*56533Sbostic #include <netiso/clnp.h> 54*56533Sbostic #include <netiso/clnp_stat.h> 55*56533Sbostic #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); 22136369Ssklower #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 } 26036369Ssklower #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 * 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 * 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; 760*56533Sbostic #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 */ 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 83336369Ssklower #endif TROLL 834