The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netiso/clnp_frag.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: clnp_frag.c,v 1.18 2005/12/11 12:25:12 christos Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)clnp_frag.c 8.1 (Berkeley) 6/10/93
   32  */
   33 
   34 /***********************************************************
   35                 Copyright IBM Corporation 1987
   36 
   37                       All Rights Reserved
   38 
   39 Permission to use, copy, modify, and distribute this software and its
   40 documentation for any purpose and without fee is hereby granted,
   41 provided that the above copyright notice appear in all copies and that
   42 both that copyright notice and this permission notice appear in
   43 supporting documentation, and that the name of IBM not be
   44 used in advertising or publicity pertaining to distribution of the
   45 software without specific, written prior permission.
   46 
   47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
   49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   53 SOFTWARE.
   54 
   55 ******************************************************************/
   56 
   57 /*
   58  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
   59  */
   60 
   61 #include <sys/cdefs.h>
   62 __KERNEL_RCSID(0, "$NetBSD: clnp_frag.c,v 1.18 2005/12/11 12:25:12 christos Exp $");
   63 
   64 #include <sys/param.h>
   65 #include <sys/systm.h>
   66 #include <sys/mbuf.h>
   67 #include <sys/domain.h>
   68 #include <sys/protosw.h>
   69 #include <sys/socket.h>
   70 #include <sys/socketvar.h>
   71 #include <sys/errno.h>
   72 
   73 #include <net/if.h>
   74 #include <net/route.h>
   75 
   76 #include <netiso/iso.h>
   77 #include <netiso/iso_var.h>
   78 #include <netiso/clnp.h>
   79 #include <netiso/clnp_stat.h>
   80 #include <netiso/argo_debug.h>
   81 
   82 /* all fragments are hung off this list */
   83 struct clnp_fragl *clnp_frags = NULL;
   84 
   85 /*
   86  * FUNCTION:            clnp_fragment
   87  *
   88  * PURPOSE:             Fragment a datagram, and send the itty bitty pieces
   89  *                      out over an interface.
   90  *
   91  * RETURNS:             success - 0
   92  *                      failure - unix error code
   93  *
   94  * SIDE EFFECTS:
   95  *
   96  * NOTES:               If there is an error sending the packet, clnp_discard
   97  *                      is called to discard the packet and send an ER. If
   98  *                      clnp_fragment was called from clnp_output, then
   99  *                      we generated the packet, and should not send an
  100  *                      ER -- clnp_emit_er will check for this. Otherwise,
  101  *                      the packet was fragmented during forwarding. In this
  102  *                      case, we ought to send an ER back.
  103  */
  104 int
  105 clnp_fragment(
  106         struct ifnet   *ifp,    /* ptr to outgoing interface */
  107         struct mbuf    *m,      /* ptr to packet */
  108         struct sockaddr *first_hop,     /* ptr to first hop */
  109         int             total_len,      /* length of datagram */
  110         int             segoff, /* offset of segpart in hdr */
  111         int             flags,  /* flags passed to clnp_output */
  112         struct rtentry *rt)     /* route if direct ether */
  113 {
  114         struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
  115         int             hdr_len = (int) clnp->cnf_hdr_len;
  116         int             frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7;
  117 
  118         total_len -= hdr_len;
  119         if ((clnp->cnf_type & CNF_SEG_OK) &&
  120             (total_len >= 8) &&
  121             (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) {
  122                 struct mbuf    *hdr = NULL;     /* save copy of clnp hdr */
  123                 struct mbuf    *frag_hdr = NULL;
  124                 struct mbuf    *frag_data = NULL;
  125                 struct clnp_segment seg_part;   /* segmentation header */
  126                 int             frag_base;
  127                 int             error = 0;
  128 
  129 
  130                 INCSTAT(cns_fragmented);
  131                 (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t) & seg_part,
  132                              sizeof(seg_part));
  133                 frag_base = ntohs(seg_part.cng_off);
  134                 /*
  135                  *      Duplicate header, and remove from packet
  136                  */
  137                 if ((hdr = m_copy(m, 0, hdr_len)) == NULL) {
  138                         clnp_discard(m, GEN_CONGEST);
  139                         return (ENOBUFS);
  140                 }
  141                 m_adj(m, hdr_len);
  142 
  143                 while (total_len > 0) {
  144                         int             remaining, last_frag;
  145 
  146 #ifdef ARGO_DEBUG
  147                         if (argo_debug[D_FRAG]) {
  148                                 struct mbuf    *mdump = frag_hdr;
  149                                 int             tot_mlen = 0;
  150                                 printf("clnp_fragment: total_len %d:\n",
  151                                     total_len);
  152                                 while (mdump != NULL) {
  153                                         printf("\tmbuf %p, m_len %d\n",
  154                                             mdump, mdump->m_len);
  155                                         tot_mlen += mdump->m_len;
  156                                         mdump = mdump->m_next;
  157                                 }
  158                                 printf("clnp_fragment: sum of mbuf chain %d:\n",
  159                                     tot_mlen);
  160                         }
  161 #endif
  162 
  163                         frag_size = min(total_len, frag_size);
  164                         if ((remaining = total_len - frag_size) == 0)
  165                                 last_frag = 1;
  166                         else {
  167                                 /*
  168                                  * If this fragment will cause the last one to
  169                                  * be less than 8 bytes, shorten this fragment
  170                                  * a bit. The obscure test on frag_size above
  171                                  * ensures that frag_size will be positive.
  172                                  */
  173                                 last_frag = 0;
  174                                 if (remaining < 8)
  175                                         frag_size -= 8;
  176                         }
  177 
  178 
  179 #ifdef ARGO_DEBUG
  180                         if (argo_debug[D_FRAG]) {
  181                                 printf(
  182                                     "clnp_fragment: seg off %d, size %d, rem %d\n",
  183                                     ntohs(seg_part.cng_off), frag_size,
  184                                        total_len - frag_size);
  185                                 if (last_frag)
  186                                         printf(
  187                                           "clnp_fragment: last fragment\n");
  188                         }
  189 #endif
  190 
  191                         if (last_frag) {
  192                                 /*
  193                                  * this is the last fragment; we don't need
  194                                  * to get any other mbufs.
  195                                  */
  196                                 frag_hdr = hdr;
  197                                 frag_data = m;
  198                         } else {
  199                                 /* duplicate header and data mbufs */
  200                                 frag_hdr = m_copy(hdr, 0, (int) M_COPYALL);
  201                                 if (frag_hdr == NULL) {
  202                                         clnp_discard(hdr, GEN_CONGEST);
  203                                         m_freem(m);
  204                                         return (ENOBUFS);
  205                                 }
  206                                 frag_data = m_copy(m, 0, frag_size);
  207                                 if (frag_data == NULL) {
  208                                         clnp_discard(hdr, GEN_CONGEST);
  209                                         m_freem(m);
  210                                         m_freem(frag_hdr);
  211                                         return (ENOBUFS);
  212                                 }
  213                                 INCSTAT(cns_fragments);
  214                         }
  215                         clnp = mtod(frag_hdr, struct clnp_fixed *);
  216 
  217                         if (!last_frag)
  218                                 clnp->cnf_type |= CNF_MORE_SEGS;
  219 
  220                         /* link together */
  221                         m_cat(frag_hdr, frag_data);
  222 
  223                         /* insert segmentation part; updated below */
  224                         bcopy((caddr_t) & seg_part,
  225                               mtod(frag_hdr, caddr_t) + segoff,
  226                               sizeof(struct clnp_segment));
  227 
  228                         {
  229                                 int             derived_len = hdr_len + frag_size;
  230                                 HTOC(clnp->cnf_seglen_msb,
  231                                      clnp->cnf_seglen_lsb, derived_len);
  232                                 if ((frag_hdr->m_flags & M_PKTHDR) == 0)
  233                                         panic("clnp_frag:lost header");
  234                                 frag_hdr->m_pkthdr.len = derived_len;
  235                         }
  236 
  237                         /* compute clnp checksum (on header only) */
  238                         if (flags & CLNP_NO_CKSUM) {
  239                                 HTOC(clnp->cnf_cksum_msb,
  240                                      clnp->cnf_cksum_lsb, 0);
  241                         } else {
  242                                 iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len);
  243                         }
  244 
  245 #ifdef ARGO_DEBUG
  246                         if (argo_debug[D_DUMPOUT]) {
  247                                 struct mbuf    *mdump = frag_hdr;
  248                                 printf("clnp_fragment: sending dg:\n");
  249                                 while (mdump != NULL) {
  250                                         printf("\tmbuf %p, m_len %d\n",
  251                                             mdump, mdump->m_len);
  252                                         mdump = mdump->m_next;
  253                                 }
  254                         }
  255 #endif
  256 
  257 #ifdef  TROLL
  258                         error = troll_output(ifp, frag_hdr, first_hop, rt);
  259 #else
  260                         error = (*ifp->if_output) (ifp, frag_hdr, first_hop, rt);
  261 #endif                          /* TROLL */
  262 
  263                         /*
  264                          * Tough situation: if the error occurred on the last
  265                          * fragment, we can not send an ER, as the if_output
  266                          * routine consumed the packet. If the error occurred
  267                          * on any intermediate packets, we can send an ER
  268                          * because we still have the original header in (m).
  269                          */
  270                         if (error) {
  271                                 if (frag_hdr != hdr) {
  272                                         /*
  273                                          * The error was not on the last
  274                                          * fragment. We must free hdr and m
  275                                          * before returning
  276                                          */
  277                                         clnp_discard(hdr, GEN_NOREAS);
  278                                         m_freem(m);
  279                                 }
  280                                 return (error);
  281                         }
  282                         /*
  283                          * bump segment offset, trim data mbuf, and decrement
  284                          * count left
  285                          */
  286 #ifdef  TROLL
  287                         /*
  288                          * Decrement frag_size by some fraction. This will
  289                          * cause the next fragment to start 'early', thus
  290                          * duplicating the end of the current fragment.
  291                          * troll.tr_dup_size controls the fraction. If
  292                          * positive, it specifies the fraction. If
  293                          * negative, a random fraction is used.
  294                          */
  295                         if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) {
  296                                 int             num_bytes = frag_size;
  297 
  298                                 if (trollctl.tr_dup_size > 0)
  299                                         num_bytes *= trollctl.tr_dup_size;
  300                                 else
  301                                         num_bytes *= troll_random();
  302                                 frag_size -= num_bytes;
  303                         }
  304 #endif                          /* TROLL */
  305                         total_len -= frag_size;
  306                         if (!last_frag) {
  307                                 frag_base += frag_size;
  308                                 seg_part.cng_off = htons(frag_base);
  309                                 m_adj(m, frag_size);
  310                         }
  311                 }
  312                 return (0);
  313         } else {
  314                 INCSTAT(cns_cantfrag);
  315                 clnp_discard(m, GEN_SEGNEEDED);
  316                 return (EMSGSIZE);
  317         }
  318 }
  319 
  320 /*
  321  * FUNCTION:            clnp_reass
  322  *
  323  * PURPOSE:             Attempt to reassemble a clnp packet given the current
  324  *                      fragment. If reassembly succeeds (all the fragments
  325  *                      are present), then return a pointer to an mbuf chain
  326  *                      containing the reassembled packet. This packet will
  327  *                      appear in the mbufs as if it had just arrived in
  328  *                      one piece.
  329  *
  330  *                      If reassembly fails, then save this fragment and
  331  *                      return 0.
  332  *
  333  * RETURNS:             Ptr to assembled packet, or 0
  334  *
  335  * SIDE EFFECTS:
  336  *
  337  * NOTES:               clnp_slowtimo can not affect this code because
  338  *                      clnpintr, and thus this code, is called at a higher
  339  *                      priority than clnp_slowtimo.
  340  */
  341 struct mbuf    *
  342 clnp_reass(
  343         struct mbuf    *m,      /* new fragment */
  344         struct iso_addr *src,   /* src of new fragment */
  345         struct iso_addr *dst,   /* dst of new fragment */
  346         struct clnp_segment *seg)       /* segment part of fragment header */
  347 {
  348         struct clnp_fragl *cfh;
  349 
  350         /* look for other fragments of this datagram */
  351         for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) {
  352                 if (seg->cng_id == cfh->cfl_id &&
  353                     iso_addrmatch1(src, &cfh->cfl_src) &&
  354                     iso_addrmatch1(dst, &cfh->cfl_dst)) {
  355 #ifdef ARGO_DEBUG
  356                         if (argo_debug[D_REASS]) {
  357                                 printf("clnp_reass: found packet\n");
  358                         }
  359 #endif
  360                         /*
  361                          * There are other fragments here already. Lets see if
  362                          * this fragment is of any help
  363                          */
  364                         clnp_insert_frag(cfh, m, seg);
  365                         if ((m = clnp_comp_pdu(cfh)) != NULL) {
  366                                 struct clnp_fixed *clnp =
  367                                 mtod(m, struct clnp_fixed *);
  368                                 HTOC(clnp->cnf_seglen_msb,
  369                                      clnp->cnf_seglen_lsb,
  370                                      seg->cng_tot_len);
  371                         }
  372                         return (m);
  373                 }
  374         }
  375 
  376 #ifdef ARGO_DEBUG
  377         if (argo_debug[D_REASS]) {
  378                 printf("clnp_reass: new packet!\n");
  379         }
  380 #endif
  381 
  382         /*
  383          * This is the first fragment. If src is not consuming too many
  384          * resources, then create a new fragment list and add
  385          * this fragment to the list.
  386          */
  387         /* TODO: don't let one src hog all the reassembly buffers */
  388         if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */ ) {
  389                 INCSTAT(cns_fragdropped);
  390                 clnp_discard(m, GEN_CONGEST);
  391         }
  392         return (NULL);
  393 }
  394 
  395 /*
  396  * FUNCTION:            clnp_newpkt
  397  *
  398  * PURPOSE:             Create the necessary structures to handle a new
  399  *                      fragmented clnp packet.
  400  *
  401  * RETURNS:             non-zero if it succeeds, zero if fails.
  402  *
  403  * SIDE EFFECTS:
  404  *
  405  * NOTES:               Failure is only due to insufficient resources.
  406  */
  407 int
  408 clnp_newpkt(
  409         struct mbuf *m,         /* new fragment */
  410         struct iso_addr *src,   /* src of new fragment */
  411         struct iso_addr *dst,   /* dst of new fragment */
  412         struct clnp_segment *seg)       /* segment part of fragment header */
  413 {
  414         struct clnp_fragl *cfh;
  415         struct clnp_fixed *clnp;
  416 
  417         clnp = mtod(m, struct clnp_fixed *);
  418 
  419         /*
  420          * Allocate new clnp fragl structure to act as header of all
  421          * fragments for this datagram.
  422          */
  423         MALLOC(cfh, struct clnp_fragl *, sizeof (struct clnp_fragl),
  424            M_FTABLE, M_NOWAIT);
  425         if (cfh == NULL) {
  426                 return (0);
  427         }
  428 
  429         /*
  430          * Duplicate the header of this fragment, and save in cfh. Free m0
  431          * and return if m_copy does not succeed.
  432          */
  433         cfh->cfl_orighdr = m_copy(m, 0, (int) clnp->cnf_hdr_len);
  434         if (cfh->cfl_orighdr == NULL) {
  435                 FREE(cfh, M_FTABLE);
  436                 return (0);
  437         }
  438         /* Fill in rest of fragl structure */
  439         bcopy((caddr_t) src, (caddr_t) & cfh->cfl_src, sizeof(struct iso_addr));
  440         bcopy((caddr_t) dst, (caddr_t) & cfh->cfl_dst, sizeof(struct iso_addr));
  441         cfh->cfl_id = seg->cng_id;
  442         cfh->cfl_ttl = clnp->cnf_ttl;
  443         cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1;
  444         cfh->cfl_frags = NULL;
  445         cfh->cfl_next = NULL;
  446 
  447         /* Insert into list of packets */
  448         cfh->cfl_next = clnp_frags;
  449         clnp_frags = cfh;
  450 
  451         /* Insert this fragment into list headed by cfh */
  452         clnp_insert_frag(cfh, m, seg);
  453         return (1);
  454 }
  455 
  456 /*
  457  * FUNCTION:            clnp_insert_frag
  458  *
  459  * PURPOSE:             Insert fragment into list headed by 'cf'.
  460  *
  461  * RETURNS:             nothing
  462  *
  463  * SIDE EFFECTS:
  464  *
  465  * NOTES:               This is the 'guts' of the reassembly algorithm.
  466  *                      Each fragment in this list contains a clnp_frag
  467  *                      structure followed by the data of the fragment.
  468  *                      The clnp_frag structure actually lies on top of
  469  *                      part of the old clnp header.
  470  */
  471 void
  472 clnp_insert_frag(
  473         struct clnp_fragl *cfh, /* header of list of packet fragments */
  474         struct mbuf *m,         /* new fragment */
  475         struct clnp_segment *seg)       /* segment part of fragment header */
  476 {
  477         struct clnp_fixed *clnp;                /* clnp hdr of fragment */
  478         struct clnp_frag *cf;                   /* generic fragment ptr */
  479         struct clnp_frag *cf_sub = NULL;        /* frag subseq to new
  480                                                          * one */
  481         struct clnp_frag *cf_prev = NULL;       /* frag prev to new one */
  482         u_short         first;  /* offset of first byte of initial pdu */
  483         u_short         last;   /* offset of last byte of initial pdu */
  484         u_short         fraglen;/* length of fragment */
  485 
  486         clnp = mtod(m, struct clnp_fixed *);
  487         first = seg->cng_off;
  488         CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen);
  489         fraglen -= clnp->cnf_hdr_len;
  490         last = (first + fraglen) - 1;
  491 
  492 #ifdef ARGO_DEBUG
  493         if (argo_debug[D_REASS]) {
  494                 printf("clnp_insert_frag: New fragment: [%d-%d], len %d\n",
  495                     first, last, fraglen);
  496                 printf("clnp_insert_frag: current fragments:\n");
  497                 for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) {
  498                         printf("\tcf %p: [%d-%d]\n",
  499                             cf, cf->cfr_first, cf->cfr_last);
  500                 }
  501         }
  502 #endif
  503 
  504         if (cfh->cfl_frags != NULL) {
  505                 /*
  506                  * Find fragment which begins after the new one
  507                  */
  508                 for (cf = cfh->cfl_frags; cf != NULL;
  509                      cf_prev = cf, cf = cf->cfr_next) {
  510                         if (cf->cfr_first > first) {
  511                                 cf_sub = cf;
  512                                 break;
  513                         }
  514                 }
  515 
  516 #ifdef ARGO_DEBUG
  517                 if (argo_debug[D_REASS]) {
  518                         printf("clnp_insert_frag: Previous frag is ");
  519                         if (cf_prev == NULL)
  520                                 printf("NULL\n");
  521                         else
  522                                 printf("[%d-%d]\n", cf_prev->cfr_first,
  523                                     cf_prev->cfr_last);
  524                         printf("clnp_insert_frag: Subsequent frag is ");
  525                         if (cf_sub == NULL)
  526                                 printf("NULL\n");
  527                         else
  528                                 printf("[%d-%d]\n", cf_sub->cfr_first,
  529                                     cf_sub->cfr_last);
  530                 }
  531 #endif
  532 
  533                 /*
  534                  * If there is a fragment before the new one, check if it
  535                  * overlaps the new one. If so, then trim the end of the
  536                  * previous one.
  537                  */
  538                 if (cf_prev != NULL) {
  539                         if (cf_prev->cfr_last > first) {
  540                                 u_short         overlap = cf_prev->cfr_last - first;
  541 
  542 #ifdef ARGO_DEBUG
  543                                 if (argo_debug[D_REASS]) {
  544                                         printf(
  545                                             "clnp_insert_frag: previous overlaps by %d\n",
  546                                             overlap);
  547                                 }
  548 #endif
  549 
  550                                 if (overlap > fraglen) {
  551                                         /*
  552                                          * The new fragment is entirely
  553                                          * contained in the preceding one.
  554                                          * We can punt on the new frag
  555                                          * completely.
  556                                          */
  557                                         m_freem(m);
  558                                         return;
  559                                 } else {
  560                                         /*
  561                                          * Trim data off of end of previous
  562                                          * fragment
  563                                          */
  564                                         /*
  565                                          * inc overlap to prevent duplication
  566                                          * of last byte
  567                                          */
  568                                         overlap++;
  569                                         m_adj(cf_prev->cfr_data, -(int) overlap);
  570                                         cf_prev->cfr_last -= overlap;
  571                                 }
  572                         }
  573                 }
  574                 /*
  575                  *      For all fragments past the new one, check if any data on
  576                  *      the new one overlaps data on existing fragments. If so,
  577                  *      then trim the extra data off the end of the new one.
  578                  */
  579                 for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) {
  580                         if (cf->cfr_first < last) {
  581                                 u_short         overlap = last - cf->cfr_first;
  582 
  583 #ifdef ARGO_DEBUG
  584                                 if (argo_debug[D_REASS]) {
  585                                         printf(
  586                                             "clnp_insert_frag: subsequent overlaps by %d\n",
  587                                             overlap);
  588                                 }
  589 #endif
  590 
  591                                 if (overlap > fraglen) {
  592                                         /*
  593                                          * The new fragment is entirely
  594                                          * contained in the succeeding one.
  595                                          * This should not happen, because
  596                                          * early on in this code we scanned
  597                                          * for the fragment which started
  598                                          * after the new one!
  599                                          */
  600                                         m_freem(m);
  601                                         printf(
  602                                             "clnp_insert_frag: internal error!\n");
  603                                         return;
  604                                 } else {
  605                                         /*
  606                                          * Trim data off of end of new fragment
  607                                          * inc overlap to prevent duplication
  608                                          * of last byte
  609                                          */
  610                                         overlap++;
  611                                         m_adj(m, -(int) overlap);
  612                                         last -= overlap;
  613                                 }
  614                         }
  615                 }
  616         }
  617         /*
  618          * Insert the new fragment beween cf_prev and cf_sub
  619          *
  620          * Note: the clnp hdr is still in the mbuf.
  621          * If the data of the mbuf is not word aligned, shave off enough
  622          * so that it is. Then, cast the clnp_frag structure on top
  623          * of the clnp header.
  624          * The clnp_hdr will not be used again (as we already have
  625          * saved a copy of it).
  626          *
  627          * Save in cfr_bytes the number of bytes to shave off to get to
  628          * the data of the packet. This is used when we coalesce fragments;
  629          * the clnp_frag structure must be removed before joining mbufs.
  630          */
  631         {
  632                 int             pad;
  633                 u_int           bytes;
  634 
  635                 /* determine if header is not word aligned */
  636                 pad = (long) clnp % 4;
  637                 if (pad < 0)
  638                         pad = -pad;
  639 
  640                 /* bytes is number of bytes left in front of data */
  641                 bytes = clnp->cnf_hdr_len - pad;
  642 
  643 #ifdef ARGO_DEBUG
  644                 if (argo_debug[D_REASS]) {
  645                         printf(
  646                         "clnp_insert_frag: clnp %p requires %d alignment\n",
  647                                clnp, pad);
  648                 }
  649 #endif
  650 
  651                 /* make it word aligned if necessary */
  652                 if (pad)
  653                         m_adj(m, pad);
  654 
  655                 cf = mtod(m, struct clnp_frag *);
  656                 cf->cfr_bytes = bytes;
  657 
  658 #ifdef ARGO_DEBUG
  659                 if (argo_debug[D_REASS]) {
  660                         printf("clnp_insert_frag: cf now %p, cfr_bytes %d\n",
  661                                cf, cf->cfr_bytes);
  662                 }
  663 #endif
  664         }
  665         cf->cfr_first = first;
  666         cf->cfr_last = last;
  667 
  668 
  669         /*
  670          * The data is the mbuf itself, although we must remember that the
  671          * first few bytes are actually a clnp_frag structure
  672          */
  673         cf->cfr_data = m;
  674 
  675         /* link into place */
  676         cf->cfr_next = cf_sub;
  677         if (cf_prev == NULL)
  678                 cfh->cfl_frags = cf;
  679         else
  680                 cf_prev->cfr_next = cf;
  681 }
  682 
  683 /*
  684  * FUNCTION:            clnp_comp_pdu
  685  *
  686  * PURPOSE:             Scan the list of fragments headed by cfh. Merge
  687  *                      any contigious fragments into one. If, after
  688  *                      traversing all the fragments, it is determined that
  689  *                      the packet is complete, then return a pointer to
  690  *                      the packet (with header prepended). Otherwise,
  691  *                      return NULL.
  692  *
  693  * RETURNS:             NULL, or a pointer to the assembled pdu in an mbuf
  694  *                      chain.
  695  *
  696  * SIDE EFFECTS:        Will colapse contigious fragments into one.
  697  *
  698  * NOTES:               This code assumes that there are no overlaps of
  699  *                      fragment pdus.
  700  */
  701 struct mbuf    *
  702 clnp_comp_pdu(
  703         struct clnp_fragl *cfh) /* fragment header */
  704 {
  705         struct clnp_frag *cf = cfh->cfl_frags;
  706 
  707         while (cf->cfr_next != NULL) {
  708                 struct clnp_frag *cf_next = cf->cfr_next;
  709 
  710 #ifdef ARGO_DEBUG
  711                 if (argo_debug[D_REASS]) {
  712                         printf("clnp_comp_pdu: comparing: [%d-%d] to [%d-%d]\n",
  713                             cf->cfr_first, cf->cfr_last, cf_next->cfr_first,
  714                             cf_next->cfr_last);
  715                 }
  716 #endif
  717 
  718                 if (cf->cfr_last == (cf_next->cfr_first - 1)) {
  719                         /*
  720                          * Merge fragment cf and cf_next
  721                          *
  722                          * - update cf header
  723                          * - trim clnp_frag structure off of cf_next
  724                          * - append cf_next to cf
  725                          */
  726                         struct clnp_frag cf_next_hdr;
  727                         struct clnp_frag *next_frag;
  728 
  729                         cf_next_hdr = *cf_next;
  730                         next_frag = cf_next->cfr_next;
  731 
  732 #ifdef ARGO_DEBUG
  733                         if (argo_debug[D_REASS]) {
  734                                 struct mbuf    *mdump;
  735                                 int             l;
  736                                 printf("clnp_comp_pdu: merging fragments\n");
  737                                 printf(
  738                                     "clnp_comp_pdu: 1st: [%d-%d] (bytes %d)\n",
  739                                     cf->cfr_first, cf->cfr_last,
  740                                     cf->cfr_bytes);
  741                                 mdump = cf->cfr_data;
  742                                 l = 0;
  743                                 while (mdump != NULL) {
  744                                         printf("\tmbuf %p, m_len %d\n",
  745                                             mdump, mdump->m_len);
  746                                         l += mdump->m_len;
  747                                         mdump = mdump->m_next;
  748                                 }
  749                                 printf("\ttotal len: %d\n", l);
  750                                 printf(
  751                                     "clnp_comp_pdu: 2nd: [%d-%d] (bytes %d)\n",
  752                                     cf_next->cfr_first, cf_next->cfr_last,
  753                                        cf_next->cfr_bytes);
  754                                 mdump = cf_next->cfr_data;
  755                                 l = 0;
  756                                 while (mdump != NULL) {
  757                                         printf("\tmbuf %p, m_len %d\n",
  758                                                mdump, mdump->m_len);
  759                                         l += mdump->m_len;
  760                                         mdump = mdump->m_next;
  761                                 }
  762                                 printf("\ttotal len: %d\n", l);
  763                         }
  764 #endif
  765 
  766                         cf->cfr_last = cf_next->cfr_last;
  767                         /*
  768                          * After this m_adj, the cf_next ptr is useless
  769                          * because we have adjusted the clnp_frag structure
  770                          * away...
  771                          */
  772 #ifdef ARGO_DEBUG
  773                         if (argo_debug[D_REASS]) {
  774                                 printf("clnp_comp_pdu: shaving off %d bytes\n",
  775                                        cf_next_hdr.cfr_bytes);
  776                         }
  777 #endif
  778                         m_adj(cf_next_hdr.cfr_data,
  779                               (int) cf_next_hdr.cfr_bytes);
  780                         m_cat(cf->cfr_data, cf_next_hdr.cfr_data);
  781                         cf->cfr_next = next_frag;
  782                 } else {
  783                         cf = cf->cfr_next;
  784                 }
  785         }
  786 
  787         cf = cfh->cfl_frags;
  788 
  789 #ifdef ARGO_DEBUG
  790         if (argo_debug[D_REASS]) {
  791                 struct mbuf    *mdump = cf->cfr_data;
  792                 printf("clnp_comp_pdu: first frag now: [%d-%d]\n",
  793                     cf->cfr_first, cf->cfr_last);
  794                 printf("clnp_comp_pdu: data for frag:\n");
  795                 while (mdump != NULL) {
  796                         printf("mbuf %p, m_len %d\n", mdump, mdump->m_len);
  797                         /* dump_buf(mtod(mdump, caddr_t), mdump->m_len); */
  798                         mdump = mdump->m_next;
  799                 }
  800         }
  801 #endif
  802 
  803         /* Check if datagram is complete */
  804         if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) {
  805                 /*
  806                  * We have a complete pdu!
  807                  * - Remove the frag header from (only) remaining fragment
  808                  *   (which is not really a fragment anymore, as the datagram
  809                  *    is complete).
  810                  * - Prepend a clnp header
  811                  */
  812                 struct mbuf    *data = cf->cfr_data;
  813                 struct mbuf    *hdr = cfh->cfl_orighdr;
  814                 struct clnp_fragl *scan;
  815 
  816 #ifdef ARGO_DEBUG
  817                 if (argo_debug[D_REASS]) {
  818                         printf("clnp_comp_pdu: complete pdu!\n");
  819                 }
  820 #endif
  821 
  822                 m_adj(data, (int) cf->cfr_bytes);
  823                 m_cat(hdr, data);
  824 
  825 #ifdef ARGO_DEBUG
  826                 if (argo_debug[D_DUMPIN]) {
  827                         struct mbuf    *mdump = hdr;
  828                         printf("clnp_comp_pdu: pdu is:\n");
  829                         while (mdump != NULL) {
  830                                 printf("mbuf %p, m_len %d\n",
  831                                        mdump, mdump->m_len);
  832 #if 0
  833                                 dump_buf(mtod(mdump, caddr_t), mdump->m_len);
  834 #endif
  835                                 mdump = mdump->m_next;
  836                         }
  837                 }
  838 #endif
  839 
  840                 /*
  841                  * Remove cfh from the list of fragmented pdus
  842                  */
  843                 if (clnp_frags == cfh) {
  844                         clnp_frags = cfh->cfl_next;
  845                 } else {
  846                         for (scan = clnp_frags; scan != NULL;
  847                              scan = scan->cfl_next) {
  848                                 if (scan->cfl_next == cfh) {
  849                                         scan->cfl_next = cfh->cfl_next;
  850                                         break;
  851                                 }
  852                         }
  853                 }
  854 
  855                 /* free cfh */
  856                 FREE(cfh, M_FTABLE);
  857 
  858                 return (hdr);
  859         }
  860         return (NULL);
  861 }
  862 #ifdef  TROLL
  863 static int      troll_cnt;
  864 #include <sys/time.h>
  865 /*
  866  * FUNCTION:            troll_random
  867  *
  868  * PURPOSE:             generate a pseudo-random number between 0 and 1
  869  *
  870  * RETURNS:             the random number
  871  *
  872  * SIDE EFFECTS:
  873  *
  874  * NOTES:               This is based on the clock.
  875  */
  876 float
  877 troll_random()
  878 {
  879         extern struct timeval time;
  880         long            t = time.tv_usec % 100;
  881 
  882         return ((float) t / (float) 100);
  883 }
  884 
  885 /*
  886  * FUNCTION:            troll_output
  887  *
  888  * PURPOSE:             Do something sneaky with the datagram passed. Possible
  889  *                      operations are:
  890  *                              Duplicate the packet
  891  *                              Drop the packet
  892  *                              Trim some number of bytes from the packet
  893  *                              Munge some byte in the packet
  894  *
  895  * RETURNS:             0, or unix error code
  896  *
  897  * SIDE EFFECTS:
  898  *
  899  * NOTES:               The operation of this procedure is regulated by the
  900  *                      troll control structure (Troll).
  901  */
  902 int
  903 troll_output(ifp, m, dst, rt)
  904         struct ifnet   *ifp;
  905         struct mbuf    *m;
  906         struct sockaddr *dst;
  907         struct rtentry *rt;
  908 {
  909         int             err = 0;
  910         troll_cnt++;
  911 
  912         if (trollctl.tr_ops & TR_DUPPKT) {
  913                 /*
  914                  *      Duplicate every Nth packet
  915                  *      TODO: random?
  916                  */
  917                 float           f_freq = troll_cnt * trollctl.tr_dup_freq;
  918                 int             i_freq = troll_cnt * trollctl.tr_dup_freq;
  919                 if (i_freq == f_freq) {
  920                         struct mbuf    *dup = m_copy(m, 0, (int) M_COPYALL);
  921                         if (dup != NULL)
  922                                 err = (*ifp->if_output) (ifp, dup, dst, rt);
  923                 }
  924                 if (!err)
  925                         err = (*ifp->if_output) (ifp, m, dst, rt);
  926                 return (err);
  927         } else if (trollctl.tr_ops & TR_DROPPKT) {
  928         } else if (trollctl.tr_ops & TR_CHANGE) {
  929                 struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *);
  930                 clnp->cnf_cksum_msb = 0;
  931                 err = (*ifp->if_output) (ifp, m, dst, rt);
  932                 return (err);
  933         } else {
  934                 err = (*ifp->if_output) (ifp, m, dst, rt);
  935                 return (err);
  936         }
  937 }
  938 
  939 #endif                          /* TROLL */

Cache object: ea777fb130884f3f2e9febbf6ba86fd3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.