xref: /csrg-svn/sys/netiso/clnp_output.c (revision 36372)
1*36372Ssklower /***********************************************************
2*36372Ssklower 		Copyright IBM Corporation 1987
3*36372Ssklower 
4*36372Ssklower                       All Rights Reserved
5*36372Ssklower 
6*36372Ssklower Permission to use, copy, modify, and distribute this software and its
7*36372Ssklower documentation for any purpose and without fee is hereby granted,
8*36372Ssklower provided that the above copyright notice appear in all copies and that
9*36372Ssklower both that copyright notice and this permission notice appear in
10*36372Ssklower supporting documentation, and that the name of IBM not be
11*36372Ssklower used in advertising or publicity pertaining to distribution of the
12*36372Ssklower software without specific, written prior permission.
13*36372Ssklower 
14*36372Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36372Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36372Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36372Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36372Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36372Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36372Ssklower SOFTWARE.
21*36372Ssklower 
22*36372Ssklower ******************************************************************/
23*36372Ssklower 
24*36372Ssklower /*
25*36372Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36372Ssklower  */
27*36372Ssklower /* $Header: clnp_output.c,v 4.5 88/09/15 18:57:57 hagens Exp $ */
28*36372Ssklower /* $Source: /usr/argo/sys/netiso/RCS/clnp_output.c,v $ */
29*36372Ssklower 
30*36372Ssklower #ifndef lint
31*36372Ssklower static char *rcsid = "$Header: clnp_output.c,v 4.5 88/09/15 18:57:57 hagens Exp $";
32*36372Ssklower #endif lint
33*36372Ssklower 
34*36372Ssklower #ifdef ISO
35*36372Ssklower #include "../h/types.h"
36*36372Ssklower #include "../h/param.h"
37*36372Ssklower #include "../h/mbuf.h"
38*36372Ssklower #include "../h/domain.h"
39*36372Ssklower #include "../h/protosw.h"
40*36372Ssklower #include "../h/socket.h"
41*36372Ssklower #include "../h/socketvar.h"
42*36372Ssklower #include "../h/errno.h"
43*36372Ssklower #include "../h/time.h"
44*36372Ssklower 
45*36372Ssklower #include "../net/if.h"
46*36372Ssklower #include "../net/route.h"
47*36372Ssklower 
48*36372Ssklower #include "../netiso/iso.h"
49*36372Ssklower #include "../netiso/iso_pcb.h"
50*36372Ssklower #include "../netiso/clnp.h"
51*36372Ssklower #include "../netiso/clnp_stat.h"
52*36372Ssklower #include "../netiso/argo_debug.h"
53*36372Ssklower 
54*36372Ssklower static struct clnp_fixed dt_template = {
55*36372Ssklower 	ISO8473_CLNP,	/* network identifier */
56*36372Ssklower 	0,				/* length */
57*36372Ssklower 	ISO8473_V1,		/* version */
58*36372Ssklower 	CLNP_TTL,		/* ttl */
59*36372Ssklower #if BYTE_ORDER == LITTLE_ENDIAN
60*36372Ssklower 	CLNP_DT,		/* type */
61*36372Ssklower 	1, 				/* error report */
62*36372Ssklower 	0, 				/* more segments */
63*36372Ssklower 	1, 				/* segmentation permitted */
64*36372Ssklower #endif
65*36372Ssklower #if BYTE_ORDER == BIG_ENDIAN
66*36372Ssklower 	1, 				/* segmentation permitted */
67*36372Ssklower 	0, 				/* more segments */
68*36372Ssklower 	1, 				/* error report */
69*36372Ssklower 	CLNP_DT,		/* type */
70*36372Ssklower #endif
71*36372Ssklower 	0,				/* segment length */
72*36372Ssklower 	0				/* checksum */
73*36372Ssklower };
74*36372Ssklower 
75*36372Ssklower static struct clnp_fixed raw_template = {
76*36372Ssklower 	ISO8473_CLNP,	/* network identifier */
77*36372Ssklower 	0,				/* length */
78*36372Ssklower 	ISO8473_V1,		/* version */
79*36372Ssklower 	CLNP_TTL,		/* ttl */
80*36372Ssklower #if BYTE_ORDER == LITTLE_ENDIAN
81*36372Ssklower 	CLNP_RAW,		/* type */
82*36372Ssklower 	1, 				/* error report */
83*36372Ssklower 	0, 				/* more segments */
84*36372Ssklower 	1, 				/* segmentation permitted */
85*36372Ssklower #endif
86*36372Ssklower #if BYTE_ORDER == BIG_ENDIAN
87*36372Ssklower 	1, 				/* segmentation permitted */
88*36372Ssklower 	0, 				/* more segments */
89*36372Ssklower 	1, 				/* error report */
90*36372Ssklower 	CLNP_RAW,		/* type */
91*36372Ssklower #endif
92*36372Ssklower 	0,				/* segment length */
93*36372Ssklower 	0				/* checksum */
94*36372Ssklower };
95*36372Ssklower 
96*36372Ssklower static struct clnp_fixed echo_template = {
97*36372Ssklower 	ISO8473_CLNP,	/* network identifier */
98*36372Ssklower 	0,				/* length */
99*36372Ssklower 	ISO8473_V1,		/* version */
100*36372Ssklower 	CLNP_TTL,		/* ttl */
101*36372Ssklower #if BYTE_ORDER == LITTLE_ENDIAN
102*36372Ssklower 	CLNP_EC,		/* type */
103*36372Ssklower 	1, 				/* error report */
104*36372Ssklower 	0, 				/* more segments */
105*36372Ssklower 	1, 				/* segmentation permitted */
106*36372Ssklower #endif
107*36372Ssklower #if BYTE_ORDER == BIG_ENDIAN
108*36372Ssklower 	1, 				/* segmentation permitted */
109*36372Ssklower 	0, 				/* more segments */
110*36372Ssklower 	1, 				/* error report */
111*36372Ssklower 	CLNP_EC,		/* type */
112*36372Ssklower #endif
113*36372Ssklower 	0,				/* segment length */
114*36372Ssklower 	0				/* checksum */
115*36372Ssklower };
116*36372Ssklower 
117*36372Ssklower int				clnp_id = 0;		/* id for segmented dgrams */
118*36372Ssklower 
119*36372Ssklower /*
120*36372Ssklower  * FUNCTION:		clnp_output
121*36372Ssklower  *
122*36372Ssklower  * PURPOSE:			output the data in the mbuf as a clnp datagram
123*36372Ssklower  *
124*36372Ssklower  *					The data specified by m0 is sent as a clnp datagram.
125*36372Ssklower  *					The mbuf chain m0 will be freed when this routine has
126*36372Ssklower  *					returned.
127*36372Ssklower  *
128*36372Ssklower  *					If options is non-null, it points to an mbuf which contains
129*36372Ssklower  *					options to be sent with the datagram. The options must
130*36372Ssklower  *					be formatted in the mbuf according to clnp rules. Options
131*36372Ssklower  *					will not be freed.
132*36372Ssklower  *
133*36372Ssklower  *					Datalen specifies the length of the data in m0.
134*36372Ssklower  *
135*36372Ssklower  *					Src and dst are the addresses for the packet.
136*36372Ssklower  *
137*36372Ssklower  *					If route is non-null, it is used as the route for
138*36372Ssklower  *					the packet.
139*36372Ssklower  *
140*36372Ssklower  *					By default, a DT is sent. However, if flags & CNLP_SEND_ER
141*36372Ssklower  *					then an ER will be sent. If flags & CLNP_SEND_RAW, then
142*36372Ssklower  *					the packet will be send as raw clnp.
143*36372Ssklower  *
144*36372Ssklower  * RETURNS:			0	success
145*36372Ssklower  *					appropriate error code
146*36372Ssklower  *
147*36372Ssklower  * SIDE EFFECTS:	none
148*36372Ssklower  *
149*36372Ssklower  * NOTES:
150*36372Ssklower  *					Flags are interpretated as follows:
151*36372Ssklower  *						CLNP_NO_SEG - do not allow this pkt to be segmented.
152*36372Ssklower  *						CLNP_NO_ER  - have pkt request ER suppression.
153*36372Ssklower  *						CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT
154*36372Ssklower  *						CLNP_NO_CKSUM - don't compute clnp checksum
155*36372Ssklower  *						CLNP_ECHO - send as ECHO packet
156*36372Ssklower  *
157*36372Ssklower  *					When checking for a cached packet, clnp checks
158*36372Ssklower  *					that the route taken is still up. It does not
159*36372Ssklower  *					check that the route is still to the same destination.
160*36372Ssklower  *					This means that any entity that alters an existing
161*36372Ssklower  *					route for an isopcb (such as when a redirect arrives)
162*36372Ssklower  *					must invalidate the clnp cache. It might be perferable
163*36372Ssklower  *					to have clnp check that the route has the same dest, but
164*36372Ssklower  *					by avoiding this check, we save a call to iso_addrmatch1.
165*36372Ssklower  */
166*36372Ssklower clnp_output(m0, isop, datalen, flags)
167*36372Ssklower struct mbuf			*m0;		/* data for the packet */
168*36372Ssklower struct isopcb		*isop;		/* iso pcb */
169*36372Ssklower int					datalen;	/* number of bytes of data in m */
170*36372Ssklower int					flags;		/* flags */
171*36372Ssklower {
172*36372Ssklower 	int							error = 0;		/* return value of function */
173*36372Ssklower 	register struct mbuf		*m;				/* mbuf for clnp header chain */
174*36372Ssklower 	register struct clnp_fixed	*clnp;			/* ptr to fixed part of hdr */
175*36372Ssklower 	register caddr_t			hoff;			/* offset into header */
176*36372Ssklower 	int							total_len;		/* total length of packet */
177*36372Ssklower 	struct iso_addr				*src;		/* ptr to source address */
178*36372Ssklower 	struct iso_addr				*dst;		/* ptr to destination address */
179*36372Ssklower 	struct clnp_cache			clc;		/* storage for cache information */
180*36372Ssklower 	struct clnp_cache			*clcp = NULL;	/* ptr to clc */
181*36372Ssklower 
182*36372Ssklower 	src = &isop->isop_laddr.siso_addr;
183*36372Ssklower 	dst = &isop->isop_faddr.siso_addr;
184*36372Ssklower 
185*36372Ssklower 	IFDEBUG(D_OUTPUT)
186*36372Ssklower 		printf("clnp_output: to %s", clnp_iso_addrp(dst));
187*36372Ssklower 		printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen);
188*36372Ssklower 		printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n",
189*36372Ssklower 			isop->isop_options, flags, isop->isop_clnpcache);
190*36372Ssklower 	ENDDEBUG
191*36372Ssklower 
192*36372Ssklower 	if (isop->isop_clnpcache != NULL) {
193*36372Ssklower 		clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
194*36372Ssklower 	}
195*36372Ssklower 
196*36372Ssklower 	/*
197*36372Ssklower 	 *	Check if cache is valid ...
198*36372Ssklower 	 */
199*36372Ssklower 	IFDEBUG(D_OUTPUT)
200*36372Ssklower 		printf("clnp_output: ck cache: clcp %x\n", clcp);
201*36372Ssklower 		if (clcp != NULL) {
202*36372Ssklower 			printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst));
203*36372Ssklower 			printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options,
204*36372Ssklower 				clcp->clc_options);
205*36372Ssklower 			if (isop->isop_route.ro_rt)
206*36372Ssklower 				printf("\tro_rt x%x, rt_flags x%x\n",
207*36372Ssklower 					isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags);
208*36372Ssklower 			printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags);
209*36372Ssklower 			printf("\tclc_hdr x%x\n", clcp->clc_hdr);
210*36372Ssklower 		}
211*36372Ssklower 	ENDDEBUG
212*36372Ssklower 	if ((clcp != NULL) &&								/* cache exists */
213*36372Ssklower 		(isop->isop_options == clcp->clc_options) && 	/* same options */
214*36372Ssklower 		(iso_addrmatch1(dst, &clcp->clc_dst)) &&		/* dst still same */
215*36372Ssklower 		(isop->isop_route.ro_rt != NULL) &&				/* route exists */
216*36372Ssklower 		(isop->isop_route.ro_rt->rt_flags & RTF_UP) &&	/* route still up */
217*36372Ssklower 		(flags == clcp->clc_flags) &&					/* same flags */
218*36372Ssklower 		(clcp->clc_hdr != NULL)) {						/* hdr mbuf exists */
219*36372Ssklower 		/*
220*36372Ssklower 		 *	The cache is valid
221*36372Ssklower 		 */
222*36372Ssklower 
223*36372Ssklower 		IFDEBUG(D_OUTPUT)
224*36372Ssklower 			printf("clnp_output: using cache\n");
225*36372Ssklower 		ENDDEBUG
226*36372Ssklower 
227*36372Ssklower 		m = m_copy(clcp->clc_hdr, 0, M_COPYALL);
228*36372Ssklower 		if (m == NULL) {
229*36372Ssklower 			/*
230*36372Ssklower 			 *	No buffers left to copy cached packet header. Use
231*36372Ssklower 			 *	the cached packet header this time, and
232*36372Ssklower 			 *	mark the hdr as vacant
233*36372Ssklower 			 */
234*36372Ssklower 			m = clcp->clc_hdr;
235*36372Ssklower 			clcp->clc_hdr = NULL;
236*36372Ssklower 		}
237*36372Ssklower 		m->m_next = m0;	/* ASSUMES pkt hdr is 1 mbuf long */
238*36372Ssklower 		clnp = mtod(m, struct clnp_fixed *);
239*36372Ssklower 	} else {
240*36372Ssklower 		struct clnp_optidx	*oidx = NULL;		/* index to clnp options */
241*36372Ssklower 
242*36372Ssklower 		/*
243*36372Ssklower 		 *	The cache is not valid. Allocate an mbuf (if necessary)
244*36372Ssklower 		 *	to hold cached info. If one is not available, then
245*36372Ssklower 		 *	don't bother with the cache
246*36372Ssklower 		 */
247*36372Ssklower 		INCSTAT(cns_cachemiss);
248*36372Ssklower 		if (flags & CLNP_NOCACHE) {
249*36372Ssklower 			clcp = &clc;
250*36372Ssklower 		} else {
251*36372Ssklower 			if (isop->isop_clnpcache == NULL) {
252*36372Ssklower 				/*
253*36372Ssklower 				 *	There is no clnpcache. Allocate an mbuf to hold one
254*36372Ssklower 				 */
255*36372Ssklower 				if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER))
256*36372Ssklower 					== NULL) {
257*36372Ssklower 					/*
258*36372Ssklower 					 *	No mbufs available. Pretend that we don't want
259*36372Ssklower 					 *	caching this time.
260*36372Ssklower 					 */
261*36372Ssklower 					IFDEBUG(D_OUTPUT)
262*36372Ssklower 						printf("clnp_output: no mbufs to allocate to cache\n");
263*36372Ssklower 					ENDDEBUG
264*36372Ssklower 					flags  |= CLNP_NOCACHE;
265*36372Ssklower 					clcp = &clc;
266*36372Ssklower 				} else {
267*36372Ssklower 					clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
268*36372Ssklower 				}
269*36372Ssklower 			} else {
270*36372Ssklower 				/*
271*36372Ssklower 				 *	A clnpcache mbuf exists. If the clc_hdr is not null,
272*36372Ssklower 				 *	we must free it, as a new one is about to be created.
273*36372Ssklower 				 */
274*36372Ssklower 				clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
275*36372Ssklower 				if (clcp->clc_hdr != NULL) {
276*36372Ssklower 					/*
277*36372Ssklower 					 *	The clc_hdr is not null but a clnpcache mbuf exists.
278*36372Ssklower 					 *	This means that there was a cache, but the existing
279*36372Ssklower 					 *	copy of the hdr is no longer valid. Free it now
280*36372Ssklower 					 *	before we lose the pointer to it.
281*36372Ssklower 					 */
282*36372Ssklower 					IFDEBUG(D_OUTPUT)
283*36372Ssklower 						printf("clnp_output: freeing old clc_hdr 0x%x\n",
284*36372Ssklower 						clcp->clc_hdr);
285*36372Ssklower 					ENDDEBUG
286*36372Ssklower 					m_free(clcp->clc_hdr);
287*36372Ssklower 					IFDEBUG(D_OUTPUT)
288*36372Ssklower 						printf("clnp_output: freed old clc_hdr (done)\n");
289*36372Ssklower 					ENDDEBUG
290*36372Ssklower 				}
291*36372Ssklower 			}
292*36372Ssklower 		}
293*36372Ssklower 		IFDEBUG(D_OUTPUT)
294*36372Ssklower 			printf("clnp_output: NEW clcp x%x\n",clcp);
295*36372Ssklower 		ENDDEBUG
296*36372Ssklower 		bzero((caddr_t)clcp, sizeof(struct clnp_cache));
297*36372Ssklower 
298*36372Ssklower 		if (isop->isop_optindex)
299*36372Ssklower 			oidx = mtod(isop->isop_optindex, struct clnp_optidx *);
300*36372Ssklower 
301*36372Ssklower 		/*
302*36372Ssklower 		 *	Don't allow packets with security, quality of service,
303*36372Ssklower 		 *	priority, or error report options to be sent.
304*36372Ssklower 		 */
305*36372Ssklower 		if ((isop->isop_options) && (oidx)) {
306*36372Ssklower 			if ((oidx->cni_securep) ||
307*36372Ssklower 				(oidx->cni_priorp) ||
308*36372Ssklower 				(oidx->cni_qos_formatp) ||
309*36372Ssklower 				(oidx->cni_er_reason != ER_INVALREAS)) {
310*36372Ssklower 				IFDEBUG(D_OUTPUT)
311*36372Ssklower 					printf("clnp_output: pkt dropped - option unsupported\n");
312*36372Ssklower 				ENDDEBUG
313*36372Ssklower 				m_freem(m0);
314*36372Ssklower 				return(EINVAL);
315*36372Ssklower 			}
316*36372Ssklower 		}
317*36372Ssklower 
318*36372Ssklower 		/*
319*36372Ssklower 		 *	Don't allow any invalid flags to be set
320*36372Ssklower 		 */
321*36372Ssklower 		if ((flags & (CLNP_VFLAGS)) != flags) {
322*36372Ssklower 			IFDEBUG(D_OUTPUT)
323*36372Ssklower 				printf("clnp_output: packet dropped - flags unsupported\n");
324*36372Ssklower 			ENDDEBUG
325*36372Ssklower 			m_freem(m0);
326*36372Ssklower 			return(EINVAL);
327*36372Ssklower 		}
328*36372Ssklower 
329*36372Ssklower 		/*
330*36372Ssklower 		 *	Don't allow funny lengths on dst; src may be zero in which
331*36372Ssklower 		 *	case we insert the source address based upon the interface
332*36372Ssklower 		 */
333*36372Ssklower 		if ((src->isoa_len > sizeof(struct iso_addr)) ||
334*36372Ssklower 			(dst->isoa_len == 0) ||
335*36372Ssklower 			(dst->isoa_len > sizeof(struct iso_addr))) {
336*36372Ssklower 			m_freem(m0);
337*36372Ssklower 			return(ENAMETOOLONG);
338*36372Ssklower 		}
339*36372Ssklower 
340*36372Ssklower 		/*
341*36372Ssklower 		 *	Grab mbuf to contain header
342*36372Ssklower 		 */
343*36372Ssklower 		MGET(m, M_DONTWAIT, MT_HEADER);
344*36372Ssklower 		if (m == 0) {
345*36372Ssklower 			m_freem(m0);
346*36372Ssklower 			return(ENOBUFS);
347*36372Ssklower 		}
348*36372Ssklower 
349*36372Ssklower 		m->m_next = m0;
350*36372Ssklower 		clnp = mtod(m, struct clnp_fixed *);
351*36372Ssklower 		clcp->clc_segoff = 0;
352*36372Ssklower 
353*36372Ssklower 		/*
354*36372Ssklower 		 *	Fill in all of fixed hdr except lengths and checksum
355*36372Ssklower 		 */
356*36372Ssklower 		if (flags & CLNP_SEND_RAW) {
357*36372Ssklower 			*clnp = raw_template;
358*36372Ssklower 		} else if (flags & CLNP_ECHO) {
359*36372Ssklower 			*clnp = echo_template;
360*36372Ssklower 		} else {
361*36372Ssklower 			*clnp = dt_template;
362*36372Ssklower 		}
363*36372Ssklower 		if (flags & CLNP_NO_SEG)
364*36372Ssklower 			clnp->cnf_seg_ok = 0;
365*36372Ssklower 		if (flags & CLNP_NO_ER)
366*36372Ssklower 			clnp->cnf_err_ok = 0;
367*36372Ssklower 
368*36372Ssklower 		/*
369*36372Ssklower 		 *	Route packet; special case for source rt
370*36372Ssklower 		 */
371*36372Ssklower 		if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) {
372*36372Ssklower 			IFDEBUG(D_OUTPUT)
373*36372Ssklower 				printf("clnp_output: calling clnp_srcroute\n");
374*36372Ssklower 			ENDDEBUG
375*36372Ssklower 			error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route,
376*36372Ssklower 				&clcp->clc_firsthop, &clcp->clc_ifp, dst);
377*36372Ssklower 		} else {
378*36372Ssklower 			IFDEBUG(D_OUTPUT)
379*36372Ssklower 			ENDDEBUG
380*36372Ssklower 			error = clnp_route(dst, &isop->isop_route, flags,
381*36372Ssklower 				&clcp->clc_firsthop, &clcp->clc_ifp);
382*36372Ssklower 		}
383*36372Ssklower 		if (error != 0) {
384*36372Ssklower 			IFDEBUG(D_OUTPUT)
385*36372Ssklower 				printf("clnp_output: route failed, errno %d\n", error);
386*36372Ssklower 				printf("@clcp:\n");
387*36372Ssklower 				dump_buf(clcp, sizeof (struct clnp_cache));
388*36372Ssklower 			ENDDEBUG
389*36372Ssklower 			goto bad;
390*36372Ssklower 		}
391*36372Ssklower 
392*36372Ssklower 		IFDEBUG(D_OUTPUT)
393*36372Ssklower 			printf("clnp_output: packet routed to %s\n",
394*36372Ssklower 				clnp_iso_addrp(
395*36372Ssklower 					&((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr));
396*36372Ssklower 		ENDDEBUG
397*36372Ssklower 
398*36372Ssklower 		/*
399*36372Ssklower 		 *	If src address is not yet specified, use address of
400*36372Ssklower 		 *	interface. NOTE: this will now update the laddr field in
401*36372Ssklower 		 *	the isopcb. Is this desirable? RAH?
402*36372Ssklower 		 */
403*36372Ssklower 		if (src->isoa_len == 0) {
404*36372Ssklower 			src = clnp_srcaddr(clcp->clc_ifp,
405*36372Ssklower 				&((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr);
406*36372Ssklower 			if (src == NULL) {
407*36372Ssklower 				error = ENETDOWN;
408*36372Ssklower 				goto bad;
409*36372Ssklower 			}
410*36372Ssklower 			IFDEBUG(D_OUTPUT)
411*36372Ssklower 				printf("clnp_output: new src %s\n", clnp_iso_addrp(src));
412*36372Ssklower 			ENDDEBUG
413*36372Ssklower 		}
414*36372Ssklower 
415*36372Ssklower 		/*
416*36372Ssklower 		 *	Insert the source and destination address,
417*36372Ssklower 		 */
418*36372Ssklower 		hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
419*36372Ssklower 		CLNP_INSERT_ADDR(hoff, dst);
420*36372Ssklower 		CLNP_INSERT_ADDR(hoff, src);
421*36372Ssklower 
422*36372Ssklower 		/*
423*36372Ssklower 		 *	Leave room for the segment part, if segmenting is selected
424*36372Ssklower 		 */
425*36372Ssklower 		if (clnp->cnf_seg_ok) {
426*36372Ssklower 			clcp->clc_segoff = hoff - (caddr_t)clnp;
427*36372Ssklower 			hoff += sizeof(struct clnp_segment);
428*36372Ssklower 		}
429*36372Ssklower 
430*36372Ssklower 		clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp);
431*36372Ssklower 
432*36372Ssklower 		/*
433*36372Ssklower 		 *	If an options mbuf is present, concatenate a copy to the hdr mbuf.
434*36372Ssklower 		 */
435*36372Ssklower 		if (isop->isop_options) {
436*36372Ssklower 			struct mbuf *opt_copy = m_copy(isop->isop_options, 0, M_COPYALL);
437*36372Ssklower 			if (opt_copy == NULL) {
438*36372Ssklower 				error = ENOBUFS;
439*36372Ssklower 				goto bad;
440*36372Ssklower 			}
441*36372Ssklower 			/* Link in place */
442*36372Ssklower 			opt_copy->m_next = m->m_next;
443*36372Ssklower 			m->m_next = opt_copy;
444*36372Ssklower 
445*36372Ssklower 			/* update size of header */
446*36372Ssklower 			clnp->cnf_hdr_len += opt_copy->m_len;
447*36372Ssklower 		}
448*36372Ssklower 
449*36372Ssklower 		/*
450*36372Ssklower 		 *	Now set up the cache entry in the pcb
451*36372Ssklower 		 */
452*36372Ssklower 		if ((flags & CLNP_NOCACHE) == 0) {
453*36372Ssklower 			if ((clcp->clc_hdr = m_copy(m, 0, clnp->cnf_hdr_len)) != NULL) {
454*36372Ssklower 				bcopy((caddr_t)dst, (caddr_t)&clcp->clc_dst,
455*36372Ssklower 					sizeof(struct iso_addr));
456*36372Ssklower 				clcp->clc_flags = flags;
457*36372Ssklower 				clcp->clc_options = isop->isop_options;
458*36372Ssklower 			}
459*36372Ssklower 		}
460*36372Ssklower 	}
461*36372Ssklower 	INCSTAT(cns_sent);
462*36372Ssklower 	/*
463*36372Ssklower 	 *	If small enough for interface, send directly
464*36372Ssklower 	 *	Fill in segmentation part of hdr if using the full protocol
465*36372Ssklower 	 */
466*36372Ssklower 	if ((total_len = clnp->cnf_hdr_len + datalen) <= SN_MTU(clcp->clc_ifp)) {
467*36372Ssklower 		if (clnp->cnf_seg_ok) {
468*36372Ssklower 			struct clnp_segment	seg_part;		/* segment part of hdr */
469*36372Ssklower 			seg_part.cng_id = htons(clnp_id++);
470*36372Ssklower 			seg_part.cng_off = htons(0);
471*36372Ssklower 			seg_part.cng_tot_len = htons(total_len);
472*36372Ssklower 			(void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff,
473*36372Ssklower 				sizeof(seg_part));
474*36372Ssklower 		}
475*36372Ssklower 		HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len);
476*36372Ssklower 
477*36372Ssklower 		/*
478*36372Ssklower 		 *	Compute clnp checksum (on header only)
479*36372Ssklower 		 */
480*36372Ssklower 		if (flags & CLNP_NO_CKSUM) {
481*36372Ssklower 			HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
482*36372Ssklower 		} else {
483*36372Ssklower 			iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
484*36372Ssklower 		}
485*36372Ssklower 
486*36372Ssklower 		IFDEBUG(D_DUMPOUT)
487*36372Ssklower 			struct mbuf *mdump = m;
488*36372Ssklower 			printf("clnp_output: sending dg:\n");
489*36372Ssklower 			while (mdump != NULL) {
490*36372Ssklower 				dump_buf(mtod(mdump, caddr_t), mdump->m_len);
491*36372Ssklower 				mdump = mdump->m_next;
492*36372Ssklower 			}
493*36372Ssklower 		ENDDEBUG
494*36372Ssklower 
495*36372Ssklower 		error = SN_OUTPUT(clcp, m);
496*36372Ssklower 		goto done;
497*36372Ssklower 	} else {
498*36372Ssklower 		/*
499*36372Ssklower 		 * Too large for interface; fragment if possible.
500*36372Ssklower 		 */
501*36372Ssklower 		error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop, total_len,
502*36372Ssklower 			clcp->clc_segoff, flags);
503*36372Ssklower 		goto done;
504*36372Ssklower 	}
505*36372Ssklower bad:
506*36372Ssklower 	m_freem(m);
507*36372Ssklower 
508*36372Ssklower done:
509*36372Ssklower 	return(error);
510*36372Ssklower }
511*36372Ssklower 
512*36372Ssklower int clnp_ctloutput()
513*36372Ssklower {
514*36372Ssklower }
515*36372Ssklower 
516*36372Ssklower #endif ISO
517