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*39232Ssklower /* @(#)clnp_frag.c 7.7 (Berkeley) 09/26/89 */ 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 */ 7736369Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags) 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 */ 8436369Ssklower { 85*39232Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 86*39232Ssklower int hdr_len = (int)clnp->cnf_hdr_len; 87*39232Ssklower int frag_size = (ifp->if_mtu - hdr_len) & ~7; 8836369Ssklower 89*39232Ssklower total_len -= hdr_len; 90*39232Ssklower if ((clnp->cnf_type & CNF_SEG_OK) && 91*39232Ssklower (total_len >= 8) && 92*39232Ssklower (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { 9336369Ssklower 9436369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 9536369Ssklower struct mbuf *frag_hdr = NULL; 9636369Ssklower struct mbuf *frag_data = NULL; 9736369Ssklower struct clnp_segment seg_part, tmp_seg; /* segmentation header */ 9836369Ssklower extern int clnp_id; /* id of datagram */ 99*39232Ssklower int frag_size; 10036369Ssklower int error = 0; 10136369Ssklower 102*39232Ssklower 10339195Ssklower INCSTAT(cns_fragmented); 10436369Ssklower seg_part.cng_id = clnp_id++; 10536369Ssklower seg_part.cng_off = 0; 106*39232Ssklower seg_part.cng_tot_len = total_len + hdr_len; 10736369Ssklower /* 10836369Ssklower * Duplicate header, and remove from packet 10936369Ssklower */ 110*39232Ssklower if ((hdr = m_copy(m, 0, hdr_len)) == NULL) { 11136369Ssklower clnp_discard(m, GEN_CONGEST); 11236369Ssklower return(ENOBUFS); 11336369Ssklower } 114*39232Ssklower m_adj(m, hdr_len); 115*39232Ssklower 11636369Ssklower while (total_len > 0) { 117*39232Ssklower 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 132*39232Ssklower frag_size = min(total_len, frag_size); 133*39232Ssklower if ((remaining = total_len - frag_size) == 0) 134*39232Ssklower last_frag = 1; 135*39232Ssklower else { 136*39232Ssklower /* 137*39232Ssklower * If this fragment will cause the last one to 138*39232Ssklower * be less than 8 bytes, shorten this fragment a bit. 139*39232Ssklower * The obscure test on frag_size above ensures that 140*39232Ssklower * frag_size will be positive. 141*39232Ssklower */ 142*39232Ssklower last_frag = 0; 143*39232Ssklower if (remaining < 8) 144*39232Ssklower frag_size -= 8; 145*39232Ssklower } 14636369Ssklower 14736369Ssklower 14836369Ssklower IFDEBUG(D_FRAG) 14936369Ssklower printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 15036369Ssklower 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) { 165*39232Ssklower clnp_discard(hdr, GEN_CONGEST); 166*39232Ssklower m_freem(m); 16736369Ssklower return(ENOBUFS); 16836369Ssklower } 16936369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { 170*39232Ssklower clnp_discard(hdr, GEN_CONGEST); 171*39232Ssklower 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 18536369Ssklower /* make sure segmentation fields are in network order */ 18636369Ssklower tmp_seg.cng_id = htons(seg_part.cng_id); 18736369Ssklower tmp_seg.cng_off = htons(seg_part.cng_off); 18836369Ssklower tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len); 18936369Ssklower 19036369Ssklower /* insert segmentation part */ 19136369Ssklower bcopy((caddr_t)&tmp_seg, mtod(frag_hdr, caddr_t) + segoff, 19236369Ssklower sizeof(struct clnp_segment)); 19336369Ssklower 19436369Ssklower { 195*39232Ssklower 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 { 205*39232Ssklower 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 21836369Ssklower error = troll_output(ifp, frag_hdr, first_hop); 21936369Ssklower #else 22036369Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop); 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 */ 236*39232Ssklower clnp_discard(hdr, GEN_NOREAS); 237*39232Ssklower 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) { 26336369Ssklower seg_part.cng_off += frag_size; 26436369Ssklower m_adj(m, frag_size); 26536369Ssklower } 26636369Ssklower } 26736369Ssklower return(0); 26836369Ssklower } else { 269*39232Ssklower cantfrag: 27039195Ssklower INCSTAT(cns_cantfrag); 27136369Ssklower clnp_discard(m, GEN_SEGNEEDED); 27236369Ssklower return(EMSGSIZE); 27336369Ssklower } 27436369Ssklower } 27536369Ssklower 27636369Ssklower /* 27736369Ssklower * FUNCTION: clnp_reass 27836369Ssklower * 27936369Ssklower * PURPOSE: Attempt to reassemble a clnp packet given the current 28036369Ssklower * fragment. If reassembly succeeds (all the fragments 28136369Ssklower * are present), then return a pointer to an mbuf chain 28236369Ssklower * containing the reassembled packet. This packet will 28336369Ssklower * appear in the mbufs as if it had just arrived in 28436369Ssklower * one piece. 28536369Ssklower * 28636369Ssklower * If reassembly fails, then save this fragment and 28736369Ssklower * return 0. 28836369Ssklower * 28936369Ssklower * RETURNS: Ptr to assembled packet, or 0 29036369Ssklower * 29136369Ssklower * SIDE EFFECTS: 29236369Ssklower * 29336369Ssklower * NOTES: 29436369Ssklower * clnp_slowtimo can not affect this code because clnpintr, and thus 29536369Ssklower * this code, is called at a higher priority than clnp_slowtimo. 29636369Ssklower */ 29736369Ssklower struct mbuf * 29836369Ssklower clnp_reass(m, src, dst, seg) 29936369Ssklower struct mbuf *m; /* new fragment */ 30036369Ssklower struct iso_addr *src; /* src of new fragment */ 30136369Ssklower struct iso_addr *dst; /* dst of new fragment */ 30236369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 30336369Ssklower { 30436369Ssklower register struct clnp_fragl *cfh; 30536369Ssklower 30636369Ssklower /* look for other fragments of this datagram */ 30736369Ssklower for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { 30836369Ssklower if (iso_addrmatch1(src, &cfh->cfl_src) && 30936369Ssklower iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) { 31036369Ssklower IFDEBUG(D_REASS) 31136369Ssklower printf("clnp_reass: found packet\n"); 31236369Ssklower ENDDEBUG 31336369Ssklower /* 31436369Ssklower * There are other fragments here already. Lets see if 31536369Ssklower * this fragment is of any help 31636369Ssklower */ 31736369Ssklower clnp_insert_frag(cfh, m, seg); 31836369Ssklower return (clnp_comp_pdu(cfh)); 31936369Ssklower } 32036369Ssklower } 32136369Ssklower 32236369Ssklower IFDEBUG(D_REASS) 32336369Ssklower printf("clnp_reass: new packet!\n"); 32436369Ssklower ENDDEBUG 32536369Ssklower 32636369Ssklower /* 32736369Ssklower * This is the first fragment. If src is not consuming too many 32836369Ssklower * resources, then create a new fragment list and add 32936369Ssklower * this fragment to the list. 33036369Ssklower */ 33136369Ssklower /* TODO: don't let one src hog all the reassembly buffers */ 33236369Ssklower if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { 33339195Ssklower INCSTAT(cns_fragdropped); 33436369Ssklower clnp_discard(m, GEN_CONGEST); 33536369Ssklower } 33636369Ssklower 33736369Ssklower return(NULL); 33836369Ssklower } 33936369Ssklower 34036369Ssklower /* 34136369Ssklower * FUNCTION: clnp_newpkt 34236369Ssklower * 34336369Ssklower * PURPOSE: Create the necessary structures to handle a new 34436369Ssklower * fragmented clnp packet. 34536369Ssklower * 34636369Ssklower * RETURNS: non-zero if it succeeds, zero if fails. 34736369Ssklower * 34836369Ssklower * SIDE EFFECTS: 34936369Ssklower * 35036369Ssklower * NOTES: Failure is only due to insufficient resources. 35136369Ssklower */ 35236369Ssklower clnp_newpkt(m, src, dst, seg) 35336369Ssklower struct mbuf *m; /* new fragment */ 35436369Ssklower struct iso_addr *src; /* src of new fragment */ 35536369Ssklower struct iso_addr *dst; /* dst of new fragment */ 35636369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 35736369Ssklower { 35836369Ssklower register struct clnp_fragl *cfh; 35936369Ssklower register struct clnp_fixed *clnp; 36036369Ssklower struct mbuf *m0; 36136369Ssklower 36236369Ssklower clnp = mtod(m, struct clnp_fixed *); 36336369Ssklower 36436369Ssklower /* 36536369Ssklower * Allocate new clnp fragl structure to act as header of all fragments 36636369Ssklower * for this datagram. 36736369Ssklower */ 36836369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE); 36936369Ssklower if (m0 == NULL) { 37036369Ssklower return (0); 37136369Ssklower } 37236369Ssklower cfh = mtod(m0, struct clnp_fragl *); 37336369Ssklower 37436369Ssklower /* 37536369Ssklower * Duplicate the header of this fragment, and save in cfh. 37636369Ssklower * Free m0 and return if m_copy does not succeed. 37736369Ssklower */ 37837469Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 37936369Ssklower m_freem(m0); 38036369Ssklower return (0); 38136369Ssklower } 38236369Ssklower 38336369Ssklower /* Fill in rest of fragl structure */ 38436369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 38536369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 38636369Ssklower cfh->cfl_id = seg->cng_id; 38736369Ssklower cfh->cfl_ttl = clnp->cnf_ttl; 38836369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 38936369Ssklower cfh->cfl_frags = NULL; 39036369Ssklower cfh->cfl_next = NULL; 39136369Ssklower 39236369Ssklower /* Insert into list of packets */ 39336369Ssklower cfh->cfl_next = clnp_frags; 39436369Ssklower clnp_frags = cfh; 39536369Ssklower 39636369Ssklower /* Insert this fragment into list headed by cfh */ 39736369Ssklower clnp_insert_frag(cfh, m, seg); 39836369Ssklower return(1); 39936369Ssklower } 40036369Ssklower 40136369Ssklower /* 40236369Ssklower * FUNCTION: clnp_insert_frag 40336369Ssklower * 40436369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'. 40536369Ssklower * 40636369Ssklower * RETURNS: nothing 40736369Ssklower * 40836369Ssklower * SIDE EFFECTS: 40936369Ssklower * 41036369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm. 41136369Ssklower * Each fragment in this list contains a clnp_frag 41236369Ssklower * structure followed by the data of the fragment. 41336369Ssklower * The clnp_frag structure actually lies on top of 41436369Ssklower * part of the old clnp header. 41536369Ssklower */ 41636369Ssklower clnp_insert_frag(cfh, m, seg) 41736369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */ 41836369Ssklower struct mbuf *m; /* new fragment */ 41936369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 42036369Ssklower { 42136369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 42236369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */ 42336369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 42436369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 42536369Ssklower u_short first; /* offset of first byte of initial pdu*/ 42636369Ssklower u_short last; /* offset of last byte of initial pdu */ 42736369Ssklower u_short fraglen;/* length of fragment */ 42836369Ssklower 42936369Ssklower clnp = mtod(m, struct clnp_fixed *); 43036369Ssklower first = seg->cng_off; 43136369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 43236369Ssklower fraglen -= clnp->cnf_hdr_len; 43336369Ssklower last = (first + fraglen) - 1; 43436369Ssklower 43536369Ssklower IFDEBUG(D_REASS) 43636369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 43736369Ssklower first, last, fraglen); 43836369Ssklower printf("clnp_insert_frag: current fragments:\n"); 43936369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 44036369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 44136369Ssklower } 44236369Ssklower ENDDEBUG 44336369Ssklower 44436369Ssklower if (cfh->cfl_frags != NULL) { 44536369Ssklower /* 44636369Ssklower * Find fragment which begins after the new one 44736369Ssklower */ 44836369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 44936369Ssklower if (cf->cfr_first > first) { 45036369Ssklower cf_sub = cf; 45136369Ssklower break; 45236369Ssklower } 45336369Ssklower } 45436369Ssklower 45536369Ssklower IFDEBUG(D_REASS) 45636369Ssklower printf("clnp_insert_frag: Previous frag is "); 45736369Ssklower if (cf_prev == NULL) 45836369Ssklower printf("NULL\n"); 45936369Ssklower else 46036369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 46136369Ssklower printf("clnp_insert_frag: Subsequent frag is "); 46236369Ssklower if (cf_sub == NULL) 46336369Ssklower printf("NULL\n"); 46436369Ssklower else 46536369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 46636369Ssklower ENDDEBUG 46736369Ssklower 46836369Ssklower /* 46936369Ssklower * If there is a fragment before the new one, check if it 47036369Ssklower * overlaps the new one. If so, then trim the end of the 47136369Ssklower * previous one. 47236369Ssklower */ 47336369Ssklower if (cf_prev != NULL) { 47436369Ssklower if (cf_prev->cfr_last > first) { 47536369Ssklower u_short overlap = cf_prev->cfr_last - first; 47636369Ssklower 47736369Ssklower IFDEBUG(D_REASS) 47836369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n", 47936369Ssklower overlap); 48036369Ssklower ENDDEBUG 48136369Ssklower 48236369Ssklower if (overlap > fraglen) { 48336369Ssklower /* 48436369Ssklower * The new fragment is entirely contained in the 48536369Ssklower * preceeding one. We can punt on the new frag 48636369Ssklower * completely. 48736369Ssklower */ 48836369Ssklower m_freem(m); 48936369Ssklower return; 49036369Ssklower } else { 49136369Ssklower /* Trim data off of end of previous fragment */ 49236369Ssklower /* inc overlap to prevent duplication of last byte */ 49336369Ssklower overlap++; 49437469Ssklower m_adj(cf_prev->cfr_data, -(int)overlap); 49536369Ssklower cf_prev->cfr_last -= overlap; 49636369Ssklower } 49736369Ssklower } 49836369Ssklower } 49936369Ssklower 50036369Ssklower /* 50136369Ssklower * For all fragments past the new one, check if any data on 50236369Ssklower * the new one overlaps data on existing fragments. If so, 50336369Ssklower * then trim the extra data off the end of the new one. 50436369Ssklower */ 50536369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 50636369Ssklower if (cf->cfr_first < last) { 50736369Ssklower u_short overlap = last - cf->cfr_first; 50836369Ssklower 50936369Ssklower IFDEBUG(D_REASS) 51036369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n", 51136369Ssklower overlap); 51236369Ssklower ENDDEBUG 51336369Ssklower 51436369Ssklower if (overlap > fraglen) { 51536369Ssklower /* 51636369Ssklower * The new fragment is entirely contained in the 51736369Ssklower * succeeding one. This should not happen, because 51836369Ssklower * early on in this code we scanned for the fragment 51936369Ssklower * which started after the new one! 52036369Ssklower */ 52136369Ssklower m_freem(m); 52236369Ssklower printf("clnp_insert_frag: internal error!\n"); 52336369Ssklower return; 52436369Ssklower } else { 52536369Ssklower /* Trim data off of end of new fragment */ 52636369Ssklower /* inc overlap to prevent duplication of last byte */ 52736369Ssklower overlap++; 52837469Ssklower m_adj(m, -(int)overlap); 52936369Ssklower last -= overlap; 53036369Ssklower } 53136369Ssklower } 53236369Ssklower } 53336369Ssklower } 53436369Ssklower 53536369Ssklower /* 53636369Ssklower * Insert the new fragment beween cf_prev and cf_sub 53736369Ssklower * 53836369Ssklower * Note: the clnp hdr is still in the mbuf. 53936369Ssklower * If the data of the mbuf is not word aligned, shave off enough 54036369Ssklower * so that it is. Then, cast the clnp_frag structure on top 54136369Ssklower * of the clnp header. 54236369Ssklower * The clnp_hdr will not be used again (as we already have 54336369Ssklower * saved a copy of it). 54436369Ssklower * 54536369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to 54636369Ssklower * the data of the packet. This is used when we coalesce fragments; 54736369Ssklower * the clnp_frag structure must be removed before joining mbufs. 54836369Ssklower */ 54936369Ssklower { 55036369Ssklower int pad; 55136369Ssklower u_int bytes; 55236369Ssklower 55336369Ssklower /* determine if header is not word aligned */ 55436369Ssklower pad = (int)clnp % 4; 55536369Ssklower if (pad < 0) 55636369Ssklower pad = -pad; 55736369Ssklower 55836369Ssklower /* bytes is number of bytes left in front of data */ 55936369Ssklower bytes = clnp->cnf_hdr_len - pad; 56036369Ssklower 56136764Ssklower IFDEBUG(D_REASS) 56236764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 56336764Ssklower clnp, pad); 56436764Ssklower ENDDEBUG 56536764Ssklower 56636369Ssklower /* make it word aligned if necessary */ 56736369Ssklower if (pad) 56836369Ssklower m_adj(m, pad); 56936369Ssklower 57036369Ssklower cf = mtod(m, struct clnp_frag *); 57136369Ssklower cf->cfr_bytes = bytes; 57236764Ssklower 57336764Ssklower IFDEBUG(D_REASS) 57436764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 57536764Ssklower cf->cfr_bytes); 57636764Ssklower ENDDEBUG 57736369Ssklower } 57836369Ssklower cf->cfr_first = first; 57936369Ssklower cf->cfr_last = last; 58036369Ssklower 58136369Ssklower 58236369Ssklower /* 58336369Ssklower * The data is the mbuf itself, although we must remember that the 58436369Ssklower * first few bytes are actually a clnp_frag structure 58536369Ssklower */ 58636369Ssklower cf->cfr_data = m; 58736369Ssklower 58836369Ssklower /* link into place */ 58936369Ssklower cf->cfr_next = cf_sub; 59036369Ssklower if (cf_prev == NULL) 59136369Ssklower cfh->cfl_frags = cf; 59236369Ssklower else 59336369Ssklower cf_prev->cfr_next = cf; 59436369Ssklower } 59536369Ssklower 59636369Ssklower /* 59736369Ssklower * FUNCTION: clnp_comp_pdu 59836369Ssklower * 59936369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge 60036369Ssklower * any contigious fragments into one. If, after 60136369Ssklower * traversing all the fragments, it is determined that 60236369Ssklower * the packet is complete, then return a pointer to 60336369Ssklower * the packet (with header prepended). Otherwise, 60436369Ssklower * return NULL. 60536369Ssklower * 60636369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 60736369Ssklower * 60836369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one. 60936369Ssklower * 61036369Ssklower * NOTES: This code assumes that there are no overlaps of 61136369Ssklower * fragment pdus. 61236369Ssklower */ 61336369Ssklower struct mbuf * 61436369Ssklower clnp_comp_pdu(cfh) 61536369Ssklower struct clnp_fragl *cfh; /* fragment header */ 61636369Ssklower { 61736369Ssklower register struct clnp_frag *cf = cfh->cfl_frags; 61836369Ssklower 61936369Ssklower while (cf->cfr_next != NULL) { 62036369Ssklower register struct clnp_frag *cf_next = cf->cfr_next; 62136369Ssklower 62236369Ssklower IFDEBUG(D_REASS) 62336369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 62436369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 62536369Ssklower cf_next->cfr_last); 62636369Ssklower ENDDEBUG 62736369Ssklower 62836369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) { 62936369Ssklower /* 63036369Ssklower * Merge fragment cf and cf_next 63136369Ssklower * 63236369Ssklower * - update cf header 63336369Ssklower * - trim clnp_frag structure off of cf_next 63436369Ssklower * - append cf_next to cf 63536369Ssklower */ 63636369Ssklower struct clnp_frag cf_next_hdr; 63736369Ssklower struct clnp_frag *next_frag; 63836369Ssklower 63936369Ssklower cf_next_hdr = *cf_next; 64036369Ssklower next_frag = cf_next->cfr_next; 64136369Ssklower 64236369Ssklower IFDEBUG(D_REASS) 64336369Ssklower struct mbuf *mdump; 64436764Ssklower int l; 64536369Ssklower printf("clnp_comp_pdu: merging fragments\n"); 64636764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 64736764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 64836369Ssklower mdump = cf->cfr_data; 64936764Ssklower l = 0; 65036369Ssklower while (mdump != NULL) { 65136369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 65236764Ssklower l += mdump->m_len; 65336369Ssklower mdump = mdump->m_next; 65436369Ssklower } 65536764Ssklower printf("\ttotal len: %d\n", l); 65636764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 65736764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 65836369Ssklower mdump = cf_next->cfr_data; 65936764Ssklower l = 0; 66036369Ssklower while (mdump != NULL) { 66136369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 66236764Ssklower l += mdump->m_len; 66336369Ssklower mdump = mdump->m_next; 66436369Ssklower } 66536764Ssklower printf("\ttotal len: %d\n", l); 66636369Ssklower ENDDEBUG 66736369Ssklower 66836369Ssklower cf->cfr_last = cf_next->cfr_last; 66936369Ssklower /* 67036369Ssklower * After this m_adj, the cf_next ptr is useless because we 67136369Ssklower * have adjusted the clnp_frag structure away... 67236369Ssklower */ 67336764Ssklower IFDEBUG(D_REASS) 67436764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n", 67536764Ssklower cf_next_hdr.cfr_bytes); 67636764Ssklower ENDDEBUG 67737469Ssklower m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); 67836369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 67936369Ssklower cf->cfr_next = next_frag; 68036369Ssklower } else { 68136369Ssklower cf = cf->cfr_next; 68236369Ssklower } 68336369Ssklower } 68436369Ssklower 68536369Ssklower cf = cfh->cfl_frags; 68636369Ssklower 68736369Ssklower IFDEBUG(D_REASS) 68836369Ssklower struct mbuf *mdump = cf->cfr_data; 68936369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 69036369Ssklower cf->cfr_last); 69136369Ssklower printf("clnp_comp_pdu: data for frag:\n"); 69236369Ssklower while (mdump != NULL) { 69336369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 69436369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 69536369Ssklower mdump = mdump->m_next; 69636369Ssklower } 69736369Ssklower ENDDEBUG 69836369Ssklower 69936369Ssklower /* Check if datagram is complete */ 70036369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 70136369Ssklower /* 70236369Ssklower * We have a complete pdu! 70336369Ssklower * - Remove the frag header from (only) remaining fragment 70436369Ssklower * (which is not really a fragment anymore, as the datagram is 70536369Ssklower * complete). 70636369Ssklower * - Prepend a clnp header 70736369Ssklower */ 70836369Ssklower struct mbuf *data = cf->cfr_data; 70936369Ssklower struct mbuf *hdr = cfh->cfl_orighdr; 71036369Ssklower struct clnp_fragl *scan; 71136369Ssklower 71236369Ssklower IFDEBUG(D_REASS) 71336369Ssklower printf("clnp_comp_pdu: complete pdu!\n"); 71436369Ssklower ENDDEBUG 71536369Ssklower 71637469Ssklower m_adj(data, (int)cf->cfr_bytes); 71736369Ssklower m_cat(hdr, data); 71836369Ssklower 71936369Ssklower IFDEBUG(D_DUMPIN) 72036369Ssklower struct mbuf *mdump = hdr; 72136369Ssklower printf("clnp_comp_pdu: pdu is:\n"); 72236369Ssklower while (mdump != NULL) { 72336369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 72436369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 72536369Ssklower mdump = mdump->m_next; 72636369Ssklower } 72736369Ssklower ENDDEBUG 72836369Ssklower 72936369Ssklower /* 73036369Ssklower * Remove cfh from the list of fragmented pdus 73136369Ssklower */ 73236369Ssklower if (clnp_frags == cfh) { 73336369Ssklower clnp_frags = cfh->cfl_next; 73436369Ssklower } else { 73536369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 73636369Ssklower if (scan->cfl_next == cfh) { 73736369Ssklower scan->cfl_next = cfh->cfl_next; 73836369Ssklower break; 73936369Ssklower } 74036369Ssklower } 74136369Ssklower } 74236369Ssklower 74336369Ssklower /* free cfh */ 74436369Ssklower m_freem(dtom(cfh)); 74536369Ssklower 74636369Ssklower return(hdr); 74736369Ssklower } 74836369Ssklower 74936369Ssklower return(NULL); 75036369Ssklower } 75136369Ssklower #ifdef TROLL 75237469Ssklower static int troll_cnt; 75337536Smckusick #include "time.h" 75436369Ssklower /* 75536369Ssklower * FUNCTION: troll_random 75636369Ssklower * 75736369Ssklower * PURPOSE: generate a pseudo-random number between 0 and 1 75836369Ssklower * 75936369Ssklower * RETURNS: the random number 76036369Ssklower * 76136369Ssklower * SIDE EFFECTS: 76236369Ssklower * 76336369Ssklower * NOTES: This is based on the clock. 76436369Ssklower */ 76536369Ssklower float troll_random() 76636369Ssklower { 76736369Ssklower extern struct timeval time; 76836369Ssklower long t = time.tv_usec % 100; 76936369Ssklower 77036369Ssklower return((float)t / (float) 100); 77136369Ssklower } 77236369Ssklower 77336369Ssklower /* 77436369Ssklower * FUNCTION: troll_output 77536369Ssklower * 77636369Ssklower * PURPOSE: Do something sneaky with the datagram passed. Possible 77736369Ssklower * operations are: 77836369Ssklower * Duplicate the packet 77936369Ssklower * Drop the packet 78036369Ssklower * Trim some number of bytes from the packet 78136369Ssklower * Munge some byte in the packet 78236369Ssklower * 78336369Ssklower * RETURNS: 0, or unix error code 78436369Ssklower * 78536369Ssklower * SIDE EFFECTS: 78636369Ssklower * 78736369Ssklower * NOTES: The operation of this procedure is regulated by the 78836369Ssklower * troll control structure (Troll). 78936369Ssklower */ 79036369Ssklower troll_output(ifp, m, dst) 79136369Ssklower struct ifnet *ifp; 79236369Ssklower struct mbuf *m; 79336369Ssklower struct sockaddr *dst; 79436369Ssklower { 79536369Ssklower int err = 0; 79636369Ssklower troll_cnt++; 79736369Ssklower 79836369Ssklower if (trollctl.tr_ops & TR_DUPPKT) { 79936369Ssklower /* 80036369Ssklower * Duplicate every Nth packet 80136369Ssklower * TODO: random? 80236369Ssklower */ 80336369Ssklower float f_freq = troll_cnt * trollctl.tr_dup_freq; 80436369Ssklower int i_freq = troll_cnt * trollctl.tr_dup_freq; 80536369Ssklower if (i_freq == f_freq) { 80637469Ssklower struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); 80736369Ssklower if (dup != NULL) 80836369Ssklower err = (*ifp->if_output)(ifp, dup, dst); 80936369Ssklower } 81036369Ssklower if (!err) 81136369Ssklower err = (*ifp->if_output)(ifp, m, dst); 81236369Ssklower return(err); 81336369Ssklower } else if (trollctl.tr_ops & TR_DROPPKT) { 81436369Ssklower } else if (trollctl.tr_ops & TR_CHANGE) { 81536369Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 81636369Ssklower clnp->cnf_cksum_msb = 0; 81736369Ssklower err = (*ifp->if_output)(ifp, m, dst); 81836369Ssklower return(err); 81936369Ssklower } else { 82036369Ssklower err = (*ifp->if_output)(ifp, m, dst); 82136369Ssklower return(err); 82236369Ssklower } 82336369Ssklower } 82436369Ssklower 82536369Ssklower #endif TROLL 826