BSD 4_4 release
[unix-history] / usr / src / sys / netiso / clnp_frag.c
index 64c0b8f..546a592 100644 (file)
@@ -1,3 +1,38 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)clnp_frag.c 8.1 (Berkeley) 6/10/93
+ */
+
 /***********************************************************
                Copyright IBM Corporation 1987
 
 /***********************************************************
                Copyright IBM Corporation 1987
 
@@ -26,31 +61,24 @@ SOFTWARE.
  */
 /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */
 /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */
  */
 /* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */
 /* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */
-/*     @(#)clnp_frag.c 7.5 (Berkeley) %G% */
 
 
-#ifndef lint
-static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $";
-#endif lint
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
 
 
-#ifdef ISO
+#include <net/if.h>
+#include <net/route.h>
 
 
-#include "types.h"
-#include "param.h"
-#include "mbuf.h"
-#include "domain.h"
-#include "protosw.h"
-#include "socket.h"
-#include "socketvar.h"
-#include "errno.h"
-
-#include "../net/if.h"
-#include "../net/route.h"
-
-#include "iso.h"
-#include "iso_var.h"
-#include "clnp.h"
-#include "clnp_stat.h"
-#include "argo_debug.h"
+#include <netiso/iso.h>
+#include <netiso/iso_var.h>
+#include <netiso/clnp.h>
+#include <netiso/clnp_stat.h>
+#include <netiso/argo_debug.h>
 
 /* all fragments are hung off this list */
 struct clnp_fragl      *clnp_frags = NULL;
 
 /* all fragments are hung off this list */
 struct clnp_fragl      *clnp_frags = NULL;
@@ -77,45 +105,47 @@ struct mbuf        *clnp_comp_pdu();
  *                                     the packet was fragmented during forwarding. In this
  *                                     case, we ought to send an ER back.
  */
  *                                     the packet was fragmented during forwarding. In this
  *                                     case, we ought to send an ER back.
  */
-clnp_fragment(ifp, m, first_hop, total_len, segoff, flags)
+clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt)
 struct ifnet   *ifp;           /* ptr to outgoing interface */
 struct mbuf            *m;                     /* ptr to packet */
 struct sockaddr        *first_hop;     /* ptr to first hop */
 int                            total_len;      /* length of datagram */
 int                            segoff;         /* offset of segpart in hdr */
 int                            flags;          /* flags passed to clnp_output */
 struct ifnet   *ifp;           /* ptr to outgoing interface */
 struct mbuf            *m;                     /* ptr to packet */
 struct sockaddr        *first_hop;     /* ptr to first hop */
 int                            total_len;      /* length of datagram */
 int                            segoff;         /* offset of segpart in hdr */
 int                            flags;          /* flags passed to clnp_output */
