home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / clnp_output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-09  |  16.6 KB  |  550 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)clnp_output.c    7.10 (Berkeley) 5/6/91
  34.  */
  35.  
  36. /***********************************************************
  37.         Copyright IBM Corporation 1987
  38.  
  39.                       All Rights Reserved
  40.  
  41. Permission to use, copy, modify, and distribute this software and its 
  42. documentation for any purpose and without fee is hereby granted, 
  43. provided that the above copyright notice appear in all copies and that
  44. both that copyright notice and this permission notice appear in 
  45. supporting documentation, and that the name of IBM not be
  46. used in advertising or publicity pertaining to distribution of the
  47. software without specific, written prior permission.  
  48.  
  49. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  50. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  51. IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  52. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  53. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  54. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  55. SOFTWARE.
  56.  
  57. ******************************************************************/
  58.  
  59. /*
  60.  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
  61.  */
  62. /* $Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $ */
  63. /* $Source: /var/src/sys/netiso/RCS/clnp_output.c,v $ */
  64.  
  65. #include "param.h"
  66. #include "mbuf.h"
  67. #include "domain.h"
  68. #include "protosw.h"
  69. #include "socket.h"
  70. #include "socketvar.h"
  71. #include "errno.h"
  72. #include "time.h"
  73.  
  74. #include "../net/if.h"
  75. #include "../net/route.h"
  76.  
  77. #include "iso.h"
  78. #include "iso_var.h"
  79. #include "iso_pcb.h"
  80. #include "clnp.h"
  81. #include "clnp_stat.h"
  82. #include "argo_debug.h"
  83.  
  84. static struct clnp_fixed dt_template = {
  85.     ISO8473_CLNP,    /* network identifier */
  86.     0,                /* length */
  87.     ISO8473_V1,        /* version */
  88.     CLNP_TTL,        /* ttl */
  89.     CLNP_DT|CNF_SEG_OK|CNF_ERR_OK,        /* type */
  90.     0,                /* segment length */
  91.     0                /* checksum */
  92. };
  93.  
  94. static struct clnp_fixed raw_template = {
  95.     ISO8473_CLNP,    /* network identifier */
  96.     0,                /* length */
  97.     ISO8473_V1,        /* version */
  98.     CLNP_TTL,        /* ttl */
  99.     CLNP_RAW|CNF_SEG_OK|CNF_ERR_OK,        /* type */
  100.     0,                /* segment length */
  101.     0                /* checksum */
  102. };
  103.  
  104. static struct clnp_fixed echo_template = {
  105.     ISO8473_CLNP,    /* network identifier */
  106.     0,                /* length */
  107.     ISO8473_V1,        /* version */
  108.     CLNP_TTL,        /* ttl */
  109.     CLNP_EC|CNF_SEG_OK|CNF_ERR_OK,        /* type */
  110.     0,                /* segment length */
  111.     0                /* checksum */
  112. };
  113.  
  114. #ifdef    DECBIT
  115. u_char qos_option[] = {CLNPOVAL_QOS, 1, 
  116.     CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY};
  117. #endif    DECBIT
  118.  
  119. int                clnp_id = 0;        /* id for segmented dgrams */
  120.  
  121. /*
  122.  * FUNCTION:        clnp_output
  123.  *
  124.  * PURPOSE:            output the data in the mbuf as a clnp datagram
  125.  *
  126.  *                    The data specified by m0 is sent as a clnp datagram. 
  127.  *                    The mbuf chain m0 will be freed when this routine has
  128.  *                    returned.
  129.  *
  130.  *                    If options is non-null, it points to an mbuf which contains
  131.  *                    options to be sent with the datagram. The options must
  132.  *                    be formatted in the mbuf according to clnp rules. Options
  133.  *                    will not be freed.
  134.  *
  135.  *                    Datalen specifies the length of the data in m0. 
  136.  *
  137.  *                    Src and dst are the addresses for the packet. 
  138.  *
  139.  *                    If route is non-null, it is used as the route for 
  140.  *                    the packet. 
  141.  *
  142.  *                    By default, a DT is sent. However, if flags & CNLP_SEND_ER
  143.  *                    then an ER will be sent. If flags & CLNP_SEND_RAW, then
  144.  *                    the packet will be send as raw clnp.
  145.  *
  146.  * RETURNS:            0    success
  147.  *                    appropriate error code
  148.  *
  149.  * SIDE EFFECTS:    none
  150.  *
  151.  * NOTES:            
  152.  *                    Flags are interpretated as follows:
  153.  *                        CLNP_NO_SEG - do not allow this pkt to be segmented.
  154.  *                        CLNP_NO_ER  - have pkt request ER suppression.
  155.  *                        CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT
  156.  *                        CLNP_NO_CKSUM - don't compute clnp checksum
  157.  *                        CLNP_ECHO - send as ECHO packet
  158.  *
  159.  *                    When checking for a cached packet, clnp checks
  160.  *                    that the route taken is still up. It does not
  161.  *                    check that the route is still to the same destination.
  162.  *                    This means that any entity that alters an existing
  163.  *                    route for an isopcb (such as when a redirect arrives)
  164.  *                    must invalidate the clnp cache. It might be perferable
  165.  *                    to have clnp check that the route has the same dest, but
  166.  *                    by avoiding this check, we save a call to iso_addrmatch1.
  167.  */
  168. clnp_output(m0, isop, datalen, flags)
  169. struct mbuf            *m0;        /* data for the packet */
  170. struct isopcb        *isop;        /* iso pcb */
  171. int                    datalen;    /* number of bytes of data in m0 */
  172. int                    flags;        /* flags */
  173. {
  174.     int                            error = 0;        /* return value of function */
  175.     register struct mbuf        *m = m0;        /* mbuf for clnp header chain */
  176.     register struct clnp_fixed    *clnp;            /* ptr to fixed part of hdr */
  177.     register caddr_t            hoff;            /* offset into header */
  178.     int                            total_len;        /* total length of packet */
  179.     struct iso_addr                *src;        /* ptr to source address */
  180.     struct iso_addr                *dst;        /* ptr to destination address */
  181.     struct clnp_cache            clc;        /* storage for cache information */
  182.     struct clnp_cache            *clcp = NULL;    /* ptr to clc */
  183.     int                            hdrlen = 0;
  184.  
  185.     dst = &isop->isop_faddr->siso_addr;
  186.     if (isop->isop_laddr == 0) {
  187.         struct iso_ifaddr *ia = 0;
  188.         clnp_route(dst, &isop->isop_route, flags, 0, &ia);
  189.         if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO)
  190.             return (ENETUNREACH);
  191.         src = &ia->ia_addr.siso_addr;
  192.     } else
  193.         src = &isop->isop_laddr->siso_addr;
  194.  
  195.     IFDEBUG(D_OUTPUT)
  196.         printf("clnp_output: to %s", clnp_iso_addrp(dst));
  197.         printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen);
  198.         printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n", 
  199.             isop->isop_options, flags, isop->isop_clnpcache);
  200.     ENDDEBUG
  201.  
  202.     if (isop->isop_clnpcache != NULL) {
  203.         clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
  204.     }
  205.     
  206.     /*
  207.      *    Check if cache is valid ...
  208.      */
  209.     IFDEBUG(D_OUTPUT)
  210.         printf("clnp_output: ck cache: clcp %x\n", clcp);
  211.         if (clcp != NULL) {
  212.             printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst));
  213.             printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options,
  214.                 clcp->clc_options);
  215.             if (isop->isop_route.ro_rt)
  216.                 printf("\tro_rt x%x, rt_flags x%x\n",
  217.                     isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags);
  218.             printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags);
  219.             printf("\tclc_hdr x%x\n", clcp->clc_hdr);
  220.         }
  221.     ENDDEBUG
  222.     if ((clcp != NULL) &&                                /* cache exists */
  223.         (isop->isop_options == clcp->clc_options) &&     /* same options */
  224.         (iso_addrmatch1(dst, &clcp->clc_dst)) &&        /* dst still same */
  225.         (isop->isop_route.ro_rt != NULL) &&                /* route exists */
  226.         (isop->isop_route.ro_rt == clcp->clc_rt) &&        /* and is cached */
  227.         (isop->isop_route.ro_rt->rt_flags & RTF_UP) &&    /* route still up */
  228.         (flags == clcp->clc_flags) &&                    /* same flags */
  229.         (clcp->clc_hdr != NULL)) {                        /* hdr mbuf exists */
  230.         /*
  231.          *    The cache is valid
  232.          */
  233.  
  234.         IFDEBUG(D_OUTPUT)
  235.             printf("clnp_output: using cache\n");
  236.         ENDDEBUG
  237.  
  238.         m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL);
  239.         if (m == NULL) {
  240.             /*
  241.              *    No buffers left to copy cached packet header. Use
  242.              *    the cached packet header this time, and
  243.              *    mark the hdr as vacant
  244.              */
  245.             m = clcp->clc_hdr;
  246.             clcp->clc_hdr = NULL;
  247.         }
  248.         m->m_next = m0;    /* ASSUMES pkt hdr is 1 mbuf long */
  249.         clnp = mtod(m, struct clnp_fixed *);
  250.     } else {
  251.         struct clnp_optidx    *oidx = NULL;        /* index to clnp options */
  252.  
  253.         /*
  254.          *    The cache is not valid. Allocate an mbuf (if necessary)
  255.          *    to hold cached info. If one is not available, then
  256.          *    don't bother with the cache
  257.          */
  258.         INCSTAT(cns_cachemiss);
  259.         if (flags & CLNP_NOCACHE) {
  260.             clcp = &clc;
  261.         } else {
  262.             if (isop->isop_clnpcache == NULL) {
  263.                 /*
  264.                  *    There is no clnpcache. Allocate an mbuf to hold one
  265.                  */
  266.                 if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER))
  267.                     == NULL) {
  268.                     /*
  269.                      *    No mbufs available. Pretend that we don't want
  270.                      *    caching this time.
  271.                      */
  272.                     IFDEBUG(D_OUTPUT)
  273.                         printf("clnp_output: no mbufs to allocate to cache\n");
  274.                     ENDDEBUG
  275.                     flags  |= CLNP_NOCACHE;
  276.                     clcp = &clc;
  277.                 } else {
  278.                     clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
  279.                 }
  280.             } else {
  281.                 /*
  282.                  *    A clnpcache mbuf exists. If the clc_hdr is not null,
  283.                  *    we must free it, as a new one is about to be created.
  284.                  */
  285.                 clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
  286.                 if (clcp->clc_hdr != NULL) {
  287.                     /*
  288.                      *    The clc_hdr is not null but a clnpcache mbuf exists.
  289.                      *    This means that there was a cache, but the existing
  290.                      *    copy of the hdr is no longer valid. Free it now
  291.                      *    before we lose the pointer to it.
  292.                      */
  293.                     IFDEBUG(D_OUTPUT)
  294.                         printf("clnp_output: freeing old clc_hdr 0x%x\n",
  295.                         clcp->clc_hdr);
  296.                     ENDDEBUG
  297.                     m_free(clcp->clc_hdr);
  298.                     IFDEBUG(D_OUTPUT)
  299.                         printf("clnp_output: freed old clc_hdr (done)\n");
  300.                     ENDDEBUG
  301.                 }
  302.             }
  303.         }
  304.         IFDEBUG(D_OUTPUT)
  305.             printf("clnp_output: NEW clcp x%x\n",clcp);
  306.         ENDDEBUG
  307.         bzero((caddr_t)clcp, sizeof(struct clnp_cache));
  308.  
  309.         if (isop->isop_optindex)
  310.             oidx = mtod(isop->isop_optindex, struct clnp_optidx *);
  311.  
  312.         /*
  313.          *    Don't allow packets with security, quality of service,
  314.          *    priority, or error report options to be sent.
  315.          */
  316.         if ((isop->isop_options) && (oidx)) {
  317.             if ((oidx->cni_securep) ||
  318.                 (oidx->cni_priorp) ||
  319.                 (oidx->cni_qos_formatp) ||
  320.                 (oidx->cni_er_reason != ER_INVALREAS)) {
  321.                 IFDEBUG(D_OUTPUT)
  322.                     printf("clnp_output: pkt dropped - option unsupported\n");
  323.                 ENDDEBUG
  324.                 m_freem(m0);
  325.                 return(EINVAL);
  326.             }
  327.         }
  328.  
  329.         /*
  330.          *    Don't allow any invalid flags to be set
  331.          */
  332.         if ((flags & (CLNP_VFLAGS)) != flags) {
  333.             IFDEBUG(D_OUTPUT)
  334.                 printf("clnp_output: packet dropped - flags unsupported\n");
  335.             ENDDEBUG
  336.             INCSTAT(cns_odropped);
  337.             m_freem(m0);
  338.             return(EINVAL);
  339.         }
  340.  
  341.         /*
  342.          *    Don't allow funny lengths on dst; src may be zero in which
  343.          *    case we insert the source address based upon the interface
  344.          */
  345.         if ((src->isoa_len > sizeof(struct iso_addr)) || 
  346.             (dst->isoa_len == 0) ||
  347.             (dst->isoa_len > sizeof(struct iso_addr))) {
  348.             m_freem(m0);
  349.             INCSTAT(cns_odropped);
  350.             return(ENAMETOOLONG);
  351.         }
  352.  
  353.         /*
  354.          *    Grab mbuf to contain header
  355.          */
  356.         MGETHDR(m, M_DONTWAIT, MT_HEADER);
  357.         if (m == 0) {
  358.             m_freem(m0);
  359.             INCSTAT(cns_odropped);
  360.             return(ENOBUFS);
  361.         }
  362.         INCSTAT(cns_sent);
  363.         m->m_next = m0;
  364.         clnp = mtod(m, struct clnp_fixed *);
  365.         clcp->clc_segoff = 0;
  366.  
  367.         /*
  368.          *    Fill in all of fixed hdr except lengths and checksum
  369.          */
  370.         if (flags & CLNP_SEND_RAW) {
  371.             *clnp = raw_template;
  372.         } else if (flags & CLNP_ECHO) {
  373.             *clnp = echo_template;
  374.         } else {
  375.             *clnp = dt_template;
  376.         }
  377.         if (flags & CLNP_NO_SEG)
  378.             clnp->cnf_type &= ~CNF_SEG_OK;
  379.         if (flags & CLNP_NO_ER)
  380.             clnp->cnf_type &= ~CNF_ERR_OK;
  381.  
  382.         /*
  383.          *    Route packet; special case for source rt
  384.          */
  385.         if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) {
  386.             IFDEBUG(D_OUTPUT)
  387.                 printf("clnp_output: calling clnp_srcroute\n");
  388.             ENDDEBUG
  389.             error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route,
  390.                 &clcp->clc_firsthop, &clcp->clc_ifa, dst);
  391.         } else {
  392.             IFDEBUG(D_OUTPUT)
  393.             ENDDEBUG
  394.             error = clnp_route(dst, &isop->isop_route, flags, 
  395.                 &clcp->clc_firsthop, &clcp->clc_ifa);
  396.         }
  397.         if (error || (clcp->clc_ifa == 0)) {
  398.             IFDEBUG(D_OUTPUT)
  399.                 printf("clnp_output: route failed, errno %d\n", error);
  400.                 printf("@clcp:\n");
  401.                 dump_buf(clcp, sizeof (struct clnp_cache));
  402.             ENDDEBUG
  403.             goto bad;
  404.         }
  405.         clcp->clc_rt = isop->isop_route.ro_rt;    /* XXX */
  406.         clcp->clc_ifp = clcp->clc_ifa->ia_ifp;  /* XXX */
  407.  
  408.         IFDEBUG(D_OUTPUT)
  409.             printf("clnp_output: packet routed to %s\n", 
  410.                 clnp_iso_addrp(
  411.                     &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr));
  412.         ENDDEBUG
  413.         
  414.         /*
  415.          *    If src address is not yet specified, use address of 
  416.          *    interface. NOTE: this will now update the laddr field in
  417.          *    the isopcb. Is this desirable? RAH?
  418.          */
  419.         if (src->isoa_len == 0) {
  420.             src = &(clcp->clc_ifa->ia_addr.siso_addr);
  421.             IFDEBUG(D_OUTPUT)
  422.                 printf("clnp_output: new src %s\n", clnp_iso_addrp(src));
  423.             ENDDEBUG
  424.         }
  425.  
  426.         /*
  427.          *    Insert the source and destination address,
  428.          */
  429.         hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
  430.         CLNP_INSERT_ADDR(hoff, *dst);
  431.         CLNP_INSERT_ADDR(hoff, *src);
  432.  
  433.         /*
  434.          *    Leave room for the segment part, if segmenting is selected
  435.          */
  436.         if (clnp->cnf_type & CNF_SEG_OK) {
  437.             clcp->clc_segoff = hoff - (caddr_t)clnp;
  438.             hoff += sizeof(struct clnp_segment);
  439.         }
  440.  
  441.         clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp);
  442.         hdrlen = clnp->cnf_hdr_len;
  443.  
  444. #ifdef    DECBIT
  445.         /*
  446.          *    Add the globally unique QOS (with room for congestion experienced
  447.          *    bit). I can safely assume that this option is not in the options
  448.          *    mbuf below because I checked that the option was not specified
  449.          *    previously
  450.          */
  451.         if ((m->m_len + sizeof(qos_option)) < MLEN) {
  452.             bcopy((caddr_t)qos_option, hoff, sizeof(qos_option));
  453.             clnp->cnf_hdr_len += sizeof(qos_option);
  454.             hdrlen += sizeof(qos_option);
  455.             m->m_len += sizeof(qos_option);
  456.         }
  457. #endif    DECBIT
  458.  
  459.         /*
  460.          *    If an options mbuf is present, concatenate a copy to the hdr mbuf.
  461.          */
  462.         if (isop->isop_options) {
  463.             struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL);
  464.             if (opt_copy == NULL) {
  465.                 error = ENOBUFS;
  466.                 goto bad;
  467.             }
  468.             /* Link in place */
  469.             opt_copy->m_next = m->m_next;
  470.             m->m_next = opt_copy;
  471.  
  472.             /* update size of header */
  473.             clnp->cnf_hdr_len += opt_copy->m_len;
  474.             hdrlen += opt_copy->m_len;
  475.         }
  476.  
  477.         if (hdrlen > CLNP_HDR_MAX) {
  478.             error = EMSGSIZE;
  479.             goto bad;
  480.         }
  481.  
  482.         /*
  483.          *    Now set up the cache entry in the pcb
  484.          */
  485.         if ((flags & CLNP_NOCACHE) == 0) {
  486.             if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) {
  487.                 clcp->clc_dst  = *dst;
  488.                 clcp->clc_flags = flags;
  489.                 clcp->clc_options = isop->isop_options;
  490.             }
  491.         }
  492.     }
  493.     /*
  494.      *    If small enough for interface, send directly
  495.      *    Fill in segmentation part of hdr if using the full protocol
  496.      */
  497.     total_len = clnp->cnf_hdr_len + datalen;
  498.     if (clnp->cnf_type & CNF_SEG_OK) {
  499.         struct clnp_segment    seg_part;        /* segment part of hdr */
  500.         seg_part.cng_id = htons(clnp_id++);
  501.         seg_part.cng_off = htons(0);
  502.         seg_part.cng_tot_len = htons(total_len);
  503.         (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff, 
  504.             sizeof(seg_part));
  505.     }
  506.     if (total_len <= SN_MTU(clcp->clc_ifp, clcp->clc_rt)) {
  507.         HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len);
  508.         m->m_pkthdr.len = total_len;
  509.         /*
  510.          *    Compute clnp checksum (on header only)
  511.          */
  512.         if (flags & CLNP_NO_CKSUM) {
  513.             HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
  514.         } else {
  515.             iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
  516.         }
  517.  
  518.         IFDEBUG(D_DUMPOUT)
  519.             struct mbuf *mdump = m;
  520.             printf("clnp_output: sending dg:\n");
  521.             while (mdump != NULL) {
  522.                 dump_buf(mtod(mdump, caddr_t), mdump->m_len);
  523.                 mdump = mdump->m_next;
  524.             }
  525.         ENDDEBUG
  526.  
  527.         error = SN_OUTPUT(clcp, m);
  528.         goto done;
  529.     } else {
  530.         /*
  531.          * Too large for interface; fragment if possible.
  532.          */
  533.         error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop,
  534.                             total_len, clcp->clc_segoff, flags, clcp->clc_rt);
  535.         goto done;
  536.     }
  537. bad:
  538.     m_freem(m);
  539. done:
  540.     if (error) {
  541.         clnp_stat.cns_sent--;
  542.         clnp_stat.cns_odropped++;
  543.     }
  544.     return (error);
  545. }
  546.  
  547. int clnp_ctloutput()
  548. {
  549. }
  550.