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*39195Ssklower /* @(#)clnp_frag.c 7.6 (Berkeley) 09/22/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 { 8536369Ssklower struct clnp_fixed *clnp; /* ptr to fixed part of header */ 8636369Ssklower 8736369Ssklower clnp = mtod(m, struct clnp_fixed *); 8836369Ssklower 8937469Ssklower if (clnp->cnf_type & CNF_SEG_OK) { 9036369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 9136369Ssklower struct mbuf *frag_hdr = NULL; 9236369Ssklower struct mbuf *frag_data = NULL; 9336369Ssklower struct clnp_segment seg_part, tmp_seg; /* segmentation header */ 9436369Ssklower extern int clnp_id; /* id of datagram */ 9536369Ssklower int error = 0; 9636369Ssklower 97*39195Ssklower INCSTAT(cns_fragmented); 9836369Ssklower 9936369Ssklower seg_part.cng_id = clnp_id++; 10036369Ssklower seg_part.cng_off = 0; 10136369Ssklower seg_part.cng_tot_len = total_len; 10236369Ssklower 10336369Ssklower /* 10436369Ssklower * Duplicate header, and remove from packet 10536369Ssklower */ 10637469Ssklower if ((hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 10736369Ssklower clnp_discard(m, GEN_CONGEST); 10836369Ssklower return(ENOBUFS); 10936369Ssklower } 11037469Ssklower m_adj(m, (int)clnp->cnf_hdr_len); 11136369Ssklower total_len -= clnp->cnf_hdr_len; 11236369Ssklower 11336369Ssklower while (total_len > 0) { 11436369Ssklower int frag_size; 11536369Ssklower int last_frag = 0; /* true if this is the last fragment */ 11636764Ssklower 11736764Ssklower IFDEBUG(D_FRAG) 11836764Ssklower struct mbuf *mdump = frag_hdr; 11936764Ssklower int tot_mlen = 0; 12036764Ssklower printf("clnp_fragment: total_len %d:\n", total_len); 12136764Ssklower while (mdump != NULL) { 12236764Ssklower printf("\tmbuf x%x, m_len %d\n", 12336764Ssklower mdump, mdump->m_len); 12436764Ssklower tot_mlen += mdump->m_len; 12536764Ssklower mdump = mdump->m_next; 12636764Ssklower } 12736764Ssklower printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); 12836764Ssklower ENDDEBUG 12936369Ssklower 13036369Ssklower frag_size = min(total_len, ifp->if_mtu - clnp->cnf_hdr_len); 13136369Ssklower 13236369Ssklower /* 13336369Ssklower * For some stupid reason, fragments must be at least 8 bytes 13436369Ssklower * in length. If this fragment will cause the last one to 13536369Ssklower * be less than 8 bytes, shorten this fragment a bit. 13636369Ssklower */ 13736369Ssklower if (((total_len - frag_size) > 0) && ((total_len - frag_size) < 8)) 13836369Ssklower frag_size -= (8 - (total_len - frag_size)); 13936369Ssklower 14036369Ssklower last_frag = ((total_len - frag_size) == 0); 14136369Ssklower 14236369Ssklower IFDEBUG(D_FRAG) 14336369Ssklower printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 14436369Ssklower seg_part.cng_off, frag_size, total_len-frag_size); 14536369Ssklower if (last_frag) 14636369Ssklower printf("clnp_fragment: last fragment\n"); 14736369Ssklower ENDDEBUG 14836369Ssklower 14936369Ssklower if (last_frag) { 15036369Ssklower /* 15136369Ssklower * this is the last fragment; we don't need to get any other 15236369Ssklower * mbufs. 15336369Ssklower */ 15436369Ssklower frag_hdr = hdr; 15536369Ssklower frag_data = m; 15636369Ssklower } else { 15736369Ssklower /* duplicate header and data mbufs */ 15837469Ssklower if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { 15936369Ssklower clnp_discard(m, GEN_CONGEST); 16036369Ssklower m_freem(hdr); 16136369Ssklower return(ENOBUFS); 16236369Ssklower } 16336369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { 16436369Ssklower clnp_discard(m, GEN_CONGEST); 16536369Ssklower m_freem(hdr); 16636369Ssklower m_freem(frag_hdr); 16736369Ssklower return(ENOBUFS); 16836369Ssklower } 169*39195Ssklower INCSTAT(cns_fragments); 17036369Ssklower } 17136369Ssklower clnp = mtod(frag_hdr, struct clnp_fixed *); 17236369Ssklower 17336369Ssklower if (!last_frag) 17437469Ssklower clnp->cnf_type |= CNF_MORE_SEGS; 17536369Ssklower 17636369Ssklower /* link together */ 17736369Ssklower m_cat(frag_hdr, frag_data); 17836369Ssklower 17936369Ssklower /* make sure segmentation fields are in network order */ 18036369Ssklower tmp_seg.cng_id = htons(seg_part.cng_id); 18136369Ssklower tmp_seg.cng_off = htons(seg_part.cng_off); 18236369Ssklower tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len); 18336369Ssklower 18436369Ssklower /* insert segmentation part */ 18536369Ssklower bcopy((caddr_t)&tmp_seg, mtod(frag_hdr, caddr_t) + segoff, 18636369Ssklower sizeof(struct clnp_segment)); 18736369Ssklower 18836369Ssklower { 18936369Ssklower int derived_len = clnp->cnf_hdr_len + frag_size; 19036369Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); 19137469Ssklower if ((frag_hdr->m_flags & M_PKTHDR) == 0) 19237469Ssklower panic("clnp_frag:lost header"); 19337469Ssklower frag_hdr->m_pkthdr.len = derived_len; 19436369Ssklower } 19536369Ssklower /* compute clnp checksum (on header only) */ 19636369Ssklower if (flags & CLNP_NO_CKSUM) { 19736369Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 19836369Ssklower } else { 19936369Ssklower iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 20036369Ssklower } 20136369Ssklower 20236369Ssklower IFDEBUG(D_DUMPOUT) 20336369Ssklower struct mbuf *mdump = frag_hdr; 20436369Ssklower printf("clnp_fragment: sending dg:\n"); 20536369Ssklower while (mdump != NULL) { 20636764Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 20736369Ssklower mdump = mdump->m_next; 20836369Ssklower } 20936369Ssklower ENDDEBUG 21036369Ssklower 21136369Ssklower #ifdef TROLL 21236369Ssklower error = troll_output(ifp, frag_hdr, first_hop); 21336369Ssklower #else 21436369Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop); 21536369Ssklower #endif TROLL 21636369Ssklower 21736369Ssklower /* 21836369Ssklower * Tough situation: if the error occured on the last 21936369Ssklower * fragment, we can not send an ER, as the if_output 22036369Ssklower * routine consumed the packet. If the error occured 22136369Ssklower * on any intermediate packets, we can send an ER 22236369Ssklower * because we still have the original header in (m). 22336369Ssklower */ 22436369Ssklower if (error) { 22536369Ssklower if (frag_hdr != hdr) { 22636369Ssklower /* 22736369Ssklower * The error was not on the last fragment. We must 22836369Ssklower * free hdr and m before returning 22936369Ssklower */ 23036369Ssklower clnp_discard(m, GEN_NOREAS); 23136369Ssklower m_freem(hdr); 23236369Ssklower } 23336369Ssklower return(error); 23436369Ssklower } 23536369Ssklower 23636369Ssklower /* bump segment offset, trim data mbuf, and decrement count left */ 23736369Ssklower #ifdef TROLL 23836369Ssklower /* 23936369Ssklower * Decrement frag_size by some fraction. This will cause the 24036369Ssklower * next fragment to start 'early', thus duplicating the end 24136369Ssklower * of the current fragment. troll.tr_dup_size controls 24236369Ssklower * the fraction. If positive, it specifies the fraction. If 24336369Ssklower * negative, a random fraction is used. 24436369Ssklower */ 24536369Ssklower if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { 24636369Ssklower int num_bytes = frag_size; 24736369Ssklower 24836369Ssklower if (trollctl.tr_dup_size > 0) 24936369Ssklower num_bytes *= trollctl.tr_dup_size; 25036369Ssklower else 25136369Ssklower num_bytes *= troll_random(); 25236369Ssklower frag_size -= num_bytes; 25336369Ssklower } 25436369Ssklower #endif TROLL 25536369Ssklower total_len -= frag_size; 25636369Ssklower if (!last_frag) { 25736369Ssklower seg_part.cng_off += frag_size; 25836369Ssklower m_adj(m, frag_size); 25936369Ssklower } 26036369Ssklower } 26136369Ssklower return(0); 26236369Ssklower } else { 263*39195Ssklower INCSTAT(cns_cantfrag); 26436369Ssklower clnp_discard(m, GEN_SEGNEEDED); 26536369Ssklower return(EMSGSIZE); 26636369Ssklower } 26736369Ssklower } 26836369Ssklower 26936369Ssklower /* 27036369Ssklower * FUNCTION: clnp_reass 27136369Ssklower * 27236369Ssklower * PURPOSE: Attempt to reassemble a clnp packet given the current 27336369Ssklower * fragment. If reassembly succeeds (all the fragments 27436369Ssklower * are present), then return a pointer to an mbuf chain 27536369Ssklower * containing the reassembled packet. This packet will 27636369Ssklower * appear in the mbufs as if it had just arrived in 27736369Ssklower * one piece. 27836369Ssklower * 27936369Ssklower * If reassembly fails, then save this fragment and 28036369Ssklower * return 0. 28136369Ssklower * 28236369Ssklower * RETURNS: Ptr to assembled packet, or 0 28336369Ssklower * 28436369Ssklower * SIDE EFFECTS: 28536369Ssklower * 28636369Ssklower * NOTES: 28736369Ssklower * clnp_slowtimo can not affect this code because clnpintr, and thus 28836369Ssklower * this code, is called at a higher priority than clnp_slowtimo. 28936369Ssklower */ 29036369Ssklower struct mbuf * 29136369Ssklower clnp_reass(m, src, dst, seg) 29236369Ssklower struct mbuf *m; /* new fragment */ 29336369Ssklower struct iso_addr *src; /* src of new fragment */ 29436369Ssklower struct iso_addr *dst; /* dst of new fragment */ 29536369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 29636369Ssklower { 29736369Ssklower register struct clnp_fragl *cfh; 29836369Ssklower 29936369Ssklower /* look for other fragments of this datagram */ 30036369Ssklower for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { 30136369Ssklower if (iso_addrmatch1(src, &cfh->cfl_src) && 30236369Ssklower iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) { 30336369Ssklower IFDEBUG(D_REASS) 30436369Ssklower printf("clnp_reass: found packet\n"); 30536369Ssklower ENDDEBUG 30636369Ssklower /* 30736369Ssklower * There are other fragments here already. Lets see if 30836369Ssklower * this fragment is of any help 30936369Ssklower */ 31036369Ssklower clnp_insert_frag(cfh, m, seg); 31136369Ssklower return (clnp_comp_pdu(cfh)); 31236369Ssklower } 31336369Ssklower } 31436369Ssklower 31536369Ssklower IFDEBUG(D_REASS) 31636369Ssklower printf("clnp_reass: new packet!\n"); 31736369Ssklower ENDDEBUG 31836369Ssklower 31936369Ssklower /* 32036369Ssklower * This is the first fragment. If src is not consuming too many 32136369Ssklower * resources, then create a new fragment list and add 32236369Ssklower * this fragment to the list. 32336369Ssklower */ 32436369Ssklower /* TODO: don't let one src hog all the reassembly buffers */ 32536369Ssklower if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { 326*39195Ssklower INCSTAT(cns_fragdropped); 32736369Ssklower clnp_discard(m, GEN_CONGEST); 32836369Ssklower } 32936369Ssklower 33036369Ssklower return(NULL); 33136369Ssklower } 33236369Ssklower 33336369Ssklower /* 33436369Ssklower * FUNCTION: clnp_newpkt 33536369Ssklower * 33636369Ssklower * PURPOSE: Create the necessary structures to handle a new 33736369Ssklower * fragmented clnp packet. 33836369Ssklower * 33936369Ssklower * RETURNS: non-zero if it succeeds, zero if fails. 34036369Ssklower * 34136369Ssklower * SIDE EFFECTS: 34236369Ssklower * 34336369Ssklower * NOTES: Failure is only due to insufficient resources. 34436369Ssklower */ 34536369Ssklower clnp_newpkt(m, src, dst, seg) 34636369Ssklower struct mbuf *m; /* new fragment */ 34736369Ssklower struct iso_addr *src; /* src of new fragment */ 34836369Ssklower struct iso_addr *dst; /* dst of new fragment */ 34936369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 35036369Ssklower { 35136369Ssklower register struct clnp_fragl *cfh; 35236369Ssklower register struct clnp_fixed *clnp; 35336369Ssklower struct mbuf *m0; 35436369Ssklower 35536369Ssklower clnp = mtod(m, struct clnp_fixed *); 35636369Ssklower 35736369Ssklower /* 35836369Ssklower * Allocate new clnp fragl structure to act as header of all fragments 35936369Ssklower * for this datagram. 36036369Ssklower */ 36136369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE); 36236369Ssklower if (m0 == NULL) { 36336369Ssklower return (0); 36436369Ssklower } 36536369Ssklower cfh = mtod(m0, struct clnp_fragl *); 36636369Ssklower 36736369Ssklower /* 36836369Ssklower * Duplicate the header of this fragment, and save in cfh. 36936369Ssklower * Free m0 and return if m_copy does not succeed. 37036369Ssklower */ 37137469Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 37236369Ssklower m_freem(m0); 37336369Ssklower return (0); 37436369Ssklower } 37536369Ssklower 37636369Ssklower /* Fill in rest of fragl structure */ 37736369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 37836369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 37936369Ssklower cfh->cfl_id = seg->cng_id; 38036369Ssklower cfh->cfl_ttl = clnp->cnf_ttl; 38136369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 38236369Ssklower cfh->cfl_frags = NULL; 38336369Ssklower cfh->cfl_next = NULL; 38436369Ssklower 38536369Ssklower /* Insert into list of packets */ 38636369Ssklower cfh->cfl_next = clnp_frags; 38736369Ssklower clnp_frags = cfh; 38836369Ssklower 38936369Ssklower /* Insert this fragment into list headed by cfh */ 39036369Ssklower clnp_insert_frag(cfh, m, seg); 39136369Ssklower return(1); 39236369Ssklower } 39336369Ssklower 39436369Ssklower /* 39536369Ssklower * FUNCTION: clnp_insert_frag 39636369Ssklower * 39736369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'. 39836369Ssklower * 39936369Ssklower * RETURNS: nothing 40036369Ssklower * 40136369Ssklower * SIDE EFFECTS: 40236369Ssklower * 40336369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm. 40436369Ssklower * Each fragment in this list contains a clnp_frag 40536369Ssklower * structure followed by the data of the fragment. 40636369Ssklower * The clnp_frag structure actually lies on top of 40736369Ssklower * part of the old clnp header. 40836369Ssklower */ 40936369Ssklower clnp_insert_frag(cfh, m, seg) 41036369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */ 41136369Ssklower struct mbuf *m; /* new fragment */ 41236369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 41336369Ssklower { 41436369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 41536369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */ 41636369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 41736369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 41836369Ssklower u_short first; /* offset of first byte of initial pdu*/ 41936369Ssklower u_short last; /* offset of last byte of initial pdu */ 42036369Ssklower u_short fraglen;/* length of fragment */ 42136369Ssklower 42236369Ssklower clnp = mtod(m, struct clnp_fixed *); 42336369Ssklower first = seg->cng_off; 42436369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 42536369Ssklower fraglen -= clnp->cnf_hdr_len; 42636369Ssklower last = (first + fraglen) - 1; 42736369Ssklower 42836369Ssklower IFDEBUG(D_REASS) 42936369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 43036369Ssklower first, last, fraglen); 43136369Ssklower printf("clnp_insert_frag: current fragments:\n"); 43236369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 43336369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 43436369Ssklower } 43536369Ssklower ENDDEBUG 43636369Ssklower 43736369Ssklower if (cfh->cfl_frags != NULL) { 43836369Ssklower /* 43936369Ssklower * Find fragment which begins after the new one 44036369Ssklower */ 44136369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 44236369Ssklower if (cf->cfr_first > first) { 44336369Ssklower cf_sub = cf; 44436369Ssklower break; 44536369Ssklower } 44636369Ssklower } 44736369Ssklower 44836369Ssklower IFDEBUG(D_REASS) 44936369Ssklower printf("clnp_insert_frag: Previous frag is "); 45036369Ssklower if (cf_prev == NULL) 45136369Ssklower printf("NULL\n"); 45236369Ssklower else 45336369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 45436369Ssklower printf("clnp_insert_frag: Subsequent frag is "); 45536369Ssklower if (cf_sub == NULL) 45636369Ssklower printf("NULL\n"); 45736369Ssklower else 45836369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 45936369Ssklower ENDDEBUG 46036369Ssklower 46136369Ssklower /* 46236369Ssklower * If there is a fragment before the new one, check if it 46336369Ssklower * overlaps the new one. If so, then trim the end of the 46436369Ssklower * previous one. 46536369Ssklower */ 46636369Ssklower if (cf_prev != NULL) { 46736369Ssklower if (cf_prev->cfr_last > first) { 46836369Ssklower u_short overlap = cf_prev->cfr_last - first; 46936369Ssklower 47036369Ssklower IFDEBUG(D_REASS) 47136369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n", 47236369Ssklower overlap); 47336369Ssklower ENDDEBUG 47436369Ssklower 47536369Ssklower if (overlap > fraglen) { 47636369Ssklower /* 47736369Ssklower * The new fragment is entirely contained in the 47836369Ssklower * preceeding one. We can punt on the new frag 47936369Ssklower * completely. 48036369Ssklower */ 48136369Ssklower m_freem(m); 48236369Ssklower return; 48336369Ssklower } else { 48436369Ssklower /* Trim data off of end of previous fragment */ 48536369Ssklower /* inc overlap to prevent duplication of last byte */ 48636369Ssklower overlap++; 48737469Ssklower m_adj(cf_prev->cfr_data, -(int)overlap); 48836369Ssklower cf_prev->cfr_last -= overlap; 48936369Ssklower } 49036369Ssklower } 49136369Ssklower } 49236369Ssklower 49336369Ssklower /* 49436369Ssklower * For all fragments past the new one, check if any data on 49536369Ssklower * the new one overlaps data on existing fragments. If so, 49636369Ssklower * then trim the extra data off the end of the new one. 49736369Ssklower */ 49836369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 49936369Ssklower if (cf->cfr_first < last) { 50036369Ssklower u_short overlap = last - cf->cfr_first; 50136369Ssklower 50236369Ssklower IFDEBUG(D_REASS) 50336369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n", 50436369Ssklower overlap); 50536369Ssklower ENDDEBUG 50636369Ssklower 50736369Ssklower if (overlap > fraglen) { 50836369Ssklower /* 50936369Ssklower * The new fragment is entirely contained in the 51036369Ssklower * succeeding one. This should not happen, because 51136369Ssklower * early on in this code we scanned for the fragment 51236369Ssklower * which started after the new one! 51336369Ssklower */ 51436369Ssklower m_freem(m); 51536369Ssklower printf("clnp_insert_frag: internal error!\n"); 51636369Ssklower return; 51736369Ssklower } else { 51836369Ssklower /* Trim data off of end of new fragment */ 51936369Ssklower /* inc overlap to prevent duplication of last byte */ 52036369Ssklower overlap++; 52137469Ssklower m_adj(m, -(int)overlap); 52236369Ssklower last -= overlap; 52336369Ssklower } 52436369Ssklower } 52536369Ssklower } 52636369Ssklower } 52736369Ssklower 52836369Ssklower /* 52936369Ssklower * Insert the new fragment beween cf_prev and cf_sub 53036369Ssklower * 53136369Ssklower * Note: the clnp hdr is still in the mbuf. 53236369Ssklower * If the data of the mbuf is not word aligned, shave off enough 53336369Ssklower * so that it is. Then, cast the clnp_frag structure on top 53436369Ssklower * of the clnp header. 53536369Ssklower * The clnp_hdr will not be used again (as we already have 53636369Ssklower * saved a copy of it). 53736369Ssklower * 53836369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to 53936369Ssklower * the data of the packet. This is used when we coalesce fragments; 54036369Ssklower * the clnp_frag structure must be removed before joining mbufs. 54136369Ssklower */ 54236369Ssklower { 54336369Ssklower int pad; 54436369Ssklower u_int bytes; 54536369Ssklower 54636369Ssklower /* determine if header is not word aligned */ 54736369Ssklower pad = (int)clnp % 4; 54836369Ssklower if (pad < 0) 54936369Ssklower pad = -pad; 55036369Ssklower 55136369Ssklower /* bytes is number of bytes left in front of data */ 55236369Ssklower bytes = clnp->cnf_hdr_len - pad; 55336369Ssklower 55436764Ssklower IFDEBUG(D_REASS) 55536764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 55636764Ssklower clnp, pad); 55736764Ssklower ENDDEBUG 55836764Ssklower 55936369Ssklower /* make it word aligned if necessary */ 56036369Ssklower if (pad) 56136369Ssklower m_adj(m, pad); 56236369Ssklower 56336369Ssklower cf = mtod(m, struct clnp_frag *); 56436369Ssklower cf->cfr_bytes = bytes; 56536764Ssklower 56636764Ssklower IFDEBUG(D_REASS) 56736764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 56836764Ssklower cf->cfr_bytes); 56936764Ssklower ENDDEBUG 57036369Ssklower } 57136369Ssklower cf->cfr_first = first; 57236369Ssklower cf->cfr_last = last; 57336369Ssklower 57436369Ssklower 57536369Ssklower /* 57636369Ssklower * The data is the mbuf itself, although we must remember that the 57736369Ssklower * first few bytes are actually a clnp_frag structure 57836369Ssklower */ 57936369Ssklower cf->cfr_data = m; 58036369Ssklower 58136369Ssklower /* link into place */ 58236369Ssklower cf->cfr_next = cf_sub; 58336369Ssklower if (cf_prev == NULL) 58436369Ssklower cfh->cfl_frags = cf; 58536369Ssklower else 58636369Ssklower cf_prev->cfr_next = cf; 58736369Ssklower } 58836369Ssklower 58936369Ssklower /* 59036369Ssklower * FUNCTION: clnp_comp_pdu 59136369Ssklower * 59236369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge 59336369Ssklower * any contigious fragments into one. If, after 59436369Ssklower * traversing all the fragments, it is determined that 59536369Ssklower * the packet is complete, then return a pointer to 59636369Ssklower * the packet (with header prepended). Otherwise, 59736369Ssklower * return NULL. 59836369Ssklower * 59936369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 60036369Ssklower * 60136369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one. 60236369Ssklower * 60336369Ssklower * NOTES: This code assumes that there are no overlaps of 60436369Ssklower * fragment pdus. 60536369Ssklower */ 60636369Ssklower struct mbuf * 60736369Ssklower clnp_comp_pdu(cfh) 60836369Ssklower struct clnp_fragl *cfh; /* fragment header */ 60936369Ssklower { 61036369Ssklower register struct clnp_frag *cf = cfh->cfl_frags; 61136369Ssklower 61236369Ssklower while (cf->cfr_next != NULL) { 61336369Ssklower register struct clnp_frag *cf_next = cf->cfr_next; 61436369Ssklower 61536369Ssklower IFDEBUG(D_REASS) 61636369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 61736369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 61836369Ssklower cf_next->cfr_last); 61936369Ssklower ENDDEBUG 62036369Ssklower 62136369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) { 62236369Ssklower /* 62336369Ssklower * Merge fragment cf and cf_next 62436369Ssklower * 62536369Ssklower * - update cf header 62636369Ssklower * - trim clnp_frag structure off of cf_next 62736369Ssklower * - append cf_next to cf 62836369Ssklower */ 62936369Ssklower struct clnp_frag cf_next_hdr; 63036369Ssklower struct clnp_frag *next_frag; 63136369Ssklower 63236369Ssklower cf_next_hdr = *cf_next; 63336369Ssklower next_frag = cf_next->cfr_next; 63436369Ssklower 63536369Ssklower IFDEBUG(D_REASS) 63636369Ssklower struct mbuf *mdump; 63736764Ssklower int l; 63836369Ssklower printf("clnp_comp_pdu: merging fragments\n"); 63936764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 64036764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 64136369Ssklower mdump = cf->cfr_data; 64236764Ssklower l = 0; 64336369Ssklower while (mdump != NULL) { 64436369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 64536764Ssklower l += mdump->m_len; 64636369Ssklower mdump = mdump->m_next; 64736369Ssklower } 64836764Ssklower printf("\ttotal len: %d\n", l); 64936764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 65036764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 65136369Ssklower mdump = cf_next->cfr_data; 65236764Ssklower l = 0; 65336369Ssklower while (mdump != NULL) { 65436369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 65536764Ssklower l += mdump->m_len; 65636369Ssklower mdump = mdump->m_next; 65736369Ssklower } 65836764Ssklower printf("\ttotal len: %d\n", l); 65936369Ssklower ENDDEBUG 66036369Ssklower 66136369Ssklower cf->cfr_last = cf_next->cfr_last; 66236369Ssklower /* 66336369Ssklower * After this m_adj, the cf_next ptr is useless because we 66436369Ssklower * have adjusted the clnp_frag structure away... 66536369Ssklower */ 66636764Ssklower IFDEBUG(D_REASS) 66736764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n", 66836764Ssklower cf_next_hdr.cfr_bytes); 66936764Ssklower ENDDEBUG 67037469Ssklower m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); 67136369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 67236369Ssklower cf->cfr_next = next_frag; 67336369Ssklower } else { 67436369Ssklower cf = cf->cfr_next; 67536369Ssklower } 67636369Ssklower } 67736369Ssklower 67836369Ssklower cf = cfh->cfl_frags; 67936369Ssklower 68036369Ssklower IFDEBUG(D_REASS) 68136369Ssklower struct mbuf *mdump = cf->cfr_data; 68236369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 68336369Ssklower cf->cfr_last); 68436369Ssklower printf("clnp_comp_pdu: data for frag:\n"); 68536369Ssklower while (mdump != NULL) { 68636369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 68736369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 68836369Ssklower mdump = mdump->m_next; 68936369Ssklower } 69036369Ssklower ENDDEBUG 69136369Ssklower 69236369Ssklower /* Check if datagram is complete */ 69336369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 69436369Ssklower /* 69536369Ssklower * We have a complete pdu! 69636369Ssklower * - Remove the frag header from (only) remaining fragment 69736369Ssklower * (which is not really a fragment anymore, as the datagram is 69836369Ssklower * complete). 69936369Ssklower * - Prepend a clnp header 70036369Ssklower */ 70136369Ssklower struct mbuf *data = cf->cfr_data; 70236369Ssklower struct mbuf *hdr = cfh->cfl_orighdr; 70336369Ssklower struct clnp_fragl *scan; 70436369Ssklower 70536369Ssklower IFDEBUG(D_REASS) 70636369Ssklower printf("clnp_comp_pdu: complete pdu!\n"); 70736369Ssklower ENDDEBUG 70836369Ssklower 70937469Ssklower m_adj(data, (int)cf->cfr_bytes); 71036369Ssklower m_cat(hdr, data); 71136369Ssklower 71236369Ssklower IFDEBUG(D_DUMPIN) 71336369Ssklower struct mbuf *mdump = hdr; 71436369Ssklower printf("clnp_comp_pdu: pdu is:\n"); 71536369Ssklower while (mdump != NULL) { 71636369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 71736369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 71836369Ssklower mdump = mdump->m_next; 71936369Ssklower } 72036369Ssklower ENDDEBUG 72136369Ssklower 72236369Ssklower /* 72336369Ssklower * Remove cfh from the list of fragmented pdus 72436369Ssklower */ 72536369Ssklower if (clnp_frags == cfh) { 72636369Ssklower clnp_frags = cfh->cfl_next; 72736369Ssklower } else { 72836369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 72936369Ssklower if (scan->cfl_next == cfh) { 73036369Ssklower scan->cfl_next = cfh->cfl_next; 73136369Ssklower break; 73236369Ssklower } 73336369Ssklower } 73436369Ssklower } 73536369Ssklower 73636369Ssklower /* free cfh */ 73736369Ssklower m_freem(dtom(cfh)); 73836369Ssklower 73936369Ssklower return(hdr); 74036369Ssklower } 74136369Ssklower 74236369Ssklower return(NULL); 74336369Ssklower } 74436369Ssklower #ifdef TROLL 74537469Ssklower static int troll_cnt; 74637536Smckusick #include "time.h" 74736369Ssklower /* 74836369Ssklower * FUNCTION: troll_random 74936369Ssklower * 75036369Ssklower * PURPOSE: generate a pseudo-random number between 0 and 1 75136369Ssklower * 75236369Ssklower * RETURNS: the random number 75336369Ssklower * 75436369Ssklower * SIDE EFFECTS: 75536369Ssklower * 75636369Ssklower * NOTES: This is based on the clock. 75736369Ssklower */ 75836369Ssklower float troll_random() 75936369Ssklower { 76036369Ssklower extern struct timeval time; 76136369Ssklower long t = time.tv_usec % 100; 76236369Ssklower 76336369Ssklower return((float)t / (float) 100); 76436369Ssklower } 76536369Ssklower 76636369Ssklower /* 76736369Ssklower * FUNCTION: troll_output 76836369Ssklower * 76936369Ssklower * PURPOSE: Do something sneaky with the datagram passed. Possible 77036369Ssklower * operations are: 77136369Ssklower * Duplicate the packet 77236369Ssklower * Drop the packet 77336369Ssklower * Trim some number of bytes from the packet 77436369Ssklower * Munge some byte in the packet 77536369Ssklower * 77636369Ssklower * RETURNS: 0, or unix error code 77736369Ssklower * 77836369Ssklower * SIDE EFFECTS: 77936369Ssklower * 78036369Ssklower * NOTES: The operation of this procedure is regulated by the 78136369Ssklower * troll control structure (Troll). 78236369Ssklower */ 78336369Ssklower troll_output(ifp, m, dst) 78436369Ssklower struct ifnet *ifp; 78536369Ssklower struct mbuf *m; 78636369Ssklower struct sockaddr *dst; 78736369Ssklower { 78836369Ssklower int err = 0; 78936369Ssklower troll_cnt++; 79036369Ssklower 79136369Ssklower if (trollctl.tr_ops & TR_DUPPKT) { 79236369Ssklower /* 79336369Ssklower * Duplicate every Nth packet 79436369Ssklower * TODO: random? 79536369Ssklower */ 79636369Ssklower float f_freq = troll_cnt * trollctl.tr_dup_freq; 79736369Ssklower int i_freq = troll_cnt * trollctl.tr_dup_freq; 79836369Ssklower if (i_freq == f_freq) { 79937469Ssklower struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); 80036369Ssklower if (dup != NULL) 80136369Ssklower err = (*ifp->if_output)(ifp, dup, dst); 80236369Ssklower } 80336369Ssklower if (!err) 80436369Ssklower err = (*ifp->if_output)(ifp, m, dst); 80536369Ssklower return(err); 80636369Ssklower } else if (trollctl.tr_ops & TR_DROPPKT) { 80736369Ssklower } else if (trollctl.tr_ops & TR_CHANGE) { 80836369Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 80936369Ssklower clnp->cnf_cksum_msb = 0; 81036369Ssklower err = (*ifp->if_output)(ifp, m, dst); 81136369Ssklower return(err); 81236369Ssklower } else { 81336369Ssklower err = (*ifp->if_output)(ifp, m, dst); 81436369Ssklower return(err); 81536369Ssklower } 81636369Ssklower } 81736369Ssklower 81836369Ssklower #endif TROLL 819