1*49267Sbostic /*- 2*49267Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*49267Sbostic * All rights reserved. 4*49267Sbostic * 5*49267Sbostic * %sccs.include.redist.c% 6*49267Sbostic * 7*49267Sbostic * @(#)clnp_output.c 7.10 (Berkeley) 05/06/91 8*49267Sbostic */ 9*49267Sbostic 1036372Ssklower /*********************************************************** 1136372Ssklower Copyright IBM Corporation 1987 1236372Ssklower 1336372Ssklower All Rights Reserved 1436372Ssklower 1536372Ssklower Permission to use, copy, modify, and distribute this software and its 1636372Ssklower documentation for any purpose and without fee is hereby granted, 1736372Ssklower provided that the above copyright notice appear in all copies and that 1836372Ssklower both that copyright notice and this permission notice appear in 1936372Ssklower supporting documentation, and that the name of IBM not be 2036372Ssklower used in advertising or publicity pertaining to distribution of the 2136372Ssklower software without specific, written prior permission. 2236372Ssklower 2336372Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436372Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536372Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636372Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736372Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836372Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936372Ssklower SOFTWARE. 3036372Ssklower 3136372Ssklower ******************************************************************/ 3236372Ssklower 3336372Ssklower /* 3436372Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536372Ssklower */ 3636768Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $ */ 3736768Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_output.c,v $ */ 3836372Ssklower 3937469Ssklower #include "param.h" 4037469Ssklower #include "mbuf.h" 4137469Ssklower #include "domain.h" 4237469Ssklower #include "protosw.h" 4337469Ssklower #include "socket.h" 4437469Ssklower #include "socketvar.h" 4537469Ssklower #include "errno.h" 4637469Ssklower #include "time.h" 4736372Ssklower 4836372Ssklower #include "../net/if.h" 4936372Ssklower #include "../net/route.h" 5036372Ssklower 5137469Ssklower #include "iso.h" 5237469Ssklower #include "iso_var.h" 5337469Ssklower #include "iso_pcb.h" 5437469Ssklower #include "clnp.h" 5537469Ssklower #include "clnp_stat.h" 5637469Ssklower #include "argo_debug.h" 5736372Ssklower 5836372Ssklower static struct clnp_fixed dt_template = { 5936372Ssklower ISO8473_CLNP, /* network identifier */ 6036372Ssklower 0, /* length */ 6136372Ssklower ISO8473_V1, /* version */ 6236372Ssklower CLNP_TTL, /* ttl */ 6337469Ssklower CLNP_DT|CNF_SEG_OK|CNF_ERR_OK, /* type */ 6436372Ssklower 0, /* segment length */ 6536372Ssklower 0 /* checksum */ 6636372Ssklower }; 6736372Ssklower 6836372Ssklower static struct clnp_fixed raw_template = { 6936372Ssklower ISO8473_CLNP, /* network identifier */ 7036372Ssklower 0, /* length */ 7136372Ssklower ISO8473_V1, /* version */ 7236372Ssklower CLNP_TTL, /* ttl */ 7337469Ssklower CLNP_RAW|CNF_SEG_OK|CNF_ERR_OK, /* type */ 7436372Ssklower 0, /* segment length */ 7536372Ssklower 0 /* checksum */ 7636372Ssklower }; 7736372Ssklower 7836372Ssklower static struct clnp_fixed echo_template = { 7936372Ssklower ISO8473_CLNP, /* network identifier */ 8036372Ssklower 0, /* length */ 8136372Ssklower ISO8473_V1, /* version */ 8236372Ssklower CLNP_TTL, /* ttl */ 8337469Ssklower CLNP_EC|CNF_SEG_OK|CNF_ERR_OK, /* type */ 8436372Ssklower 0, /* segment length */ 8536372Ssklower 0 /* checksum */ 8636372Ssklower }; 8736372Ssklower 8836768Ssklower #ifdef DECBIT 8936768Ssklower u_char qos_option[] = {CLNPOVAL_QOS, 1, 9036768Ssklower CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY}; 9136768Ssklower #endif DECBIT 9236768Ssklower 9336372Ssklower int clnp_id = 0; /* id for segmented dgrams */ 9436372Ssklower 9536372Ssklower /* 9636372Ssklower * FUNCTION: clnp_output 9736372Ssklower * 9836372Ssklower * PURPOSE: output the data in the mbuf as a clnp datagram 9936372Ssklower * 10036372Ssklower * The data specified by m0 is sent as a clnp datagram. 10136372Ssklower * The mbuf chain m0 will be freed when this routine has 10236372Ssklower * returned. 10336372Ssklower * 10436372Ssklower * If options is non-null, it points to an mbuf which contains 10536372Ssklower * options to be sent with the datagram. The options must 10636372Ssklower * be formatted in the mbuf according to clnp rules. Options 10736372Ssklower * will not be freed. 10836372Ssklower * 10936372Ssklower * Datalen specifies the length of the data in m0. 11036372Ssklower * 11136372Ssklower * Src and dst are the addresses for the packet. 11236372Ssklower * 11336372Ssklower * If route is non-null, it is used as the route for 11436372Ssklower * the packet. 11536372Ssklower * 11636372Ssklower * By default, a DT is sent. However, if flags & CNLP_SEND_ER 11736372Ssklower * then an ER will be sent. If flags & CLNP_SEND_RAW, then 11836372Ssklower * the packet will be send as raw clnp. 11936372Ssklower * 12036372Ssklower * RETURNS: 0 success 12136372Ssklower * appropriate error code 12236372Ssklower * 12336372Ssklower * SIDE EFFECTS: none 12436372Ssklower * 12536372Ssklower * NOTES: 12636372Ssklower * Flags are interpretated as follows: 12736372Ssklower * CLNP_NO_SEG - do not allow this pkt to be segmented. 12836372Ssklower * CLNP_NO_ER - have pkt request ER suppression. 12936372Ssklower * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT 13036372Ssklower * CLNP_NO_CKSUM - don't compute clnp checksum 13136372Ssklower * CLNP_ECHO - send as ECHO packet 13236372Ssklower * 13336372Ssklower * When checking for a cached packet, clnp checks 13436372Ssklower * that the route taken is still up. It does not 13536372Ssklower * check that the route is still to the same destination. 13636372Ssklower * This means that any entity that alters an existing 13736372Ssklower * route for an isopcb (such as when a redirect arrives) 13836372Ssklower * must invalidate the clnp cache. It might be perferable 13936372Ssklower * to have clnp check that the route has the same dest, but 14036372Ssklower * by avoiding this check, we save a call to iso_addrmatch1. 14136372Ssklower */ 14238841Ssklower clnp_output(m0, isop, datalen, flags) 14336372Ssklower struct mbuf *m0; /* data for the packet */ 14436372Ssklower struct isopcb *isop; /* iso pcb */ 14538841Ssklower int datalen; /* number of bytes of data in m0 */ 14636372Ssklower int flags; /* flags */ 14736372Ssklower { 14836372Ssklower int error = 0; /* return value of function */ 14937469Ssklower register struct mbuf *m = m0; /* mbuf for clnp header chain */ 15036372Ssklower register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */ 15136372Ssklower register caddr_t hoff; /* offset into header */ 15236372Ssklower int total_len; /* total length of packet */ 15336372Ssklower struct iso_addr *src; /* ptr to source address */ 15436372Ssklower struct iso_addr *dst; /* ptr to destination address */ 15536372Ssklower struct clnp_cache clc; /* storage for cache information */ 15636372Ssklower struct clnp_cache *clcp = NULL; /* ptr to clc */ 15736768Ssklower int hdrlen = 0; 15836372Ssklower 15937469Ssklower dst = &isop->isop_faddr->siso_addr; 16041338Ssklower if (isop->isop_laddr == 0) { 16141338Ssklower struct iso_ifaddr *ia = 0; 16241338Ssklower clnp_route(dst, &isop->isop_route, flags, 0, &ia); 16341338Ssklower if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO) 16441338Ssklower return (ENETUNREACH); 16541338Ssklower src = &ia->ia_addr.siso_addr; 16641338Ssklower } else 16741338Ssklower src = &isop->isop_laddr->siso_addr; 16836372Ssklower 16936372Ssklower IFDEBUG(D_OUTPUT) 17036372Ssklower printf("clnp_output: to %s", clnp_iso_addrp(dst)); 17136372Ssklower printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen); 17236372Ssklower printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n", 17336372Ssklower isop->isop_options, flags, isop->isop_clnpcache); 17436372Ssklower ENDDEBUG 17536372Ssklower 17636372Ssklower if (isop->isop_clnpcache != NULL) { 17736372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 17836372Ssklower } 17936372Ssklower 18036372Ssklower /* 18136372Ssklower * Check if cache is valid ... 18236372Ssklower */ 18336372Ssklower IFDEBUG(D_OUTPUT) 18436372Ssklower printf("clnp_output: ck cache: clcp %x\n", clcp); 18536372Ssklower if (clcp != NULL) { 18636372Ssklower printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst)); 18736372Ssklower printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options, 18836372Ssklower clcp->clc_options); 18936372Ssklower if (isop->isop_route.ro_rt) 19036372Ssklower printf("\tro_rt x%x, rt_flags x%x\n", 19136372Ssklower isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags); 19236372Ssklower printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags); 19336372Ssklower printf("\tclc_hdr x%x\n", clcp->clc_hdr); 19436372Ssklower } 19536372Ssklower ENDDEBUG 19636372Ssklower if ((clcp != NULL) && /* cache exists */ 19736372Ssklower (isop->isop_options == clcp->clc_options) && /* same options */ 19836372Ssklower (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */ 19936372Ssklower (isop->isop_route.ro_rt != NULL) && /* route exists */ 20040777Ssklower (isop->isop_route.ro_rt == clcp->clc_rt) && /* and is cached */ 20136372Ssklower (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */ 20236372Ssklower (flags == clcp->clc_flags) && /* same flags */ 20336372Ssklower (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */ 20436372Ssklower /* 20536372Ssklower * The cache is valid 20636372Ssklower */ 20736372Ssklower 20836372Ssklower IFDEBUG(D_OUTPUT) 20936372Ssklower printf("clnp_output: using cache\n"); 21036372Ssklower ENDDEBUG 21136372Ssklower 21237469Ssklower m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL); 21336372Ssklower if (m == NULL) { 21436372Ssklower /* 21536372Ssklower * No buffers left to copy cached packet header. Use 21636372Ssklower * the cached packet header this time, and 21736372Ssklower * mark the hdr as vacant 21836372Ssklower */ 21936372Ssklower m = clcp->clc_hdr; 22036372Ssklower clcp->clc_hdr = NULL; 22136372Ssklower } 22236372Ssklower m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */ 22336372Ssklower clnp = mtod(m, struct clnp_fixed *); 22436372Ssklower } else { 22536372Ssklower struct clnp_optidx *oidx = NULL; /* index to clnp options */ 22636372Ssklower 22736372Ssklower /* 22836372Ssklower * The cache is not valid. Allocate an mbuf (if necessary) 22936372Ssklower * to hold cached info. If one is not available, then 23036372Ssklower * don't bother with the cache 23136372Ssklower */ 23236372Ssklower INCSTAT(cns_cachemiss); 23336372Ssklower if (flags & CLNP_NOCACHE) { 23436372Ssklower clcp = &clc; 23536372Ssklower } else { 23636372Ssklower if (isop->isop_clnpcache == NULL) { 23736372Ssklower /* 23836372Ssklower * There is no clnpcache. Allocate an mbuf to hold one 23936372Ssklower */ 24036372Ssklower if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER)) 24136372Ssklower == NULL) { 24236372Ssklower /* 24336372Ssklower * No mbufs available. Pretend that we don't want 24436372Ssklower * caching this time. 24536372Ssklower */ 24636372Ssklower IFDEBUG(D_OUTPUT) 24736372Ssklower printf("clnp_output: no mbufs to allocate to cache\n"); 24836372Ssklower ENDDEBUG 24936372Ssklower flags |= CLNP_NOCACHE; 25036372Ssklower clcp = &clc; 25136372Ssklower } else { 25236372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 25336372Ssklower } 25436372Ssklower } else { 25536372Ssklower /* 25636372Ssklower * A clnpcache mbuf exists. If the clc_hdr is not null, 25736372Ssklower * we must free it, as a new one is about to be created. 25836372Ssklower */ 25936372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 26036372Ssklower if (clcp->clc_hdr != NULL) { 26136372Ssklower /* 26236372Ssklower * The clc_hdr is not null but a clnpcache mbuf exists. 26336372Ssklower * This means that there was a cache, but the existing 26436372Ssklower * copy of the hdr is no longer valid. Free it now 26536372Ssklower * before we lose the pointer to it. 26636372Ssklower */ 26736372Ssklower IFDEBUG(D_OUTPUT) 26836372Ssklower printf("clnp_output: freeing old clc_hdr 0x%x\n", 26936372Ssklower clcp->clc_hdr); 27036372Ssklower ENDDEBUG 27136372Ssklower m_free(clcp->clc_hdr); 27236372Ssklower IFDEBUG(D_OUTPUT) 27336372Ssklower printf("clnp_output: freed old clc_hdr (done)\n"); 27436372Ssklower ENDDEBUG 27536372Ssklower } 27636372Ssklower } 27736372Ssklower } 27836372Ssklower IFDEBUG(D_OUTPUT) 27936372Ssklower printf("clnp_output: NEW clcp x%x\n",clcp); 28036372Ssklower ENDDEBUG 28136372Ssklower bzero((caddr_t)clcp, sizeof(struct clnp_cache)); 28236372Ssklower 28336372Ssklower if (isop->isop_optindex) 28436372Ssklower oidx = mtod(isop->isop_optindex, struct clnp_optidx *); 28536372Ssklower 28636372Ssklower /* 28736372Ssklower * Don't allow packets with security, quality of service, 28836372Ssklower * priority, or error report options to be sent. 28936372Ssklower */ 29036372Ssklower if ((isop->isop_options) && (oidx)) { 29136372Ssklower if ((oidx->cni_securep) || 29236372Ssklower (oidx->cni_priorp) || 29336372Ssklower (oidx->cni_qos_formatp) || 29436372Ssklower (oidx->cni_er_reason != ER_INVALREAS)) { 29536372Ssklower IFDEBUG(D_OUTPUT) 29636372Ssklower printf("clnp_output: pkt dropped - option unsupported\n"); 29736372Ssklower ENDDEBUG 29836372Ssklower m_freem(m0); 29936372Ssklower return(EINVAL); 30036372Ssklower } 30136372Ssklower } 30236372Ssklower 30336372Ssklower /* 30436372Ssklower * Don't allow any invalid flags to be set 30536372Ssklower */ 30636372Ssklower if ((flags & (CLNP_VFLAGS)) != flags) { 30736372Ssklower IFDEBUG(D_OUTPUT) 30836372Ssklower printf("clnp_output: packet dropped - flags unsupported\n"); 30936372Ssklower ENDDEBUG 31039195Ssklower INCSTAT(cns_odropped); 31136372Ssklower m_freem(m0); 31236372Ssklower return(EINVAL); 31336372Ssklower } 31436372Ssklower 31536372Ssklower /* 31636372Ssklower * Don't allow funny lengths on dst; src may be zero in which 31736372Ssklower * case we insert the source address based upon the interface 31836372Ssklower */ 31936372Ssklower if ((src->isoa_len > sizeof(struct iso_addr)) || 32036372Ssklower (dst->isoa_len == 0) || 32136372Ssklower (dst->isoa_len > sizeof(struct iso_addr))) { 32236372Ssklower m_freem(m0); 32339195Ssklower INCSTAT(cns_odropped); 32436372Ssklower return(ENAMETOOLONG); 32536372Ssklower } 32636372Ssklower 32736372Ssklower /* 32836372Ssklower * Grab mbuf to contain header 32936372Ssklower */ 33037469Ssklower MGETHDR(m, M_DONTWAIT, MT_HEADER); 33136372Ssklower if (m == 0) { 33236372Ssklower m_freem(m0); 33339195Ssklower INCSTAT(cns_odropped); 33436372Ssklower return(ENOBUFS); 33536372Ssklower } 33639195Ssklower INCSTAT(cns_sent); 33736372Ssklower m->m_next = m0; 33836372Ssklower clnp = mtod(m, struct clnp_fixed *); 33936372Ssklower clcp->clc_segoff = 0; 34036372Ssklower 34136372Ssklower /* 34236372Ssklower * Fill in all of fixed hdr except lengths and checksum 34336372Ssklower */ 34436372Ssklower if (flags & CLNP_SEND_RAW) { 34536372Ssklower *clnp = raw_template; 34636372Ssklower } else if (flags & CLNP_ECHO) { 34736372Ssklower *clnp = echo_template; 34836372Ssklower } else { 34936372Ssklower *clnp = dt_template; 35036372Ssklower } 35136372Ssklower if (flags & CLNP_NO_SEG) 35237469Ssklower clnp->cnf_type &= ~CNF_SEG_OK; 35336372Ssklower if (flags & CLNP_NO_ER) 35437469Ssklower clnp->cnf_type &= ~CNF_ERR_OK; 35536372Ssklower 35636372Ssklower /* 35736372Ssklower * Route packet; special case for source rt 35836372Ssklower */ 35936372Ssklower if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) { 36036372Ssklower IFDEBUG(D_OUTPUT) 36136372Ssklower printf("clnp_output: calling clnp_srcroute\n"); 36236372Ssklower ENDDEBUG 36336372Ssklower error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route, 36437469Ssklower &clcp->clc_firsthop, &clcp->clc_ifa, dst); 36536372Ssklower } else { 36636372Ssklower IFDEBUG(D_OUTPUT) 36736372Ssklower ENDDEBUG 36836372Ssklower error = clnp_route(dst, &isop->isop_route, flags, 36937469Ssklower &clcp->clc_firsthop, &clcp->clc_ifa); 37036372Ssklower } 37137469Ssklower if (error || (clcp->clc_ifa == 0)) { 37236372Ssklower IFDEBUG(D_OUTPUT) 37336372Ssklower printf("clnp_output: route failed, errno %d\n", error); 37436372Ssklower printf("@clcp:\n"); 37536372Ssklower dump_buf(clcp, sizeof (struct clnp_cache)); 37636372Ssklower ENDDEBUG 37736372Ssklower goto bad; 37836372Ssklower } 37940777Ssklower clcp->clc_rt = isop->isop_route.ro_rt; /* XXX */ 38048742Ssklower clcp->clc_ifp = clcp->clc_ifa->ia_ifp; /* XXX */ 38136372Ssklower 38236372Ssklower IFDEBUG(D_OUTPUT) 38336372Ssklower printf("clnp_output: packet routed to %s\n", 38436372Ssklower clnp_iso_addrp( 38536372Ssklower &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr)); 38636372Ssklower ENDDEBUG 38736372Ssklower 38836372Ssklower /* 38936372Ssklower * If src address is not yet specified, use address of 39036372Ssklower * interface. NOTE: this will now update the laddr field in 39136372Ssklower * the isopcb. Is this desirable? RAH? 39236372Ssklower */ 39336372Ssklower if (src->isoa_len == 0) { 39437469Ssklower src = &(clcp->clc_ifa->ia_addr.siso_addr); 39536372Ssklower IFDEBUG(D_OUTPUT) 39636372Ssklower printf("clnp_output: new src %s\n", clnp_iso_addrp(src)); 39736372Ssklower ENDDEBUG 39836372Ssklower } 39936372Ssklower 40036372Ssklower /* 40136372Ssklower * Insert the source and destination address, 40236372Ssklower */ 40336372Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 40437469Ssklower CLNP_INSERT_ADDR(hoff, *dst); 40537469Ssklower CLNP_INSERT_ADDR(hoff, *src); 40636372Ssklower 40736372Ssklower /* 40836372Ssklower * Leave room for the segment part, if segmenting is selected 40936372Ssklower */ 41037469Ssklower if (clnp->cnf_type & CNF_SEG_OK) { 41136372Ssklower clcp->clc_segoff = hoff - (caddr_t)clnp; 41236372Ssklower hoff += sizeof(struct clnp_segment); 41336372Ssklower } 41436372Ssklower 41536372Ssklower clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp); 41636768Ssklower hdrlen = clnp->cnf_hdr_len; 41736372Ssklower 41836768Ssklower #ifdef DECBIT 41936372Ssklower /* 42036768Ssklower * Add the globally unique QOS (with room for congestion experienced 42136768Ssklower * bit). I can safely assume that this option is not in the options 42236768Ssklower * mbuf below because I checked that the option was not specified 42336768Ssklower * previously 42436768Ssklower */ 42536768Ssklower if ((m->m_len + sizeof(qos_option)) < MLEN) { 42636768Ssklower bcopy((caddr_t)qos_option, hoff, sizeof(qos_option)); 42736768Ssklower clnp->cnf_hdr_len += sizeof(qos_option); 42836768Ssklower hdrlen += sizeof(qos_option); 42936768Ssklower m->m_len += sizeof(qos_option); 43036768Ssklower } 43136768Ssklower #endif DECBIT 43236768Ssklower 43336768Ssklower /* 43436372Ssklower * If an options mbuf is present, concatenate a copy to the hdr mbuf. 43536372Ssklower */ 43636372Ssklower if (isop->isop_options) { 43737469Ssklower struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL); 43836372Ssklower if (opt_copy == NULL) { 43936372Ssklower error = ENOBUFS; 44036372Ssklower goto bad; 44136372Ssklower } 44236372Ssklower /* Link in place */ 44336372Ssklower opt_copy->m_next = m->m_next; 44436372Ssklower m->m_next = opt_copy; 44536372Ssklower 44636372Ssklower /* update size of header */ 44736372Ssklower clnp->cnf_hdr_len += opt_copy->m_len; 44836768Ssklower hdrlen += opt_copy->m_len; 44936372Ssklower } 45036372Ssklower 45136768Ssklower if (hdrlen > CLNP_HDR_MAX) { 45236768Ssklower error = EMSGSIZE; 45336768Ssklower goto bad; 45436768Ssklower } 45536768Ssklower 45636372Ssklower /* 45736372Ssklower * Now set up the cache entry in the pcb 45836372Ssklower */ 45936372Ssklower if ((flags & CLNP_NOCACHE) == 0) { 46037469Ssklower if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) { 46137469Ssklower clcp->clc_dst = *dst; 46236372Ssklower clcp->clc_flags = flags; 46336372Ssklower clcp->clc_options = isop->isop_options; 46436372Ssklower } 46536372Ssklower } 46636372Ssklower } 46736372Ssklower /* 46836372Ssklower * If small enough for interface, send directly 46936372Ssklower * Fill in segmentation part of hdr if using the full protocol 47036372Ssklower */ 47142865Ssklower total_len = clnp->cnf_hdr_len + datalen; 47242865Ssklower if (clnp->cnf_type & CNF_SEG_OK) { 47342865Ssklower struct clnp_segment seg_part; /* segment part of hdr */ 47442865Ssklower seg_part.cng_id = htons(clnp_id++); 47542865Ssklower seg_part.cng_off = htons(0); 47642865Ssklower seg_part.cng_tot_len = htons(total_len); 47742865Ssklower (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff, 47842865Ssklower sizeof(seg_part)); 47942865Ssklower } 48048742Ssklower if (total_len <= SN_MTU(clcp->clc_ifp, clcp->clc_rt)) { 48136372Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len); 48237469Ssklower m->m_pkthdr.len = total_len; 48336372Ssklower /* 48436372Ssklower * Compute clnp checksum (on header only) 48536372Ssklower */ 48636372Ssklower if (flags & CLNP_NO_CKSUM) { 48736372Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 48836372Ssklower } else { 48936372Ssklower iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 49036372Ssklower } 49136372Ssklower 49236372Ssklower IFDEBUG(D_DUMPOUT) 49336372Ssklower struct mbuf *mdump = m; 49436372Ssklower printf("clnp_output: sending dg:\n"); 49536372Ssklower while (mdump != NULL) { 49636372Ssklower dump_buf(mtod(mdump, caddr_t), mdump->m_len); 49736372Ssklower mdump = mdump->m_next; 49836372Ssklower } 49936372Ssklower ENDDEBUG 50036372Ssklower 50136372Ssklower error = SN_OUTPUT(clcp, m); 50236372Ssklower goto done; 50336372Ssklower } else { 50436372Ssklower /* 50536372Ssklower * Too large for interface; fragment if possible. 50636372Ssklower */ 50748742Ssklower error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop, 50840777Ssklower total_len, clcp->clc_segoff, flags, clcp->clc_rt); 50936372Ssklower goto done; 51036372Ssklower } 51136372Ssklower bad: 51236372Ssklower m_freem(m); 51336372Ssklower done: 51439195Ssklower if (error) { 51539195Ssklower clnp_stat.cns_sent--; 51639195Ssklower clnp_stat.cns_odropped++; 51739195Ssklower } 51839195Ssklower return (error); 51936372Ssklower } 52036372Ssklower 52136372Ssklower int clnp_ctloutput() 52236372Ssklower { 52336372Ssklower } 524