+struct rtentry *rt;                    /* route if direct ether */
 {
 {
-       struct clnp_fixed       *clnp;          /* ptr to fixed part of header */
+       struct clnp_fixed               *clnp = mtod(m, struct clnp_fixed *);
+       int                                             hdr_len = (int)clnp->cnf_hdr_len;
+       int                                             frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7;
 
 
-       clnp = mtod(m, struct clnp_fixed *);
+       total_len -= hdr_len;
+       if ((clnp->cnf_type & CNF_SEG_OK) &&
+               (total_len >= 8) &&
+               (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) {
 
 
-       if (clnp->cnf_type & CNF_SEG_OK) {
                struct mbuf                     *hdr = NULL;            /* save copy of clnp hdr */
                struct mbuf                     *frag_hdr = NULL;
                struct mbuf                     *frag_data = NULL;
                struct mbuf                     *hdr = NULL;            /* save copy of clnp hdr */
                struct mbuf                     *frag_hdr = NULL;
                struct mbuf                     *frag_data = NULL;
-               struct clnp_segment     seg_part, tmp_seg;      /* segmentation header */
-               extern int                      clnp_id;                        /* id of datagram */
+               struct clnp_segment     seg_part;                       /* segmentation header */
+               int                                     frag_base;
                int                                     error = 0;
 
                int                                     error = 0;
 
-               INCSTAT(cns_frag);
-
-               seg_part.cng_id = clnp_id++;
-               seg_part.cng_off = 0;
-               seg_part.cng_tot_len = total_len;
 
 
+               INCSTAT(cns_fragmented);
+        (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part,
+            sizeof(seg_part));
+               frag_base = ntohs(seg_part.cng_off);
                /*
                 *      Duplicate header, and remove from packet
                 */
                /*
                 *      Duplicate header, and remove from packet
                 */
-               if ((hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) {
+               if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
                        clnp_discard(m, GEN_CONGEST);
                        return(ENOBUFS);
                }
                        clnp_discard(m, GEN_CONGEST);
                        return(ENOBUFS);
                }
-               m_adj(m, (int)clnp->cnf_hdr_len);
-               total_len -= clnp->cnf_hdr_len;
-               
+               m_adj(m, hdr_len);
+
                while (total_len > 0) {
                while (total_len > 0) {
-                       int             frag_size;
-                       int             last_frag = 0;          /* true if this is the last fragment */
+                       int             remaining, last_frag;
 
                        IFDEBUG(D_FRAG)
                                struct mbuf *mdump = frag_hdr;
 
                        IFDEBUG(D_FRAG)
                                struct mbuf *mdump = frag_hdr;
@@ -130,21 +160,25 @@ int                               flags;          /* flags passed to clnp_output */
                                printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen);
                        ENDDEBUG
                        
                                printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen);
                        ENDDEBUG
                        
-                       frag_size = min(total_len, ifp->if_mtu - clnp->cnf_hdr_len);
-
-                       /*
-                        *      For some stupid reason, fragments must be at least 8 bytes
-                        *      in length. If this fragment will cause the last one to 
-                        *      be less than 8 bytes, shorten this fragment a bit.
-                        */
-                       if (((total_len - frag_size) > 0) && ((total_len - frag_size) < 8))
-                               frag_size -= (8 - (total_len - frag_size));
+                       frag_size = min(total_len, frag_size);
+                       if ((remaining = total_len - frag_size) == 0)
+                               last_frag = 1;
+                       else {
+                               /*
+                                *  If this fragment will cause the last one to 
+                                *      be less than 8 bytes, shorten this fragment a bit.
+                                *  The obscure test on frag_size above ensures that
+                                *  frag_size will be positive.
+                                */
+                               last_frag = 0;
+                               if (remaining < 8)
+                                               frag_size -= 8;
+                       }
                        
                        
-                       last_frag = ((total_len - frag_size) == 0);
 
                        IFDEBUG(D_FRAG)
                                printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 
 
                        IFDEBUG(D_FRAG)
                                printf("clnp_fragment: seg off %d, size %d, remaining %d\n", 
-                                       seg_part.cng_off, frag_size, total_len-frag_size);
+                                       ntohs(seg_part.cng_off), frag_size, total_len-frag_size);
                                if (last_frag)
                                        printf("clnp_fragment: last fragment\n");
                        ENDDEBUG
                                if (last_frag)
                                        printf("clnp_fragment: last fragment\n");
                        ENDDEBUG
@@ -159,16 +193,17 @@ int                               flags;          /* flags passed to clnp_output */
                        } else {
                                /* duplicate header and data mbufs */
                                if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) {
                        } else {
                                /* duplicate header and data mbufs */
                                if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) {
-                                       clnp_discard(m, GEN_CONGEST);
-                                       m_freem(hdr);
+                                       clnp_discard(hdr, GEN_CONGEST);
+                                       m_freem(m);
                                        return(ENOBUFS);
                                }
                                if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
                                        return(ENOBUFS);
                                }
                                if ((frag_data = m_copy(m, 0, frag_size)) == NULL) {
-                                       clnp_discard(m, GEN_CONGEST);
-                                       m_freem(hdr);
+                                       clnp_discard(hdr, GEN_CONGEST);
+                                       m_freem(m);
                                        m_freem(frag_hdr);
                                        return(ENOBUFS);
                                }
                                        m_freem(frag_hdr);
                                        return(ENOBUFS);
                                }
+                               INCSTAT(cns_fragments);
                        }
                        clnp = mtod(frag_hdr, struct clnp_fixed *);
 
                        }
                        clnp = mtod(frag_hdr, struct clnp_fixed *);
 
