149267Sbostic /*-
2*63222Sbostic * Copyright (c) 1991, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
449267Sbostic *
549267Sbostic * %sccs.include.redist.c%
649267Sbostic *
7*63222Sbostic * @(#)clnp_output.c 8.1 (Berkeley) 06/10/93
849267Sbostic */
949267Sbostic
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
3956533Sbostic #include <sys/param.h>
4056533Sbostic #include <sys/mbuf.h>
4156533Sbostic #include <sys/domain.h>
4256533Sbostic #include <sys/protosw.h>
4356533Sbostic #include <sys/socket.h>
4456533Sbostic #include <sys/socketvar.h>
4556533Sbostic #include <sys/errno.h>
4656533Sbostic #include <sys/time.h>
4736372Ssklower
4856533Sbostic #include <net/if.h>
4956533Sbostic #include <net/route.h>
5036372Ssklower
5156533Sbostic #include <netiso/iso.h>
5256533Sbostic #include <netiso/iso_var.h>
5356533Sbostic #include <netiso/iso_pcb.h>
5456533Sbostic #include <netiso/clnp.h>
5556533Sbostic #include <netiso/clnp_stat.h>
5656533Sbostic #include <netiso/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
8852487Ssklower static struct clnp_fixed echor_template = {
8952487Ssklower ISO8473_CLNP, /* network identifier */
9052487Ssklower 0, /* length */
9152487Ssklower ISO8473_V1, /* version */
9252487Ssklower CLNP_TTL, /* ttl */
9352487Ssklower CLNP_ECR|CNF_SEG_OK|CNF_ERR_OK, /* type */
9452487Ssklower 0, /* segment length */
9552487Ssklower 0 /* checksum */
9652487Ssklower };
9752487Ssklower
9836768Ssklower #ifdef DECBIT
9936768Ssklower u_char qos_option[] = {CLNPOVAL_QOS, 1,
10036768Ssklower CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY};
10161294Ssklower #endif /* DECBIT */
10236768Ssklower
10336372Ssklower int clnp_id = 0; /* id for segmented dgrams */
10436372Ssklower
10536372Ssklower /*
10636372Ssklower * FUNCTION: clnp_output
10736372Ssklower *
10836372Ssklower * PURPOSE: output the data in the mbuf as a clnp datagram
10936372Ssklower *
11036372Ssklower * The data specified by m0 is sent as a clnp datagram.
11136372Ssklower * The mbuf chain m0 will be freed when this routine has
11236372Ssklower * returned.
11336372Ssklower *
11436372Ssklower * If options is non-null, it points to an mbuf which contains
11536372Ssklower * options to be sent with the datagram. The options must
11636372Ssklower * be formatted in the mbuf according to clnp rules. Options
11736372Ssklower * will not be freed.
11836372Ssklower *
11936372Ssklower * Datalen specifies the length of the data in m0.
12036372Ssklower *
12136372Ssklower * Src and dst are the addresses for the packet.
12236372Ssklower *
12336372Ssklower * If route is non-null, it is used as the route for
12436372Ssklower * the packet.
12536372Ssklower *
12636372Ssklower * By default, a DT is sent. However, if flags & CNLP_SEND_ER
12736372Ssklower * then an ER will be sent. If flags & CLNP_SEND_RAW, then
12836372Ssklower * the packet will be send as raw clnp.
12936372Ssklower *
13036372Ssklower * RETURNS: 0 success
13136372Ssklower * appropriate error code
13236372Ssklower *
13336372Ssklower * SIDE EFFECTS: none
13436372Ssklower *
13536372Ssklower * NOTES:
13636372Ssklower * Flags are interpretated as follows:
13736372Ssklower * CLNP_NO_SEG - do not allow this pkt to be segmented.
13836372Ssklower * CLNP_NO_ER - have pkt request ER suppression.
13936372Ssklower * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT
14036372Ssklower * CLNP_NO_CKSUM - don't compute clnp checksum
14136372Ssklower * CLNP_ECHO - send as ECHO packet
14236372Ssklower *
14336372Ssklower * When checking for a cached packet, clnp checks
14436372Ssklower * that the route taken is still up. It does not
14536372Ssklower * check that the route is still to the same destination.
14636372Ssklower * This means that any entity that alters an existing
14736372Ssklower * route for an isopcb (such as when a redirect arrives)
14836372Ssklower * must invalidate the clnp cache. It might be perferable
14936372Ssklower * to have clnp check that the route has the same dest, but
15036372Ssklower * by avoiding this check, we save a call to iso_addrmatch1.
15136372Ssklower */
15238841Ssklower clnp_output(m0, isop, datalen, flags)
15336372Ssklower struct mbuf *m0; /* data for the packet */
15436372Ssklower struct isopcb *isop; /* iso pcb */
15538841Ssklower int datalen; /* number of bytes of data in m0 */
15636372Ssklower int flags; /* flags */
15736372Ssklower {
15836372Ssklower int error = 0; /* return value of function */
15937469Ssklower register struct mbuf *m = m0; /* mbuf for clnp header chain */
16036372Ssklower register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */
16136372Ssklower register caddr_t hoff; /* offset into header */
16236372Ssklower int total_len; /* total length of packet */
16336372Ssklower struct iso_addr *src; /* ptr to source address */
16436372Ssklower struct iso_addr *dst; /* ptr to destination address */
16536372Ssklower struct clnp_cache clc; /* storage for cache information */
16636372Ssklower struct clnp_cache *clcp = NULL; /* ptr to clc */
16736768Ssklower int hdrlen = 0;
16836372Ssklower
16937469Ssklower dst = &isop->isop_faddr->siso_addr;
17041338Ssklower if (isop->isop_laddr == 0) {
17141338Ssklower struct iso_ifaddr *ia = 0;
17241338Ssklower clnp_route(dst, &isop->isop_route, flags, 0, &ia);
17341338Ssklower if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO)
17441338Ssklower return (ENETUNREACH);
17541338Ssklower src = &ia->ia_addr.siso_addr;
17641338Ssklower } else
17741338Ssklower src = &isop->isop_laddr->siso_addr;
17836372Ssklower
17936372Ssklower IFDEBUG(D_OUTPUT)
18036372Ssklower printf("clnp_output: to %s", clnp_iso_addrp(dst));
18136372Ssklower printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen);
18236372Ssklower printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n",
18336372Ssklower isop->isop_options, flags, isop->isop_clnpcache);
18436372Ssklower ENDDEBUG
18536372Ssklower
18636372Ssklower if (isop->isop_clnpcache != NULL) {
18736372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
18836372Ssklower }
18936372Ssklower
19036372Ssklower /*
19136372Ssklower * Check if cache is valid ...
19236372Ssklower */
19336372Ssklower IFDEBUG(D_OUTPUT)
19436372Ssklower printf("clnp_output: ck cache: clcp %x\n", clcp);
19536372Ssklower if (clcp != NULL) {
19636372Ssklower printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst));
19736372Ssklower printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options,
19836372Ssklower clcp->clc_options);
19936372Ssklower if (isop->isop_route.ro_rt)
20036372Ssklower printf("\tro_rt x%x, rt_flags x%x\n",
20136372Ssklower isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags);
20236372Ssklower printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags);
20336372Ssklower printf("\tclc_hdr x%x\n", clcp->clc_hdr);
20436372Ssklower }
20536372Ssklower ENDDEBUG
20636372Ssklower if ((clcp != NULL) && /* cache exists */
20736372Ssklower (isop->isop_options == clcp->clc_options) && /* same options */
20836372Ssklower (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */
20936372Ssklower (isop->isop_route.ro_rt != NULL) && /* route exists */
21040777Ssklower (isop->isop_route.ro_rt == clcp->clc_rt) && /* and is cached */
21136372Ssklower (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */
21236372Ssklower (flags == clcp->clc_flags) && /* same flags */
21336372Ssklower (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */
21436372Ssklower /*
21536372Ssklower * The cache is valid
21636372Ssklower */
21736372Ssklower
21836372Ssklower IFDEBUG(D_OUTPUT)
21936372Ssklower printf("clnp_output: using cache\n");
22036372Ssklower ENDDEBUG
22136372Ssklower
22237469Ssklower m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL);
22336372Ssklower if (m == NULL) {
22436372Ssklower /*
22536372Ssklower * No buffers left to copy cached packet header. Use
22636372Ssklower * the cached packet header this time, and
22736372Ssklower * mark the hdr as vacant
22836372Ssklower */
22936372Ssklower m = clcp->clc_hdr;
23036372Ssklower clcp->clc_hdr = NULL;
23136372Ssklower }
23236372Ssklower m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */
23336372Ssklower clnp = mtod(m, struct clnp_fixed *);
23436372Ssklower } else {
23536372Ssklower struct clnp_optidx *oidx = NULL; /* index to clnp options */
23636372Ssklower
23736372Ssklower /*
23836372Ssklower * The cache is not valid. Allocate an mbuf (if necessary)
23936372Ssklower * to hold cached info. If one is not available, then
24036372Ssklower * don't bother with the cache
24136372Ssklower */
24236372Ssklower INCSTAT(cns_cachemiss);
24336372Ssklower if (flags & CLNP_NOCACHE) {
24436372Ssklower clcp = &clc;
24536372Ssklower } else {
24636372Ssklower if (isop->isop_clnpcache == NULL) {
24736372Ssklower /*
24836372Ssklower * There is no clnpcache. Allocate an mbuf to hold one
24936372Ssklower */
25036372Ssklower if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER))
25136372Ssklower == NULL) {
25236372Ssklower /*
25336372Ssklower * No mbufs available. Pretend that we don't want
25436372Ssklower * caching this time.
25536372Ssklower */
25636372Ssklower IFDEBUG(D_OUTPUT)
25736372Ssklower printf("clnp_output: no mbufs to allocate to cache\n");
25836372Ssklower ENDDEBUG
25936372Ssklower flags |= CLNP_NOCACHE;
26036372Ssklower clcp = &clc;
26136372Ssklower } else {
26236372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
26336372Ssklower }
26436372Ssklower } else {
26536372Ssklower /*
26636372Ssklower * A clnpcache mbuf exists. If the clc_hdr is not null,
26736372Ssklower * we must free it, as a new one is about to be created.
26836372Ssklower */
26936372Ssklower clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
27036372Ssklower if (clcp->clc_hdr != NULL) {
27136372Ssklower /*
27236372Ssklower * The clc_hdr is not null but a clnpcache mbuf exists.
27336372Ssklower * This means that there was a cache, but the existing
27436372Ssklower * copy of the hdr is no longer valid. Free it now
27536372Ssklower * before we lose the pointer to it.
27636372Ssklower */
27736372Ssklower IFDEBUG(D_OUTPUT)
27836372Ssklower printf("clnp_output: freeing old clc_hdr 0x%x\n",
27936372Ssklower clcp->clc_hdr);
28036372Ssklower ENDDEBUG
28136372Ssklower m_free(clcp->clc_hdr);
28236372Ssklower IFDEBUG(D_OUTPUT)
28336372Ssklower printf("clnp_output: freed old clc_hdr (done)\n");
28436372Ssklower ENDDEBUG
28536372Ssklower }
28636372Ssklower }
28736372Ssklower }
28836372Ssklower IFDEBUG(D_OUTPUT)
28936372Ssklower printf("clnp_output: NEW clcp x%x\n",clcp);
29036372Ssklower ENDDEBUG
29136372Ssklower bzero((caddr_t)clcp, sizeof(struct clnp_cache));
29236372Ssklower
29336372Ssklower if (isop->isop_optindex)
29436372Ssklower oidx = mtod(isop->isop_optindex, struct clnp_optidx *);
29536372Ssklower
29636372Ssklower /*
29736372Ssklower * Don't allow packets with security, quality of service,
29836372Ssklower * priority, or error report options to be sent.
29936372Ssklower */
30036372Ssklower if ((isop->isop_options) && (oidx)) {
30136372Ssklower if ((oidx->cni_securep) ||
30236372Ssklower (oidx->cni_priorp) ||
30336372Ssklower (oidx->cni_qos_formatp) ||
30436372Ssklower (oidx->cni_er_reason != ER_INVALREAS)) {
30536372Ssklower IFDEBUG(D_OUTPUT)
30636372Ssklower printf("clnp_output: pkt dropped - option unsupported\n");
30736372Ssklower ENDDEBUG
30836372Ssklower m_freem(m0);
30936372Ssklower return(EINVAL);
31036372Ssklower }
31136372Ssklower }
31236372Ssklower
31336372Ssklower /*
31436372Ssklower * Don't allow any invalid flags to be set
31536372Ssklower */
31636372Ssklower if ((flags & (CLNP_VFLAGS)) != flags) {
31736372Ssklower IFDEBUG(D_OUTPUT)
31836372Ssklower printf("clnp_output: packet dropped - flags unsupported\n");
31936372Ssklower ENDDEBUG
32039195Ssklower INCSTAT(cns_odropped);
32136372Ssklower m_freem(m0);
32236372Ssklower return(EINVAL);
32336372Ssklower }
32436372Ssklower
32536372Ssklower /*
32636372Ssklower * Don't allow funny lengths on dst; src may be zero in which
32736372Ssklower * case we insert the source address based upon the interface
32836372Ssklower */
32936372Ssklower if ((src->isoa_len > sizeof(struct iso_addr)) ||
33036372Ssklower (dst->isoa_len == 0) ||
33136372Ssklower (dst->isoa_len > sizeof(struct iso_addr))) {
33236372Ssklower m_freem(m0);
33339195Ssklower INCSTAT(cns_odropped);
33436372Ssklower return(ENAMETOOLONG);
33536372Ssklower }
33636372Ssklower
33736372Ssklower /*
33836372Ssklower * Grab mbuf to contain header
33936372Ssklower */
34037469Ssklower MGETHDR(m, M_DONTWAIT, MT_HEADER);
34136372Ssklower if (m == 0) {
34236372Ssklower m_freem(m0);
34339195Ssklower INCSTAT(cns_odropped);
34436372Ssklower return(ENOBUFS);
34536372Ssklower }
34639195Ssklower INCSTAT(cns_sent);
34736372Ssklower m->m_next = m0;
34836372Ssklower clnp = mtod(m, struct clnp_fixed *);
34936372Ssklower clcp->clc_segoff = 0;
35036372Ssklower
35136372Ssklower /*
35236372Ssklower * Fill in all of fixed hdr except lengths and checksum
35336372Ssklower */
35436372Ssklower if (flags & CLNP_SEND_RAW) {
35536372Ssklower *clnp = raw_template;
35636372Ssklower } else if (flags & CLNP_ECHO) {
35736372Ssklower *clnp = echo_template;
35852487Ssklower } else if (flags & CLNP_ECHOR) {
35952487Ssklower *clnp = echor_template;
36036372Ssklower } else {
36136372Ssklower *clnp = dt_template;
36236372Ssklower }
36336372Ssklower if (flags & CLNP_NO_SEG)
36437469Ssklower clnp->cnf_type &= ~CNF_SEG_OK;
36536372Ssklower if (flags & CLNP_NO_ER)
36637469Ssklower clnp->cnf_type &= ~CNF_ERR_OK;
36736372Ssklower
36836372Ssklower /*
36936372Ssklower * Route packet; special case for source rt
37036372Ssklower */
37136372Ssklower if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) {
37236372Ssklower IFDEBUG(D_OUTPUT)
37336372Ssklower printf("clnp_output: calling clnp_srcroute\n");
37436372Ssklower ENDDEBUG
37536372Ssklower error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route,
37637469Ssklower &clcp->clc_firsthop, &clcp->clc_ifa, dst);
37736372Ssklower } else {
37836372Ssklower IFDEBUG(D_OUTPUT)
37936372Ssklower ENDDEBUG
38036372Ssklower error = clnp_route(dst, &isop->isop_route, flags,
38137469Ssklower &clcp->clc_firsthop, &clcp->clc_ifa);
38236372Ssklower }
38337469Ssklower if (error || (clcp->clc_ifa == 0)) {
38436372Ssklower IFDEBUG(D_OUTPUT)
38536372Ssklower printf("clnp_output: route failed, errno %d\n", error);
38636372Ssklower printf("@clcp:\n");
38736372Ssklower dump_buf(clcp, sizeof (struct clnp_cache));
38836372Ssklower ENDDEBUG
38936372Ssklower goto bad;
39036372Ssklower }
39140777Ssklower clcp->clc_rt = isop->isop_route.ro_rt; /* XXX */
39248742Ssklower clcp->clc_ifp = clcp->clc_ifa->ia_ifp; /* XXX */
39336372Ssklower
39436372Ssklower IFDEBUG(D_OUTPUT)
39536372Ssklower printf("clnp_output: packet routed to %s\n",
39636372Ssklower clnp_iso_addrp(
39736372Ssklower &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr));
39836372Ssklower ENDDEBUG
39936372Ssklower
40036372Ssklower /*
40136372Ssklower * If src address is not yet specified, use address of
40236372Ssklower * interface. NOTE: this will now update the laddr field in
40336372Ssklower * the isopcb. Is this desirable? RAH?
40436372Ssklower */
40536372Ssklower if (src->isoa_len == 0) {
40637469Ssklower src = &(clcp->clc_ifa->ia_addr.siso_addr);
40736372Ssklower IFDEBUG(D_OUTPUT)
40836372Ssklower printf("clnp_output: new src %s\n", clnp_iso_addrp(src));
40936372Ssklower ENDDEBUG
41036372Ssklower }
41136372Ssklower
41236372Ssklower /*
41336372Ssklower * Insert the source and destination address,
41436372Ssklower */
41536372Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
41637469Ssklower CLNP_INSERT_ADDR(hoff, *dst);
41737469Ssklower CLNP_INSERT_ADDR(hoff, *src);
41836372Ssklower
41936372Ssklower /*
42036372Ssklower * Leave room for the segment part, if segmenting is selected
42136372Ssklower */
42237469Ssklower if (clnp->cnf_type & CNF_SEG_OK) {
42336372Ssklower clcp->clc_segoff = hoff - (caddr_t)clnp;
42436372Ssklower hoff += sizeof(struct clnp_segment);
42536372Ssklower }
42636372Ssklower
42736372Ssklower clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp);
42836768Ssklower hdrlen = clnp->cnf_hdr_len;
42936372Ssklower
43036768Ssklower #ifdef DECBIT
43136372Ssklower /*
43236768Ssklower * Add the globally unique QOS (with room for congestion experienced
43336768Ssklower * bit). I can safely assume that this option is not in the options
43436768Ssklower * mbuf below because I checked that the option was not specified
43536768Ssklower * previously
43636768Ssklower */
43736768Ssklower if ((m->m_len + sizeof(qos_option)) < MLEN) {
43836768Ssklower bcopy((caddr_t)qos_option, hoff, sizeof(qos_option));
43936768Ssklower clnp->cnf_hdr_len += sizeof(qos_option);
44036768Ssklower hdrlen += sizeof(qos_option);
44136768Ssklower m->m_len += sizeof(qos_option);
44236768Ssklower }
44361294Ssklower #endif /* DECBIT */
44436768Ssklower
44536768Ssklower /*
44636372Ssklower * If an options mbuf is present, concatenate a copy to the hdr mbuf.
44736372Ssklower */
44836372Ssklower if (isop->isop_options) {
44937469Ssklower struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL);
45036372Ssklower if (opt_copy == NULL) {
45136372Ssklower error = ENOBUFS;
45236372Ssklower goto bad;
45336372Ssklower }
45436372Ssklower /* Link in place */
45536372Ssklower opt_copy->m_next = m->m_next;
45636372Ssklower m->m_next = opt_copy;
45736372Ssklower
45836372Ssklower /* update size of header */
45936372Ssklower clnp->cnf_hdr_len += opt_copy->m_len;
46036768Ssklower hdrlen += opt_copy->m_len;
46136372Ssklower }
46236372Ssklower
46336768Ssklower if (hdrlen > CLNP_HDR_MAX) {
46436768Ssklower error = EMSGSIZE;
46536768Ssklower goto bad;
46636768Ssklower }
46736768Ssklower
46836372Ssklower /*
46936372Ssklower * Now set up the cache entry in the pcb
47036372Ssklower */
47136372Ssklower if ((flags & CLNP_NOCACHE) == 0) {
47237469Ssklower if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) {
47337469Ssklower clcp->clc_dst = *dst;
47436372Ssklower clcp->clc_flags = flags;
47536372Ssklower clcp->clc_options = isop->isop_options;
47636372Ssklower }
47736372Ssklower }
47836372Ssklower }
47936372Ssklower /*
48036372Ssklower * If small enough for interface, send directly
48136372Ssklower * Fill in segmentation part of hdr if using the full protocol
48236372Ssklower */
48342865Ssklower total_len = clnp->cnf_hdr_len + datalen;
48442865Ssklower if (clnp->cnf_type & CNF_SEG_OK) {
48542865Ssklower struct clnp_segment seg_part; /* segment part of hdr */
48642865Ssklower seg_part.cng_id = htons(clnp_id++);
48742865Ssklower seg_part.cng_off = htons(0);
48842865Ssklower seg_part.cng_tot_len = htons(total_len);
48942865Ssklower (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff,
49042865Ssklower sizeof(seg_part));
49142865Ssklower }
49248742Ssklower if (total_len <= SN_MTU(clcp->clc_ifp, clcp->clc_rt)) {
49336372Ssklower HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len);
49437469Ssklower m->m_pkthdr.len = total_len;
49536372Ssklower /*
49636372Ssklower * Compute clnp checksum (on header only)
49736372Ssklower */
49836372Ssklower if (flags & CLNP_NO_CKSUM) {
49936372Ssklower HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
50036372Ssklower } else {
50136372Ssklower iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
50236372Ssklower }
50336372Ssklower
50436372Ssklower IFDEBUG(D_DUMPOUT)
50536372Ssklower struct mbuf *mdump = m;
50636372Ssklower printf("clnp_output: sending dg:\n");
50736372Ssklower while (mdump != NULL) {
50836372Ssklower dump_buf(mtod(mdump, caddr_t), mdump->m_len);
50936372Ssklower mdump = mdump->m_next;
51036372Ssklower }
51136372Ssklower ENDDEBUG
51236372Ssklower
51336372Ssklower error = SN_OUTPUT(clcp, m);
51436372Ssklower goto done;
51536372Ssklower } else {
51636372Ssklower /*
51736372Ssklower * Too large for interface; fragment if possible.
51836372Ssklower */
51948742Ssklower error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop,
52040777Ssklower total_len, clcp->clc_segoff, flags, clcp->clc_rt);
52136372Ssklower goto done;
52236372Ssklower }
52336372Ssklower bad:
52436372Ssklower m_freem(m);
52536372Ssklower done:
52639195Ssklower if (error) {
52739195Ssklower clnp_stat.cns_sent--;
52839195Ssklower clnp_stat.cns_odropped++;
52939195Ssklower }
53039195Ssklower return (error);
53136372Ssklower }
53236372Ssklower
clnp_ctloutput()53336372Ssklower int clnp_ctloutput()
53436372Ssklower {
53536372Ssklower }
536