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*40776Ssklower /* @(#)clnp_frag.c 7.8 (Berkeley) 04/05/90 */ 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 */ 77*40776Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt) 7836369Ssklower struct ifnet *ifp; /* ptr to outgoing interface */ 7936369Ssklower struct mbuf *m; /* ptr to packet */ 8036369Ssklower struct sockaddr *first_hop; /* ptr to first hop */ 8136369Ssklower int total_len; /* length of datagram */ 8236369Ssklower int segoff; /* offset of segpart in hdr */ 8336369Ssklower int flags; /* flags passed to clnp_output */ 84*40776Ssklower struct rtentry *rt; /* route if direct ether */ 8536369Ssklower { 8639232Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 8739232Ssklower int hdr_len = (int)clnp->cnf_hdr_len; 8839232Ssklower int frag_size = (ifp->if_mtu - hdr_len) & ~7; 8936369Ssklower 9039232Ssklower total_len -= hdr_len; 9139232Ssklower if ((clnp->cnf_type & CNF_SEG_OK) && 9239232Ssklower (total_len >= 8) && 9339232Ssklower (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { 9436369Ssklower 9536369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 9636369Ssklower struct mbuf *frag_hdr = NULL; 9736369Ssklower struct mbuf *frag_data = NULL; 9836369Ssklower struct clnp_segment seg_part, tmp_seg; /* segmentation header */ 9936369Ssklower extern int clnp_id; /* id of datagram */ 10039232Ssklower int frag_size; 10136369Ssklower int error = 0; 10236369Ssklower 10339232Ssklower 10439195Ssklower INCSTAT(cns_fragmented); 10536369Ssklower seg_part.cng_id = clnp_id++; 10636369Ssklower seg_part.cng_off = 0; 10739232Ssklower seg_part.cng_tot_len = total_len + hdr_len; 10836369Ssklower /* 10936369Ssklower * Duplicate header, and remove from packet 11036369Ssklower */ 11139232Ssklower if ((hdr = m_copy(m, 0, hdr_len)) == NULL) { 11236369Ssklower clnp_discard(m, GEN_CONGEST); 11336369Ssklower return(ENOBUFS); 11436369Ssklower } 11539232Ssklower m_adj(m, hdr_len); 11639232Ssklower 11736369Ssklower while (total_len > 0) { 11839232Ssklower int remaining, last_frag; 11936764Ssklower 12036764Ssklower IFDEBUG(D_FRAG) 12136764Ssklower struct mbuf *mdump = frag_hdr; 12236764Ssklower int tot_mlen = 0; 12336764Ssklower printf("clnp_fragment: total_len %d:\n", total_len); 12436764Ssklower while (mdump != NULL) { 12536764Ssklower printf("\tmbuf x%x, m_len %d\n", 12636764Ssklower mdump, mdump->m_len); 12736764Ssklower tot_mlen += mdump->m_len; 12836764Ssklower mdump = mdump->m_next; 12936764Ssklower } 13036764Ssklower printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); 13136764Ssklower ENDDEBUG 13236369Ssklower 13339232Ssklower frag_size = min(total_len, frag_size); 13439232Ssklower if ((remaining = total_len - frag_size) == 0) 13539232Ssklower last_frag = 1; 13639232Ssklower else { 13739232Ssklower /* 13839232Ssklower * If this fragment will cause the last one to 13939232Ssklower * be less than 8 bytes, shorten this fragment a bit. 14039232Ssklower * The obscure test on frag_size above ensures that 14139232Ssklower * frag_size will be positive. 14239232Ssklower */ 14339232Ssklower last_frag = 0; 14439232Ssklower if (remaining < 8) 14539232Ssklower frag_size -= 8; 14639232Ssklower } 14736369Ssklower 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 */ 16537469Ssklower if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { 16639232Ssklower clnp_discard(hdr, GEN_CONGEST); 16739232Ssklower m_freem(m); 16836369Ssklower return(ENOBUFS); 16936369Ssklower } 17036369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { 17139232Ssklower clnp_discard(hdr, GEN_CONGEST); 17239232Ssklower m_freem(m); 17336369Ssklower m_freem(frag_hdr); 17436369Ssklower return(ENOBUFS); 17536369Ssklower } 17639195Ssklower INCSTAT(cns_fragments); 17736369Ssklower } 17836369Ssklower clnp = mtod(frag_hdr, struct clnp_fixed *); 17936369Ssklower 18036369Ssklower if (!last_frag) 18137469Ssklower clnp->cnf_type |= CNF_MORE_SEGS; 18236369Ssklower 18336369Ssklower /* link together */ 18436369Ssklower m_cat(frag_hdr, frag_data); 18536369Ssklower 18636369Ssklower /* make sure segmentation fields are in network order */ 18736369Ssklower tmp_seg.cng_id = htons(seg_part.cng_id); 18836369Ssklower tmp_seg.cng_off = htons(seg_part.cng_off); 18936369Ssklower tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len); 19036369Ssklower 19136369Ssklower /* insert segmentation part */ 19236369Ssklower bcopy((caddr_t)&tmp_seg, mtod(frag_hdr, caddr_t) + segoff, 19336369Ssklower sizeof(struct clnp_segment)); 19436369Ssklower 19536369Ssklower { 19639232Ssklower int derived_len = hdr_len + frag_size; 19736369Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); 19837469Ssklower if ((frag_hdr->m_flags & M_PKTHDR) == 0) 19937469Ssklower panic("clnp_frag:lost header"); 20037469Ssklower frag_hdr->m_pkthdr.len = derived_len; 20136369Ssklower } 20236369Ssklower /* compute clnp checksum (on header only) */ 20336369Ssklower if (flags & CLNP_NO_CKSUM) { 20436369Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 20536369Ssklower } else { 20639232Ssklower iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len); 20736369Ssklower } 20836369Ssklower 20936369Ssklower IFDEBUG(D_DUMPOUT) 21036369Ssklower struct mbuf *mdump = frag_hdr; 21136369Ssklower printf("clnp_fragment: sending dg:\n"); 21236369Ssklower while (mdump != NULL) { 21336764Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 21436369Ssklower mdump = mdump->m_next; 21536369Ssklower } 21636369Ssklower ENDDEBUG 21736369Ssklower 21836369Ssklower #ifdef TROLL 219*40776Ssklower error = troll_output(ifp, frag_hdr, first_hop, rt); 22036369Ssklower #else 221*40776Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt); 22236369Ssklower #endif TROLL 22336369Ssklower 22436369Ssklower /* 22536369Ssklower * Tough situation: if the error occured on the last 22636369Ssklower * fragment, we can not send an ER, as the if_output 22736369Ssklower * routine consumed the packet. If the error occured 22836369Ssklower * on any intermediate packets, we can send an ER 22936369Ssklower * because we still have the original header in (m). 23036369Ssklower */ 23136369Ssklower if (error) { 23236369Ssklower if (frag_hdr != hdr) { 23336369Ssklower /* 23436369Ssklower * The error was not on the last fragment. We must 23536369Ssklower * free hdr and m before returning 23636369Ssklower */ 23739232Ssklower clnp_discard(hdr, GEN_NOREAS); 23839232Ssklower m_freem(m); 23936369Ssklower } 24036369Ssklower return(error); 24136369Ssklower } 24236369Ssklower 24336369Ssklower /* bump segment offset, trim data mbuf, and decrement count left */ 24436369Ssklower #ifdef TROLL 24536369Ssklower /* 24636369Ssklower * Decrement frag_size by some fraction. This will cause the 24736369Ssklower * next fragment to start 'early', thus duplicating the end 24836369Ssklower * of the current fragment. troll.tr_dup_size controls 24936369Ssklower * the fraction. If positive, it specifies the fraction. If 25036369Ssklower * negative, a random fraction is used. 25136369Ssklower */ 25236369Ssklower if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { 25336369Ssklower int num_bytes = frag_size; 25436369Ssklower 25536369Ssklower if (trollctl.tr_dup_size > 0) 25636369Ssklower num_bytes *= trollctl.tr_dup_size; 25736369Ssklower else 25836369Ssklower num_bytes *= troll_random(); 25936369Ssklower frag_size -= num_bytes; 26036369Ssklower } 26136369Ssklower #endif TROLL 26236369Ssklower total_len -= frag_size; 26336369Ssklower if (!last_frag) { 26436369Ssklower seg_part.cng_off += frag_size; 26536369Ssklower m_adj(m, frag_size); 26636369Ssklower } 26736369Ssklower } 26836369Ssklower return(0); 26936369Ssklower } else { 27039232Ssklower cantfrag: 27139195Ssklower INCSTAT(cns_cantfrag); 27236369Ssklower clnp_discard(m, GEN_SEGNEEDED); 27336369Ssklower return(EMSGSIZE); 27436369Ssklower } 27536369Ssklower } 27636369Ssklower 27736369Ssklower /* 27836369Ssklower * FUNCTION: clnp_reass 27936369Ssklower * 28036369Ssklower * PURPOSE: Attempt to reassemble a clnp packet given the current 28136369Ssklower * fragment. If reassembly succeeds (all the fragments 28236369Ssklower * are present), then return a pointer to an mbuf chain 28336369Ssklower * containing the reassembled packet. This packet will 28436369Ssklower * appear in the mbufs as if it had just arrived in 28536369Ssklower * one piece. 28636369Ssklower * 28736369Ssklower * If reassembly fails, then save this fragment and 28836369Ssklower * return 0. 28936369Ssklower * 29036369Ssklower * RETURNS: Ptr to assembled packet, or 0 29136369Ssklower * 29236369Ssklower * SIDE EFFECTS: 29336369Ssklower * 29436369Ssklower * NOTES: 29536369Ssklower * clnp_slowtimo can not affect this code because clnpintr, and thus 29636369Ssklower * this code, is called at a higher priority than clnp_slowtimo. 29736369Ssklower */ 29836369Ssklower struct mbuf * 29936369Ssklower clnp_reass(m, src, dst, seg) 30036369Ssklower struct mbuf *m; /* new fragment */ 30136369Ssklower struct iso_addr *src; /* src of new fragment */ 30236369Ssklower struct iso_addr *dst; /* dst of new fragment */ 30336369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 30436369Ssklower { 30536369Ssklower register struct clnp_fragl *cfh; 30636369Ssklower 30736369Ssklower /* look for other fragments of this datagram */ 30836369Ssklower for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { 30936369Ssklower if (iso_addrmatch1(src, &cfh->cfl_src) && 31036369Ssklower iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) { 31136369Ssklower IFDEBUG(D_REASS) 31236369Ssklower printf("clnp_reass: found packet\n"); 31336369Ssklower ENDDEBUG 31436369Ssklower /* 31536369Ssklower * There are other fragments here already. Lets see if 31636369Ssklower * this fragment is of any help 31736369Ssklower */ 31836369Ssklower clnp_insert_frag(cfh, m, seg); 31936369Ssklower return (clnp_comp_pdu(cfh)); 32036369Ssklower } 32136369Ssklower } 32236369Ssklower 32336369Ssklower IFDEBUG(D_REASS) 32436369Ssklower printf("clnp_reass: new packet!\n"); 32536369Ssklower ENDDEBUG 32636369Ssklower 32736369Ssklower /* 32836369Ssklower * This is the first fragment. If src is not consuming too many 32936369Ssklower * resources, then create a new fragment list and add 33036369Ssklower * this fragment to the list. 33136369Ssklower */ 33236369Ssklower /* TODO: don't let one src hog all the reassembly buffers */ 33336369Ssklower if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { 33439195Ssklower INCSTAT(cns_fragdropped); 33536369Ssklower clnp_discard(m, GEN_CONGEST); 33636369Ssklower } 33736369Ssklower 33836369Ssklower return(NULL); 33936369Ssklower } 34036369Ssklower 34136369Ssklower /* 34236369Ssklower * FUNCTION: clnp_newpkt 34336369Ssklower * 34436369Ssklower * PURPOSE: Create the necessary structures to handle a new 34536369Ssklower * fragmented clnp packet. 34636369Ssklower * 34736369Ssklower * RETURNS: non-zero if it succeeds, zero if fails. 34836369Ssklower * 34936369Ssklower * SIDE EFFECTS: 35036369Ssklower * 35136369Ssklower * NOTES: Failure is only due to insufficient resources. 35236369Ssklower */ 35336369Ssklower clnp_newpkt(m, src, dst, seg) 35436369Ssklower struct mbuf *m; /* new fragment */ 35536369Ssklower struct iso_addr *src; /* src of new fragment */ 35636369Ssklower struct iso_addr *dst; /* dst of new fragment */ 35736369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 35836369Ssklower { 35936369Ssklower register struct clnp_fragl *cfh; 36036369Ssklower register struct clnp_fixed *clnp; 36136369Ssklower struct mbuf *m0; 36236369Ssklower 36336369Ssklower clnp = mtod(m, struct clnp_fixed *); 36436369Ssklower 36536369Ssklower /* 36636369Ssklower * Allocate new clnp fragl structure to act as header of all fragments 36736369Ssklower * for this datagram. 36836369Ssklower */ 36936369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE); 37036369Ssklower if (m0 == NULL) { 37136369Ssklower return (0); 37236369Ssklower } 37336369Ssklower cfh = mtod(m0, struct clnp_fragl *); 37436369Ssklower 37536369Ssklower /* 37636369Ssklower * Duplicate the header of this fragment, and save in cfh. 37736369Ssklower * Free m0 and return if m_copy does not succeed. 37836369Ssklower */ 37937469Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 38036369Ssklower m_freem(m0); 38136369Ssklower return (0); 38236369Ssklower } 38336369Ssklower 38436369Ssklower /* Fill in rest of fragl structure */ 38536369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 38636369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 38736369Ssklower cfh->cfl_id = seg->cng_id; 38836369Ssklower cfh->cfl_ttl = clnp->cnf_ttl; 38936369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 39036369Ssklower cfh->cfl_frags = NULL; 39136369Ssklower cfh->cfl_next = NULL; 39236369Ssklower 39336369Ssklower /* Insert into list of packets */ 39436369Ssklower cfh->cfl_next = clnp_frags; 39536369Ssklower clnp_frags = cfh; 39636369Ssklower 39736369Ssklower /* Insert this fragment into list headed by cfh */ 39836369Ssklower clnp_insert_frag(cfh, m, seg); 39936369Ssklower return(1); 40036369Ssklower } 40136369Ssklower 40236369Ssklower /* 40336369Ssklower * FUNCTION: clnp_insert_frag 40436369Ssklower * 40536369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'. 40636369Ssklower * 40736369Ssklower * RETURNS: nothing 40836369Ssklower * 40936369Ssklower * SIDE EFFECTS: 41036369Ssklower * 41136369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm. 41236369Ssklower * Each fragment in this list contains a clnp_frag 41336369Ssklower * structure followed by the data of the fragment. 41436369Ssklower * The clnp_frag structure actually lies on top of 41536369Ssklower * part of the old clnp header. 41636369Ssklower */ 41736369Ssklower clnp_insert_frag(cfh, m, seg) 41836369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */ 41936369Ssklower struct mbuf *m; /* new fragment */ 42036369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 42136369Ssklower { 42236369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 42336369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */ 42436369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 42536369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 42636369Ssklower u_short first; /* offset of first byte of initial pdu*/ 42736369Ssklower u_short last; /* offset of last byte of initial pdu */ 42836369Ssklower u_short fraglen;/* length of fragment */ 42936369Ssklower 43036369Ssklower clnp = mtod(m, struct clnp_fixed *); 43136369Ssklower first = seg->cng_off; 43236369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 43336369Ssklower fraglen -= clnp->cnf_hdr_len; 43436369Ssklower last = (first + fraglen) - 1; 43536369Ssklower 43636369Ssklower IFDEBUG(D_REASS) 43736369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 43836369Ssklower first, last, fraglen); 43936369Ssklower printf("clnp_insert_frag: current fragments:\n"); 44036369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 44136369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 44236369Ssklower } 44336369Ssklower ENDDEBUG 44436369Ssklower 44536369Ssklower if (cfh->cfl_frags != NULL) { 44636369Ssklower /* 44736369Ssklower * Find fragment which begins after the new one 44836369Ssklower */ 44936369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 45036369Ssklower if (cf->cfr_first > first) { 45136369Ssklower cf_sub = cf; 45236369Ssklower break; 45336369Ssklower } 45436369Ssklower } 45536369Ssklower 45636369Ssklower IFDEBUG(D_REASS) 45736369Ssklower printf("clnp_insert_frag: Previous frag is "); 45836369Ssklower if (cf_prev == NULL) 45936369Ssklower printf("NULL\n"); 46036369Ssklower else 46136369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 46236369Ssklower printf("clnp_insert_frag: Subsequent frag is "); 46336369Ssklower if (cf_sub == NULL) 46436369Ssklower printf("NULL\n"); 46536369Ssklower else 46636369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 46736369Ssklower ENDDEBUG 46836369Ssklower 46936369Ssklower /* 47036369Ssklower * If there is a fragment before the new one, check if it 47136369Ssklower * overlaps the new one. If so, then trim the end of the 47236369Ssklower * previous one. 47336369Ssklower */ 47436369Ssklower if (cf_prev != NULL) { 47536369Ssklower if (cf_prev->cfr_last > first) { 47636369Ssklower u_short overlap = cf_prev->cfr_last - first; 47736369Ssklower 47836369Ssklower IFDEBUG(D_REASS) 47936369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n", 48036369Ssklower overlap); 48136369Ssklower ENDDEBUG 48236369Ssklower 48336369Ssklower if (overlap > fraglen) { 48436369Ssklower /* 48536369Ssklower * The new fragment is entirely contained in the 48636369Ssklower * preceeding one. We can punt on the new frag 48736369Ssklower * completely. 48836369Ssklower */ 48936369Ssklower m_freem(m); 49036369Ssklower return; 49136369Ssklower } else { 49236369Ssklower /* Trim data off of end of previous fragment */ 49336369Ssklower /* inc overlap to prevent duplication of last byte */ 49436369Ssklower overlap++; 49537469Ssklower m_adj(cf_prev->cfr_data, -(int)overlap); 49636369Ssklower cf_prev->cfr_last -= overlap; 49736369Ssklower } 49836369Ssklower } 49936369Ssklower } 50036369Ssklower 50136369Ssklower /* 50236369Ssklower * For all fragments past the new one, check if any data on 50336369Ssklower * the new one overlaps data on existing fragments. If so, 50436369Ssklower * then trim the extra data off the end of the new one. 50536369Ssklower */ 50636369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 50736369Ssklower if (cf->cfr_first < last) { 50836369Ssklower u_short overlap = last - cf->cfr_first; 50936369Ssklower 51036369Ssklower IFDEBUG(D_REASS) 51136369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n", 51236369Ssklower overlap); 51336369Ssklower ENDDEBUG 51436369Ssklower 51536369Ssklower if (overlap > fraglen) { 51636369Ssklower /* 51736369Ssklower * The new fragment is entirely contained in the 51836369Ssklower * succeeding one. This should not happen, because 51936369Ssklower * early on in this code we scanned for the fragment 52036369Ssklower * which started after the new one! 52136369Ssklower */ 52236369Ssklower m_freem(m); 52336369Ssklower printf("clnp_insert_frag: internal error!\n"); 52436369Ssklower return; 52536369Ssklower } else { 52636369Ssklower /* Trim data off of end of new fragment */ 52736369Ssklower /* inc overlap to prevent duplication of last byte */ 52836369Ssklower overlap++; 52937469Ssklower m_adj(m, -(int)overlap); 53036369Ssklower last -= overlap; 53136369Ssklower } 53236369Ssklower } 53336369Ssklower } 53436369Ssklower } 53536369Ssklower 53636369Ssklower /* 53736369Ssklower * Insert the new fragment beween cf_prev and cf_sub 53836369Ssklower * 53936369Ssklower * Note: the clnp hdr is still in the mbuf. 54036369Ssklower * If the data of the mbuf is not word aligned, shave off enough 54136369Ssklower * so that it is. Then, cast the clnp_frag structure on top 54236369Ssklower * of the clnp header. 54336369Ssklower * The clnp_hdr will not be used again (as we already have 54436369Ssklower * saved a copy of it). 54536369Ssklower * 54636369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to 54736369Ssklower * the data of the packet. This is used when we coalesce fragments; 54836369Ssklower * the clnp_frag structure must be removed before joining mbufs. 54936369Ssklower */ 55036369Ssklower { 55136369Ssklower int pad; 55236369Ssklower u_int bytes; 55336369Ssklower 55436369Ssklower /* determine if header is not word aligned */ 55536369Ssklower pad = (int)clnp % 4; 55636369Ssklower if (pad < 0) 55736369Ssklower pad = -pad; 55836369Ssklower 55936369Ssklower /* bytes is number of bytes left in front of data */ 56036369Ssklower bytes = clnp->cnf_hdr_len - pad; 56136369Ssklower 56236764Ssklower IFDEBUG(D_REASS) 56336764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 56436764Ssklower clnp, pad); 56536764Ssklower ENDDEBUG 56636764Ssklower 56736369Ssklower /* make it word aligned if necessary */ 56836369Ssklower if (pad) 56936369Ssklower m_adj(m, pad); 57036369Ssklower 57136369Ssklower cf = mtod(m, struct clnp_frag *); 57236369Ssklower cf->cfr_bytes = bytes; 57336764Ssklower 57436764Ssklower IFDEBUG(D_REASS) 57536764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 57636764Ssklower cf->cfr_bytes); 57736764Ssklower ENDDEBUG 57836369Ssklower } 57936369Ssklower cf->cfr_first = first; 58036369Ssklower cf->cfr_last = last; 58136369Ssklower 58236369Ssklower 58336369Ssklower /* 58436369Ssklower * The data is the mbuf itself, although we must remember that the 58536369Ssklower * first few bytes are actually a clnp_frag structure 58636369Ssklower */ 58736369Ssklower cf->cfr_data = m; 58836369Ssklower 58936369Ssklower /* link into place */ 59036369Ssklower cf->cfr_next = cf_sub; 59136369Ssklower if (cf_prev == NULL) 59236369Ssklower cfh->cfl_frags = cf; 59336369Ssklower else 59436369Ssklower cf_prev->cfr_next = cf; 59536369Ssklower } 59636369Ssklower 59736369Ssklower /* 59836369Ssklower * FUNCTION: clnp_comp_pdu 59936369Ssklower * 60036369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge 60136369Ssklower * any contigious fragments into one. If, after 60236369Ssklower * traversing all the fragments, it is determined that 60336369Ssklower * the packet is complete, then return a pointer to 60436369Ssklower * the packet (with header prepended). Otherwise, 60536369Ssklower * return NULL. 60636369Ssklower * 60736369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 60836369Ssklower * 60936369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one. 61036369Ssklower * 61136369Ssklower * NOTES: This code assumes that there are no overlaps of 61236369Ssklower * fragment pdus. 61336369Ssklower */ 61436369Ssklower struct mbuf * 61536369Ssklower clnp_comp_pdu(cfh) 61636369Ssklower struct clnp_fragl *cfh; /* fragment header */ 61736369Ssklower { 61836369Ssklower register struct clnp_frag *cf = cfh->cfl_frags; 61936369Ssklower 62036369Ssklower while (cf->cfr_next != NULL) { 62136369Ssklower register struct clnp_frag *cf_next = cf->cfr_next; 62236369Ssklower 62336369Ssklower IFDEBUG(D_REASS) 62436369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 62536369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 62636369Ssklower cf_next->cfr_last); 62736369Ssklower ENDDEBUG 62836369Ssklower 62936369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) { 63036369Ssklower /* 63136369Ssklower * Merge fragment cf and cf_next 63236369Ssklower * 63336369Ssklower * - update cf header 63436369Ssklower * - trim clnp_frag structure off of cf_next 63536369Ssklower * - append cf_next to cf 63636369Ssklower */ 63736369Ssklower struct clnp_frag cf_next_hdr; 63836369Ssklower struct clnp_frag *next_frag; 63936369Ssklower 64036369Ssklower cf_next_hdr = *cf_next; 64136369Ssklower next_frag = cf_next->cfr_next; 64236369Ssklower 64336369Ssklower IFDEBUG(D_REASS) 64436369Ssklower struct mbuf *mdump; 64536764Ssklower int l; 64636369Ssklower printf("clnp_comp_pdu: merging fragments\n"); 64736764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 64836764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 64936369Ssklower mdump = cf->cfr_data; 65036764Ssklower l = 0; 65136369Ssklower while (mdump != NULL) { 65236369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 65336764Ssklower l += mdump->m_len; 65436369Ssklower mdump = mdump->m_next; 65536369Ssklower } 65636764Ssklower printf("\ttotal len: %d\n", l); 65736764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 65836764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 65936369Ssklower mdump = cf_next->cfr_data; 66036764Ssklower l = 0; 66136369Ssklower while (mdump != NULL) { 66236369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 66336764Ssklower l += mdump->m_len; 66436369Ssklower mdump = mdump->m_next; 66536369Ssklower } 66636764Ssklower printf("\ttotal len: %d\n", l); 66736369Ssklower ENDDEBUG 66836369Ssklower 66936369Ssklower cf->cfr_last = cf_next->cfr_last; 67036369Ssklower /* 67136369Ssklower * After this m_adj, the cf_next ptr is useless because we 67236369Ssklower * have adjusted the clnp_frag structure away... 67336369Ssklower */ 67436764Ssklower IFDEBUG(D_REASS) 67536764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n", 67636764Ssklower cf_next_hdr.cfr_bytes); 67736764Ssklower ENDDEBUG 67837469Ssklower m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); 67936369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 68036369Ssklower cf->cfr_next = next_frag; 68136369Ssklower } else { 68236369Ssklower cf = cf->cfr_next; 68336369Ssklower } 68436369Ssklower } 68536369Ssklower 68636369Ssklower cf = cfh->cfl_frags; 68736369Ssklower 68836369Ssklower IFDEBUG(D_REASS) 68936369Ssklower struct mbuf *mdump = cf->cfr_data; 69036369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 69136369Ssklower cf->cfr_last); 69236369Ssklower printf("clnp_comp_pdu: data for frag:\n"); 69336369Ssklower while (mdump != NULL) { 69436369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 69536369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 69636369Ssklower mdump = mdump->m_next; 69736369Ssklower } 69836369Ssklower ENDDEBUG 69936369Ssklower 70036369Ssklower /* Check if datagram is complete */ 70136369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 70236369Ssklower /* 70336369Ssklower * We have a complete pdu! 70436369Ssklower * - Remove the frag header from (only) remaining fragment 70536369Ssklower * (which is not really a fragment anymore, as the datagram is 70636369Ssklower * complete). 70736369Ssklower * - Prepend a clnp header 70836369Ssklower */ 70936369Ssklower struct mbuf *data = cf->cfr_data; 71036369Ssklower struct mbuf *hdr = cfh->cfl_orighdr; 71136369Ssklower struct clnp_fragl *scan; 71236369Ssklower 71336369Ssklower IFDEBUG(D_REASS) 71436369Ssklower printf("clnp_comp_pdu: complete pdu!\n"); 71536369Ssklower ENDDEBUG 71636369Ssklower 71737469Ssklower m_adj(data, (int)cf->cfr_bytes); 71836369Ssklower m_cat(hdr, data); 71936369Ssklower 72036369Ssklower IFDEBUG(D_DUMPIN) 72136369Ssklower struct mbuf *mdump = hdr; 72236369Ssklower printf("clnp_comp_pdu: pdu is:\n"); 72336369Ssklower while (mdump != NULL) { 72436369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 72536369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 72636369Ssklower mdump = mdump->m_next; 72736369Ssklower } 72836369Ssklower ENDDEBUG 72936369Ssklower 73036369Ssklower /* 73136369Ssklower * Remove cfh from the list of fragmented pdus 73236369Ssklower */ 73336369Ssklower if (clnp_frags == cfh) { 73436369Ssklower clnp_frags = cfh->cfl_next; 73536369Ssklower } else { 73636369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 73736369Ssklower if (scan->cfl_next == cfh) { 73836369Ssklower scan->cfl_next = cfh->cfl_next; 73936369Ssklower break; 74036369Ssklower } 74136369Ssklower } 74236369Ssklower } 74336369Ssklower 74436369Ssklower /* free cfh */ 74536369Ssklower m_freem(dtom(cfh)); 74636369Ssklower 74736369Ssklower return(hdr); 74836369Ssklower } 74936369Ssklower 75036369Ssklower return(NULL); 75136369Ssklower } 75236369Ssklower #ifdef TROLL 75337469Ssklower static int troll_cnt; 75437536Smckusick #include "time.h" 75536369Ssklower /* 75636369Ssklower * FUNCTION: troll_random 75736369Ssklower * 75836369Ssklower * PURPOSE: generate a pseudo-random number between 0 and 1 75936369Ssklower * 76036369Ssklower * RETURNS: the random number 76136369Ssklower * 76236369Ssklower * SIDE EFFECTS: 76336369Ssklower * 76436369Ssklower * NOTES: This is based on the clock. 76536369Ssklower */ 76636369Ssklower float troll_random() 76736369Ssklower { 76836369Ssklower extern struct timeval time; 76936369Ssklower long t = time.tv_usec % 100; 77036369Ssklower 77136369Ssklower return((float)t / (float) 100); 77236369Ssklower } 77336369Ssklower 77436369Ssklower /* 77536369Ssklower * FUNCTION: troll_output 77636369Ssklower * 77736369Ssklower * PURPOSE: Do something sneaky with the datagram passed. Possible 77836369Ssklower * operations are: 77936369Ssklower * Duplicate the packet 78036369Ssklower * Drop the packet 78136369Ssklower * Trim some number of bytes from the packet 78236369Ssklower * Munge some byte in the packet 78336369Ssklower * 78436369Ssklower * RETURNS: 0, or unix error code 78536369Ssklower * 78636369Ssklower * SIDE EFFECTS: 78736369Ssklower * 78836369Ssklower * NOTES: The operation of this procedure is regulated by the 78936369Ssklower * troll control structure (Troll). 79036369Ssklower */ 791*40776Ssklower troll_output(ifp, m, dst, rt) 79236369Ssklower struct ifnet *ifp; 79336369Ssklower struct mbuf *m; 79436369Ssklower struct sockaddr *dst; 795*40776Ssklower struct rtentry *rt; 79636369Ssklower { 79736369Ssklower int err = 0; 79836369Ssklower troll_cnt++; 79936369Ssklower 80036369Ssklower if (trollctl.tr_ops & TR_DUPPKT) { 80136369Ssklower /* 80236369Ssklower * Duplicate every Nth packet 80336369Ssklower * TODO: random? 80436369Ssklower */ 80536369Ssklower float f_freq = troll_cnt * trollctl.tr_dup_freq; 80636369Ssklower int i_freq = troll_cnt * trollctl.tr_dup_freq; 80736369Ssklower if (i_freq == f_freq) { 80837469Ssklower struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); 80936369Ssklower if (dup != NULL) 810*40776Ssklower err = (*ifp->if_output)(ifp, dup, dst, rt); 81136369Ssklower } 81236369Ssklower if (!err) 813*40776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 81436369Ssklower return(err); 81536369Ssklower } else if (trollctl.tr_ops & TR_DROPPKT) { 81636369Ssklower } else if (trollctl.tr_ops & TR_CHANGE) { 81736369Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 81836369Ssklower clnp->cnf_cksum_msb = 0; 819*40776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 82036369Ssklower return(err); 82136369Ssklower } else { 822*40776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 82336369Ssklower return(err); 82436369Ssklower } 82536369Ssklower } 82636369Ssklower 82736369Ssklower #endif TROLL 828