1*49267Sbostic /*- 2*49267Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*49267Sbostic * All rights reserved. 4*49267Sbostic * 5*49267Sbostic * %sccs.include.redist.c% 6*49267Sbostic * 7*49267Sbostic * @(#)clnp_frag.c 7.12 (Berkeley) 05/06/91 8*49267Sbostic */ 9*49267Sbostic 1036369Ssklower /*********************************************************** 1136369Ssklower Copyright IBM Corporation 1987 1236369Ssklower 1336369Ssklower All Rights Reserved 1436369Ssklower 1536369Ssklower Permission to use, copy, modify, and distribute this software and its 1636369Ssklower documentation for any purpose and without fee is hereby granted, 1736369Ssklower provided that the above copyright notice appear in all copies and that 1836369Ssklower both that copyright notice and this permission notice appear in 1936369Ssklower supporting documentation, and that the name of IBM not be 2036369Ssklower used in advertising or publicity pertaining to distribution of the 2136369Ssklower software without specific, written prior permission. 2236369Ssklower 2336369Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436369Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536369Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636369Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736369Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836369Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936369Ssklower SOFTWARE. 3036369Ssklower 3136369Ssklower ******************************************************************/ 3236369Ssklower 3336369Ssklower /* 3436369Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536369Ssklower */ 3636764Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */ 3736764Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */ 3836369Ssklower 3937536Smckusick #include "param.h" 4037536Smckusick #include "mbuf.h" 4137536Smckusick #include "domain.h" 4237536Smckusick #include "protosw.h" 4337536Smckusick #include "socket.h" 4437536Smckusick #include "socketvar.h" 4537536Smckusick #include "errno.h" 4636369Ssklower 4736369Ssklower #include "../net/if.h" 4836369Ssklower #include "../net/route.h" 4936369Ssklower 5037469Ssklower #include "iso.h" 5137469Ssklower #include "iso_var.h" 5237469Ssklower #include "clnp.h" 5337469Ssklower #include "clnp_stat.h" 5437469Ssklower #include "argo_debug.h" 5536369Ssklower 5636369Ssklower /* all fragments are hung off this list */ 5736369Ssklower struct clnp_fragl *clnp_frags = NULL; 5836369Ssklower 5936369Ssklower struct mbuf *clnp_comp_pdu(); 6036369Ssklower 6136369Ssklower 6236369Ssklower /* 6336369Ssklower * FUNCTION: clnp_fragment 6436369Ssklower * 6536369Ssklower * PURPOSE: Fragment a datagram, and send the itty bitty pieces 6636369Ssklower * out over an interface. 6736369Ssklower * 6836369Ssklower * RETURNS: success - 0 6936369Ssklower * failure - unix error code 7036369Ssklower * 7136369Ssklower * SIDE EFFECTS: 7236369Ssklower * 7336369Ssklower * NOTES: If there is an error sending the packet, clnp_discard 7436369Ssklower * is called to discard the packet and send an ER. If 7536369Ssklower * clnp_fragment was called from clnp_output, then 7636369Ssklower * we generated the packet, and should not send an 7736369Ssklower * ER -- clnp_emit_er will check for this. Otherwise, 7836369Ssklower * the packet was fragmented during forwarding. In this 7936369Ssklower * case, we ought to send an ER back. 8036369Ssklower */ 8140776Ssklower clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt) 8236369Ssklower struct ifnet *ifp; /* ptr to outgoing interface */ 8336369Ssklower struct mbuf *m; /* ptr to packet */ 8436369Ssklower struct sockaddr *first_hop; /* ptr to first hop */ 8536369Ssklower int total_len; /* length of datagram */ 8636369Ssklower int segoff; /* offset of segpart in hdr */ 8736369Ssklower int flags; /* flags passed to clnp_output */ 8840776Ssklower struct rtentry *rt; /* route if direct ether */ 8936369Ssklower { 9039232Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 9139232Ssklower int hdr_len = (int)clnp->cnf_hdr_len; 9248730Ssklower int frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7; 9336369Ssklower 9439232Ssklower total_len -= hdr_len; 9539232Ssklower if ((clnp->cnf_type & CNF_SEG_OK) && 9639232Ssklower (total_len >= 8) && 9739232Ssklower (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { 9836369Ssklower 9936369Ssklower struct mbuf *hdr = NULL; /* save copy of clnp hdr */ 10036369Ssklower struct mbuf *frag_hdr = NULL; 10136369Ssklower struct mbuf *frag_data = NULL; 10242865Ssklower struct clnp_segment seg_part; /* segmentation header */ 10347598Ssklower int frag_base; 10436369Ssklower int error = 0; 10536369Ssklower 10639232Ssklower 10739195Ssklower INCSTAT(cns_fragmented); 10842865Ssklower (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part, 10942865Ssklower sizeof(seg_part)); 11042865Ssklower frag_base = ntohs(seg_part.cng_off); 11136369Ssklower /* 11236369Ssklower * Duplicate header, and remove from packet 11336369Ssklower */ 11439232Ssklower if ((hdr = m_copy(m, 0, hdr_len)) == NULL) { 11536369Ssklower clnp_discard(m, GEN_CONGEST); 11636369Ssklower return(ENOBUFS); 11736369Ssklower } 11839232Ssklower m_adj(m, hdr_len); 11939232Ssklower 12036369Ssklower while (total_len > 0) { 12139232Ssklower int remaining, last_frag; 12236764Ssklower 12336764Ssklower IFDEBUG(D_FRAG) 12436764Ssklower struct mbuf *mdump = frag_hdr; 12536764Ssklower int tot_mlen = 0; 12636764Ssklower printf("clnp_fragment: total_len %d:\n", total_len); 12736764Ssklower while (mdump != NULL) { 12836764Ssklower printf("\tmbuf x%x, m_len %d\n", 12936764Ssklower mdump, mdump->m_len); 13036764Ssklower tot_mlen += mdump->m_len; 13136764Ssklower mdump = mdump->m_next; 13236764Ssklower } 13336764Ssklower printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); 13436764Ssklower ENDDEBUG 13536369Ssklower 13639232Ssklower frag_size = min(total_len, frag_size); 13739232Ssklower if ((remaining = total_len - frag_size) == 0) 13839232Ssklower last_frag = 1; 13939232Ssklower else { 14039232Ssklower /* 14139232Ssklower * If this fragment will cause the last one to 14239232Ssklower * be less than 8 bytes, shorten this fragment a bit. 14339232Ssklower * The obscure test on frag_size above ensures that 14439232Ssklower * frag_size will be positive. 14539232Ssklower */ 14639232Ssklower last_frag = 0; 14739232Ssklower if (remaining < 8) 14839232Ssklower frag_size -= 8; 14939232Ssklower } 15036369Ssklower 15136369Ssklower 15236369Ssklower IFDEBUG(D_FRAG) 15336369Ssklower printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 15442865Ssklower ntohs(seg_part.cng_off), frag_size, total_len-frag_size); 15536369Ssklower if (last_frag) 15636369Ssklower printf("clnp_fragment: last fragment\n"); 15736369Ssklower ENDDEBUG 15836369Ssklower 15936369Ssklower if (last_frag) { 16036369Ssklower /* 16136369Ssklower * this is the last fragment; we don't need to get any other 16236369Ssklower * mbufs. 16336369Ssklower */ 16436369Ssklower frag_hdr = hdr; 16536369Ssklower frag_data = m; 16636369Ssklower } else { 16736369Ssklower /* duplicate header and data mbufs */ 16837469Ssklower if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { 16939232Ssklower clnp_discard(hdr, GEN_CONGEST); 17039232Ssklower m_freem(m); 17136369Ssklower return(ENOBUFS); 17236369Ssklower } 17336369Ssklower if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { 17439232Ssklower clnp_discard(hdr, GEN_CONGEST); 17539232Ssklower m_freem(m); 17636369Ssklower m_freem(frag_hdr); 17736369Ssklower return(ENOBUFS); 17836369Ssklower } 17939195Ssklower INCSTAT(cns_fragments); 18036369Ssklower } 18136369Ssklower clnp = mtod(frag_hdr, struct clnp_fixed *); 18236369Ssklower 18336369Ssklower if (!last_frag) 18437469Ssklower clnp->cnf_type |= CNF_MORE_SEGS; 18536369Ssklower 18636369Ssklower /* link together */ 18736369Ssklower m_cat(frag_hdr, frag_data); 18836369Ssklower 18942865Ssklower /* insert segmentation part; updated below */ 19042865Ssklower bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff, 19136369Ssklower sizeof(struct clnp_segment)); 19236369Ssklower 19336369Ssklower { 19439232Ssklower int derived_len = hdr_len + frag_size; 19536369Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); 19637469Ssklower if ((frag_hdr->m_flags & M_PKTHDR) == 0) 19737469Ssklower panic("clnp_frag:lost header"); 19837469Ssklower frag_hdr->m_pkthdr.len = derived_len; 19936369Ssklower } 20036369Ssklower /* compute clnp checksum (on header only) */ 20136369Ssklower if (flags & CLNP_NO_CKSUM) { 20236369Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 20336369Ssklower } else { 20439232Ssklower iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len); 20536369Ssklower } 20636369Ssklower 20736369Ssklower IFDEBUG(D_DUMPOUT) 20836369Ssklower struct mbuf *mdump = frag_hdr; 20936369Ssklower printf("clnp_fragment: sending dg:\n"); 21036369Ssklower while (mdump != NULL) { 21136764Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 21236369Ssklower mdump = mdump->m_next; 21336369Ssklower } 21436369Ssklower ENDDEBUG 21536369Ssklower 21636369Ssklower #ifdef TROLL 21740776Ssklower error = troll_output(ifp, frag_hdr, first_hop, rt); 21836369Ssklower #else 21940776Ssklower error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt); 22036369Ssklower #endif TROLL 22136369Ssklower 22236369Ssklower /* 22336369Ssklower * Tough situation: if the error occured on the last 22436369Ssklower * fragment, we can not send an ER, as the if_output 22536369Ssklower * routine consumed the packet. If the error occured 22636369Ssklower * on any intermediate packets, we can send an ER 22736369Ssklower * because we still have the original header in (m). 22836369Ssklower */ 22936369Ssklower if (error) { 23036369Ssklower if (frag_hdr != hdr) { 23136369Ssklower /* 23236369Ssklower * The error was not on the last fragment. We must 23336369Ssklower * free hdr and m before returning 23436369Ssklower */ 23539232Ssklower clnp_discard(hdr, GEN_NOREAS); 23639232Ssklower m_freem(m); 23736369Ssklower } 23836369Ssklower return(error); 23936369Ssklower } 24036369Ssklower 24136369Ssklower /* bump segment offset, trim data mbuf, and decrement count left */ 24236369Ssklower #ifdef TROLL 24336369Ssklower /* 24436369Ssklower * Decrement frag_size by some fraction. This will cause the 24536369Ssklower * next fragment to start 'early', thus duplicating the end 24636369Ssklower * of the current fragment. troll.tr_dup_size controls 24736369Ssklower * the fraction. If positive, it specifies the fraction. If 24836369Ssklower * negative, a random fraction is used. 24936369Ssklower */ 25036369Ssklower if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { 25136369Ssklower int num_bytes = frag_size; 25236369Ssklower 25336369Ssklower if (trollctl.tr_dup_size > 0) 25436369Ssklower num_bytes *= trollctl.tr_dup_size; 25536369Ssklower else 25636369Ssklower num_bytes *= troll_random(); 25736369Ssklower frag_size -= num_bytes; 25836369Ssklower } 25936369Ssklower #endif TROLL 26036369Ssklower total_len -= frag_size; 26136369Ssklower if (!last_frag) { 26242865Ssklower frag_base += frag_size; 26342865Ssklower seg_part.cng_off = htons(frag_base); 26436369Ssklower m_adj(m, frag_size); 26536369Ssklower } 26636369Ssklower } 26736369Ssklower return(0); 26836369Ssklower } else { 26939232Ssklower cantfrag: 27039195Ssklower INCSTAT(cns_cantfrag); 27136369Ssklower clnp_discard(m, GEN_SEGNEEDED); 27236369Ssklower return(EMSGSIZE); 27336369Ssklower } 27436369Ssklower } 27536369Ssklower 27636369Ssklower /* 27736369Ssklower * FUNCTION: clnp_reass 27836369Ssklower * 27936369Ssklower * PURPOSE: Attempt to reassemble a clnp packet given the current 28036369Ssklower * fragment. If reassembly succeeds (all the fragments 28136369Ssklower * are present), then return a pointer to an mbuf chain 28236369Ssklower * containing the reassembled packet. This packet will 28336369Ssklower * appear in the mbufs as if it had just arrived in 28436369Ssklower * one piece. 28536369Ssklower * 28636369Ssklower * If reassembly fails, then save this fragment and 28736369Ssklower * return 0. 28836369Ssklower * 28936369Ssklower * RETURNS: Ptr to assembled packet, or 0 29036369Ssklower * 29136369Ssklower * SIDE EFFECTS: 29236369Ssklower * 29336369Ssklower * NOTES: 29436369Ssklower * clnp_slowtimo can not affect this code because clnpintr, and thus 29536369Ssklower * this code, is called at a higher priority than clnp_slowtimo. 29636369Ssklower */ 29736369Ssklower struct mbuf * 29836369Ssklower clnp_reass(m, src, dst, seg) 29936369Ssklower struct mbuf *m; /* new fragment */ 30036369Ssklower struct iso_addr *src; /* src of new fragment */ 30136369Ssklower struct iso_addr *dst; /* dst of new fragment */ 30236369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 30336369Ssklower { 30436369Ssklower register struct clnp_fragl *cfh; 30536369Ssklower 30636369Ssklower /* look for other fragments of this datagram */ 30736369Ssklower for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { 30842865Ssklower if (seg->cng_id == cfh->cfl_id && 30942865Ssklower iso_addrmatch1(src, &cfh->cfl_src) && 31042865Ssklower iso_addrmatch1(dst, &cfh->cfl_dst)) { 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); 31942865Ssklower if (m = clnp_comp_pdu(cfh)) { 32042865Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 32142865Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, 32242865Ssklower seg->cng_tot_len); 32342865Ssklower } 32442865Ssklower return (m); 32536369Ssklower } 32636369Ssklower } 32736369Ssklower 32836369Ssklower IFDEBUG(D_REASS) 32936369Ssklower printf("clnp_reass: new packet!\n"); 33036369Ssklower ENDDEBUG 33136369Ssklower 33236369Ssklower /* 33336369Ssklower * This is the first fragment. If src is not consuming too many 33436369Ssklower * resources, then create a new fragment list and add 33536369Ssklower * this fragment to the list. 33636369Ssklower */ 33736369Ssklower /* TODO: don't let one src hog all the reassembly buffers */ 33836369Ssklower if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { 33939195Ssklower INCSTAT(cns_fragdropped); 34036369Ssklower clnp_discard(m, GEN_CONGEST); 34136369Ssklower } 34236369Ssklower 34336369Ssklower return(NULL); 34436369Ssklower } 34536369Ssklower 34636369Ssklower /* 34736369Ssklower * FUNCTION: clnp_newpkt 34836369Ssklower * 34936369Ssklower * PURPOSE: Create the necessary structures to handle a new 35036369Ssklower * fragmented clnp packet. 35136369Ssklower * 35236369Ssklower * RETURNS: non-zero if it succeeds, zero if fails. 35336369Ssklower * 35436369Ssklower * SIDE EFFECTS: 35536369Ssklower * 35636369Ssklower * NOTES: Failure is only due to insufficient resources. 35736369Ssklower */ 35836369Ssklower clnp_newpkt(m, src, dst, seg) 35936369Ssklower struct mbuf *m; /* new fragment */ 36036369Ssklower struct iso_addr *src; /* src of new fragment */ 36136369Ssklower struct iso_addr *dst; /* dst of new fragment */ 36236369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 36336369Ssklower { 36436369Ssklower register struct clnp_fragl *cfh; 36536369Ssklower register struct clnp_fixed *clnp; 36636369Ssklower struct mbuf *m0; 36736369Ssklower 36836369Ssklower clnp = mtod(m, struct clnp_fixed *); 36936369Ssklower 37036369Ssklower /* 37136369Ssklower * Allocate new clnp fragl structure to act as header of all fragments 37236369Ssklower * for this datagram. 37336369Ssklower */ 37436369Ssklower MGET(m0, M_DONTWAIT, MT_FTABLE); 37536369Ssklower if (m0 == NULL) { 37636369Ssklower return (0); 37736369Ssklower } 37836369Ssklower cfh = mtod(m0, struct clnp_fragl *); 37936369Ssklower 38036369Ssklower /* 38136369Ssklower * Duplicate the header of this fragment, and save in cfh. 38236369Ssklower * Free m0 and return if m_copy does not succeed. 38336369Ssklower */ 38437469Ssklower if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { 38536369Ssklower m_freem(m0); 38636369Ssklower return (0); 38736369Ssklower } 38836369Ssklower 38936369Ssklower /* Fill in rest of fragl structure */ 39036369Ssklower bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); 39136369Ssklower bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); 39236369Ssklower cfh->cfl_id = seg->cng_id; 39336369Ssklower cfh->cfl_ttl = clnp->cnf_ttl; 39436369Ssklower cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; 39536369Ssklower cfh->cfl_frags = NULL; 39636369Ssklower cfh->cfl_next = NULL; 39736369Ssklower 39836369Ssklower /* Insert into list of packets */ 39936369Ssklower cfh->cfl_next = clnp_frags; 40036369Ssklower clnp_frags = cfh; 40136369Ssklower 40236369Ssklower /* Insert this fragment into list headed by cfh */ 40336369Ssklower clnp_insert_frag(cfh, m, seg); 40436369Ssklower return(1); 40536369Ssklower } 40636369Ssklower 40736369Ssklower /* 40836369Ssklower * FUNCTION: clnp_insert_frag 40936369Ssklower * 41036369Ssklower * PURPOSE: Insert fragment into list headed by 'cf'. 41136369Ssklower * 41236369Ssklower * RETURNS: nothing 41336369Ssklower * 41436369Ssklower * SIDE EFFECTS: 41536369Ssklower * 41636369Ssklower * NOTES: This is the 'guts' of the reassembly algorithm. 41736369Ssklower * Each fragment in this list contains a clnp_frag 41836369Ssklower * structure followed by the data of the fragment. 41936369Ssklower * The clnp_frag structure actually lies on top of 42036369Ssklower * part of the old clnp header. 42136369Ssklower */ 42236369Ssklower clnp_insert_frag(cfh, m, seg) 42336369Ssklower struct clnp_fragl *cfh; /* header of list of packet fragments */ 42436369Ssklower struct mbuf *m; /* new fragment */ 42536369Ssklower struct clnp_segment *seg; /* segment part of fragment header */ 42636369Ssklower { 42736369Ssklower register struct clnp_fixed *clnp; /* clnp hdr of fragment */ 42836369Ssklower register struct clnp_frag *cf; /* generic fragment ptr */ 42936369Ssklower register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ 43036369Ssklower register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ 43136369Ssklower u_short first; /* offset of first byte of initial pdu*/ 43236369Ssklower u_short last; /* offset of last byte of initial pdu */ 43336369Ssklower u_short fraglen;/* length of fragment */ 43436369Ssklower 43536369Ssklower clnp = mtod(m, struct clnp_fixed *); 43636369Ssklower first = seg->cng_off; 43736369Ssklower CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); 43836369Ssklower fraglen -= clnp->cnf_hdr_len; 43936369Ssklower last = (first + fraglen) - 1; 44036369Ssklower 44136369Ssklower IFDEBUG(D_REASS) 44236369Ssklower printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", 44336369Ssklower first, last, fraglen); 44436369Ssklower printf("clnp_insert_frag: current fragments:\n"); 44536369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { 44636369Ssklower printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); 44736369Ssklower } 44836369Ssklower ENDDEBUG 44936369Ssklower 45036369Ssklower if (cfh->cfl_frags != NULL) { 45136369Ssklower /* 45236369Ssklower * Find fragment which begins after the new one 45336369Ssklower */ 45436369Ssklower for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { 45536369Ssklower if (cf->cfr_first > first) { 45636369Ssklower cf_sub = cf; 45736369Ssklower break; 45836369Ssklower } 45936369Ssklower } 46036369Ssklower 46136369Ssklower IFDEBUG(D_REASS) 46236369Ssklower printf("clnp_insert_frag: Previous frag is "); 46336369Ssklower if (cf_prev == NULL) 46436369Ssklower printf("NULL\n"); 46536369Ssklower else 46636369Ssklower printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); 46736369Ssklower printf("clnp_insert_frag: Subsequent frag is "); 46836369Ssklower if (cf_sub == NULL) 46936369Ssklower printf("NULL\n"); 47036369Ssklower else 47136369Ssklower printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); 47236369Ssklower ENDDEBUG 47336369Ssklower 47436369Ssklower /* 47536369Ssklower * If there is a fragment before the new one, check if it 47636369Ssklower * overlaps the new one. If so, then trim the end of the 47736369Ssklower * previous one. 47836369Ssklower */ 47936369Ssklower if (cf_prev != NULL) { 48036369Ssklower if (cf_prev->cfr_last > first) { 48136369Ssklower u_short overlap = cf_prev->cfr_last - first; 48236369Ssklower 48336369Ssklower IFDEBUG(D_REASS) 48436369Ssklower printf("clnp_insert_frag: previous overlaps by %d\n", 48536369Ssklower overlap); 48636369Ssklower ENDDEBUG 48736369Ssklower 48836369Ssklower if (overlap > fraglen) { 48936369Ssklower /* 49036369Ssklower * The new fragment is entirely contained in the 49136369Ssklower * preceeding one. We can punt on the new frag 49236369Ssklower * completely. 49336369Ssklower */ 49436369Ssklower m_freem(m); 49536369Ssklower return; 49636369Ssklower } else { 49736369Ssklower /* Trim data off of end of previous fragment */ 49836369Ssklower /* inc overlap to prevent duplication of last byte */ 49936369Ssklower overlap++; 50037469Ssklower m_adj(cf_prev->cfr_data, -(int)overlap); 50136369Ssklower cf_prev->cfr_last -= overlap; 50236369Ssklower } 50336369Ssklower } 50436369Ssklower } 50536369Ssklower 50636369Ssklower /* 50736369Ssklower * For all fragments past the new one, check if any data on 50836369Ssklower * the new one overlaps data on existing fragments. If so, 50936369Ssklower * then trim the extra data off the end of the new one. 51036369Ssklower */ 51136369Ssklower for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { 51236369Ssklower if (cf->cfr_first < last) { 51336369Ssklower u_short overlap = last - cf->cfr_first; 51436369Ssklower 51536369Ssklower IFDEBUG(D_REASS) 51636369Ssklower printf("clnp_insert_frag: subsequent overlaps by %d\n", 51736369Ssklower overlap); 51836369Ssklower ENDDEBUG 51936369Ssklower 52036369Ssklower if (overlap > fraglen) { 52136369Ssklower /* 52236369Ssklower * The new fragment is entirely contained in the 52336369Ssklower * succeeding one. This should not happen, because 52436369Ssklower * early on in this code we scanned for the fragment 52536369Ssklower * which started after the new one! 52636369Ssklower */ 52736369Ssklower m_freem(m); 52836369Ssklower printf("clnp_insert_frag: internal error!\n"); 52936369Ssklower return; 53036369Ssklower } else { 53136369Ssklower /* Trim data off of end of new fragment */ 53236369Ssklower /* inc overlap to prevent duplication of last byte */ 53336369Ssklower overlap++; 53437469Ssklower m_adj(m, -(int)overlap); 53536369Ssklower last -= overlap; 53636369Ssklower } 53736369Ssklower } 53836369Ssklower } 53936369Ssklower } 54036369Ssklower 54136369Ssklower /* 54236369Ssklower * Insert the new fragment beween cf_prev and cf_sub 54336369Ssklower * 54436369Ssklower * Note: the clnp hdr is still in the mbuf. 54536369Ssklower * If the data of the mbuf is not word aligned, shave off enough 54636369Ssklower * so that it is. Then, cast the clnp_frag structure on top 54736369Ssklower * of the clnp header. 54836369Ssklower * The clnp_hdr will not be used again (as we already have 54936369Ssklower * saved a copy of it). 55036369Ssklower * 55136369Ssklower * Save in cfr_bytes the number of bytes to shave off to get to 55236369Ssklower * the data of the packet. This is used when we coalesce fragments; 55336369Ssklower * the clnp_frag structure must be removed before joining mbufs. 55436369Ssklower */ 55536369Ssklower { 55636369Ssklower int pad; 55736369Ssklower u_int bytes; 55836369Ssklower 55936369Ssklower /* determine if header is not word aligned */ 56036369Ssklower pad = (int)clnp % 4; 56136369Ssklower if (pad < 0) 56236369Ssklower pad = -pad; 56336369Ssklower 56436369Ssklower /* bytes is number of bytes left in front of data */ 56536369Ssklower bytes = clnp->cnf_hdr_len - pad; 56636369Ssklower 56736764Ssklower IFDEBUG(D_REASS) 56836764Ssklower printf("clnp_insert_frag: clnp x%x requires %d alignment\n", 56936764Ssklower clnp, pad); 57036764Ssklower ENDDEBUG 57136764Ssklower 57236369Ssklower /* make it word aligned if necessary */ 57336369Ssklower if (pad) 57436369Ssklower m_adj(m, pad); 57536369Ssklower 57636369Ssklower cf = mtod(m, struct clnp_frag *); 57736369Ssklower cf->cfr_bytes = bytes; 57836764Ssklower 57936764Ssklower IFDEBUG(D_REASS) 58036764Ssklower printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, 58136764Ssklower cf->cfr_bytes); 58236764Ssklower ENDDEBUG 58336369Ssklower } 58436369Ssklower cf->cfr_first = first; 58536369Ssklower cf->cfr_last = last; 58636369Ssklower 58736369Ssklower 58836369Ssklower /* 58936369Ssklower * The data is the mbuf itself, although we must remember that the 59036369Ssklower * first few bytes are actually a clnp_frag structure 59136369Ssklower */ 59236369Ssklower cf->cfr_data = m; 59336369Ssklower 59436369Ssklower /* link into place */ 59536369Ssklower cf->cfr_next = cf_sub; 59636369Ssklower if (cf_prev == NULL) 59736369Ssklower cfh->cfl_frags = cf; 59836369Ssklower else 59936369Ssklower cf_prev->cfr_next = cf; 60036369Ssklower } 60136369Ssklower 60236369Ssklower /* 60336369Ssklower * FUNCTION: clnp_comp_pdu 60436369Ssklower * 60536369Ssklower * PURPOSE: Scan the list of fragments headed by cfh. Merge 60636369Ssklower * any contigious fragments into one. If, after 60736369Ssklower * traversing all the fragments, it is determined that 60836369Ssklower * the packet is complete, then return a pointer to 60936369Ssklower * the packet (with header prepended). Otherwise, 61036369Ssklower * return NULL. 61136369Ssklower * 61236369Ssklower * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. 61336369Ssklower * 61436369Ssklower * SIDE EFFECTS: Will colapse contigious fragments into one. 61536369Ssklower * 61636369Ssklower * NOTES: This code assumes that there are no overlaps of 61736369Ssklower * fragment pdus. 61836369Ssklower */ 61936369Ssklower struct mbuf * 62036369Ssklower clnp_comp_pdu(cfh) 62136369Ssklower struct clnp_fragl *cfh; /* fragment header */ 62236369Ssklower { 62336369Ssklower register struct clnp_frag *cf = cfh->cfl_frags; 62436369Ssklower 62536369Ssklower while (cf->cfr_next != NULL) { 62636369Ssklower register struct clnp_frag *cf_next = cf->cfr_next; 62736369Ssklower 62836369Ssklower IFDEBUG(D_REASS) 62936369Ssklower printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", 63036369Ssklower cf->cfr_first, cf->cfr_last, cf_next->cfr_first, 63136369Ssklower cf_next->cfr_last); 63236369Ssklower ENDDEBUG 63336369Ssklower 63436369Ssklower if (cf->cfr_last == (cf_next->cfr_first - 1)) { 63536369Ssklower /* 63636369Ssklower * Merge fragment cf and cf_next 63736369Ssklower * 63836369Ssklower * - update cf header 63936369Ssklower * - trim clnp_frag structure off of cf_next 64036369Ssklower * - append cf_next to cf 64136369Ssklower */ 64236369Ssklower struct clnp_frag cf_next_hdr; 64336369Ssklower struct clnp_frag *next_frag; 64436369Ssklower 64536369Ssklower cf_next_hdr = *cf_next; 64636369Ssklower next_frag = cf_next->cfr_next; 64736369Ssklower 64836369Ssklower IFDEBUG(D_REASS) 64936369Ssklower struct mbuf *mdump; 65036764Ssklower int l; 65136369Ssklower printf("clnp_comp_pdu: merging fragments\n"); 65236764Ssklower printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", 65336764Ssklower cf->cfr_first, cf->cfr_last, cf->cfr_bytes); 65436369Ssklower mdump = cf->cfr_data; 65536764Ssklower l = 0; 65636369Ssklower while (mdump != NULL) { 65736369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 65836764Ssklower l += mdump->m_len; 65936369Ssklower mdump = mdump->m_next; 66036369Ssklower } 66136764Ssklower printf("\ttotal len: %d\n", l); 66236764Ssklower printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", 66336764Ssklower cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); 66436369Ssklower mdump = cf_next->cfr_data; 66536764Ssklower l = 0; 66636369Ssklower while (mdump != NULL) { 66736369Ssklower printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); 66836764Ssklower l += mdump->m_len; 66936369Ssklower mdump = mdump->m_next; 67036369Ssklower } 67136764Ssklower printf("\ttotal len: %d\n", l); 67236369Ssklower ENDDEBUG 67336369Ssklower 67436369Ssklower cf->cfr_last = cf_next->cfr_last; 67536369Ssklower /* 67636369Ssklower * After this m_adj, the cf_next ptr is useless because we 67736369Ssklower * have adjusted the clnp_frag structure away... 67836369Ssklower */ 67936764Ssklower IFDEBUG(D_REASS) 68036764Ssklower printf("clnp_comp_pdu: shaving off %d bytes\n", 68136764Ssklower cf_next_hdr.cfr_bytes); 68236764Ssklower ENDDEBUG 68337469Ssklower m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); 68436369Ssklower m_cat(cf->cfr_data, cf_next_hdr.cfr_data); 68536369Ssklower cf->cfr_next = next_frag; 68636369Ssklower } else { 68736369Ssklower cf = cf->cfr_next; 68836369Ssklower } 68936369Ssklower } 69036369Ssklower 69136369Ssklower cf = cfh->cfl_frags; 69236369Ssklower 69336369Ssklower IFDEBUG(D_REASS) 69436369Ssklower struct mbuf *mdump = cf->cfr_data; 69536369Ssklower printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, 69636369Ssklower cf->cfr_last); 69736369Ssklower printf("clnp_comp_pdu: data for frag:\n"); 69836369Ssklower while (mdump != NULL) { 69936369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 70036369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 70136369Ssklower mdump = mdump->m_next; 70236369Ssklower } 70336369Ssklower ENDDEBUG 70436369Ssklower 70536369Ssklower /* Check if datagram is complete */ 70636369Ssklower if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { 70736369Ssklower /* 70836369Ssklower * We have a complete pdu! 70936369Ssklower * - Remove the frag header from (only) remaining fragment 71036369Ssklower * (which is not really a fragment anymore, as the datagram is 71136369Ssklower * complete). 71236369Ssklower * - Prepend a clnp header 71336369Ssklower */ 71436369Ssklower struct mbuf *data = cf->cfr_data; 71536369Ssklower struct mbuf *hdr = cfh->cfl_orighdr; 71636369Ssklower struct clnp_fragl *scan; 71736369Ssklower 71836369Ssklower IFDEBUG(D_REASS) 71936369Ssklower printf("clnp_comp_pdu: complete pdu!\n"); 72036369Ssklower ENDDEBUG 72136369Ssklower 72237469Ssklower m_adj(data, (int)cf->cfr_bytes); 72336369Ssklower m_cat(hdr, data); 72436369Ssklower 72536369Ssklower IFDEBUG(D_DUMPIN) 72636369Ssklower struct mbuf *mdump = hdr; 72736369Ssklower printf("clnp_comp_pdu: pdu is:\n"); 72836369Ssklower while (mdump != NULL) { 72936369Ssklower printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); 73036369Ssklower /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ 73136369Ssklower mdump = mdump->m_next; 73236369Ssklower } 73336369Ssklower ENDDEBUG 73436369Ssklower 73536369Ssklower /* 73636369Ssklower * Remove cfh from the list of fragmented pdus 73736369Ssklower */ 73836369Ssklower if (clnp_frags == cfh) { 73936369Ssklower clnp_frags = cfh->cfl_next; 74036369Ssklower } else { 74136369Ssklower for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { 74236369Ssklower if (scan->cfl_next == cfh) { 74336369Ssklower scan->cfl_next = cfh->cfl_next; 74436369Ssklower break; 74536369Ssklower } 74636369Ssklower } 74736369Ssklower } 74836369Ssklower 74936369Ssklower /* free cfh */ 75036369Ssklower m_freem(dtom(cfh)); 75136369Ssklower 75236369Ssklower return(hdr); 75336369Ssklower } 75436369Ssklower 75536369Ssklower return(NULL); 75636369Ssklower } 75736369Ssklower #ifdef TROLL 75837469Ssklower static int troll_cnt; 75937536Smckusick #include "time.h" 76036369Ssklower /* 76136369Ssklower * FUNCTION: troll_random 76236369Ssklower * 76336369Ssklower * PURPOSE: generate a pseudo-random number between 0 and 1 76436369Ssklower * 76536369Ssklower * RETURNS: the random number 76636369Ssklower * 76736369Ssklower * SIDE EFFECTS: 76836369Ssklower * 76936369Ssklower * NOTES: This is based on the clock. 77036369Ssklower */ 77136369Ssklower float troll_random() 77236369Ssklower { 77336369Ssklower extern struct timeval time; 77436369Ssklower long t = time.tv_usec % 100; 77536369Ssklower 77636369Ssklower return((float)t / (float) 100); 77736369Ssklower } 77836369Ssklower 77936369Ssklower /* 78036369Ssklower * FUNCTION: troll_output 78136369Ssklower * 78236369Ssklower * PURPOSE: Do something sneaky with the datagram passed. Possible 78336369Ssklower * operations are: 78436369Ssklower * Duplicate the packet 78536369Ssklower * Drop the packet 78636369Ssklower * Trim some number of bytes from the packet 78736369Ssklower * Munge some byte in the packet 78836369Ssklower * 78936369Ssklower * RETURNS: 0, or unix error code 79036369Ssklower * 79136369Ssklower * SIDE EFFECTS: 79236369Ssklower * 79336369Ssklower * NOTES: The operation of this procedure is regulated by the 79436369Ssklower * troll control structure (Troll). 79536369Ssklower */ 79640776Ssklower troll_output(ifp, m, dst, rt) 79736369Ssklower struct ifnet *ifp; 79836369Ssklower struct mbuf *m; 79936369Ssklower struct sockaddr *dst; 80040776Ssklower struct rtentry *rt; 80136369Ssklower { 80236369Ssklower int err = 0; 80336369Ssklower troll_cnt++; 80436369Ssklower 80536369Ssklower if (trollctl.tr_ops & TR_DUPPKT) { 80636369Ssklower /* 80736369Ssklower * Duplicate every Nth packet 80836369Ssklower * TODO: random? 80936369Ssklower */ 81036369Ssklower float f_freq = troll_cnt * trollctl.tr_dup_freq; 81136369Ssklower int i_freq = troll_cnt * trollctl.tr_dup_freq; 81236369Ssklower if (i_freq == f_freq) { 81337469Ssklower struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); 81436369Ssklower if (dup != NULL) 81540776Ssklower err = (*ifp->if_output)(ifp, dup, dst, rt); 81636369Ssklower } 81736369Ssklower if (!err) 81840776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 81936369Ssklower return(err); 82036369Ssklower } else if (trollctl.tr_ops & TR_DROPPKT) { 82136369Ssklower } else if (trollctl.tr_ops & TR_CHANGE) { 82236369Ssklower struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 82336369Ssklower clnp->cnf_cksum_msb = 0; 82440776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 82536369Ssklower return(err); 82636369Ssklower } else { 82740776Ssklower err = (*ifp->if_output)(ifp, m, dst, rt); 82836369Ssklower return(err); 82936369Ssklower } 83036369Ssklower } 83136369Ssklower 83236369Ssklower #endif TROLL 833