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