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 $ */ 2936369Ssklower 3036369Ssklower #ifndef lint 3136764Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $"; 3236369Ssklower #endif lint 3336369Ssklower 3436369Ssklower #ifdef ISO 3536369Ssklower 36*37536Smckusick #include "types.h" 37*37536Smckusick #include "param.h" 38*37536Smckusick #include "mbuf.h" 39*37536Smckusick #include "domain.h" 40*37536Smckusick #include "protosw.h" 41*37536Smckusick #include "socket.h" 42*37536Smckusick #include "socketvar.h" 43*37536Smckusick #include "errno.h" 4436369Ssklower 4536369Ssklower #include "../net/if.h" 4636369Ssklower #include "../net/route.h" 4736369Ssklower 4837469Ssklower #include "iso.h" 4937469Ssklower #include "iso_var.h" 5037469Ssklower #include "clnp.h" 5137469Ssklower #include "clnp_stat.h" 5237469Ssklower #include "argo_debug.h" 5336369Ssklower 5436369Ssklower /* all fragments are hung off this list */ 5536369Ssklower struct clnp_fragl *clnp_frags = NULL; 5636369Ssklower 5736369Ssklower struct mbuf *clnp_comp_pdu(); 5836369Ssklower 5936369Ssklower 6036369Ssklower /* 6136369Ssklower * FUNCTION: clnp_fragment 6236369Ssklower * 6336369Ssklower * PURPOSE: Fragment a datagram, and send the itty bitty pieces 6436369Ssklower * out over an interface. 6536369Ssklower * 6636369Ssklower * RETURNS: success - 0 6736369Ssklower * failure - unix error code 6836369Ssklower * 6936369Ssklower * SIDE EFFECTS: 7036369Ssklower * 7136369Ssklower * NOTES: If there is an error sending the packet, clnp_discard 7236369Ssklower * is called to discard the packet and send an ER. If 7336369Ssklower * clnp_fragment was called from clnp_output, then 7436369Ssklower * we generated the packet, and should not send an 7536369Ssklower * ER -- clnp_emit_er will check for this. Otherwise, 7636369Ssklower * the packet was fragmented during forwarding. In this 7736369Ssklower * case, we ought to send an ER back. 7836369Ssklower */ 7936369Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags) 8036369Ssklower struct ifnet *ifp; /* ptr to outgoing interface */ 8136369Ssklower struct mbuf *m; /* ptr to packet */ 8236369Ssklower struct sockaddr *first_hop; /* ptr to first hop */ 8336369Ssklower int total_len; /* length of datagram */ 8436369Ssklower int segoff; /* offset of segpart in hdr */ 8536369Ssklower int flags; /* flags passed to clnp_output */ 8636369Ssklower { 8736369Ssklower struct clnp_fixed *clnp; /* ptr to fixed part of header */ 8836369Ssklower 8936369Ssklower clnp = mtod(m, struct clnp_fixed *); 9036369Ssklower 9137469Ssklower if (clnp->cnf_type & CNF_SEG_OK) { 9236369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 9336369Ssklower struct mbuf *frag_hdr = NULL; 9436369Ssklower struct mbuf *frag_data = NULL; 9536369Ssklower struct clnp_segment seg_part, tmp_seg; /* segmentation header */ 9636369Ssklower extern int clnp_id; /* id of datagram */ 9736369Ssklower int error = 0; 9836369Ssklower 9936369Ssklower INCSTAT(cns_frag); 10036369Ssklower 10136369Ssklower seg_part.cng_id = clnp_id++; 10236369Ssklower seg_part.cng_off = 0; 10336369Ssklower seg_part.cng_tot_len = total_len; 10436369Ssklower 10536369Ssklower /* 10636369Ssklower * Duplicate header, and remove from packet 10736369Ssklower */ 10837469Ssklower if ((hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 10936369Ssklower clnp_discard(m, GEN_CONGEST); 11036369Ssklower return(ENOBUFS); 11136369Ssklower } 11237469Ssklower m_adj(m, (int)clnp->cnf_hdr_len); 11336369Ssklower total_len -= clnp->cnf_hdr_len; 11436369Ssklower 11536369Ssklower while (total_len > 0) { 11636369Ssklower int frag_size; 11736369Ssklower int last_frag = 0; /* true if this is the last fragment */ 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 13236369Ssklower frag_size = min(total_len, ifp->if_mtu - clnp->cnf_hdr_len); 13336369Ssklower 13436369Ssklower /* 13536369Ssklower * For some stupid reason, fragments must be at least 8 bytes 13636369Ssklower * in length. If this fragment will cause the last one to 13736369Ssklower * be less than 8 bytes, shorten this fragment a bit. 13836369Ssklower */ 13936369Ssklower if (((total_len - frag_size) > 0) && ((total_len - frag_size) < 8)) 14036369Ssklower frag_size -= (8 - (total_len - frag_size)); 14136369Ssklower 14236369Ssklower last_frag = ((total_len - frag_size) == 0); 14336369Ssklower 14436369Ssklower IFDEBUG(D_FRAG) 14536369Ssklower printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 14636369Ssklower seg_part.cng_off, frag_size, total_len-frag_size); 14736369Ssklower if (last_frag) 14836369Ssklower printf("clnp_fragment: last fragment\n"); 14936369Ssklower ENDDEBUG 15036369Ssklower 15136369Ssklower if (last_frag) { 15236369Ssklower /* 15336369Ssklower * this is the last fragment; we don't need to get any other 15436369Ssklower * mbufs. 15536369Ssklower */ 15636369Ssklower frag_hdr = hdr; 15736369Ssklower frag_data = m; 15836369Ssklower } else { 15936369Ssklower /* duplicate header and data mbufs */ 16037469Ssklower if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { 16136369Ssklower clnp_discard(m, GEN_CONGEST); 16236369Ssklower m_freem(hdr); 16336369Ssklower return(ENOBUFS); 16436369Ssklower } 16536369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { 16636369Ssklower clnp_discard(m, GEN_CONGEST); 16736369Ssklower m_freem(hdr); 16836369Ssklower m_freem(frag_hdr); 16936369Ssklower return(ENOBUFS); 17036369Ssklower } 17136369Ssklower } 17236369Ssklower clnp = mtod(frag_hdr, struct clnp_fixed *); 17336369Ssklower 17436369Ssklower if (!last_frag) 17537469Ssklower clnp->cnf_type |= CNF_MORE_SEGS; 17636369Ssklower 17736369Ssklower /* link together */ 17836369Ssklower m_cat(frag_hdr, frag_data); 17936369Ssklower 18036369Ssklower /* make sure segmentation fields are in network order */ 18136369Ssklower tmp_seg.cng_id = htons(seg_part.cng_id); 18236369Ssklower tmp_seg.cng_off = htons(seg_part.cng_off); 18336369Ssklower tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len); 18436369Ssklower 18536369Ssklower /* insert segmentation part */ 18636369Ssklower bcopy((caddr_t)&tmp_seg, mtod(frag_hdr, caddr_t) + segoff, 18736369Ssklower sizeof(struct clnp_segment)); 18836369Ssklower 18936369Ssklower { 19036369Ssklower int derived_len = clnp->cnf_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 { 20036369Ssklower iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, (int)clnp->cnf_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 21336369Ssklower error = troll_output(ifp, frag_hdr, first_hop); 21436369Ssklower #else 21536369Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop); 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 */ 23136369Ssklower clnp_discard(m, GEN_NOREAS); 23236369Ssklower m_freem(hdr); 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) { 25836369Ssklower seg_part.cng_off += frag_size; 25936369Ssklower m_adj(m, frag_size); 26036369Ssklower } 26136369Ssklower } 26236369Ssklower return(0); 26336369Ssklower } else { 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 */) { 32636369Ssklower clnp_discard(m, GEN_CONGEST); 32736369Ssklower } 32836369Ssklower 32936369Ssklower return(NULL); 33036369Ssklower } 33136369Ssklower 33236369Ssklower /* 33336369Ssklower * FUNCTION: clnp_newpkt 33436369Ssklower * 33536369Ssklower * PURPOSE: Create the necessary structures to handle a new 33636369Ssklower * fragmented clnp packet. 33736369Ssklower * 33836369Ssklower * RETURNS: non-zero if it succeeds, zero if fails. 33936369Ssklower * 34036369Ssklower * SIDE EFFECTS: 34136369Ssklower * 34236369Ssklower * NOTES: Failure is only due to insufficient resources. 34336369Ssklower */ 34436369Ssklower clnp_newpkt(m, src, dst, seg) 34536369Ssklower struct mbuf *m; /* new fragment */ 34636369Ssklower struct iso_addr *src; /* src of new fragment */ 34736369Ssklower struct iso_addr *dst; /* dst of new fragment */ 34836369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 34936369Ssklower { 35036369Ssklower register struct clnp_fragl *cfh; 35136369Ssklower register struct clnp_fixed *clnp; 35236369Ssklower struct mbuf *m0; 35336369Ssklower 35436369Ssklower clnp = mtod(m, struct clnp_fixed *); 35536369Ssklower 35636369Ssklower /* 35736369Ssklower * Allocate new clnp fragl structure to act as header of all fragments 35836369Ssklower * for this datagram. 35936369Ssklower */ 36036369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE); 36136369Ssklower if (m0 == NULL) { 36236369Ssklower return (0); 36336369Ssklower } 36436369Ssklower cfh = mtod(m0, struct clnp_fragl *); 36536369Ssklower 36636369Ssklower /* 36736369Ssklower * Duplicate the header of this fragment, and save in cfh. 36836369Ssklower * Free m0 and return if m_copy does not succeed. 36936369Ssklower */ 37037469Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 37136369Ssklower m_freem(m0); 37236369Ssklower return (0); 37336369Ssklower } 37436369Ssklower 37536369Ssklower /* Fill in rest of fragl structure */ 37636369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 37736369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 37836369Ssklower cfh->cfl_id = seg->cng_id; 37936369Ssklower cfh->cfl_ttl = clnp->cnf_ttl; 38036369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 38136369Ssklower cfh->cfl_frags = NULL; 38236369Ssklower cfh->cfl_next = NULL; 38336369Ssklower 38436369Ssklower /* Insert into list of packets */ 38536369Ssklower cfh->cfl_next = clnp_frags; 38636369Ssklower clnp_frags = cfh; 38736369Ssklower 38836369Ssklower /* Insert this fragment into list headed by cfh */ 38936369Ssklower clnp_insert_frag(cfh, m, seg); 39036369Ssklower return(1); 39136369Ssklower } 39236369Ssklower 39336369Ssklower /* 39436369Ssklower * FUNCTION: clnp_insert_frag 39536369Ssklower * 39636369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'. 39736369Ssklower * 39836369Ssklower * RETURNS: nothing 39936369Ssklower * 40036369Ssklower * SIDE EFFECTS: 40136369Ssklower * 40236369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm. 40336369Ssklower * Each fragment in this list contains a clnp_frag 40436369Ssklower * structure followed by the data of the fragment. 40536369Ssklower * The clnp_frag structure actually lies on top of 40636369Ssklower * part of the old clnp header. 40736369Ssklower */ 40836369Ssklower clnp_insert_frag(cfh, m, seg) 40936369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */ 41036369Ssklower struct mbuf *m; /* new fragment */ 41136369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 41236369Ssklower { 41336369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 41436369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */ 41536369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 41636369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 41736369Ssklower u_short first; /* offset of first byte of initial pdu*/ 41836369Ssklower u_short last; /* offset of last byte of initial pdu */ 41936369Ssklower u_short fraglen;/* length of fragment */ 42036369Ssklower 42136369Ssklower clnp = mtod(m, struct clnp_fixed *); 42236369Ssklower first = seg->cng_off; 42336369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 42436369Ssklower fraglen -= clnp->cnf_hdr_len; 42536369Ssklower last = (first + fraglen) - 1; 42636369Ssklower 42736369Ssklower IFDEBUG(D_REASS) 42836369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 42936369Ssklower first, last, fraglen); 43036369Ssklower printf("clnp_insert_frag: current fragments:\n"); 43136369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 43236369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 43336369Ssklower } 43436369Ssklower ENDDEBUG 43536369Ssklower 43636369Ssklower if (cfh->cfl_frags != NULL) { 43736369Ssklower /* 43836369Ssklower * Find fragment which begins after the new one 43936369Ssklower */ 44036369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 44136369Ssklower if (cf->cfr_first > first) { 44236369Ssklower cf_sub = cf; 44336369Ssklower break; 44436369Ssklower } 44536369Ssklower } 44636369Ssklower 44736369Ssklower IFDEBUG(D_REASS) 44836369Ssklower printf("clnp_insert_frag: Previous frag is "); 44936369Ssklower if (cf_prev == NULL) 45036369Ssklower printf("NULL\n"); 45136369Ssklower else 45236369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 45336369Ssklower printf("clnp_insert_frag: Subsequent frag is "); 45436369Ssklower if (cf_sub == NULL) 45536369Ssklower printf("NULL\n"); 45636369Ssklower else 45736369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 45836369Ssklower ENDDEBUG 45936369Ssklower 46036369Ssklower /* 46136369Ssklower * If there is a fragment before the new one, check if it 46236369Ssklower * overlaps the new one. If so, then trim the end of the 46336369Ssklower * previous one. 46436369Ssklower */ 46536369Ssklower if (cf_prev != NULL) { 46636369Ssklower if (cf_prev->cfr_last > first) { 46736369Ssklower u_short overlap = cf_prev->cfr_last - first; 46836369Ssklower 46936369Ssklower IFDEBUG(D_REASS) 47036369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n", 47136369Ssklower overlap); 47236369Ssklower ENDDEBUG 47336369Ssklower 47436369Ssklower if (overlap > fraglen) { 47536369Ssklower /* 47636369Ssklower * The new fragment is entirely contained in the 47736369Ssklower * preceeding one. We can punt on the new frag 47836369Ssklower * completely. 47936369Ssklower */ 48036369Ssklower m_freem(m); 48136369Ssklower return; 48236369Ssklower } else { 48336369Ssklower /* Trim data off of end of previous fragment */ 48436369Ssklower /* inc overlap to prevent duplication of last byte */ 48536369Ssklower overlap++; 48637469Ssklower m_adj(cf_prev->cfr_data, -(int)overlap); 48736369Ssklower cf_prev->cfr_last -= overlap; 48836369Ssklower } 48936369Ssklower } 49036369Ssklower } 49136369Ssklower 49236369Ssklower /* 49336369Ssklower * For all fragments past the new one, check if any data on 49436369Ssklower * the new one overlaps data on existing fragments. If so, 49536369Ssklower * then trim the extra data off the end of the new one. 49636369Ssklower */ 49736369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 49836369Ssklower if (cf->cfr_first < last) { 49936369Ssklower u_short overlap = last - cf->cfr_first; 50036369Ssklower 50136369Ssklower IFDEBUG(D_REASS) 50236369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n", 50336369Ssklower overlap); 50436369Ssklower ENDDEBUG 50536369Ssklower 50636369Ssklower if (overlap > fraglen) { 50736369Ssklower /* 50836369Ssklower * The new fragment is entirely contained in the 50936369Ssklower * succeeding one. This should not happen, because 51036369Ssklower * early on in this code we scanned for the fragment 51136369Ssklower * which started after the new one! 51236369Ssklower */ 51336369Ssklower m_freem(m); 51436369Ssklower printf("clnp_insert_frag: internal error!\n"); 51536369Ssklower return; 51636369Ssklower } else { 51736369Ssklower /* Trim data off of end of new fragment */ 51836369Ssklower /* inc overlap to prevent duplication of last byte */ 51936369Ssklower overlap++; 52037469Ssklower m_adj(m, -(int)overlap); 52136369Ssklower last -= overlap; 52236369Ssklower } 52336369Ssklower } 52436369Ssklower } 52536369Ssklower } 52636369Ssklower 52736369Ssklower /* 52836369Ssklower * Insert the new fragment beween cf_prev and cf_sub 52936369Ssklower * 53036369Ssklower * Note: the clnp hdr is still in the mbuf. 53136369Ssklower * If the data of the mbuf is not word aligned, shave off enough 53236369Ssklower * so that it is. Then, cast the clnp_frag structure on top 53336369Ssklower * of the clnp header. 53436369Ssklower * The clnp_hdr will not be used again (as we already have 53536369Ssklower * saved a copy of it). 53636369Ssklower * 53736369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to 53836369Ssklower * the data of the packet. This is used when we coalesce fragments; 53936369Ssklower * the clnp_frag structure must be removed before joining mbufs. 54036369Ssklower */ 54136369Ssklower { 54236369Ssklower int pad; 54336369Ssklower u_int bytes; 54436369Ssklower 54536369Ssklower /* determine if header is not word aligned */ 54636369Ssklower pad = (int)clnp % 4; 54736369Ssklower if (pad < 0) 54836369Ssklower pad = -pad; 54936369Ssklower 55036369Ssklower /* bytes is number of bytes left in front of data */ 55136369Ssklower bytes = clnp->cnf_hdr_len - pad; 55236369Ssklower 55336764Ssklower IFDEBUG(D_REASS) 55436764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 55536764Ssklower clnp, pad); 55636764Ssklower ENDDEBUG 55736764Ssklower 55836369Ssklower /* make it word aligned if necessary */ 55936369Ssklower if (pad) 56036369Ssklower m_adj(m, pad); 56136369Ssklower 56236369Ssklower cf = mtod(m, struct clnp_frag *); 56336369Ssklower cf->cfr_bytes = bytes; 56436764Ssklower 56536764Ssklower IFDEBUG(D_REASS) 56636764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 56736764Ssklower cf->cfr_bytes); 56836764Ssklower ENDDEBUG 56936369Ssklower } 57036369Ssklower cf->cfr_first = first; 57136369Ssklower cf->cfr_last = last; 57236369Ssklower 57336369Ssklower 57436369Ssklower /* 57536369Ssklower * The data is the mbuf itself, although we must remember that the 57636369Ssklower * first few bytes are actually a clnp_frag structure 57736369Ssklower */ 57836369Ssklower cf->cfr_data = m; 57936369Ssklower 58036369Ssklower /* link into place */ 58136369Ssklower cf->cfr_next = cf_sub; 58236369Ssklower if (cf_prev == NULL) 58336369Ssklower cfh->cfl_frags = cf; 58436369Ssklower else 58536369Ssklower cf_prev->cfr_next = cf; 58636369Ssklower } 58736369Ssklower 58836369Ssklower /* 58936369Ssklower * FUNCTION: clnp_comp_pdu 59036369Ssklower * 59136369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge 59236369Ssklower * any contigious fragments into one. If, after 59336369Ssklower * traversing all the fragments, it is determined that 59436369Ssklower * the packet is complete, then return a pointer to 59536369Ssklower * the packet (with header prepended). Otherwise, 59636369Ssklower * return NULL. 59736369Ssklower * 59836369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 59936369Ssklower * 60036369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one. 60136369Ssklower * 60236369Ssklower * NOTES: This code assumes that there are no overlaps of 60336369Ssklower * fragment pdus. 60436369Ssklower */ 60536369Ssklower struct mbuf * 60636369Ssklower clnp_comp_pdu(cfh) 60736369Ssklower struct clnp_fragl *cfh; /* fragment header */ 60836369Ssklower { 60936369Ssklower register struct clnp_frag *cf = cfh->cfl_frags; 61036369Ssklower 61136369Ssklower while (cf->cfr_next != NULL) { 61236369Ssklower register struct clnp_frag *cf_next = cf->cfr_next; 61336369Ssklower 61436369Ssklower IFDEBUG(D_REASS) 61536369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 61636369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 61736369Ssklower cf_next->cfr_last); 61836369Ssklower ENDDEBUG 61936369Ssklower 62036369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) { 62136369Ssklower /* 62236369Ssklower * Merge fragment cf and cf_next 62336369Ssklower * 62436369Ssklower * - update cf header 62536369Ssklower * - trim clnp_frag structure off of cf_next 62636369Ssklower * - append cf_next to cf 62736369Ssklower */ 62836369Ssklower struct clnp_frag cf_next_hdr; 62936369Ssklower struct clnp_frag *next_frag; 63036369Ssklower 63136369Ssklower cf_next_hdr = *cf_next; 63236369Ssklower next_frag = cf_next->cfr_next; 63336369Ssklower 63436369Ssklower IFDEBUG(D_REASS) 63536369Ssklower struct mbuf *mdump; 63636764Ssklower int l; 63736369Ssklower printf("clnp_comp_pdu: merging fragments\n"); 63836764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 63936764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 64036369Ssklower mdump = cf->cfr_data; 64136764Ssklower l = 0; 64236369Ssklower while (mdump != NULL) { 64336369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 64436764Ssklower l += mdump->m_len; 64536369Ssklower mdump = mdump->m_next; 64636369Ssklower } 64736764Ssklower printf("\ttotal len: %d\n", l); 64836764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 64936764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 65036369Ssklower mdump = cf_next->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); 65836369Ssklower ENDDEBUG 65936369Ssklower 66036369Ssklower cf->cfr_last = cf_next->cfr_last; 66136369Ssklower /* 66236369Ssklower * After this m_adj, the cf_next ptr is useless because we 66336369Ssklower * have adjusted the clnp_frag structure away... 66436369Ssklower */ 66536764Ssklower IFDEBUG(D_REASS) 66636764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n", 66736764Ssklower cf_next_hdr.cfr_bytes); 66836764Ssklower ENDDEBUG 66937469Ssklower m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); 67036369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 67136369Ssklower cf->cfr_next = next_frag; 67236369Ssklower } else { 67336369Ssklower cf = cf->cfr_next; 67436369Ssklower } 67536369Ssklower } 67636369Ssklower 67736369Ssklower cf = cfh->cfl_frags; 67836369Ssklower 67936369Ssklower IFDEBUG(D_REASS) 68036369Ssklower struct mbuf *mdump = cf->cfr_data; 68136369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 68236369Ssklower cf->cfr_last); 68336369Ssklower printf("clnp_comp_pdu: data for frag:\n"); 68436369Ssklower while (mdump != NULL) { 68536369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 68636369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 68736369Ssklower mdump = mdump->m_next; 68836369Ssklower } 68936369Ssklower ENDDEBUG 69036369Ssklower 69136369Ssklower /* Check if datagram is complete */ 69236369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 69336369Ssklower /* 69436369Ssklower * We have a complete pdu! 69536369Ssklower * - Remove the frag header from (only) remaining fragment 69636369Ssklower * (which is not really a fragment anymore, as the datagram is 69736369Ssklower * complete). 69836369Ssklower * - Prepend a clnp header 69936369Ssklower */ 70036369Ssklower struct mbuf *data = cf->cfr_data; 70136369Ssklower struct mbuf *hdr = cfh->cfl_orighdr; 70236369Ssklower struct clnp_fragl *scan; 70336369Ssklower 70436369Ssklower IFDEBUG(D_REASS) 70536369Ssklower printf("clnp_comp_pdu: complete pdu!\n"); 70636369Ssklower ENDDEBUG 70736369Ssklower 70837469Ssklower m_adj(data, (int)cf->cfr_bytes); 70936369Ssklower m_cat(hdr, data); 71036369Ssklower 71136369Ssklower IFDEBUG(D_DUMPIN) 71236369Ssklower struct mbuf *mdump = hdr; 71336369Ssklower printf("clnp_comp_pdu: pdu is:\n"); 71436369Ssklower while (mdump != NULL) { 71536369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 71636369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 71736369Ssklower mdump = mdump->m_next; 71836369Ssklower } 71936369Ssklower ENDDEBUG 72036369Ssklower 72136369Ssklower /* 72236369Ssklower * Remove cfh from the list of fragmented pdus 72336369Ssklower */ 72436369Ssklower if (clnp_frags == cfh) { 72536369Ssklower clnp_frags = cfh->cfl_next; 72636369Ssklower } else { 72736369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 72836369Ssklower if (scan->cfl_next == cfh) { 72936369Ssklower scan->cfl_next = cfh->cfl_next; 73036369Ssklower break; 73136369Ssklower } 73236369Ssklower } 73336369Ssklower } 73436369Ssklower 73536369Ssklower /* free cfh */ 73636369Ssklower m_freem(dtom(cfh)); 73736369Ssklower 73836369Ssklower return(hdr); 73936369Ssklower } 74036369Ssklower 74136369Ssklower return(NULL); 74236369Ssklower } 74336369Ssklower #ifdef TROLL 74437469Ssklower static int troll_cnt; 745*37536Smckusick #include "time.h" 74636369Ssklower /* 74736369Ssklower * FUNCTION: troll_random 74836369Ssklower * 74936369Ssklower * PURPOSE: generate a pseudo-random number between 0 and 1 75036369Ssklower * 75136369Ssklower * RETURNS: the random number 75236369Ssklower * 75336369Ssklower * SIDE EFFECTS: 75436369Ssklower * 75536369Ssklower * NOTES: This is based on the clock. 75636369Ssklower */ 75736369Ssklower float troll_random() 75836369Ssklower { 75936369Ssklower extern struct timeval time; 76036369Ssklower long t = time.tv_usec % 100; 76136369Ssklower 76236369Ssklower return((float)t / (float) 100); 76336369Ssklower } 76436369Ssklower 76536369Ssklower /* 76636369Ssklower * FUNCTION: troll_output 76736369Ssklower * 76836369Ssklower * PURPOSE: Do something sneaky with the datagram passed. Possible 76936369Ssklower * operations are: 77036369Ssklower * Duplicate the packet 77136369Ssklower * Drop the packet 77236369Ssklower * Trim some number of bytes from the packet 77336369Ssklower * Munge some byte in the packet 77436369Ssklower * 77536369Ssklower * RETURNS: 0, or unix error code 77636369Ssklower * 77736369Ssklower * SIDE EFFECTS: 77836369Ssklower * 77936369Ssklower * NOTES: The operation of this procedure is regulated by the 78036369Ssklower * troll control structure (Troll). 78136369Ssklower */ 78236369Ssklower troll_output(ifp, m, dst) 78336369Ssklower struct ifnet *ifp; 78436369Ssklower struct mbuf *m; 78536369Ssklower struct sockaddr *dst; 78636369Ssklower { 78736369Ssklower int err = 0; 78836369Ssklower troll_cnt++; 78936369Ssklower 79036369Ssklower if (trollctl.tr_ops & TR_DUPPKT) { 79136369Ssklower /* 79236369Ssklower * Duplicate every Nth packet 79336369Ssklower * TODO: random? 79436369Ssklower */ 79536369Ssklower float f_freq = troll_cnt * trollctl.tr_dup_freq; 79636369Ssklower int i_freq = troll_cnt * trollctl.tr_dup_freq; 79736369Ssklower if (i_freq == f_freq) { 79837469Ssklower struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); 79936369Ssklower if (dup != NULL) 80036369Ssklower err = (*ifp->if_output)(ifp, dup, dst); 80136369Ssklower } 80236369Ssklower if (!err) 80336369Ssklower err = (*ifp->if_output)(ifp, m, dst); 80436369Ssklower return(err); 80536369Ssklower } else if (trollctl.tr_ops & TR_DROPPKT) { 80636369Ssklower } else if (trollctl.tr_ops & TR_CHANGE) { 80736369Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 80836369Ssklower clnp->cnf_cksum_msb = 0; 80936369Ssklower err = (*ifp->if_output)(ifp, m, dst); 81036369Ssklower return(err); 81136369Ssklower } else { 81236369Ssklower err = (*ifp->if_output)(ifp, m, dst); 81336369Ssklower return(err); 81436369Ssklower } 81536369Ssklower } 81636369Ssklower 81736369Ssklower #endif TROLL 81836369Ssklower #endif ISO 819