@@ -178,17 +213,12 @@ int                               flags;          /* flags passed to clnp_output */
                        /* link together */
                        m_cat(frag_hdr, frag_data);
 
                        /* link together */
                        m_cat(frag_hdr, frag_data);
 
-                       /* make sure segmentation fields are in network order */
-                       tmp_seg.cng_id = htons(seg_part.cng_id);
-                       tmp_seg.cng_off = htons(seg_part.cng_off);
-                       tmp_seg.cng_tot_len = htons(seg_part.cng_tot_len);
-
-                       /* insert segmentation part */
-                       bcopy((caddr_t)&tmp_seg, mtod(frag_hdr, caddr_t) + segoff,
+                       /* insert segmentation part; updated below */
+                       bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff,
                                sizeof(struct clnp_segment));
 
                        {
                                sizeof(struct clnp_segment));
 
                        {
-                               int     derived_len = clnp->cnf_hdr_len + frag_size;
+                               int     derived_len = hdr_len + frag_size;
                                HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
                                if ((frag_hdr->m_flags & M_PKTHDR) == 0)
                                        panic("clnp_frag:lost header");
                                HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len);
                                if ((frag_hdr->m_flags & M_PKTHDR) == 0)
                                        panic("clnp_frag:lost header");
@@ -198,7 +228,7 @@ int                         flags;          /* flags passed to clnp_output */
                        if (flags & CLNP_NO_CKSUM) {
                                HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
                        } else {
                        if (flags & CLNP_NO_CKSUM) {
                                HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
                        } else {
-                               iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
+                               iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len);
                        }
 
                        IFDEBUG(D_DUMPOUT)
                        }
 
                        IFDEBUG(D_DUMPOUT)
@@ -211,10 +241,10 @@ int                               flags;          /* flags passed to clnp_output */
                        ENDDEBUG
 
 #ifdef TROLL
                        ENDDEBUG
 
 #ifdef TROLL
-                       error = troll_output(ifp, frag_hdr, first_hop);
+                       error = troll_output(ifp, frag_hdr, first_hop, rt);
 #else
 #else
-                       error = (*ifp->if_output)(ifp, frag_hdr, first_hop);
-#endif TROLL
+                       error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt);
+#endif /* TROLL */
 
                        /*
                         *      Tough situation: if the error occured on the last 
 
                        /*
                         *      Tough situation: if the error occured on the last 
@@ -229,8 +259,8 @@ int                         flags;          /* flags passed to clnp_output */
                                         *      The error was not on the last fragment. We must
                                         *      free hdr and m before returning
                                         */
                                         *      The error was not on the last fragment. We must
                                         *      free hdr and m before returning
                                         */
-                                       clnp_discard(m, GEN_NOREAS);
-                                       m_freem(hdr);
+                                       clnp_discard(hdr, GEN_NOREAS);
+                                       m_freem(m);
                                }
                                return(error);
                        }
                                }
                                return(error);
                        }
@@ -253,15 +283,18 @@ int                               flags;          /* flags passed to clnp_output */
                                        num_bytes *= troll_random();
                                frag_size -= num_bytes;
                        }
                                        num_bytes *= troll_random();
                                frag_size -= num_bytes;
                        }
-#endif TROLL
+#endif /* TROLL */
                        total_len -= frag_size;
                        if (!last_frag) {
                        total_len -= frag_size;
                        if (!last_frag) {
-                               seg_part.cng_off += frag_size;
+                               frag_base += frag_size;
+                               seg_part.cng_off = htons(frag_base);
                                m_adj(m, frag_size);
                        }
                }
                return(0);
        } else {
                                m_adj(m, frag_size);
                        }
                }
                return(0);
        } else {
+       cantfrag:
+               INCSTAT(cns_cantfrag);
                clnp_discard(m, GEN_SEGNEEDED);
                return(EMSGSIZE);
        }
                clnp_discard(m, GEN_SEGNEEDED);
                return(EMSGSIZE);
        }
@@ -299,8 +332,9 @@ struct clnp_segment *seg;   /* segment part of fragment header */
 
        /* look for other fragments of this datagram */
        for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
 
        /* look for other fragments of this datagram */
        for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
