136372Ssklower /*********************************************************** 236372Ssklower Copyright IBM Corporation 1987 336372Ssklower 436372Ssklower All Rights Reserved 536372Ssklower 636372Ssklower Permission to use, copy, modify, and distribute this software and its 736372Ssklower documentation for any purpose and without fee is hereby granted, 836372Ssklower provided that the above copyright notice appear in all copies and that 936372Ssklower both that copyright notice and this permission notice appear in 1036372Ssklower supporting documentation, and that the name of IBM not be 1136372Ssklower used in advertising or publicity pertaining to distribution of the 1236372Ssklower software without specific, written prior permission. 1336372Ssklower 1436372Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536372Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636372Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736372Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836372Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936372Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036372Ssklower SOFTWARE. 2136372Ssklower 2236372Ssklower ******************************************************************/ 2336372Ssklower 2436372Ssklower /* 2536372Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636372Ssklower */ 2736768Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $ */ 2836768Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_output.c,v $ */ 2936372Ssklower 3036372Ssklower #ifndef lint 3136768Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $"; 3236372Ssklower #endif lint 3336372Ssklower 3436372Ssklower #ifdef ISO 35*37469Ssklower #include "types.h" 36*37469Ssklower #include "param.h" 37*37469Ssklower #include "mbuf.h" 38*37469Ssklower #include "domain.h" 39*37469Ssklower #include "protosw.h" 40*37469Ssklower #include "socket.h" 41*37469Ssklower #include "socketvar.h" 42*37469Ssklower #include "errno.h" 43*37469Ssklower #include "time.h" 4436372Ssklower 4536372Ssklower #include "../net/if.h" 4636372Ssklower #include "../net/route.h" 4736372Ssklower 48*37469Ssklower #include "iso.h" 49*37469Ssklower #include "iso_var.h" 50*37469Ssklower #include "iso_pcb.h" 51*37469Ssklower #include "clnp.h" 52*37469Ssklower #include "clnp_stat.h" 53*37469Ssklower #include "argo_debug.h" 5436372Ssklower 5536372Ssklower static struct clnp_fixed dt_template = { 5636372Ssklower ISO8473_CLNP, /* network identifier */ 5736372Ssklower 0, /* length */ 5836372Ssklower ISO8473_V1, /* version */ 5936372Ssklower CLNP_TTL, /* ttl */ 60*37469Ssklower CLNP_DT|CNF_SEG_OK|CNF_ERR_OK, /* type */ 6136372Ssklower 0, /* segment length */ 6236372Ssklower 0 /* checksum */ 6336372Ssklower }; 6436372Ssklower 6536372Ssklower static struct clnp_fixed raw_template = { 6636372Ssklower ISO8473_CLNP, /* network identifier */ 6736372Ssklower 0, /* length */ 6836372Ssklower ISO8473_V1, /* version */ 6936372Ssklower CLNP_TTL, /* ttl */ 70*37469Ssklower CLNP_RAW|CNF_SEG_OK|CNF_ERR_OK, /* type */ 7136372Ssklower 0, /* segment length */ 7236372Ssklower 0 /* checksum */ 7336372Ssklower }; 7436372Ssklower 7536372Ssklower static struct clnp_fixed echo_template = { 7636372Ssklower ISO8473_CLNP, /* network identifier */ 7736372Ssklower 0, /* length */ 7836372Ssklower ISO8473_V1, /* version */ 7936372Ssklower CLNP_TTL, /* ttl */ 80*37469Ssklower CLNP_EC|CNF_SEG_OK|CNF_ERR_OK, /* type */ 8136372Ssklower 0, /* segment length */ 8236372Ssklower 0 /* checksum */ 8336372Ssklower }; 8436372Ssklower 8536768Ssklower #ifdef DECBIT 8636768Ssklower u_char qos_option[] = {CLNPOVAL_QOS, 1, 8736768Ssklower CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY}; 8836768Ssklower #endif DECBIT 8936768Ssklower 9036372Ssklower int clnp_id = 0; /* id for segmented dgrams */ 9136372Ssklower 9236372Ssklower /* 9336372Ssklower * FUNCTION: clnp_output 9436372Ssklower * 9536372Ssklower * PURPOSE: output the data in the mbuf as a clnp datagram 9636372Ssklower * 9736372Ssklower * The data specified by m0 is sent as a clnp datagram. 9836372Ssklower * The mbuf chain m0 will be freed when this routine has 9936372Ssklower * returned. 10036372Ssklower * 10136372Ssklower * If options is non-null, it points to an mbuf which contains 10236372Ssklower * options to be sent with the datagram. The options must 10336372Ssklower * be formatted in the mbuf according to clnp rules. Options 10436372Ssklower * will not be freed. 10536372Ssklower * 10636372Ssklower * Datalen specifies the length of the data in m0. 10736372Ssklower * 10836372Ssklower * Src and dst are the addresses for the packet. 10936372Ssklower * 11036372Ssklower * If route is non-null, it is used as the route for 11136372Ssklower * the packet. 11236372Ssklower * 11336372Ssklower * By default, a DT is sent. However, if flags & CNLP_SEND_ER 11436372Ssklower * then an ER will be sent. If flags & CLNP_SEND_RAW, then 11536372Ssklower * the packet will be send as raw clnp. 11636372Ssklower * 11736372Ssklower * RETURNS: 0 success 11836372Ssklower * appropriate error code 11936372Ssklower * 12036372Ssklower * SIDE EFFECTS: none 12136372Ssklower * 12236372Ssklower * NOTES: 12336372Ssklower * Flags are interpretated as follows: 12436372Ssklower * CLNP_NO_SEG - do not allow this pkt to be segmented. 12536372Ssklower * CLNP_NO_ER - have pkt request ER suppression. 12636372Ssklower * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT 12736372Ssklower * CLNP_NO_CKSUM - don't compute clnp checksum 12836372Ssklower * CLNP_ECHO - send as ECHO packet 12936372Ssklower * 13036372Ssklower * When checking for a cached packet, clnp checks 13136372Ssklower * that the route taken is still up. It does not 13236372Ssklower * check that the route is still to the same destination. 13336372Ssklower * This means that any entity that alters an existing 13436372Ssklower * route for an isopcb (such as when a redirect arrives) 13536372Ssklower * must invalidate the clnp cache. It might be perferable 13636372Ssklower * to have clnp check that the route has the same dest, but 13736372Ssklower * by avoiding this check, we save a call to iso_addrmatch1. 13836372Ssklower */ 139*37469Ssklower clnp_output(m0, isop, flags) 14036372Ssklower struct mbuf *m0; /* data for the packet */ 14136372Ssklower struct isopcb *isop; /* iso pcb */ 14236372Ssklower int flags; /* flags */ 14336372Ssklower { 14436372Ssklower int error = 0; /* return value of function */ 145*37469Ssklower register struct mbuf *m = m0; /* mbuf for clnp header chain */ 146*37469Ssklower int datalen; /* number of bytes of data in m */ 14736372Ssklower register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */ 14836372Ssklower register caddr_t hoff; /* offset into header */ 14936372Ssklower int total_len; /* total length of packet */ 15036372Ssklower struct iso_addr *src; /* ptr to source address */ 15136372Ssklower struct iso_addr *dst; /* ptr to destination address */ 15236372Ssklower struct clnp_cache clc; /* storage for cache information */ 15336372Ssklower struct clnp_cache *clcp = NULL; /* ptr to clc */ 15436768Ssklower int hdrlen = 0; 15536372Ssklower 156*37469Ssklower src = &isop->isop_laddr->siso_addr; 157*37469Ssklower dst = &isop->isop_faddr->siso_addr; 15836372Ssklower 159*37469Ssklower if ((m->m_flags & M_PKTHDR) == 0) { 160*37469Ssklower m_freem(m); 161*37469Ssklower return EINVAL; 162*37469Ssklower } 163*37469Ssklower datalen = m->m_pkthdr.len; 16436372Ssklower IFDEBUG(D_OUTPUT) 16536372Ssklower printf("clnp_output: to %s", clnp_iso_addrp(dst)); 16636372Ssklower printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen); 16736372Ssklower printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n", 16836372Ssklower isop->isop_options, flags, isop->isop_clnpcache); 16936372Ssklower ENDDEBUG 17036372Ssklower 17136372Ssklower if (isop->isop_clnpcache != NULL) { 17236372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 17336372Ssklower } 17436372Ssklower 17536372Ssklower /* 17636372Ssklower * Check if cache is valid ... 17736372Ssklower */ 17836372Ssklower IFDEBUG(D_OUTPUT) 17936372Ssklower printf("clnp_output: ck cache: clcp %x\n", clcp); 18036372Ssklower if (clcp != NULL) { 18136372Ssklower printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst)); 18236372Ssklower printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options, 18336372Ssklower clcp->clc_options); 18436372Ssklower if (isop->isop_route.ro_rt) 18536372Ssklower printf("\tro_rt x%x, rt_flags x%x\n", 18636372Ssklower isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags); 18736372Ssklower printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags); 18836372Ssklower printf("\tclc_hdr x%x\n", clcp->clc_hdr); 18936372Ssklower } 19036372Ssklower ENDDEBUG 19136372Ssklower if ((clcp != NULL) && /* cache exists */ 19236372Ssklower (isop->isop_options == clcp->clc_options) && /* same options */ 19336372Ssklower (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */ 19436372Ssklower (isop->isop_route.ro_rt != NULL) && /* route exists */ 19536372Ssklower (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */ 19636372Ssklower (flags == clcp->clc_flags) && /* same flags */ 19736372Ssklower (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */ 19836372Ssklower /* 19936372Ssklower * The cache is valid 20036372Ssklower */ 20136372Ssklower 20236372Ssklower IFDEBUG(D_OUTPUT) 20336372Ssklower printf("clnp_output: using cache\n"); 20436372Ssklower ENDDEBUG 20536372Ssklower 206*37469Ssklower m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL); 20736372Ssklower if (m == NULL) { 20836372Ssklower /* 20936372Ssklower * No buffers left to copy cached packet header. Use 21036372Ssklower * the cached packet header this time, and 21136372Ssklower * mark the hdr as vacant 21236372Ssklower */ 21336372Ssklower m = clcp->clc_hdr; 21436372Ssklower clcp->clc_hdr = NULL; 21536372Ssklower } 21636372Ssklower m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */ 21736372Ssklower clnp = mtod(m, struct clnp_fixed *); 21836372Ssklower } else { 21936372Ssklower struct clnp_optidx *oidx = NULL; /* index to clnp options */ 22036372Ssklower 22136372Ssklower /* 22236372Ssklower * The cache is not valid. Allocate an mbuf (if necessary) 22336372Ssklower * to hold cached info. If one is not available, then 22436372Ssklower * don't bother with the cache 22536372Ssklower */ 22636372Ssklower INCSTAT(cns_cachemiss); 22736372Ssklower if (flags & CLNP_NOCACHE) { 22836372Ssklower clcp = &clc; 22936372Ssklower } else { 23036372Ssklower if (isop->isop_clnpcache == NULL) { 23136372Ssklower /* 23236372Ssklower * There is no clnpcache. Allocate an mbuf to hold one 23336372Ssklower */ 23436372Ssklower if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER)) 23536372Ssklower == NULL) { 23636372Ssklower /* 23736372Ssklower * No mbufs available. Pretend that we don't want 23836372Ssklower * caching this time. 23936372Ssklower */ 24036372Ssklower IFDEBUG(D_OUTPUT) 24136372Ssklower printf("clnp_output: no mbufs to allocate to cache\n"); 24236372Ssklower ENDDEBUG 24336372Ssklower flags |= CLNP_NOCACHE; 24436372Ssklower clcp = &clc; 24536372Ssklower } else { 24636372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 24736372Ssklower } 24836372Ssklower } else { 24936372Ssklower /* 25036372Ssklower * A clnpcache mbuf exists. If the clc_hdr is not null, 25136372Ssklower * we must free it, as a new one is about to be created. 25236372Ssklower */ 25336372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 25436372Ssklower if (clcp->clc_hdr != NULL) { 25536372Ssklower /* 25636372Ssklower * The clc_hdr is not null but a clnpcache mbuf exists. 25736372Ssklower * This means that there was a cache, but the existing 25836372Ssklower * copy of the hdr is no longer valid. Free it now 25936372Ssklower * before we lose the pointer to it. 26036372Ssklower */ 26136372Ssklower IFDEBUG(D_OUTPUT) 26236372Ssklower printf("clnp_output: freeing old clc_hdr 0x%x\n", 26336372Ssklower clcp->clc_hdr); 26436372Ssklower ENDDEBUG 26536372Ssklower m_free(clcp->clc_hdr); 26636372Ssklower IFDEBUG(D_OUTPUT) 26736372Ssklower printf("clnp_output: freed old clc_hdr (done)\n"); 26836372Ssklower ENDDEBUG 26936372Ssklower } 27036372Ssklower } 27136372Ssklower } 27236372Ssklower IFDEBUG(D_OUTPUT) 27336372Ssklower printf("clnp_output: NEW clcp x%x\n",clcp); 27436372Ssklower ENDDEBUG 27536372Ssklower bzero((caddr_t)clcp, sizeof(struct clnp_cache)); 27636372Ssklower 27736372Ssklower if (isop->isop_optindex) 27836372Ssklower oidx = mtod(isop->isop_optindex, struct clnp_optidx *); 27936372Ssklower 28036372Ssklower /* 28136372Ssklower * Don't allow packets with security, quality of service, 28236372Ssklower * priority, or error report options to be sent. 28336372Ssklower */ 28436372Ssklower if ((isop->isop_options) && (oidx)) { 28536372Ssklower if ((oidx->cni_securep) || 28636372Ssklower (oidx->cni_priorp) || 28736372Ssklower (oidx->cni_qos_formatp) || 28836372Ssklower (oidx->cni_er_reason != ER_INVALREAS)) { 28936372Ssklower IFDEBUG(D_OUTPUT) 29036372Ssklower printf("clnp_output: pkt dropped - option unsupported\n"); 29136372Ssklower ENDDEBUG 29236372Ssklower m_freem(m0); 29336372Ssklower return(EINVAL); 29436372Ssklower } 29536372Ssklower } 29636372Ssklower 29736372Ssklower /* 29836372Ssklower * Don't allow any invalid flags to be set 29936372Ssklower */ 30036372Ssklower if ((flags & (CLNP_VFLAGS)) != flags) { 30136372Ssklower IFDEBUG(D_OUTPUT) 30236372Ssklower printf("clnp_output: packet dropped - flags unsupported\n"); 30336372Ssklower ENDDEBUG 30436372Ssklower m_freem(m0); 30536372Ssklower return(EINVAL); 30636372Ssklower } 30736372Ssklower 30836372Ssklower /* 30936372Ssklower * Don't allow funny lengths on dst; src may be zero in which 31036372Ssklower * case we insert the source address based upon the interface 31136372Ssklower */ 31236372Ssklower if ((src->isoa_len > sizeof(struct iso_addr)) || 31336372Ssklower (dst->isoa_len == 0) || 31436372Ssklower (dst->isoa_len > sizeof(struct iso_addr))) { 31536372Ssklower m_freem(m0); 31636372Ssklower return(ENAMETOOLONG); 31736372Ssklower } 31836372Ssklower 31936372Ssklower /* 32036372Ssklower * Grab mbuf to contain header 32136372Ssklower */ 322*37469Ssklower MGETHDR(m, M_DONTWAIT, MT_HEADER); 32336372Ssklower if (m == 0) { 32436372Ssklower m_freem(m0); 32536372Ssklower return(ENOBUFS); 32636372Ssklower } 32736372Ssklower 32836372Ssklower m->m_next = m0; 32936372Ssklower clnp = mtod(m, struct clnp_fixed *); 33036372Ssklower clcp->clc_segoff = 0; 33136372Ssklower 33236372Ssklower /* 33336372Ssklower * Fill in all of fixed hdr except lengths and checksum 33436372Ssklower */ 33536372Ssklower if (flags & CLNP_SEND_RAW) { 33636372Ssklower *clnp = raw_template; 33736372Ssklower } else if (flags & CLNP_ECHO) { 33836372Ssklower *clnp = echo_template; 33936372Ssklower } else { 34036372Ssklower *clnp = dt_template; 34136372Ssklower } 34236372Ssklower if (flags & CLNP_NO_SEG) 343*37469Ssklower clnp->cnf_type &= ~CNF_SEG_OK; 34436372Ssklower if (flags & CLNP_NO_ER) 345*37469Ssklower clnp->cnf_type &= ~CNF_ERR_OK; 34636372Ssklower 34736372Ssklower /* 34836372Ssklower * Route packet; special case for source rt 34936372Ssklower */ 35036372Ssklower if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) { 35136372Ssklower IFDEBUG(D_OUTPUT) 35236372Ssklower printf("clnp_output: calling clnp_srcroute\n"); 35336372Ssklower ENDDEBUG 35436372Ssklower error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route, 355*37469Ssklower &clcp->clc_firsthop, &clcp->clc_ifa, dst); 35636372Ssklower } else { 35736372Ssklower IFDEBUG(D_OUTPUT) 35836372Ssklower ENDDEBUG 35936372Ssklower error = clnp_route(dst, &isop->isop_route, flags, 360*37469Ssklower &clcp->clc_firsthop, &clcp->clc_ifa); 36136372Ssklower } 362*37469Ssklower if (error || (clcp->clc_ifa == 0)) { 36336372Ssklower IFDEBUG(D_OUTPUT) 36436372Ssklower printf("clnp_output: route failed, errno %d\n", error); 36536372Ssklower printf("@clcp:\n"); 36636372Ssklower dump_buf(clcp, sizeof (struct clnp_cache)); 36736372Ssklower ENDDEBUG 36836372Ssklower goto bad; 36936372Ssklower } 37036372Ssklower 37136372Ssklower IFDEBUG(D_OUTPUT) 37236372Ssklower printf("clnp_output: packet routed to %s\n", 37336372Ssklower clnp_iso_addrp( 37436372Ssklower &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr)); 37536372Ssklower ENDDEBUG 37636372Ssklower 37736372Ssklower /* 37836372Ssklower * If src address is not yet specified, use address of 37936372Ssklower * interface. NOTE: this will now update the laddr field in 38036372Ssklower * the isopcb. Is this desirable? RAH? 38136372Ssklower */ 38236372Ssklower if (src->isoa_len == 0) { 383*37469Ssklower src = &(clcp->clc_ifa->ia_addr.siso_addr); 38436372Ssklower IFDEBUG(D_OUTPUT) 38536372Ssklower printf("clnp_output: new src %s\n", clnp_iso_addrp(src)); 38636372Ssklower ENDDEBUG 38736372Ssklower } 38836372Ssklower 38936372Ssklower /* 39036372Ssklower * Insert the source and destination address, 39136372Ssklower */ 39236372Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 393*37469Ssklower CLNP_INSERT_ADDR(hoff, *dst); 394*37469Ssklower CLNP_INSERT_ADDR(hoff, *src); 39536372Ssklower 39636372Ssklower /* 39736372Ssklower * Leave room for the segment part, if segmenting is selected 39836372Ssklower */ 399*37469Ssklower if (clnp->cnf_type & CNF_SEG_OK) { 40036372Ssklower clcp->clc_segoff = hoff - (caddr_t)clnp; 40136372Ssklower hoff += sizeof(struct clnp_segment); 40236372Ssklower } 40336372Ssklower 40436372Ssklower clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp); 40536768Ssklower hdrlen = clnp->cnf_hdr_len; 40636372Ssklower 40736768Ssklower #ifdef DECBIT 40836372Ssklower /* 40936768Ssklower * Add the globally unique QOS (with room for congestion experienced 41036768Ssklower * bit). I can safely assume that this option is not in the options 41136768Ssklower * mbuf below because I checked that the option was not specified 41236768Ssklower * previously 41336768Ssklower */ 41436768Ssklower if ((m->m_len + sizeof(qos_option)) < MLEN) { 41536768Ssklower bcopy((caddr_t)qos_option, hoff, sizeof(qos_option)); 41636768Ssklower clnp->cnf_hdr_len += sizeof(qos_option); 41736768Ssklower hdrlen += sizeof(qos_option); 41836768Ssklower m->m_len += sizeof(qos_option); 41936768Ssklower } 42036768Ssklower #endif DECBIT 42136768Ssklower 42236768Ssklower /* 42336372Ssklower * If an options mbuf is present, concatenate a copy to the hdr mbuf. 42436372Ssklower */ 42536372Ssklower if (isop->isop_options) { 426*37469Ssklower struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL); 42736372Ssklower if (opt_copy == NULL) { 42836372Ssklower error = ENOBUFS; 42936372Ssklower goto bad; 43036372Ssklower } 43136372Ssklower /* Link in place */ 43236372Ssklower opt_copy->m_next = m->m_next; 43336372Ssklower m->m_next = opt_copy; 43436372Ssklower 43536372Ssklower /* update size of header */ 43636372Ssklower clnp->cnf_hdr_len += opt_copy->m_len; 43736768Ssklower hdrlen += opt_copy->m_len; 43836372Ssklower } 43936372Ssklower 44036768Ssklower if (hdrlen > CLNP_HDR_MAX) { 44136768Ssklower error = EMSGSIZE; 44236768Ssklower goto bad; 44336768Ssklower } 44436768Ssklower 44536372Ssklower /* 44636372Ssklower * Now set up the cache entry in the pcb 44736372Ssklower */ 44836372Ssklower if ((flags & CLNP_NOCACHE) == 0) { 449*37469Ssklower if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) { 450*37469Ssklower clcp->clc_dst = *dst; 45136372Ssklower clcp->clc_flags = flags; 45236372Ssklower clcp->clc_options = isop->isop_options; 45336372Ssklower } 45436372Ssklower } 45536372Ssklower } 45636372Ssklower INCSTAT(cns_sent); 45736372Ssklower /* 45836372Ssklower * If small enough for interface, send directly 45936372Ssklower * Fill in segmentation part of hdr if using the full protocol 46036372Ssklower */ 461*37469Ssklower if ((total_len = clnp->cnf_hdr_len + datalen) 462*37469Ssklower <= SN_MTU(clcp->clc_ifa->ia_ifp)) { 463*37469Ssklower if (clnp->cnf_type & CNF_SEG_OK) { 46436372Ssklower struct clnp_segment seg_part; /* segment part of hdr */ 46536372Ssklower seg_part.cng_id = htons(clnp_id++); 46636372Ssklower seg_part.cng_off = htons(0); 46736372Ssklower seg_part.cng_tot_len = htons(total_len); 46836372Ssklower (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff, 46936372Ssklower sizeof(seg_part)); 47036372Ssklower } 47136372Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len); 472*37469Ssklower m->m_pkthdr.len = total_len; 47336372Ssklower /* 47436372Ssklower * Compute clnp checksum (on header only) 47536372Ssklower */ 47636372Ssklower if (flags & CLNP_NO_CKSUM) { 47736372Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 47836372Ssklower } else { 47936372Ssklower iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 48036372Ssklower } 48136372Ssklower 48236372Ssklower IFDEBUG(D_DUMPOUT) 48336372Ssklower struct mbuf *mdump = m; 48436372Ssklower printf("clnp_output: sending dg:\n"); 48536372Ssklower while (mdump != NULL) { 48636372Ssklower dump_buf(mtod(mdump, caddr_t), mdump->m_len); 48736372Ssklower mdump = mdump->m_next; 48836372Ssklower } 48936372Ssklower ENDDEBUG 49036372Ssklower 49136372Ssklower error = SN_OUTPUT(clcp, m); 49236372Ssklower goto done; 49336372Ssklower } else { 49436372Ssklower /* 49536372Ssklower * Too large for interface; fragment if possible. 49636372Ssklower */ 497*37469Ssklower error = clnp_fragment(clcp->clc_ifa->ia_ifp, m, clcp->clc_firsthop, total_len, 49836372Ssklower clcp->clc_segoff, flags); 49936372Ssklower goto done; 50036372Ssklower } 50136372Ssklower bad: 50236372Ssklower m_freem(m); 50336372Ssklower 50436372Ssklower done: 50536372Ssklower return(error); 50636372Ssklower } 50736372Ssklower 50836372Ssklower int clnp_ctloutput() 50936372Ssklower { 51036372Ssklower } 51136372Ssklower 51236372Ssklower #endif ISO 513