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 */ 27*36768Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $ */ 28*36768Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_output.c,v $ */ 2936372Ssklower 3036372Ssklower #ifndef lint 31*36768Ssklower 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 3536372Ssklower #include "../h/types.h" 3636372Ssklower #include "../h/param.h" 3736372Ssklower #include "../h/mbuf.h" 3836372Ssklower #include "../h/domain.h" 3936372Ssklower #include "../h/protosw.h" 4036372Ssklower #include "../h/socket.h" 4136372Ssklower #include "../h/socketvar.h" 4236372Ssklower #include "../h/errno.h" 4336372Ssklower #include "../h/time.h" 4436372Ssklower 4536372Ssklower #include "../net/if.h" 4636372Ssklower #include "../net/route.h" 4736372Ssklower 4836372Ssklower #include "../netiso/iso.h" 4936372Ssklower #include "../netiso/iso_pcb.h" 5036372Ssklower #include "../netiso/clnp.h" 5136372Ssklower #include "../netiso/clnp_stat.h" 5236372Ssklower #include "../netiso/argo_debug.h" 5336372Ssklower 5436372Ssklower static struct clnp_fixed dt_template = { 5536372Ssklower ISO8473_CLNP, /* network identifier */ 5636372Ssklower 0, /* length */ 5736372Ssklower ISO8473_V1, /* version */ 5836372Ssklower CLNP_TTL, /* ttl */ 5936372Ssklower #if BYTE_ORDER == LITTLE_ENDIAN 6036372Ssklower CLNP_DT, /* type */ 6136372Ssklower 1, /* error report */ 6236372Ssklower 0, /* more segments */ 6336372Ssklower 1, /* segmentation permitted */ 6436372Ssklower #endif 6536372Ssklower #if BYTE_ORDER == BIG_ENDIAN 6636372Ssklower 1, /* segmentation permitted */ 6736372Ssklower 0, /* more segments */ 6836372Ssklower 1, /* error report */ 6936372Ssklower CLNP_DT, /* type */ 7036372Ssklower #endif 7136372Ssklower 0, /* segment length */ 7236372Ssklower 0 /* checksum */ 7336372Ssklower }; 7436372Ssklower 7536372Ssklower static struct clnp_fixed raw_template = { 7636372Ssklower ISO8473_CLNP, /* network identifier */ 7736372Ssklower 0, /* length */ 7836372Ssklower ISO8473_V1, /* version */ 7936372Ssklower CLNP_TTL, /* ttl */ 8036372Ssklower #if BYTE_ORDER == LITTLE_ENDIAN 8136372Ssklower CLNP_RAW, /* type */ 8236372Ssklower 1, /* error report */ 8336372Ssklower 0, /* more segments */ 8436372Ssklower 1, /* segmentation permitted */ 8536372Ssklower #endif 8636372Ssklower #if BYTE_ORDER == BIG_ENDIAN 8736372Ssklower 1, /* segmentation permitted */ 8836372Ssklower 0, /* more segments */ 8936372Ssklower 1, /* error report */ 9036372Ssklower CLNP_RAW, /* type */ 9136372Ssklower #endif 9236372Ssklower 0, /* segment length */ 9336372Ssklower 0 /* checksum */ 9436372Ssklower }; 9536372Ssklower 9636372Ssklower static struct clnp_fixed echo_template = { 9736372Ssklower ISO8473_CLNP, /* network identifier */ 9836372Ssklower 0, /* length */ 9936372Ssklower ISO8473_V1, /* version */ 10036372Ssklower CLNP_TTL, /* ttl */ 10136372Ssklower #if BYTE_ORDER == LITTLE_ENDIAN 10236372Ssklower CLNP_EC, /* type */ 10336372Ssklower 1, /* error report */ 10436372Ssklower 0, /* more segments */ 10536372Ssklower 1, /* segmentation permitted */ 10636372Ssklower #endif 10736372Ssklower #if BYTE_ORDER == BIG_ENDIAN 10836372Ssklower 1, /* segmentation permitted */ 10936372Ssklower 0, /* more segments */ 11036372Ssklower 1, /* error report */ 11136372Ssklower CLNP_EC, /* type */ 11236372Ssklower #endif 11336372Ssklower 0, /* segment length */ 11436372Ssklower 0 /* checksum */ 11536372Ssklower }; 11636372Ssklower 117*36768Ssklower #ifdef DECBIT 118*36768Ssklower u_char qos_option[] = {CLNPOVAL_QOS, 1, 119*36768Ssklower CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY}; 120*36768Ssklower #endif DECBIT 121*36768Ssklower 12236372Ssklower int clnp_id = 0; /* id for segmented dgrams */ 12336372Ssklower 12436372Ssklower /* 12536372Ssklower * FUNCTION: clnp_output 12636372Ssklower * 12736372Ssklower * PURPOSE: output the data in the mbuf as a clnp datagram 12836372Ssklower * 12936372Ssklower * The data specified by m0 is sent as a clnp datagram. 13036372Ssklower * The mbuf chain m0 will be freed when this routine has 13136372Ssklower * returned. 13236372Ssklower * 13336372Ssklower * If options is non-null, it points to an mbuf which contains 13436372Ssklower * options to be sent with the datagram. The options must 13536372Ssklower * be formatted in the mbuf according to clnp rules. Options 13636372Ssklower * will not be freed. 13736372Ssklower * 13836372Ssklower * Datalen specifies the length of the data in m0. 13936372Ssklower * 14036372Ssklower * Src and dst are the addresses for the packet. 14136372Ssklower * 14236372Ssklower * If route is non-null, it is used as the route for 14336372Ssklower * the packet. 14436372Ssklower * 14536372Ssklower * By default, a DT is sent. However, if flags & CNLP_SEND_ER 14636372Ssklower * then an ER will be sent. If flags & CLNP_SEND_RAW, then 14736372Ssklower * the packet will be send as raw clnp. 14836372Ssklower * 14936372Ssklower * RETURNS: 0 success 15036372Ssklower * appropriate error code 15136372Ssklower * 15236372Ssklower * SIDE EFFECTS: none 15336372Ssklower * 15436372Ssklower * NOTES: 15536372Ssklower * Flags are interpretated as follows: 15636372Ssklower * CLNP_NO_SEG - do not allow this pkt to be segmented. 15736372Ssklower * CLNP_NO_ER - have pkt request ER suppression. 15836372Ssklower * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT 15936372Ssklower * CLNP_NO_CKSUM - don't compute clnp checksum 16036372Ssklower * CLNP_ECHO - send as ECHO packet 16136372Ssklower * 16236372Ssklower * When checking for a cached packet, clnp checks 16336372Ssklower * that the route taken is still up. It does not 16436372Ssklower * check that the route is still to the same destination. 16536372Ssklower * This means that any entity that alters an existing 16636372Ssklower * route for an isopcb (such as when a redirect arrives) 16736372Ssklower * must invalidate the clnp cache. It might be perferable 16836372Ssklower * to have clnp check that the route has the same dest, but 16936372Ssklower * by avoiding this check, we save a call to iso_addrmatch1. 17036372Ssklower */ 17136372Ssklower clnp_output(m0, isop, datalen, flags) 17236372Ssklower struct mbuf *m0; /* data for the packet */ 17336372Ssklower struct isopcb *isop; /* iso pcb */ 17436372Ssklower int datalen; /* number of bytes of data in m */ 17536372Ssklower int flags; /* flags */ 17636372Ssklower { 17736372Ssklower int error = 0; /* return value of function */ 17836372Ssklower register struct mbuf *m; /* mbuf for clnp header chain */ 17936372Ssklower register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */ 18036372Ssklower register caddr_t hoff; /* offset into header */ 18136372Ssklower int total_len; /* total length of packet */ 18236372Ssklower struct iso_addr *src; /* ptr to source address */ 18336372Ssklower struct iso_addr *dst; /* ptr to destination address */ 18436372Ssklower struct clnp_cache clc; /* storage for cache information */ 18536372Ssklower struct clnp_cache *clcp = NULL; /* ptr to clc */ 186*36768Ssklower int hdrlen = 0; 18736372Ssklower 18836372Ssklower src = &isop->isop_laddr.siso_addr; 18936372Ssklower dst = &isop->isop_faddr.siso_addr; 19036372Ssklower 19136372Ssklower IFDEBUG(D_OUTPUT) 19236372Ssklower printf("clnp_output: to %s", clnp_iso_addrp(dst)); 19336372Ssklower printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen); 19436372Ssklower printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n", 19536372Ssklower isop->isop_options, flags, isop->isop_clnpcache); 19636372Ssklower ENDDEBUG 19736372Ssklower 19836372Ssklower if (isop->isop_clnpcache != NULL) { 19936372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 20036372Ssklower } 20136372Ssklower 20236372Ssklower /* 20336372Ssklower * Check if cache is valid ... 20436372Ssklower */ 20536372Ssklower IFDEBUG(D_OUTPUT) 20636372Ssklower printf("clnp_output: ck cache: clcp %x\n", clcp); 20736372Ssklower if (clcp != NULL) { 20836372Ssklower printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst)); 20936372Ssklower printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options, 21036372Ssklower clcp->clc_options); 21136372Ssklower if (isop->isop_route.ro_rt) 21236372Ssklower printf("\tro_rt x%x, rt_flags x%x\n", 21336372Ssklower isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags); 21436372Ssklower printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags); 21536372Ssklower printf("\tclc_hdr x%x\n", clcp->clc_hdr); 21636372Ssklower } 21736372Ssklower ENDDEBUG 21836372Ssklower if ((clcp != NULL) && /* cache exists */ 21936372Ssklower (isop->isop_options == clcp->clc_options) && /* same options */ 22036372Ssklower (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */ 22136372Ssklower (isop->isop_route.ro_rt != NULL) && /* route exists */ 22236372Ssklower (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */ 22336372Ssklower (flags == clcp->clc_flags) && /* same flags */ 22436372Ssklower (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */ 22536372Ssklower /* 22636372Ssklower * The cache is valid 22736372Ssklower */ 22836372Ssklower 22936372Ssklower IFDEBUG(D_OUTPUT) 23036372Ssklower printf("clnp_output: using cache\n"); 23136372Ssklower ENDDEBUG 23236372Ssklower 23336372Ssklower m = m_copy(clcp->clc_hdr, 0, M_COPYALL); 23436372Ssklower if (m == NULL) { 23536372Ssklower /* 23636372Ssklower * No buffers left to copy cached packet header. Use 23736372Ssklower * the cached packet header this time, and 23836372Ssklower * mark the hdr as vacant 23936372Ssklower */ 24036372Ssklower m = clcp->clc_hdr; 24136372Ssklower clcp->clc_hdr = NULL; 24236372Ssklower } 24336372Ssklower m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */ 24436372Ssklower clnp = mtod(m, struct clnp_fixed *); 24536372Ssklower } else { 24636372Ssklower struct clnp_optidx *oidx = NULL; /* index to clnp options */ 24736372Ssklower 24836372Ssklower /* 24936372Ssklower * The cache is not valid. Allocate an mbuf (if necessary) 25036372Ssklower * to hold cached info. If one is not available, then 25136372Ssklower * don't bother with the cache 25236372Ssklower */ 25336372Ssklower INCSTAT(cns_cachemiss); 25436372Ssklower if (flags & CLNP_NOCACHE) { 25536372Ssklower clcp = &clc; 25636372Ssklower } else { 25736372Ssklower if (isop->isop_clnpcache == NULL) { 25836372Ssklower /* 25936372Ssklower * There is no clnpcache. Allocate an mbuf to hold one 26036372Ssklower */ 26136372Ssklower if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER)) 26236372Ssklower == NULL) { 26336372Ssklower /* 26436372Ssklower * No mbufs available. Pretend that we don't want 26536372Ssklower * caching this time. 26636372Ssklower */ 26736372Ssklower IFDEBUG(D_OUTPUT) 26836372Ssklower printf("clnp_output: no mbufs to allocate to cache\n"); 26936372Ssklower ENDDEBUG 27036372Ssklower flags |= CLNP_NOCACHE; 27136372Ssklower clcp = &clc; 27236372Ssklower } else { 27336372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 27436372Ssklower } 27536372Ssklower } else { 27636372Ssklower /* 27736372Ssklower * A clnpcache mbuf exists. If the clc_hdr is not null, 27836372Ssklower * we must free it, as a new one is about to be created. 27936372Ssklower */ 28036372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); 28136372Ssklower if (clcp->clc_hdr != NULL) { 28236372Ssklower /* 28336372Ssklower * The clc_hdr is not null but a clnpcache mbuf exists. 28436372Ssklower * This means that there was a cache, but the existing 28536372Ssklower * copy of the hdr is no longer valid. Free it now 28636372Ssklower * before we lose the pointer to it. 28736372Ssklower */ 28836372Ssklower IFDEBUG(D_OUTPUT) 28936372Ssklower printf("clnp_output: freeing old clc_hdr 0x%x\n", 29036372Ssklower clcp->clc_hdr); 29136372Ssklower ENDDEBUG 29236372Ssklower m_free(clcp->clc_hdr); 29336372Ssklower IFDEBUG(D_OUTPUT) 29436372Ssklower printf("clnp_output: freed old clc_hdr (done)\n"); 29536372Ssklower ENDDEBUG 29636372Ssklower } 29736372Ssklower } 29836372Ssklower } 29936372Ssklower IFDEBUG(D_OUTPUT) 30036372Ssklower printf("clnp_output: NEW clcp x%x\n",clcp); 30136372Ssklower ENDDEBUG 30236372Ssklower bzero((caddr_t)clcp, sizeof(struct clnp_cache)); 30336372Ssklower 30436372Ssklower if (isop->isop_optindex) 30536372Ssklower oidx = mtod(isop->isop_optindex, struct clnp_optidx *); 30636372Ssklower 30736372Ssklower /* 30836372Ssklower * Don't allow packets with security, quality of service, 30936372Ssklower * priority, or error report options to be sent. 31036372Ssklower */ 31136372Ssklower if ((isop->isop_options) && (oidx)) { 31236372Ssklower if ((oidx->cni_securep) || 31336372Ssklower (oidx->cni_priorp) || 31436372Ssklower (oidx->cni_qos_formatp) || 31536372Ssklower (oidx->cni_er_reason != ER_INVALREAS)) { 31636372Ssklower IFDEBUG(D_OUTPUT) 31736372Ssklower printf("clnp_output: pkt dropped - option unsupported\n"); 31836372Ssklower ENDDEBUG 31936372Ssklower m_freem(m0); 32036372Ssklower return(EINVAL); 32136372Ssklower } 32236372Ssklower } 32336372Ssklower 32436372Ssklower /* 32536372Ssklower * Don't allow any invalid flags to be set 32636372Ssklower */ 32736372Ssklower if ((flags & (CLNP_VFLAGS)) != flags) { 32836372Ssklower IFDEBUG(D_OUTPUT) 32936372Ssklower printf("clnp_output: packet dropped - flags unsupported\n"); 33036372Ssklower ENDDEBUG 33136372Ssklower m_freem(m0); 33236372Ssklower return(EINVAL); 33336372Ssklower } 33436372Ssklower 33536372Ssklower /* 33636372Ssklower * Don't allow funny lengths on dst; src may be zero in which 33736372Ssklower * case we insert the source address based upon the interface 33836372Ssklower */ 33936372Ssklower if ((src->isoa_len > sizeof(struct iso_addr)) || 34036372Ssklower (dst->isoa_len == 0) || 34136372Ssklower (dst->isoa_len > sizeof(struct iso_addr))) { 34236372Ssklower m_freem(m0); 34336372Ssklower return(ENAMETOOLONG); 34436372Ssklower } 34536372Ssklower 34636372Ssklower /* 34736372Ssklower * Grab mbuf to contain header 34836372Ssklower */ 34936372Ssklower MGET(m, M_DONTWAIT, MT_HEADER); 35036372Ssklower if (m == 0) { 35136372Ssklower m_freem(m0); 35236372Ssklower return(ENOBUFS); 35336372Ssklower } 35436372Ssklower 35536372Ssklower m->m_next = m0; 35636372Ssklower clnp = mtod(m, struct clnp_fixed *); 35736372Ssklower clcp->clc_segoff = 0; 35836372Ssklower 35936372Ssklower /* 36036372Ssklower * Fill in all of fixed hdr except lengths and checksum 36136372Ssklower */ 36236372Ssklower if (flags & CLNP_SEND_RAW) { 36336372Ssklower *clnp = raw_template; 36436372Ssklower } else if (flags & CLNP_ECHO) { 36536372Ssklower *clnp = echo_template; 36636372Ssklower } else { 36736372Ssklower *clnp = dt_template; 36836372Ssklower } 36936372Ssklower if (flags & CLNP_NO_SEG) 37036372Ssklower clnp->cnf_seg_ok = 0; 37136372Ssklower if (flags & CLNP_NO_ER) 37236372Ssklower clnp->cnf_err_ok = 0; 37336372Ssklower 37436372Ssklower /* 37536372Ssklower * Route packet; special case for source rt 37636372Ssklower */ 37736372Ssklower if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) { 37836372Ssklower IFDEBUG(D_OUTPUT) 37936372Ssklower printf("clnp_output: calling clnp_srcroute\n"); 38036372Ssklower ENDDEBUG 38136372Ssklower error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route, 38236372Ssklower &clcp->clc_firsthop, &clcp->clc_ifp, dst); 38336372Ssklower } else { 38436372Ssklower IFDEBUG(D_OUTPUT) 38536372Ssklower ENDDEBUG 38636372Ssklower error = clnp_route(dst, &isop->isop_route, flags, 38736372Ssklower &clcp->clc_firsthop, &clcp->clc_ifp); 38836372Ssklower } 38936372Ssklower if (error != 0) { 39036372Ssklower IFDEBUG(D_OUTPUT) 39136372Ssklower printf("clnp_output: route failed, errno %d\n", error); 39236372Ssklower printf("@clcp:\n"); 39336372Ssklower dump_buf(clcp, sizeof (struct clnp_cache)); 39436372Ssklower ENDDEBUG 39536372Ssklower goto bad; 39636372Ssklower } 39736372Ssklower 39836372Ssklower IFDEBUG(D_OUTPUT) 39936372Ssklower printf("clnp_output: packet routed to %s\n", 40036372Ssklower clnp_iso_addrp( 40136372Ssklower &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr)); 40236372Ssklower ENDDEBUG 40336372Ssklower 40436372Ssklower /* 40536372Ssklower * If src address is not yet specified, use address of 40636372Ssklower * interface. NOTE: this will now update the laddr field in 40736372Ssklower * the isopcb. Is this desirable? RAH? 40836372Ssklower */ 40936372Ssklower if (src->isoa_len == 0) { 41036372Ssklower src = clnp_srcaddr(clcp->clc_ifp, 41136372Ssklower &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr); 41236372Ssklower if (src == NULL) { 41336372Ssklower error = ENETDOWN; 41436372Ssklower goto bad; 41536372Ssklower } 41636372Ssklower IFDEBUG(D_OUTPUT) 41736372Ssklower printf("clnp_output: new src %s\n", clnp_iso_addrp(src)); 41836372Ssklower ENDDEBUG 41936372Ssklower } 42036372Ssklower 42136372Ssklower /* 42236372Ssklower * Insert the source and destination address, 42336372Ssklower */ 42436372Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 42536372Ssklower CLNP_INSERT_ADDR(hoff, dst); 42636372Ssklower CLNP_INSERT_ADDR(hoff, src); 42736372Ssklower 42836372Ssklower /* 42936372Ssklower * Leave room for the segment part, if segmenting is selected 43036372Ssklower */ 43136372Ssklower if (clnp->cnf_seg_ok) { 43236372Ssklower clcp->clc_segoff = hoff - (caddr_t)clnp; 43336372Ssklower hoff += sizeof(struct clnp_segment); 43436372Ssklower } 43536372Ssklower 43636372Ssklower clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp); 437*36768Ssklower hdrlen = clnp->cnf_hdr_len; 43836372Ssklower 439*36768Ssklower #ifdef DECBIT 44036372Ssklower /* 441*36768Ssklower * Add the globally unique QOS (with room for congestion experienced 442*36768Ssklower * bit). I can safely assume that this option is not in the options 443*36768Ssklower * mbuf below because I checked that the option was not specified 444*36768Ssklower * previously 445*36768Ssklower */ 446*36768Ssklower if ((m->m_len + sizeof(qos_option)) < MLEN) { 447*36768Ssklower bcopy((caddr_t)qos_option, hoff, sizeof(qos_option)); 448*36768Ssklower clnp->cnf_hdr_len += sizeof(qos_option); 449*36768Ssklower hdrlen += sizeof(qos_option); 450*36768Ssklower m->m_len += sizeof(qos_option); 451*36768Ssklower } 452*36768Ssklower #endif DECBIT 453*36768Ssklower 454*36768Ssklower /* 45536372Ssklower * If an options mbuf is present, concatenate a copy to the hdr mbuf. 45636372Ssklower */ 45736372Ssklower if (isop->isop_options) { 45836372Ssklower struct mbuf *opt_copy = m_copy(isop->isop_options, 0, M_COPYALL); 45936372Ssklower if (opt_copy == NULL) { 46036372Ssklower error = ENOBUFS; 46136372Ssklower goto bad; 46236372Ssklower } 46336372Ssklower /* Link in place */ 46436372Ssklower opt_copy->m_next = m->m_next; 46536372Ssklower m->m_next = opt_copy; 46636372Ssklower 46736372Ssklower /* update size of header */ 46836372Ssklower clnp->cnf_hdr_len += opt_copy->m_len; 469*36768Ssklower hdrlen += opt_copy->m_len; 47036372Ssklower } 47136372Ssklower 472*36768Ssklower if (hdrlen > CLNP_HDR_MAX) { 473*36768Ssklower error = EMSGSIZE; 474*36768Ssklower goto bad; 475*36768Ssklower } 476*36768Ssklower 47736372Ssklower /* 47836372Ssklower * Now set up the cache entry in the pcb 47936372Ssklower */ 48036372Ssklower if ((flags & CLNP_NOCACHE) == 0) { 48136372Ssklower if ((clcp->clc_hdr = m_copy(m, 0, clnp->cnf_hdr_len)) != NULL) { 48236372Ssklower bcopy((caddr_t)dst, (caddr_t)&clcp->clc_dst, 48336372Ssklower sizeof(struct iso_addr)); 48436372Ssklower clcp->clc_flags = flags; 48536372Ssklower clcp->clc_options = isop->isop_options; 48636372Ssklower } 48736372Ssklower } 48836372Ssklower } 48936372Ssklower INCSTAT(cns_sent); 49036372Ssklower /* 49136372Ssklower * If small enough for interface, send directly 49236372Ssklower * Fill in segmentation part of hdr if using the full protocol 49336372Ssklower */ 49436372Ssklower if ((total_len = clnp->cnf_hdr_len + datalen) <= SN_MTU(clcp->clc_ifp)) { 49536372Ssklower if (clnp->cnf_seg_ok) { 49636372Ssklower struct clnp_segment seg_part; /* segment part of hdr */ 49736372Ssklower seg_part.cng_id = htons(clnp_id++); 49836372Ssklower seg_part.cng_off = htons(0); 49936372Ssklower seg_part.cng_tot_len = htons(total_len); 50036372Ssklower (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff, 50136372Ssklower sizeof(seg_part)); 50236372Ssklower } 50336372Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len); 50436372Ssklower 50536372Ssklower /* 50636372Ssklower * Compute clnp checksum (on header only) 50736372Ssklower */ 50836372Ssklower if (flags & CLNP_NO_CKSUM) { 50936372Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); 51036372Ssklower } else { 51136372Ssklower iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); 51236372Ssklower } 51336372Ssklower 51436372Ssklower IFDEBUG(D_DUMPOUT) 51536372Ssklower struct mbuf *mdump = m; 51636372Ssklower printf("clnp_output: sending dg:\n"); 51736372Ssklower while (mdump != NULL) { 51836372Ssklower dump_buf(mtod(mdump, caddr_t), mdump->m_len); 51936372Ssklower mdump = mdump->m_next; 52036372Ssklower } 52136372Ssklower ENDDEBUG 52236372Ssklower 52336372Ssklower error = SN_OUTPUT(clcp, m); 52436372Ssklower goto done; 52536372Ssklower } else { 52636372Ssklower /* 52736372Ssklower * Too large for interface; fragment if possible. 52836372Ssklower */ 52936372Ssklower error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop, total_len, 53036372Ssklower clcp->clc_segoff, flags); 53136372Ssklower goto done; 53236372Ssklower } 53336372Ssklower bad: 53436372Ssklower m_freem(m); 53536372Ssklower 53636372Ssklower done: 53736372Ssklower return(error); 53836372Ssklower } 53936372Ssklower 54036372Ssklower int clnp_ctloutput() 54136372Ssklower { 54236372Ssklower } 54336372Ssklower 54436372Ssklower #endif ISO 545