-               if (iso_addrmatch1(src, &cfh->cfl_src) && 
-                       iso_addrmatch1(dst, &cfh->cfl_dst) && seg->cng_id == cfh->cfl_id) {
+               if (seg->cng_id == cfh->cfl_id &&
+                   iso_addrmatch1(src, &cfh->cfl_src) && 
+                       iso_addrmatch1(dst, &cfh->cfl_dst)) {
                        IFDEBUG(D_REASS)
                                printf("clnp_reass: found packet\n");
                        ENDDEBUG
                        IFDEBUG(D_REASS)
                                printf("clnp_reass: found packet\n");
                        ENDDEBUG
@@ -309,7 +343,12 @@ struct clnp_segment        *seg;   /* segment part of fragment header */
                         *      this fragment is of any help
                         */
                        clnp_insert_frag(cfh, m, seg);
                         *      this fragment is of any help
                         */
                        clnp_insert_frag(cfh, m, seg);
-                       return (clnp_comp_pdu(cfh));
+                       if (m = clnp_comp_pdu(cfh)) {
+                               register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
+                               HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb,
+                                        seg->cng_tot_len);
+                       }
+                       return (m);
                }
        }
 
                }
        }
 
@@ -324,6 +363,7 @@ struct clnp_segment *seg;   /* segment part of fragment header */
         */
        /* TODO: don't let one src hog all the reassembly buffers */
        if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) {
         */
        /* TODO: don't let one src hog all the reassembly buffers */
        if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) {
+               INCSTAT(cns_fragdropped);
                clnp_discard(m, GEN_CONGEST);
        }
 
                clnp_discard(m, GEN_CONGEST);
        }
 
@@ -743,7 +783,7 @@ struct clnp_fragl   *cfh;           /* fragment header */
 }
 #ifdef TROLL
 static int troll_cnt;
 }
 #ifdef TROLL
 static int troll_cnt;
-#include "time.h"
+#include <sys/time.h>
 /*
  * FUNCTION:           troll_random
  *
 /*
  * FUNCTION:           troll_random
  *
@@ -780,10 +820,11 @@ float troll_random()
  * NOTES:                      The operation of this procedure is regulated by the
  *                                     troll control structure (Troll).
  */
  * NOTES:                      The operation of this procedure is regulated by the
  *                                     troll control structure (Troll).
  */
-troll_output(ifp, m, dst)
+troll_output(ifp, m, dst, rt)
 struct ifnet   *ifp;
 struct mbuf            *m;
 struct sockaddr        *dst;
 struct ifnet   *ifp;
 struct mbuf            *m;
 struct sockaddr        *dst;
+struct rtentry *rt;
 {
        int     err = 0;
        troll_cnt++;
 {
        int     err = 0;
        troll_cnt++;
@@ -798,22 +839,21 @@ struct sockaddr   *dst;
                if (i_freq == f_freq) {
                        struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL);
                        if (dup != NULL)
                if (i_freq == f_freq) {
                        struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL);
                        if (dup != NULL)
-                               err = (*ifp->if_output)(ifp, dup, dst);
+                               err = (*ifp->if_output)(ifp, dup, dst, rt);
                }
                if (!err)
                }
                if (!err)
-                       err = (*ifp->if_output)(ifp, m, dst);
+                       err = (*ifp->if_output)(ifp, m, dst, rt);
                return(err);
        } else if (trollctl.tr_ops & TR_DROPPKT) {
        } else if (trollctl.tr_ops & TR_CHANGE) {
                struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
                clnp->cnf_cksum_msb = 0;
                return(err);
        } else if (trollctl.tr_ops & TR_DROPPKT) {
        } else if (trollctl.tr_ops & TR_CHANGE) {
                struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
                clnp->cnf_cksum_msb = 0;
-               err = (*ifp->if_output)(ifp, m, dst);
+               err = (*ifp->if_output)(ifp, m, dst, rt);
                return(err);
        } else {
                return(err);
        } else {
-               err = (*ifp->if_output)(ifp, m, dst);
+               err = (*ifp->if_output)(ifp, m, dst, rt);
                return(err);
        }
 }
 
                return(err);
        }
 }
 
-#endif TROLL
-#endif ISO
+#endif /* TROLL */