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 */ 27*36764Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */ 28*36764Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */ 2936369Ssklower 3036369Ssklower #ifndef lint 31*36764Ssklower 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 3636369Ssklower #include "../h/types.h" 3736369Ssklower #include "../h/param.h" 3836369Ssklower #include "../h/mbuf.h" 3936369Ssklower #include "../h/domain.h" 4036369Ssklower #include "../h/protosw.h" 4136369Ssklower #include "../h/socket.h" 4236369Ssklower #include "../h/socketvar.h" 4336369Ssklower #include "../h/errno.h" 4436369Ssklower 4536369Ssklower #include "../net/if.h" 4636369Ssklower #include "../net/route.h" 4736369Ssklower 4836369Ssklower #include "../netiso/iso.h" 4936369Ssklower #include "../netiso/iso_var.h" 5036369Ssklower #include "../netiso/clnp.h" 5136369Ssklower #include "../netiso/clnp_stat.h" 5236369Ssklower #include "../netiso/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 #ifdef TROLL 6036369Ssklower float troll_random(); 6136369Ssklower static int troll_cnt = 0; 6236369Ssklower #endif TROLL 6336369Ssklower 6436369Ssklower 6536369Ssklower /* 6636369Ssklower * FUNCTION: clnp_fragment 6736369Ssklower * 6836369Ssklower * PURPOSE: Fragment a datagram, and send the itty bitty pieces 6936369Ssklower * out over an interface. 7036369Ssklower * 7136369Ssklower * RETURNS: success - 0 7236369Ssklower * failure - unix error code 7336369Ssklower * 7436369Ssklower * SIDE EFFECTS: 7536369Ssklower * 7636369Ssklower * NOTES: If there is an error sending the packet, clnp_discard 7736369Ssklower * is called to discard the packet and send an ER. If 7836369Ssklower * clnp_fragment was called from clnp_output, then 7936369Ssklower * we generated the packet, and should not send an 8036369Ssklower * ER -- clnp_emit_er will check for this. Otherwise, 8136369Ssklower * the packet was fragmented during forwarding. In this 8236369Ssklower * case, we ought to send an ER back. 8336369Ssklower */ 8436369Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags) 8536369Ssklower struct ifnet *ifp; /* ptr to outgoing interface */ 8636369Ssklower struct mbuf *m; /* ptr to packet */ 8736369Ssklower struct sockaddr *first_hop; /* ptr to first hop */ 8836369Ssklower int total_len; /* length of datagram */ 8936369Ssklower int segoff; /* offset of segpart in hdr */ 9036369Ssklower int flags; /* flags passed to clnp_output */ 9136369Ssklower { 9236369Ssklower struct clnp_fixed *clnp; /* ptr to fixed part of header */ 9336369Ssklower 9436369Ssklower clnp = mtod(m, struct clnp_fixed *); 9536369Ssklower 9636369Ssklower if (clnp->cnf_seg_ok) { 9736369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 9836369Ssklower struct mbuf *frag_hdr = NULL; 9936369Ssklower struct mbuf *frag_data = NULL; 10036369Ssklower struct clnp_segment seg_part, tmp_seg; /* segmentation header */ 10136369Ssklower extern int clnp_id; /* id of datagram */ 10236369Ssklower int error = 0; 10336369Ssklower 10436369Ssklower INCSTAT(cns_frag); 10536369Ssklower 10636369Ssklower seg_part.cng_id = clnp_id++; 10736369Ssklower seg_part.cng_off = 0; 10836369Ssklower seg_part.cng_tot_len = total_len; 10936369Ssklower 11036369Ssklower /* 11136369Ssklower * Duplicate header, and remove from packet 11236369Ssklower */ 11336369Ssklower if ((hdr = m_copy(m, 0, clnp->cnf_hdr_len)) == NULL) { 11436369Ssklower clnp_discard(m, GEN_CONGEST); 11536369Ssklower return(ENOBUFS); 11636369Ssklower } 11736369Ssklower m_adj(m, clnp->cnf_hdr_len); 11836369Ssklower total_len -= clnp->cnf_hdr_len; 11936369Ssklower 12036369Ssklower while (total_len > 0) { 12136369Ssklower int frag_size; 12236369Ssklower int last_frag = 0; /* true if this is the last fragment */ 123*36764Ssklower 124*36764Ssklower IFDEBUG(D_FRAG) 125*36764Ssklower struct mbuf *mdump = frag_hdr; 126*36764Ssklower int tot_mlen = 0; 127*36764Ssklower printf("clnp_fragment: total_len %d:\n", total_len); 128*36764Ssklower while (mdump != NULL) { 129*36764Ssklower printf("\tmbuf x%x, m_len %d\n", 130*36764Ssklower mdump, mdump->m_len); 131*36764Ssklower tot_mlen += mdump->m_len; 132*36764Ssklower mdump = mdump->m_next; 133*36764Ssklower } 134*36764Ssklower printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); 135*36764Ssklower ENDDEBUG 13636369Ssklower 13736369Ssklower frag_size = min(total_len, ifp->if_mtu - clnp->cnf_hdr_len); 13836369Ssklower 13936369Ssklower /* 14036369Ssklower * For some stupid reason, fragments must be at least 8 bytes 14136369Ssklower * in length. If this fragment will cause the last one to 14236369Ssklower * be less than 8 bytes, shorten this fragment a bit. 14336369Ssklower */ 14436369Ssklower if (((total_len - frag_size) > 0) && ((total_len - frag_size) < 8)) 14536369Ssklower frag_size -= (8 - (total_len - frag_size)); 14636369Ssklower 14736369Ssklower last_frag = ((total_len - frag_size) == 0); 14836369Ssklower 14936369Ssklower IFDEBUG(D_FRAG) 15036369Ssklower printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 15136369Ssklower seg_part.cng_off, frag_size, total_len-frag_size); 15236369Ssklower if (last_frag) 15336369Ssklower printf("clnp_fragment: last fragment\n"); 15436369Ssklower ENDDEBUG 15536369Ssklower 15636369Ssklower if (last_frag) { 15736369Ssklower /* 15836369Ssklower * this is the last fragment; we don't need to get any other 15936369Ssklower * mbufs. 16036369Ssklower */ 16136369Ssklower frag_hdr = hdr; 16236369Ssklower frag_data = m; 16336369Ssklower } else { 16436369Ssklower /* duplicate header and data mbufs */ 16536369Ssklower if ((frag_hdr = m_copy(hdr, 0, M_COPYALL)) == NULL) { 16636369Ssklower clnp_discard(m, GEN_CONGEST); 16736369Ssklower m_freem(hdr); 16836369Ssklower return(ENOBUFS); 16936369Ssklower } 17036369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { 17136369Ssklower clnp_discard(m, GEN_CONGEST); 17236369Ssklower m_freem(hdr); 17336369Ssklower m_freem(frag_hdr); 17436369Ssklower return(ENOBUFS); 17536369Ssklower } 17636369Ssklower } 17736369Ssklower clnp = mtod(frag_hdr, struct clnp_fixed *); 17836369Ssklower 17936369Ssklower if (!last_frag) 18036369Ssklower clnp->cnf_more_segs = 1; 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 { 19536369Ssklower int derived_len = clnp->cnf_hdr_len + frag_size; 19636369Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); 19736369Ssklower } 19836369Ssklower /* compute clnp checksum (on header only) */ 19936369Ssklower if (flags & CLNP_NO_CKSUM) { 20036369Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 20136369Ssklower } else { 20236369Ssklower iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 20336369Ssklower } 20436369Ssklower 20536369Ssklower IFDEBUG(D_DUMPOUT) 20636369Ssklower struct mbuf *mdump = frag_hdr; 20736369Ssklower printf("clnp_fragment: sending dg:\n"); 20836369Ssklower while (mdump != NULL) { 209*36764Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 21036369Ssklower mdump = mdump->m_next; 21136369Ssklower } 21236369Ssklower ENDDEBUG 21336369Ssklower 21436369Ssklower #ifdef TROLL 21536369Ssklower error = troll_output(ifp, frag_hdr, first_hop); 21636369Ssklower #else 21736369Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop); 21836369Ssklower #endif TROLL 21936369Ssklower 22036369Ssklower /* 22136369Ssklower * Tough situation: if the error occured on the last 22236369Ssklower * fragment, we can not send an ER, as the if_output 22336369Ssklower * routine consumed the packet. If the error occured 22436369Ssklower * on any intermediate packets, we can send an ER 22536369Ssklower * because we still have the original header in (m). 22636369Ssklower */ 22736369Ssklower if (error) { 22836369Ssklower if (frag_hdr != hdr) { 22936369Ssklower /* 23036369Ssklower * The error was not on the last fragment. We must 23136369Ssklower * free hdr and m before returning 23236369Ssklower */ 23336369Ssklower clnp_discard(m, GEN_NOREAS); 23436369Ssklower m_freem(hdr); 23536369Ssklower } 23636369Ssklower return(error); 23736369Ssklower } 23836369Ssklower 23936369Ssklower /* bump segment offset, trim data mbuf, and decrement count left */ 24036369Ssklower #ifdef TROLL 24136369Ssklower /* 24236369Ssklower * Decrement frag_size by some fraction. This will cause the 24336369Ssklower * next fragment to start 'early', thus duplicating the end 24436369Ssklower * of the current fragment. troll.tr_dup_size controls 24536369Ssklower * the fraction. If positive, it specifies the fraction. If 24636369Ssklower * negative, a random fraction is used. 24736369Ssklower */ 24836369Ssklower if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { 24936369Ssklower int num_bytes = frag_size; 25036369Ssklower 25136369Ssklower if (trollctl.tr_dup_size > 0) 25236369Ssklower num_bytes *= trollctl.tr_dup_size; 25336369Ssklower else 25436369Ssklower num_bytes *= troll_random(); 25536369Ssklower frag_size -= num_bytes; 25636369Ssklower } 25736369Ssklower #endif TROLL 25836369Ssklower total_len -= frag_size; 25936369Ssklower if (!last_frag) { 26036369Ssklower seg_part.cng_off += frag_size; 26136369Ssklower m_adj(m, frag_size); 26236369Ssklower } 26336369Ssklower } 26436369Ssklower return(0); 26536369Ssklower } else { 26636369Ssklower clnp_discard(m, GEN_SEGNEEDED); 26736369Ssklower return(EMSGSIZE); 26836369Ssklower } 26936369Ssklower } 27036369Ssklower 27136369Ssklower /* 27236369Ssklower * FUNCTION: clnp_reass 27336369Ssklower * 27436369Ssklower * PURPOSE: Attempt to reassemble a clnp packet given the current 27536369Ssklower * fragment. If reassembly succeeds (all the fragments 27636369Ssklower * are present), then return a pointer to an mbuf chain 27736369Ssklower * containing the reassembled packet. This packet will 27836369Ssklower * appear in the mbufs as if it had just arrived in 27936369Ssklower * one piece. 28036369Ssklower * 28136369Ssklower * If reassembly fails, then save this fragment and 28236369Ssklower * return 0. 28336369Ssklower * 28436369Ssklower * RETURNS: Ptr to assembled packet, or 0 28536369Ssklower * 28636369Ssklower * SIDE EFFECTS: 28736369Ssklower * 28836369Ssklower * NOTES: 28936369Ssklower * clnp_slowtimo can not affect this code because clnpintr, and thus 29036369Ssklower * this code, is called at a higher priority than clnp_slowtimo. 29136369Ssklower */ 29236369Ssklower struct mbuf * 29336369Ssklower clnp_reass(m, src, dst, seg) 29436369Ssklower struct mbuf *m; /* new fragment */ 29536369Ssklower struct iso_addr *src; /* src of new fragment */ 29636369Ssklower struct iso_addr *dst; /* dst of new fragment */ 29736369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 29836369Ssklower { 29936369Ssklower register struct clnp_fragl *cfh; 30036369Ssklower 30136369Ssklower /* look for other fragments of this datagram */ 30236369Ssklower for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { 30336369Ssklower if (iso_addrmatch1(src, &cfh->cfl_src) && 30436369Ssklower iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) { 30536369Ssklower IFDEBUG(D_REASS) 30636369Ssklower printf("clnp_reass: found packet\n"); 30736369Ssklower ENDDEBUG 30836369Ssklower /* 30936369Ssklower * There are other fragments here already. Lets see if 31036369Ssklower * this fragment is of any help 31136369Ssklower */ 31236369Ssklower clnp_insert_frag(cfh, m, seg); 31336369Ssklower return (clnp_comp_pdu(cfh)); 31436369Ssklower } 31536369Ssklower } 31636369Ssklower 31736369Ssklower IFDEBUG(D_REASS) 31836369Ssklower printf("clnp_reass: new packet!\n"); 31936369Ssklower ENDDEBUG 32036369Ssklower 32136369Ssklower /* 32236369Ssklower * This is the first fragment. If src is not consuming too many 32336369Ssklower * resources, then create a new fragment list and add 32436369Ssklower * this fragment to the list. 32536369Ssklower */ 32636369Ssklower /* TODO: don't let one src hog all the reassembly buffers */ 32736369Ssklower if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { 32836369Ssklower clnp_discard(m, GEN_CONGEST); 32936369Ssklower } 33036369Ssklower 33136369Ssklower return(NULL); 33236369Ssklower } 33336369Ssklower 33436369Ssklower /* 33536369Ssklower * FUNCTION: clnp_newpkt 33636369Ssklower * 33736369Ssklower * PURPOSE: Create the necessary structures to handle a new 33836369Ssklower * fragmented clnp packet. 33936369Ssklower * 34036369Ssklower * RETURNS: non-zero if it succeeds, zero if fails. 34136369Ssklower * 34236369Ssklower * SIDE EFFECTS: 34336369Ssklower * 34436369Ssklower * NOTES: Failure is only due to insufficient resources. 34536369Ssklower */ 34636369Ssklower clnp_newpkt(m, src, dst, seg) 34736369Ssklower struct mbuf *m; /* new fragment */ 34836369Ssklower struct iso_addr *src; /* src of new fragment */ 34936369Ssklower struct iso_addr *dst; /* dst of new fragment */ 35036369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 35136369Ssklower { 35236369Ssklower register struct clnp_fragl *cfh; 35336369Ssklower register struct clnp_fixed *clnp; 35436369Ssklower struct mbuf *m0; 35536369Ssklower 35636369Ssklower clnp = mtod(m, struct clnp_fixed *); 35736369Ssklower 35836369Ssklower /* 35936369Ssklower * Allocate new clnp fragl structure to act as header of all fragments 36036369Ssklower * for this datagram. 36136369Ssklower */ 36236369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE); 36336369Ssklower if (m0 == NULL) { 36436369Ssklower return (0); 36536369Ssklower } 36636369Ssklower cfh = mtod(m0, struct clnp_fragl *); 36736369Ssklower 36836369Ssklower /* 36936369Ssklower * Duplicate the header of this fragment, and save in cfh. 37036369Ssklower * Free m0 and return if m_copy does not succeed. 37136369Ssklower */ 37236369Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, clnp->cnf_hdr_len)) == NULL) { 37336369Ssklower m_freem(m0); 37436369Ssklower return (0); 37536369Ssklower } 37636369Ssklower 37736369Ssklower /* Fill in rest of fragl structure */ 37836369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 37936369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 38036369Ssklower cfh->cfl_id = seg->cng_id; 38136369Ssklower cfh->cfl_ttl = clnp->cnf_ttl; 38236369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 38336369Ssklower cfh->cfl_frags = NULL; 38436369Ssklower cfh->cfl_next = NULL; 38536369Ssklower 38636369Ssklower /* Insert into list of packets */ 38736369Ssklower cfh->cfl_next = clnp_frags; 38836369Ssklower clnp_frags = cfh; 38936369Ssklower 39036369Ssklower /* Insert this fragment into list headed by cfh */ 39136369Ssklower clnp_insert_frag(cfh, m, seg); 39236369Ssklower return(1); 39336369Ssklower } 39436369Ssklower 39536369Ssklower /* 39636369Ssklower * FUNCTION: clnp_insert_frag 39736369Ssklower * 39836369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'. 39936369Ssklower * 40036369Ssklower * RETURNS: nothing 40136369Ssklower * 40236369Ssklower * SIDE EFFECTS: 40336369Ssklower * 40436369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm. 40536369Ssklower * Each fragment in this list contains a clnp_frag 40636369Ssklower * structure followed by the data of the fragment. 40736369Ssklower * The clnp_frag structure actually lies on top of 40836369Ssklower * part of the old clnp header. 40936369Ssklower */ 41036369Ssklower clnp_insert_frag(cfh, m, seg) 41136369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */ 41236369Ssklower struct mbuf *m; /* new fragment */ 41336369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 41436369Ssklower { 41536369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 41636369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */ 41736369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 41836369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 41936369Ssklower u_short first; /* offset of first byte of initial pdu*/ 42036369Ssklower u_short last; /* offset of last byte of initial pdu */ 42136369Ssklower u_short fraglen;/* length of fragment */ 42236369Ssklower 42336369Ssklower clnp = mtod(m, struct clnp_fixed *); 42436369Ssklower first = seg->cng_off; 42536369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 42636369Ssklower fraglen -= clnp->cnf_hdr_len; 42736369Ssklower last = (first + fraglen) - 1; 42836369Ssklower 42936369Ssklower IFDEBUG(D_REASS) 43036369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 43136369Ssklower first, last, fraglen); 43236369Ssklower printf("clnp_insert_frag: current fragments:\n"); 43336369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 43436369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 43536369Ssklower } 43636369Ssklower ENDDEBUG 43736369Ssklower 43836369Ssklower if (cfh->cfl_frags != NULL) { 43936369Ssklower /* 44036369Ssklower * Find fragment which begins after the new one 44136369Ssklower */ 44236369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 44336369Ssklower if (cf->cfr_first > first) { 44436369Ssklower cf_sub = cf; 44536369Ssklower break; 44636369Ssklower } 44736369Ssklower } 44836369Ssklower 44936369Ssklower IFDEBUG(D_REASS) 45036369Ssklower printf("clnp_insert_frag: Previous frag is "); 45136369Ssklower if (cf_prev == NULL) 45236369Ssklower printf("NULL\n"); 45336369Ssklower else 45436369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 45536369Ssklower printf("clnp_insert_frag: Subsequent frag is "); 45636369Ssklower if (cf_sub == NULL) 45736369Ssklower printf("NULL\n"); 45836369Ssklower else 45936369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 46036369Ssklower ENDDEBUG 46136369Ssklower 46236369Ssklower /* 46336369Ssklower * If there is a fragment before the new one, check if it 46436369Ssklower * overlaps the new one. If so, then trim the end of the 46536369Ssklower * previous one. 46636369Ssklower */ 46736369Ssklower if (cf_prev != NULL) { 46836369Ssklower if (cf_prev->cfr_last > first) { 46936369Ssklower u_short overlap = cf_prev->cfr_last - first; 47036369Ssklower 47136369Ssklower IFDEBUG(D_REASS) 47236369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n", 47336369Ssklower overlap); 47436369Ssklower ENDDEBUG 47536369Ssklower 47636369Ssklower if (overlap > fraglen) { 47736369Ssklower /* 47836369Ssklower * The new fragment is entirely contained in the 47936369Ssklower * preceeding one. We can punt on the new frag 48036369Ssklower * completely. 48136369Ssklower */ 48236369Ssklower m_freem(m); 48336369Ssklower return; 48436369Ssklower } else { 48536369Ssklower /* Trim data off of end of previous fragment */ 48636369Ssklower /* inc overlap to prevent duplication of last byte */ 48736369Ssklower overlap++; 48836369Ssklower m_adj(cf_prev->cfr_data, -overlap); 48936369Ssklower cf_prev->cfr_last -= overlap; 49036369Ssklower } 49136369Ssklower } 49236369Ssklower } 49336369Ssklower 49436369Ssklower /* 49536369Ssklower * For all fragments past the new one, check if any data on 49636369Ssklower * the new one overlaps data on existing fragments. If so, 49736369Ssklower * then trim the extra data off the end of the new one. 49836369Ssklower */ 49936369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 50036369Ssklower if (cf->cfr_first < last) { 50136369Ssklower u_short overlap = last - cf->cfr_first; 50236369Ssklower 50336369Ssklower IFDEBUG(D_REASS) 50436369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n", 50536369Ssklower overlap); 50636369Ssklower ENDDEBUG 50736369Ssklower 50836369Ssklower if (overlap > fraglen) { 50936369Ssklower /* 51036369Ssklower * The new fragment is entirely contained in the 51136369Ssklower * succeeding one. This should not happen, because 51236369Ssklower * early on in this code we scanned for the fragment 51336369Ssklower * which started after the new one! 51436369Ssklower */ 51536369Ssklower m_freem(m); 51636369Ssklower printf("clnp_insert_frag: internal error!\n"); 51736369Ssklower return; 51836369Ssklower } else { 51936369Ssklower /* Trim data off of end of new fragment */ 52036369Ssklower /* inc overlap to prevent duplication of last byte */ 52136369Ssklower overlap++; 52236369Ssklower m_adj(m, -overlap); 52336369Ssklower last -= overlap; 52436369Ssklower } 52536369Ssklower } 52636369Ssklower } 52736369Ssklower } 52836369Ssklower 52936369Ssklower /* 53036369Ssklower * Insert the new fragment beween cf_prev and cf_sub 53136369Ssklower * 53236369Ssklower * Note: the clnp hdr is still in the mbuf. 53336369Ssklower * If the data of the mbuf is not word aligned, shave off enough 53436369Ssklower * so that it is. Then, cast the clnp_frag structure on top 53536369Ssklower * of the clnp header. 53636369Ssklower * The clnp_hdr will not be used again (as we already have 53736369Ssklower * saved a copy of it). 53836369Ssklower * 53936369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to 54036369Ssklower * the data of the packet. This is used when we coalesce fragments; 54136369Ssklower * the clnp_frag structure must be removed before joining mbufs. 54236369Ssklower */ 54336369Ssklower { 54436369Ssklower int pad; 54536369Ssklower u_int bytes; 54636369Ssklower 54736369Ssklower /* determine if header is not word aligned */ 54836369Ssklower pad = (int)clnp % 4; 54936369Ssklower if (pad < 0) 55036369Ssklower pad = -pad; 55136369Ssklower 55236369Ssklower /* bytes is number of bytes left in front of data */ 55336369Ssklower bytes = clnp->cnf_hdr_len - pad; 55436369Ssklower 555*36764Ssklower IFDEBUG(D_REASS) 556*36764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 557*36764Ssklower clnp, pad); 558*36764Ssklower ENDDEBUG 559*36764Ssklower 56036369Ssklower /* make it word aligned if necessary */ 56136369Ssklower if (pad) 56236369Ssklower m_adj(m, pad); 56336369Ssklower 56436369Ssklower cf = mtod(m, struct clnp_frag *); 56536369Ssklower cf->cfr_bytes = bytes; 566*36764Ssklower 567*36764Ssklower IFDEBUG(D_REASS) 568*36764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 569*36764Ssklower cf->cfr_bytes); 570*36764Ssklower ENDDEBUG 57136369Ssklower } 57236369Ssklower cf->cfr_first = first; 57336369Ssklower cf->cfr_last = last; 57436369Ssklower 57536369Ssklower 57636369Ssklower /* 57736369Ssklower * The data is the mbuf itself, although we must remember that the 57836369Ssklower * first few bytes are actually a clnp_frag structure 57936369Ssklower */ 58036369Ssklower cf->cfr_data = m; 58136369Ssklower 58236369Ssklower /* link into place */ 58336369Ssklower cf->cfr_next = cf_sub; 58436369Ssklower if (cf_prev == NULL) 58536369Ssklower cfh->cfl_frags = cf; 58636369Ssklower else 58736369Ssklower cf_prev->cfr_next = cf; 58836369Ssklower } 58936369Ssklower 59036369Ssklower /* 59136369Ssklower * FUNCTION: clnp_comp_pdu 59236369Ssklower * 59336369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge 59436369Ssklower * any contigious fragments into one. If, after 59536369Ssklower * traversing all the fragments, it is determined that 59636369Ssklower * the packet is complete, then return a pointer to 59736369Ssklower * the packet (with header prepended). Otherwise, 59836369Ssklower * return NULL. 59936369Ssklower * 60036369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 60136369Ssklower * 60236369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one. 60336369Ssklower * 60436369Ssklower * NOTES: This code assumes that there are no overlaps of 60536369Ssklower * fragment pdus. 60636369Ssklower */ 60736369Ssklower struct mbuf * 60836369Ssklower clnp_comp_pdu(cfh) 60936369Ssklower struct clnp_fragl *cfh; /* fragment header */ 61036369Ssklower { 61136369Ssklower register struct clnp_frag *cf = cfh->cfl_frags; 61236369Ssklower 61336369Ssklower while (cf->cfr_next != NULL) { 61436369Ssklower register struct clnp_frag *cf_next = cf->cfr_next; 61536369Ssklower 61636369Ssklower IFDEBUG(D_REASS) 61736369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 61836369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 61936369Ssklower cf_next->cfr_last); 62036369Ssklower ENDDEBUG 62136369Ssklower 62236369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) { 62336369Ssklower /* 62436369Ssklower * Merge fragment cf and cf_next 62536369Ssklower * 62636369Ssklower * - update cf header 62736369Ssklower * - trim clnp_frag structure off of cf_next 62836369Ssklower * - append cf_next to cf 62936369Ssklower */ 63036369Ssklower struct clnp_frag cf_next_hdr; 63136369Ssklower struct clnp_frag *next_frag; 63236369Ssklower 63336369Ssklower cf_next_hdr = *cf_next; 63436369Ssklower next_frag = cf_next->cfr_next; 63536369Ssklower 63636369Ssklower IFDEBUG(D_REASS) 63736369Ssklower struct mbuf *mdump; 638*36764Ssklower int l; 63936369Ssklower printf("clnp_comp_pdu: merging fragments\n"); 640*36764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 641*36764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 64236369Ssklower mdump = cf->cfr_data; 643*36764Ssklower l = 0; 64436369Ssklower while (mdump != NULL) { 64536369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 646*36764Ssklower l += mdump->m_len; 64736369Ssklower mdump = mdump->m_next; 64836369Ssklower } 649*36764Ssklower printf("\ttotal len: %d\n", l); 650*36764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 651*36764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 65236369Ssklower mdump = cf_next->cfr_data; 653*36764Ssklower l = 0; 65436369Ssklower while (mdump != NULL) { 65536369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 656*36764Ssklower l += mdump->m_len; 65736369Ssklower mdump = mdump->m_next; 65836369Ssklower } 659*36764Ssklower printf("\ttotal len: %d\n", l); 66036369Ssklower ENDDEBUG 66136369Ssklower 66236369Ssklower cf->cfr_last = cf_next->cfr_last; 66336369Ssklower /* 66436369Ssklower * After this m_adj, the cf_next ptr is useless because we 66536369Ssklower * have adjusted the clnp_frag structure away... 66636369Ssklower */ 667*36764Ssklower IFDEBUG(D_REASS) 668*36764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n", 669*36764Ssklower cf_next_hdr.cfr_bytes); 670*36764Ssklower ENDDEBUG 67136369Ssklower m_adj(cf_next_hdr.cfr_data, cf_next_hdr.cfr_bytes); 67236369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 67336369Ssklower cf->cfr_next = next_frag; 67436369Ssklower } else { 67536369Ssklower cf = cf->cfr_next; 67636369Ssklower } 67736369Ssklower } 67836369Ssklower 67936369Ssklower cf = cfh->cfl_frags; 68036369Ssklower 68136369Ssklower IFDEBUG(D_REASS) 68236369Ssklower struct mbuf *mdump = cf->cfr_data; 68336369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 68436369Ssklower cf->cfr_last); 68536369Ssklower printf("clnp_comp_pdu: data for frag:\n"); 68636369Ssklower while (mdump != NULL) { 68736369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 68836369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 68936369Ssklower mdump = mdump->m_next; 69036369Ssklower } 69136369Ssklower ENDDEBUG 69236369Ssklower 69336369Ssklower /* Check if datagram is complete */ 69436369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 69536369Ssklower /* 69636369Ssklower * We have a complete pdu! 69736369Ssklower * - Remove the frag header from (only) remaining fragment 69836369Ssklower * (which is not really a fragment anymore, as the datagram is 69936369Ssklower * complete). 70036369Ssklower * - Prepend a clnp header 70136369Ssklower */ 70236369Ssklower struct mbuf *data = cf->cfr_data; 70336369Ssklower struct mbuf *hdr = cfh->cfl_orighdr; 70436369Ssklower struct clnp_fragl *scan; 70536369Ssklower 70636369Ssklower IFDEBUG(D_REASS) 70736369Ssklower printf("clnp_comp_pdu: complete pdu!\n"); 70836369Ssklower ENDDEBUG 70936369Ssklower 71036369Ssklower m_adj(data, cf->cfr_bytes); 71136369Ssklower m_cat(hdr, data); 71236369Ssklower 71336369Ssklower IFDEBUG(D_DUMPIN) 71436369Ssklower struct mbuf *mdump = hdr; 71536369Ssklower printf("clnp_comp_pdu: pdu is:\n"); 71636369Ssklower while (mdump != NULL) { 71736369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 71836369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 71936369Ssklower mdump = mdump->m_next; 72036369Ssklower } 72136369Ssklower ENDDEBUG 72236369Ssklower 72336369Ssklower /* 72436369Ssklower * Remove cfh from the list of fragmented pdus 72536369Ssklower */ 72636369Ssklower if (clnp_frags == cfh) { 72736369Ssklower clnp_frags = cfh->cfl_next; 72836369Ssklower } else { 72936369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 73036369Ssklower if (scan->cfl_next == cfh) { 73136369Ssklower scan->cfl_next = cfh->cfl_next; 73236369Ssklower break; 73336369Ssklower } 73436369Ssklower } 73536369Ssklower } 73636369Ssklower 73736369Ssklower /* free cfh */ 73836369Ssklower m_freem(dtom(cfh)); 73936369Ssklower 74036369Ssklower return(hdr); 74136369Ssklower } 74236369Ssklower 74336369Ssklower return(NULL); 74436369Ssklower } 74536369Ssklower #ifdef TROLL 74636369Ssklower #include "../h/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) { 79936369Ssklower struct mbuf *dup = m_copy(m, 0, 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 81936369Ssklower #endif ISO 820