136369Ssklower /*********************************************************** 236369Ssklower Copyright IBM Corporation 1987 336369Ssklower 436369Ssklower All Rights Reserved 536369Ssklower 636369Ssklower Permission to use, copy, modify, and distribute this software and its 736369Ssklower documentation for any purpose and without fee is hereby granted, 836369Ssklower provided that the above copyright notice appear in all copies and that 936369Ssklower both that copyright notice and this permission notice appear in 1036369Ssklower supporting documentation, and that the name of IBM not be 1136369Ssklower used in advertising or publicity pertaining to distribution of the 1236369Ssklower software without specific, written prior permission. 1336369Ssklower 1436369Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536369Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636369Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736369Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836369Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936369Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036369Ssklower SOFTWARE. 2136369Ssklower 2236369Ssklower ******************************************************************/ 2336369Ssklower 2436369Ssklower /* 2536369Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636369Ssklower */ 2736764Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */ 2836764Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */ 29*48730Ssklower /* @(#)clnp_frag.c 7.11 (Berkeley) 04/26/91 */ 3036369Ssklower 3136369Ssklower #ifndef lint 3236764Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $"; 3336369Ssklower #endif lint 3436369Ssklower 3537536Smckusick #include "param.h" 3637536Smckusick #include "mbuf.h" 3737536Smckusick #include "domain.h" 3837536Smckusick #include "protosw.h" 3937536Smckusick #include "socket.h" 4037536Smckusick #include "socketvar.h" 4137536Smckusick #include "errno.h" 4236369Ssklower 4336369Ssklower #include "../net/if.h" 4436369Ssklower #include "../net/route.h" 4536369Ssklower 4637469Ssklower #include "iso.h" 4737469Ssklower #include "iso_var.h" 4837469Ssklower #include "clnp.h" 4937469Ssklower #include "clnp_stat.h" 5037469Ssklower #include "argo_debug.h" 5136369Ssklower 5236369Ssklower /* all fragments are hung off this list */ 5336369Ssklower struct clnp_fragl *clnp_frags = NULL; 5436369Ssklower 5536369Ssklower struct mbuf *clnp_comp_pdu(); 5636369Ssklower 5736369Ssklower 5836369Ssklower /* 5936369Ssklower * FUNCTION: clnp_fragment 6036369Ssklower * 6136369Ssklower * PURPOSE: Fragment a datagram, and send the itty bitty pieces 6236369Ssklower * out over an interface. 6336369Ssklower * 6436369Ssklower * RETURNS: success - 0 6536369Ssklower * failure - unix error code 6636369Ssklower * 6736369Ssklower * SIDE EFFECTS: 6836369Ssklower * 6936369Ssklower * NOTES: If there is an error sending the packet, clnp_discard 7036369Ssklower * is called to discard the packet and send an ER. If 7136369Ssklower * clnp_fragment was called from clnp_output, then 7236369Ssklower * we generated the packet, and should not send an 7336369Ssklower * ER -- clnp_emit_er will check for this. Otherwise, 7436369Ssklower * the packet was fragmented during forwarding. In this 7536369Ssklower * case, we ought to send an ER back. 7636369Ssklower */ 7740776Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt) 7836369Ssklower struct ifnet *ifp; /* ptr to outgoing interface */ 7936369Ssklower struct mbuf *m; /* ptr to packet */ 8036369Ssklower struct sockaddr *first_hop; /* ptr to first hop */ 8136369Ssklower int total_len; /* length of datagram */ 8236369Ssklower int segoff; /* offset of segpart in hdr */ 8336369Ssklower int flags; /* flags passed to clnp_output */ 8440776Ssklower struct rtentry *rt; /* route if direct ether */ 8536369Ssklower { 8639232Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 8739232Ssklower int hdr_len = (int)clnp->cnf_hdr_len; 88*48730Ssklower int frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7; 8936369Ssklower 9039232Ssklower total_len -= hdr_len; 9139232Ssklower if ((clnp->cnf_type & CNF_SEG_OK) && 9239232Ssklower (total_len >= 8) && 9339232Ssklower (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { 9436369Ssklower 9536369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 9636369Ssklower struct mbuf *frag_hdr = NULL; 9736369Ssklower struct mbuf *frag_data = NULL; 9842865Ssklower struct clnp_segment seg_part; /* segmentation header */ 9947598Ssklower int frag_base; 10036369Ssklower int error = 0; 10136369Ssklower 10239232Ssklower 10339195Ssklower INCSTAT(cns_fragmented); 10442865Ssklower (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part, 10542865Ssklower sizeof(seg_part)); 10642865Ssklower frag_base = ntohs(seg_part.cng_off); 10736369Ssklower /* 10836369Ssklower * Duplicate header, and remove from packet 10936369Ssklower */ 11039232Ssklower if ((hdr = m_copy(m, 0, hdr_len)) == NULL) { 11136369Ssklower clnp_discard(m, GEN_CONGEST); 11236369Ssklower return(ENOBUFS); 11336369Ssklower } 11439232Ssklower m_adj(m, hdr_len); 11539232Ssklower 11636369Ssklower while (total_len > 0) { 11739232Ssklower int remaining, last_frag; 11836764Ssklower 11936764Ssklower IFDEBUG(D_FRAG) 12036764Ssklower struct mbuf *mdump = frag_hdr; 12136764Ssklower int tot_mlen = 0; 12236764Ssklower printf("clnp_fragment: total_len %d:\n", total_len); 12336764Ssklower while (mdump != NULL) { 12436764Ssklower printf("\tmbuf x%x, m_len %d\n", 12536764Ssklower mdump, mdump->m_len); 12636764Ssklower tot_mlen += mdump->m_len; 12736764Ssklower mdump = mdump->m_next; 12836764Ssklower } 12936764Ssklower printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); 13036764Ssklower ENDDEBUG 13136369Ssklower 13239232Ssklower frag_size = min(total_len, frag_size); 13339232Ssklower if ((remaining = total_len - frag_size) == 0) 13439232Ssklower last_frag = 1; 13539232Ssklower else { 13639232Ssklower /* 13739232Ssklower * If this fragment will cause the last one to 13839232Ssklower * be less than 8 bytes, shorten this fragment a bit. 13939232Ssklower * The obscure test on frag_size above ensures that 14039232Ssklower * frag_size will be positive. 14139232Ssklower */ 14239232Ssklower last_frag = 0; 14339232Ssklower if (remaining < 8) 14439232Ssklower frag_size -= 8; 14539232Ssklower } 14636369Ssklower 14736369Ssklower 14836369Ssklower IFDEBUG(D_FRAG) 14936369Ssklower printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 15042865Ssklower ntohs(seg_part.cng_off), frag_size, total_len-frag_size); 15136369Ssklower if (last_frag) 15236369Ssklower printf("clnp_fragment: last fragment\n"); 15336369Ssklower ENDDEBUG 15436369Ssklower 15536369Ssklower if (last_frag) { 15636369Ssklower /* 15736369Ssklower * this is the last fragment; we don't need to get any other 15836369Ssklower * mbufs. 15936369Ssklower */ 16036369Ssklower frag_hdr = hdr; 16136369Ssklower frag_data = m; 16236369Ssklower } else { 16336369Ssklower /* duplicate header and data mbufs */ 16437469Ssklower if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { 16539232Ssklower clnp_discard(hdr, GEN_CONGEST); 16639232Ssklower m_freem(m); 16736369Ssklower return(ENOBUFS); 16836369Ssklower } 16936369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { 17039232Ssklower clnp_discard(hdr, GEN_CONGEST); 17139232Ssklower m_freem(m); 17236369Ssklower m_freem(frag_hdr); 17336369Ssklower return(ENOBUFS); 17436369Ssklower } 17539195Ssklower INCSTAT(cns_fragments); 17636369Ssklower } 17736369Ssklower clnp = mtod(frag_hdr, struct clnp_fixed *); 17836369Ssklower 17936369Ssklower if (!last_frag) 18037469Ssklower clnp->cnf_type |= CNF_MORE_SEGS; 18136369Ssklower 18236369Ssklower /* link together */ 18336369Ssklower m_cat(frag_hdr, frag_data); 18436369Ssklower 18542865Ssklower /* insert segmentation part; updated below */ 18642865Ssklower bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff, 18736369Ssklower sizeof(struct clnp_segment)); 18836369Ssklower 18936369Ssklower { 19039232Ssklower int derived_len = hdr_len + frag_size; 19136369Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); 19237469Ssklower if ((frag_hdr->m_flags & M_PKTHDR) == 0) 19337469Ssklower panic("clnp_frag:lost header"); 19437469Ssklower frag_hdr->m_pkthdr.len = derived_len; 19536369Ssklower } 19636369Ssklower /* compute clnp checksum (on header only) */ 19736369Ssklower if (flags & CLNP_NO_CKSUM) { 19836369Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 19936369Ssklower } else { 20039232Ssklower iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len); 20136369Ssklower } 20236369Ssklower 20336369Ssklower IFDEBUG(D_DUMPOUT) 20436369Ssklower struct mbuf *mdump = frag_hdr; 20536369Ssklower printf("clnp_fragment: sending dg:\n"); 20636369Ssklower while (mdump != NULL) { 20736764Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 20836369Ssklower mdump = mdump->m_next; 20936369Ssklower } 21036369Ssklower ENDDEBUG 21136369Ssklower 21236369Ssklower #ifdef TROLL 21340776Ssklower error = troll_output(ifp, frag_hdr, first_hop, rt); 21436369Ssklower #else 21540776Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt); 21636369Ssklower #endif TROLL 21736369Ssklower 21836369Ssklower /* 21936369Ssklower * Tough situation: if the error occured on the last 22036369Ssklower * fragment, we can not send an ER, as the if_output 22136369Ssklower * routine consumed the packet. If the error occured 22236369Ssklower * on any intermediate packets, we can send an ER 22336369Ssklower * because we still have the original header in (m). 22436369Ssklower */ 22536369Ssklower if (error) { 22636369Ssklower if (frag_hdr != hdr) { 22736369Ssklower /* 22836369Ssklower * The error was not on the last fragment. We must 22936369Ssklower * free hdr and m before returning 23036369Ssklower */ 23139232Ssklower clnp_discard(hdr, GEN_NOREAS); 23239232Ssklower m_freem(m); 23336369Ssklower } 23436369Ssklower return(error); 23536369Ssklower } 23636369Ssklower 23736369Ssklower /* bump segment offset, trim data mbuf, and decrement count left */ 23836369Ssklower #ifdef TROLL 23936369Ssklower /* 24036369Ssklower * Decrement frag_size by some fraction. This will cause the 24136369Ssklower * next fragment to start 'early', thus duplicating the end 24236369Ssklower * of the current fragment. troll.tr_dup_size controls 24336369Ssklower * the fraction. If positive, it specifies the fraction. If 24436369Ssklower * negative, a random fraction is used. 24536369Ssklower */ 24636369Ssklower if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { 24736369Ssklower int num_bytes = frag_size; 24836369Ssklower 24936369Ssklower if (trollctl.tr_dup_size > 0) 25036369Ssklower num_bytes *= trollctl.tr_dup_size; 25136369Ssklower else 25236369Ssklower num_bytes *= troll_random(); 25336369Ssklower frag_size -= num_bytes; 25436369Ssklower } 25536369Ssklower #endif TROLL 25636369Ssklower total_len -= frag_size; 25736369Ssklower if (!last_frag) { 25842865Ssklower frag_base += frag_size; 25942865Ssklower seg_part.cng_off = htons(frag_base); 26036369Ssklower m_adj(m, frag_size); 26136369Ssklower } 26236369Ssklower } 26336369Ssklower return(0); 26436369Ssklower } else { 26539232Ssklower cantfrag: 26639195Ssklower INCSTAT(cns_cantfrag); 26736369Ssklower clnp_discard(m, GEN_SEGNEEDED); 26836369Ssklower return(EMSGSIZE); 26936369Ssklower } 27036369Ssklower } 27136369Ssklower 27236369Ssklower /* 27336369Ssklower * FUNCTION: clnp_reass 27436369Ssklower * 27536369Ssklower * PURPOSE: Attempt to reassemble a clnp packet given the current 27636369Ssklower * fragment. If reassembly succeeds (all the fragments 27736369Ssklower * are present), then return a pointer to an mbuf chain 27836369Ssklower * containing the reassembled packet. This packet will 27936369Ssklower * appear in the mbufs as if it had just arrived in 28036369Ssklower * one piece. 28136369Ssklower * 28236369Ssklower * If reassembly fails, then save this fragment and 28336369Ssklower * return 0. 28436369Ssklower * 28536369Ssklower * RETURNS: Ptr to assembled packet, or 0 28636369Ssklower * 28736369Ssklower * SIDE EFFECTS: 28836369Ssklower * 28936369Ssklower * NOTES: 29036369Ssklower * clnp_slowtimo can not affect this code because clnpintr, and thus 29136369Ssklower * this code, is called at a higher priority than clnp_slowtimo. 29236369Ssklower */ 29336369Ssklower struct mbuf * 29436369Ssklower clnp_reass(m, src, dst, seg) 29536369Ssklower struct mbuf *m; /* new fragment */ 29636369Ssklower struct iso_addr *src; /* src of new fragment */ 29736369Ssklower struct iso_addr *dst; /* dst of new fragment */ 29836369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 29936369Ssklower { 30036369Ssklower register struct clnp_fragl *cfh; 30136369Ssklower 30236369Ssklower /* look for other fragments of this datagram */ 30336369Ssklower for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { 30442865Ssklower if (seg->cng_id == cfh->cfl_id && 30542865Ssklower iso_addrmatch1(src, &cfh->cfl_src) && 30642865Ssklower iso_addrmatch1(dst, &cfh->cfl_dst)) { 30736369Ssklower IFDEBUG(D_REASS) 30836369Ssklower printf("clnp_reass: found packet\n"); 30936369Ssklower ENDDEBUG 31036369Ssklower /* 31136369Ssklower * There are other fragments here already. Lets see if 31236369Ssklower * this fragment is of any help 31336369Ssklower */ 31436369Ssklower clnp_insert_frag(cfh, m, seg); 31542865Ssklower if (m = clnp_comp_pdu(cfh)) { 31642865Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 31742865Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, 31842865Ssklower seg->cng_tot_len); 31942865Ssklower } 32042865Ssklower return (m); 32136369Ssklower } 32236369Ssklower } 32336369Ssklower 32436369Ssklower IFDEBUG(D_REASS) 32536369Ssklower printf("clnp_reass: new packet!\n"); 32636369Ssklower ENDDEBUG 32736369Ssklower 32836369Ssklower /* 32936369Ssklower * This is the first fragment. If src is not consuming too many 33036369Ssklower * resources, then create a new fragment list and add 33136369Ssklower * this fragment to the list. 33236369Ssklower */ 33336369Ssklower /* TODO: don't let one src hog all the reassembly buffers */ 33436369Ssklower if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { 33539195Ssklower INCSTAT(cns_fragdropped); 33636369Ssklower clnp_discard(m, GEN_CONGEST); 33736369Ssklower } 33836369Ssklower 33936369Ssklower return(NULL); 34036369Ssklower } 34136369Ssklower 34236369Ssklower /* 34336369Ssklower * FUNCTION: clnp_newpkt 34436369Ssklower * 34536369Ssklower * PURPOSE: Create the necessary structures to handle a new 34636369Ssklower * fragmented clnp packet. 34736369Ssklower * 34836369Ssklower * RETURNS: non-zero if it succeeds, zero if fails. 34936369Ssklower * 35036369Ssklower * SIDE EFFECTS: 35136369Ssklower * 35236369Ssklower * NOTES: Failure is only due to insufficient resources. 35336369Ssklower */ 35436369Ssklower clnp_newpkt(m, src, dst, seg) 35536369Ssklower struct mbuf *m; /* new fragment */ 35636369Ssklower struct iso_addr *src; /* src of new fragment */ 35736369Ssklower struct iso_addr *dst; /* dst of new fragment */ 35836369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 35936369Ssklower { 36036369Ssklower register struct clnp_fragl *cfh; 36136369Ssklower register struct clnp_fixed *clnp; 36236369Ssklower struct mbuf *m0; 36336369Ssklower 36436369Ssklower clnp = mtod(m, struct clnp_fixed *); 36536369Ssklower 36636369Ssklower /* 36736369Ssklower * Allocate new clnp fragl structure to act as header of all fragments 36836369Ssklower * for this datagram. 36936369Ssklower */ 37036369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE); 37136369Ssklower if (m0 == NULL) { 37236369Ssklower return (0); 37336369Ssklower } 37436369Ssklower cfh = mtod(m0, struct clnp_fragl *); 37536369Ssklower 37636369Ssklower /* 37736369Ssklower * Duplicate the header of this fragment, and save in cfh. 37836369Ssklower * Free m0 and return if m_copy does not succeed. 37936369Ssklower */ 38037469Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 38136369Ssklower m_freem(m0); 38236369Ssklower return (0); 38336369Ssklower } 38436369Ssklower 38536369Ssklower /* Fill in rest of fragl structure */ 38636369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 38736369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 38836369Ssklower cfh->cfl_id = seg->cng_id; 38936369Ssklower cfh->cfl_ttl = clnp->cnf_ttl; 39036369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 39136369Ssklower cfh->cfl_frags = NULL; 39236369Ssklower cfh->cfl_next = NULL; 39336369Ssklower 39436369Ssklower /* Insert into list of packets */ 39536369Ssklower cfh->cfl_next = clnp_frags; 39636369Ssklower clnp_frags = cfh; 39736369Ssklower 39836369Ssklower /* Insert this fragment into list headed by cfh */ 39936369Ssklower clnp_insert_frag(cfh, m, seg); 40036369Ssklower return(1); 40136369Ssklower } 40236369Ssklower 40336369Ssklower /* 40436369Ssklower * FUNCTION: clnp_insert_frag 40536369Ssklower * 40636369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'. 40736369Ssklower * 40836369Ssklower * RETURNS: nothing 40936369Ssklower * 41036369Ssklower * SIDE EFFECTS: 41136369Ssklower * 41236369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm. 41336369Ssklower * Each fragment in this list contains a clnp_frag 41436369Ssklower * structure followed by the data of the fragment. 41536369Ssklower * The clnp_frag structure actually lies on top of 41636369Ssklower * part of the old clnp header. 41736369Ssklower */ 41836369Ssklower clnp_insert_frag(cfh, m, seg) 41936369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */ 42036369Ssklower struct mbuf *m; /* new fragment */ 42136369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 42236369Ssklower { 42336369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 42436369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */ 42536369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 42636369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 42736369Ssklower u_short first; /* offset of first byte of initial pdu*/ 42836369Ssklower u_short last; /* offset of last byte of initial pdu */ 42936369Ssklower u_short fraglen;/* length of fragment */ 43036369Ssklower 43136369Ssklower clnp = mtod(m, struct clnp_fixed *); 43236369Ssklower first = seg->cng_off; 43336369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 43436369Ssklower fraglen -= clnp->cnf_hdr_len; 43536369Ssklower last = (first + fraglen) - 1; 43636369Ssklower 43736369Ssklower IFDEBUG(D_REASS) 43836369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 43936369Ssklower first, last, fraglen); 44036369Ssklower printf("clnp_insert_frag: current fragments:\n"); 44136369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 44236369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 44336369Ssklower } 44436369Ssklower ENDDEBUG 44536369Ssklower 44636369Ssklower if (cfh->cfl_frags != NULL) { 44736369Ssklower /* 44836369Ssklower * Find fragment which begins after the new one 44936369Ssklower */ 45036369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 45136369Ssklower if (cf->cfr_first > first) { 45236369Ssklower cf_sub = cf; 45336369Ssklower break; 45436369Ssklower } 45536369Ssklower } 45636369Ssklower 45736369Ssklower IFDEBUG(D_REASS) 45836369Ssklower printf("clnp_insert_frag: Previous frag is "); 45936369Ssklower if (cf_prev == NULL) 46036369Ssklower printf("NULL\n"); 46136369Ssklower else 46236369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 46336369Ssklower printf("clnp_insert_frag: Subsequent frag is "); 46436369Ssklower if (cf_sub == NULL) 46536369Ssklower printf("NULL\n"); 46636369Ssklower else 46736369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 46836369Ssklower ENDDEBUG 46936369Ssklower 47036369Ssklower /* 47136369Ssklower * If there is a fragment before the new one, check if it 47236369Ssklower * overlaps the new one. If so, then trim the end of the 47336369Ssklower * previous one. 47436369Ssklower */ 47536369Ssklower if (cf_prev != NULL) { 47636369Ssklower if (cf_prev->cfr_last > first) { 47736369Ssklower u_short overlap = cf_prev->cfr_last - first; 47836369Ssklower 47936369Ssklower IFDEBUG(D_REASS) 48036369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n", 48136369Ssklower overlap); 48236369Ssklower ENDDEBUG 48336369Ssklower 48436369Ssklower if (overlap > fraglen) { 48536369Ssklower /* 48636369Ssklower * The new fragment is entirely contained in the 48736369Ssklower * preceeding one. We can punt on the new frag 48836369Ssklower * completely. 48936369Ssklower */ 49036369Ssklower m_freem(m); 49136369Ssklower return; 49236369Ssklower } else { 49336369Ssklower /* Trim data off of end of previous fragment */ 49436369Ssklower /* inc overlap to prevent duplication of last byte */ 49536369Ssklower overlap++; 49637469Ssklower m_adj(cf_prev->cfr_data, -(int)overlap); 49736369Ssklower cf_prev->cfr_last -= overlap; 49836369Ssklower } 49936369Ssklower } 50036369Ssklower } 50136369Ssklower 50236369Ssklower /* 50336369Ssklower * For all fragments past the new one, check if any data on 50436369Ssklower * the new one overlaps data on existing fragments. If so, 50536369Ssklower * then trim the extra data off the end of the new one. 50636369Ssklower */ 50736369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 50836369Ssklower if (cf->cfr_first < last) { 50936369Ssklower u_short overlap = last - cf->cfr_first; 51036369Ssklower 51136369Ssklower IFDEBUG(D_REASS) 51236369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n", 51336369Ssklower overlap); 51436369Ssklower ENDDEBUG 51536369Ssklower 51636369Ssklower if (overlap > fraglen) { 51736369Ssklower /* 51836369Ssklower * The new fragment is entirely contained in the 51936369Ssklower * succeeding one. This should not happen, because 52036369Ssklower * early on in this code we scanned for the fragment 52136369Ssklower * which started after the new one! 52236369Ssklower */ 52336369Ssklower m_freem(m); 52436369Ssklower printf("clnp_insert_frag: internal error!\n"); 52536369Ssklower return; 52636369Ssklower } else { 52736369Ssklower /* Trim data off of end of new fragment */ 52836369Ssklower /* inc overlap to prevent duplication of last byte */ 52936369Ssklower overlap++; 53037469Ssklower m_adj(m, -(int)overlap); 53136369Ssklower last -= overlap; 53236369Ssklower } 53336369Ssklower } 53436369Ssklower } 53536369Ssklower } 53636369Ssklower 53736369Ssklower /* 53836369Ssklower * Insert the new fragment beween cf_prev and cf_sub 53936369Ssklower * 54036369Ssklower * Note: the clnp hdr is still in the mbuf. 54136369Ssklower * If the data of the mbuf is not word aligned, shave off enough 54236369Ssklower * so that it is. Then, cast the clnp_frag structure on top 54336369Ssklower * of the clnp header. 54436369Ssklower * The clnp_hdr will not be used again (as we already have 54536369Ssklower * saved a copy of it). 54636369Ssklower * 54736369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to 54836369Ssklower * the data of the packet. This is used when we coalesce fragments; 54936369Ssklower * the clnp_frag structure must be removed before joining mbufs. 55036369Ssklower */ 55136369Ssklower { 55236369Ssklower int pad; 55336369Ssklower u_int bytes; 55436369Ssklower 55536369Ssklower /* determine if header is not word aligned */ 55636369Ssklower pad = (int)clnp % 4; 55736369Ssklower if (pad < 0) 55836369Ssklower pad = -pad; 55936369Ssklower 56036369Ssklower /* bytes is number of bytes left in front of data */ 56136369Ssklower bytes = clnp->cnf_hdr_len - pad; 56236369Ssklower 56336764Ssklower IFDEBUG(D_REASS) 56436764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 56536764Ssklower clnp, pad); 56636764Ssklower ENDDEBUG 56736764Ssklower 56836369Ssklower /* make it word aligned if necessary */ 56936369Ssklower if (pad) 57036369Ssklower m_adj(m, pad); 57136369Ssklower 57236369Ssklower cf = mtod(m, struct clnp_frag *); 57336369Ssklower cf->cfr_bytes = bytes; 57436764Ssklower 57536764Ssklower IFDEBUG(D_REASS) 57636764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 57736764Ssklower cf->cfr_bytes); 57836764Ssklower ENDDEBUG 57936369Ssklower } 58036369Ssklower cf->cfr_first = first; 58136369Ssklower cf->cfr_last = last; 58236369Ssklower 58336369Ssklower 58436369Ssklower /* 58536369Ssklower * The data is the mbuf itself, although we must remember that the 58636369Ssklower * first few bytes are actually a clnp_frag structure 58736369Ssklower */ 58836369Ssklower cf->cfr_data = m; 58936369Ssklower 59036369Ssklower /* link into place */ 59136369Ssklower cf->cfr_next = cf_sub; 59236369Ssklower if (cf_prev == NULL) 59336369Ssklower cfh->cfl_frags = cf; 59436369Ssklower else 59536369Ssklower cf_prev->cfr_next = cf; 59636369Ssklower } 59736369Ssklower 59836369Ssklower /* 59936369Ssklower * FUNCTION: clnp_comp_pdu 60036369Ssklower * 60136369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge 60236369Ssklower * any contigious fragments into one. If, after 60336369Ssklower * traversing all the fragments, it is determined that 60436369Ssklower * the packet is complete, then return a pointer to 60536369Ssklower * the packet (with header prepended). Otherwise, 60636369Ssklower * return NULL. 60736369Ssklower * 60836369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 60936369Ssklower * 61036369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one. 61136369Ssklower * 61236369Ssklower * NOTES: This code assumes that there are no overlaps of 61336369Ssklower * fragment pdus. 61436369Ssklower */ 61536369Ssklower struct mbuf * 61636369Ssklower clnp_comp_pdu(cfh) 61736369Ssklower struct clnp_fragl *cfh; /* fragment header */ 61836369Ssklower { 61936369Ssklower register struct clnp_frag *cf = cfh->cfl_frags; 62036369Ssklower 62136369Ssklower while (cf->cfr_next != NULL) { 62236369Ssklower register struct clnp_frag *cf_next = cf->cfr_next; 62336369Ssklower 62436369Ssklower IFDEBUG(D_REASS) 62536369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 62636369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 62736369Ssklower cf_next->cfr_last); 62836369Ssklower ENDDEBUG 62936369Ssklower 63036369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) { 63136369Ssklower /* 63236369Ssklower * Merge fragment cf and cf_next 63336369Ssklower * 63436369Ssklower * - update cf header 63536369Ssklower * - trim clnp_frag structure off of cf_next 63636369Ssklower * - append cf_next to cf 63736369Ssklower */ 63836369Ssklower struct clnp_frag cf_next_hdr; 63936369Ssklower struct clnp_frag *next_frag; 64036369Ssklower 64136369Ssklower cf_next_hdr = *cf_next; 64236369Ssklower next_frag = cf_next->cfr_next; 64336369Ssklower 64436369Ssklower IFDEBUG(D_REASS) 64536369Ssklower struct mbuf *mdump; 64636764Ssklower int l; 64736369Ssklower printf("clnp_comp_pdu: merging fragments\n"); 64836764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 64936764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 65036369Ssklower mdump = cf->cfr_data; 65136764Ssklower l = 0; 65236369Ssklower while (mdump != NULL) { 65336369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 65436764Ssklower l += mdump->m_len; 65536369Ssklower mdump = mdump->m_next; 65636369Ssklower } 65736764Ssklower printf("\ttotal len: %d\n", l); 65836764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 65936764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 66036369Ssklower mdump = cf_next->cfr_data; 66136764Ssklower l = 0; 66236369Ssklower while (mdump != NULL) { 66336369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 66436764Ssklower l += mdump->m_len; 66536369Ssklower mdump = mdump->m_next; 66636369Ssklower } 66736764Ssklower printf("\ttotal len: %d\n", l); 66836369Ssklower ENDDEBUG 66936369Ssklower 67036369Ssklower cf->cfr_last = cf_next->cfr_last; 67136369Ssklower /* 67236369Ssklower * After this m_adj, the cf_next ptr is useless because we 67336369Ssklower * have adjusted the clnp_frag structure away... 67436369Ssklower */ 67536764Ssklower IFDEBUG(D_REASS) 67636764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n", 67736764Ssklower cf_next_hdr.cfr_bytes); 67836764Ssklower ENDDEBUG 67937469Ssklower m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); 68036369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 68136369Ssklower cf->cfr_next = next_frag; 68236369Ssklower } else { 68336369Ssklower cf = cf->cfr_next; 68436369Ssklower } 68536369Ssklower } 68636369Ssklower 68736369Ssklower cf = cfh->cfl_frags; 68836369Ssklower 68936369Ssklower IFDEBUG(D_REASS) 69036369Ssklower struct mbuf *mdump = cf->cfr_data; 69136369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 69236369Ssklower cf->cfr_last); 69336369Ssklower printf("clnp_comp_pdu: data for frag:\n"); 69436369Ssklower while (mdump != NULL) { 69536369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 69636369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 69736369Ssklower mdump = mdump->m_next; 69836369Ssklower } 69936369Ssklower ENDDEBUG 70036369Ssklower 70136369Ssklower /* Check if datagram is complete */ 70236369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 70336369Ssklower /* 70436369Ssklower * We have a complete pdu! 70536369Ssklower * - Remove the frag header from (only) remaining fragment 70636369Ssklower * (which is not really a fragment anymore, as the datagram is 70736369Ssklower * complete). 70836369Ssklower * - Prepend a clnp header 70936369Ssklower */ 71036369Ssklower struct mbuf *data = cf->cfr_data; 71136369Ssklower struct mbuf *hdr = cfh->cfl_orighdr; 71236369Ssklower struct clnp_fragl *scan; 71336369Ssklower 71436369Ssklower IFDEBUG(D_REASS) 71536369Ssklower printf("clnp_comp_pdu: complete pdu!\n"); 71636369Ssklower ENDDEBUG 71736369Ssklower 71837469Ssklower m_adj(data, (int)cf->cfr_bytes); 71936369Ssklower m_cat(hdr, data); 72036369Ssklower 72136369Ssklower IFDEBUG(D_DUMPIN) 72236369Ssklower struct mbuf *mdump = hdr; 72336369Ssklower printf("clnp_comp_pdu: pdu is:\n"); 72436369Ssklower while (mdump != NULL) { 72536369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 72636369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 72736369Ssklower mdump = mdump->m_next; 72836369Ssklower } 72936369Ssklower ENDDEBUG 73036369Ssklower 73136369Ssklower /* 73236369Ssklower * Remove cfh from the list of fragmented pdus 73336369Ssklower */ 73436369Ssklower if (clnp_frags == cfh) { 73536369Ssklower clnp_frags = cfh->cfl_next; 73636369Ssklower } else { 73736369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 73836369Ssklower if (scan->cfl_next == cfh) { 73936369Ssklower scan->cfl_next = cfh->cfl_next; 74036369Ssklower break; 74136369Ssklower } 74236369Ssklower } 74336369Ssklower } 74436369Ssklower 74536369Ssklower /* free cfh */ 74636369Ssklower m_freem(dtom(cfh)); 74736369Ssklower 74836369Ssklower return(hdr); 74936369Ssklower } 75036369Ssklower 75136369Ssklower return(NULL); 75236369Ssklower } 75336369Ssklower #ifdef TROLL 75437469Ssklower static int troll_cnt; 75537536Smckusick #include "time.h" 75636369Ssklower /* 75736369Ssklower * FUNCTION: troll_random 75836369Ssklower * 75936369Ssklower * PURPOSE: generate a pseudo-random number between 0 and 1 76036369Ssklower * 76136369Ssklower * RETURNS: the random number 76236369Ssklower * 76336369Ssklower * SIDE EFFECTS: 76436369Ssklower * 76536369Ssklower * NOTES: This is based on the clock. 76636369Ssklower */ 76736369Ssklower float troll_random() 76836369Ssklower { 76936369Ssklower extern struct timeval time; 77036369Ssklower long t = time.tv_usec % 100; 77136369Ssklower 77236369Ssklower return((float)t / (float) 100); 77336369Ssklower } 77436369Ssklower 77536369Ssklower /* 77636369Ssklower * FUNCTION: troll_output 77736369Ssklower * 77836369Ssklower * PURPOSE: Do something sneaky with the datagram passed. Possible 77936369Ssklower * operations are: 78036369Ssklower * Duplicate the packet 78136369Ssklower * Drop the packet 78236369Ssklower * Trim some number of bytes from the packet 78336369Ssklower * Munge some byte in the packet 78436369Ssklower * 78536369Ssklower * RETURNS: 0, or unix error code 78636369Ssklower * 78736369Ssklower * SIDE EFFECTS: 78836369Ssklower * 78936369Ssklower * NOTES: The operation of this procedure is regulated by the 79036369Ssklower * troll control structure (Troll). 79136369Ssklower */ 79240776Ssklower troll_output(ifp, m, dst, rt) 79336369Ssklower struct ifnet *ifp; 79436369Ssklower struct mbuf *m; 79536369Ssklower struct sockaddr *dst; 79640776Ssklower struct rtentry *rt; 79736369Ssklower { 79836369Ssklower int err = 0; 79936369Ssklower troll_cnt++; 80036369Ssklower 80136369Ssklower if (trollctl.tr_ops & TR_DUPPKT) { 80236369Ssklower /* 80336369Ssklower * Duplicate every Nth packet 80436369Ssklower * TODO: random? 80536369Ssklower */ 80636369Ssklower float f_freq = troll_cnt * trollctl.tr_dup_freq; 80736369Ssklower int i_freq = troll_cnt * trollctl.tr_dup_freq; 80836369Ssklower if (i_freq == f_freq) { 80937469Ssklower struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); 81036369Ssklower if (dup != NULL) 81140776Ssklower err = (*ifp->if_output)(ifp, dup, dst, rt); 81236369Ssklower } 81336369Ssklower if (!err) 81440776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 81536369Ssklower return(err); 81636369Ssklower } else if (trollctl.tr_ops & TR_DROPPKT) { 81736369Ssklower } else if (trollctl.tr_ops & TR_CHANGE) { 81836369Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 81936369Ssklower clnp->cnf_cksum_msb = 0; 82040776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 82136369Ssklower return(err); 82236369Ssklower } else { 82340776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 82436369Ssklower return(err); 82536369Ssklower } 82636369Ssklower } 82736369Ssklower 82836369Ssklower #endif TROLL 829