xref: /csrg-svn/sys/netiso/clnp_output.c (revision 63222)
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