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