1147039Ssam/*	$NetBSD: clnp_subr.c,v 1.32 2009/03/18 15:14:32 cegger Exp $	*/
2147039Ssam
3189263Ssam/*-
4172319Ssam * Copyright (c) 1991, 1993
5234711Sbschmidt *	The Regents of the University of California.  All rights reserved.
6147039Ssam *
7147039Ssam * Redistribution and use in source and binary forms, with or without
8234711Sbschmidt * modification, are permitted provided that the following conditions
9234711Sbschmidt * are met:
10234711Sbschmidt * 1. Redistributions of source code must retain the above copyright
11234711Sbschmidt *    notice, this list of conditions and the following disclaimer.
12234711Sbschmidt * 2. Redistributions in binary form must reproduce the above copyright
13234711Sbschmidt *    notice, this list of conditions and the following disclaimer in the
14234711Sbschmidt *    documentation and/or other materials provided with the distribution.
15234711Sbschmidt * 3. Neither the name of the University nor the names of its contributors
16234711Sbschmidt *    may be used to endorse or promote products derived from this software
17234711Sbschmidt *    without specific prior written permission.
18234711Sbschmidt *
19234711Sbschmidt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20234711Sbschmidt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21234711Sbschmidt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22234711Sbschmidt * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23234711Sbschmidt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24234711Sbschmidt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25234711Sbschmidt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26234711Sbschmidt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27234711Sbschmidt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28234711Sbschmidt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29234711Sbschmidt * SUCH DAMAGE.
30234711Sbschmidt *
31234711Sbschmidt *	@(#)clnp_subr.c	8.1 (Berkeley) 6/10/93
32234711Sbschmidt */
33234711Sbschmidt
34234711Sbschmidt/***********************************************************
35234711Sbschmidt		Copyright IBM Corporation 1987
36234711Sbschmidt
37234711Sbschmidt                      All Rights Reserved
38234711Sbschmidt
39234711SbschmidtPermission to use, copy, modify, and distribute this software and its
40234711Sbschmidtdocumentation for any purpose and without fee is hereby granted,
41234711Sbschmidtprovided that the above copyright notice appear in all copies and that
42234711Sbschmidtboth that copyright notice and this permission notice appear in
43234711Sbschmidtsupporting documentation, and that the name of IBM not be
44234711Sbschmidtused in advertising or publicity pertaining to distribution of the
45234711Sbschmidtsoftware without specific, written prior permission.
46234711Sbschmidt
47234711SbschmidtIBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48234711SbschmidtALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49234711SbschmidtIBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50234711SbschmidtANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51234711SbschmidtWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52234711SbschmidtARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53234711SbschmidtSOFTWARE.
54234711Sbschmidt
55234711Sbschmidt******************************************************************/
56234711Sbschmidt
57234711Sbschmidt/*
58147039Ssam * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
59147453Ssam */
60147453Ssam
61173530Ssam#include <sys/cdefs.h>
62173530Ssam__KERNEL_RCSID(0, "$NetBSD: clnp_subr.c,v 1.32 2009/03/18 15:14:32 cegger Exp $");
63189263Ssam
64173530Ssam#include "opt_iso.h"
65173530Ssam
66173530Ssam#ifdef ISO
67234711Sbschmidt
68234711Sbschmidt#include <sys/param.h>
69234711Sbschmidt#include <sys/mbuf.h>
70234711Sbschmidt#include <sys/domain.h>
71234711Sbschmidt#include <sys/protosw.h>
72172319Ssam#include <sys/socket.h>
73172319Ssam#include <sys/socketvar.h>
74172319Ssam#include <sys/errno.h>
75214735Srpaulo#include <sys/time.h>
76214735Srpaulo#include <sys/systm.h>
77214735Srpaulo
78172319Ssam#include <net/if.h>
79172319Ssam#include <net/route.h>
80189263Ssam#include <net/if_dl.h>
81189263Ssam
82189263Ssam#include <netiso/iso.h>
83189263Ssam#include <netiso/iso_var.h>
84172319Ssam#include <netiso/iso_pcb.h>
85172319Ssam#include <netiso/iso_snpac.h>
86172319Ssam#include <netiso/clnp.h>
87234711Sbschmidt#include <netiso/clnp_stat.h>
88234711Sbschmidt#include <netiso/argo_debug.h>
89234711Sbschmidt#include <netiso/esis.h>
90234711Sbschmidt
91234711Sbschmidt/*
92234711Sbschmidt * FUNCTION:		clnp_data_ck
93234711Sbschmidt *
94234711Sbschmidt * PURPOSE:		Check that the amount of data in the mbuf chain is
95234711Sbschmidt *			at least as much as the clnp header would have us
96234711Sbschmidt *			expect. Trim mbufs if longer than expected, drop
97234711Sbschmidt *			packet if shorter than expected.
98234711Sbschmidt *
99234711Sbschmidt * RETURNS:		success - ptr to mbuf chain
100234711Sbschmidt *			failure - 0
101234711Sbschmidt *
102234711Sbschmidt * SIDE EFFECTS:
103234711Sbschmidt *
104234711Sbschmidt * NOTES:
105234711Sbschmidt */
106234711Sbschmidtstruct mbuf    *
107234711Sbschmidtclnp_data_ck(
108172319Ssam	struct mbuf *m,		/* ptr to mbuf chain containing hdr & data */
109172319Ssam	int	length)		/* length (in bytes) of packet */
110172319Ssam{
111234711Sbschmidt	int    len;		/* length of data */
112234711Sbschmidt	struct mbuf *mhead;	/* ptr to head of chain */
113172319Ssam
114172319Ssam	len = -length;
115172319Ssam	mhead = m;
116172319Ssam	for (;;) {
117234711Sbschmidt		len += m->m_len;
118172319Ssam		if (m->m_next == 0)
119172319Ssam			break;
120172319Ssam		m = m->m_next;
121234711Sbschmidt	}
122234711Sbschmidt	if (len != 0) {
123234711Sbschmidt		if (len < 0) {
124234711Sbschmidt			INCSTAT(cns_toosmall);
125172319Ssam			clnp_discard(mhead, GEN_INCOMPLETE);
126172319Ssam			return 0;
127172319Ssam		}
128172319Ssam		if (len <= m->m_len)
129234711Sbschmidt			m->m_len -= len;
130234711Sbschmidt		else
131172319Ssam			m_adj(mhead, -len);
132234711Sbschmidt	}
133172319Ssam	return mhead;
134172319Ssam}
135172319Ssam
136234711Sbschmidt#ifdef notdef
137234711Sbschmidt/*
138172319Ssam * FUNCTION:		clnp_extract_addr
139172319Ssam *
140172319Ssam * PURPOSE:		Extract the source and destination address from the
141234711Sbschmidt *			supplied buffer. Place them in the supplied address buffers.
142234711Sbschmidt *			If insufficient data is supplied, then fail.
143172319Ssam *
144172319Ssam * RETURNS:		success - Address of first byte in the packet past
145172319Ssam *			the address part.
146172319Ssam *			failure - 0
147172319Ssam *
148172319Ssam * SIDE EFFECTS:
149172319Ssam *
150172319Ssam * NOTES:
151234711Sbschmidt */
152234711Sbschmidtvoid *
153172319Ssamclnp_extract_addr(
154172319Ssam	void *        bufp,	/* ptr to buffer containing addresses */
155234711Sbschmidt	int             buflen,	/* length of buffer */
156234711Sbschmidt	struct iso_addr *srcp,	/* ptr to source address buffer */
157234711Sbschmidt	struct iso_addr *destp)	/* ptr to destination address
158234711Sbschmidt						 * buffer */
159234711Sbschmidt{
160234711Sbschmidt	size_t             len;	/* argument to memcpy */
161234711Sbschmidt
162234711Sbschmidt	/*
163172319Ssam	 * check that we have enough data. Plus1 is for length octet
164172319Ssam	 */
165172319Ssam	len = (u_char)*bufp++;
166172319Ssam	if (len > buflen)
167172319Ssam		return NULL;
168172319Ssam	destp->isoa_len = len;
169171326Ssam	(void)memcpy(destp, bufp, len);
170171326Ssam	buflen -= len;
171171326Ssam	bufp += len;
172172319Ssam
173172319Ssam	/*
174147039Ssam	 * check that we have enough data. Plus1 is for length octet
175147039Ssam	 */
176	len = (u_char)*bufp++;
177	if (len > buflen)
178		return NULL;
179	srcp->isoa_len = len;
180	(void)memcpy(srcp, bufp, len);
181	bufp += len;
182
183	/*
184	 *	Insure that the addresses make sense
185	 */
186	if (iso_ck_addr(srcp) && iso_ck_addr(destp))
187		return bufp;
188	else
189		return NULL;
190}
191#endif				/* notdef */
192
193/*
194 * FUNCTION:		clnp_ours
195 *
196 * PURPOSE:		Decide whether the supplied packet is destined for
197 *			us, or that it should be forwarded on.
198 *
199 * RETURNS:		packet is for us - 1
200 *			packet is not for us - 0
201 *
202 * SIDE EFFECTS:
203 *
204 * NOTES:
205 */
206int
207clnp_ours(
208	struct iso_addr *dst)	/* ptr to destination address */
209{
210	struct iso_ifaddr *ia;	/* scan through interface addresses */
211
212	for (ia = iso_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next) {
213#ifdef ARGO_DEBUG
214		if (argo_debug[D_ROUTE]) {
215			printf("clnp_ours: ia_sis %p, dst %p\n",
216			    &ia->ia_addr, dst);
217		}
218#endif
219		/*
220		 * XXX Warning:
221		 * We are overloading siso_tlen in the if's address, as an nsel length.
222		 */
223		if (dst->isoa_len == ia->ia_addr.siso_nlen &&
224		    memcmp((void *) ia->ia_addr.siso_addr.isoa_genaddr,
225			 (void *) dst->isoa_genaddr,
226			 ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0)
227			return 1;
228	}
229	return 0;
230}
231
232/* Dec bit set if ifp qlen is greater than congest_threshold */
233int             congest_threshold = 0;
234
235/*
236 * FUNCTION:		clnp_forward
237 *
238 * PURPOSE:		Forward the datagram passed
239 *			clnpintr guarantees that the header will be
240 *			contigious (a cluster mbuf will be used if necessary).
241 *
242 *			If oidx is NULL, no options are present.
243 *
244 * RETURNS:		nothing
245 *
246 * SIDE EFFECTS:
247 *
248 * NOTES:
249 */
250void
251clnp_forward(
252	struct mbuf    *m,		/* pkt to forward */
253	int             len,		/* length of pkt */
254	struct iso_addr *dst,		/* destination address */
255	struct clnp_optidx *oidx,	/* option index */
256	int             seg_off,	/* offset of segmentation part */
257	struct snpa_hdr *inbound_shp)	/* subnetwork header of inbound
258					 * packet */
259{
260	struct clnp_fixed *clnp;	/* ptr to fixed part of header */
261	int             error;		/* return value of route function */
262	const struct sockaddr *next_hop;	/* next hop for dgram */
263	struct ifnet   *ifp;		/* ptr to outgoing interface */
264	struct iso_ifaddr *ia = 0;	/* ptr to iso name for ifp */
265	struct route route;		/* filled in by clnp_route */
266	struct rtentry *rt;
267	extern int      iso_systype;
268
269	clnp = mtod(m, struct clnp_fixed *);
270	memset((void *) & route, 0, sizeof(route));	/* MUST be done before
271							 * "bad:" */
272
273	/*
274	 *	Don't forward multicast or broadcast packets
275	 */
276	if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
277#ifdef ARGO_DEBUG
278		if (argo_debug[D_FORWARD]) {
279			printf("clnp_forward: dropping multicast packet\n");
280		}
281#endif
282		clnp->cnf_type &= ~CNF_ERR_OK;	/* so we don't generate an ER */
283		clnp_discard(m, 0);
284		INCSTAT(cns_cantforward);
285		goto done;
286	}
287#ifdef ARGO_DEBUG
288	if (argo_debug[D_FORWARD]) {
289		printf("clnp_forward: %d bytes, to %s, options %p\n", len,
290		       clnp_iso_addrp(dst), oidx);
291	}
292#endif
293
294	/*
295	 *	Decrement ttl, and if zero drop datagram
296	 *	Can't compare ttl as less than zero 'cause its a unsigned
297	 */
298	if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
299#ifdef ARGO_DEBUG
300		if (argo_debug[D_FORWARD]) {
301			printf("clnp_forward: discarding datagram because ttl is zero\n");
302		}
303#endif
304		INCSTAT(cns_ttlexpired);
305		clnp_discard(m, TTL_EXPTRANSIT);
306		goto done;
307	}
308	/*
309	 *	Route packet; special case for source rt
310	 */
311	if CLNPSRCRT_VALID
312		(oidx) {
313		/*
314		 *	Update src route first
315		 */
316		clnp_update_srcrt(m, oidx);
317		error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
318	} else {
319		error = clnp_route(dst, &route, 0, &next_hop, &ia);
320	}
321	if (error || ia == 0) {
322#ifdef ARGO_DEBUG
323		if (argo_debug[D_FORWARD]) {
324			printf("clnp_forward: can't route packet (errno %d)\n", error);
325		}
326#endif
327		clnp_discard(m, ADDR_DESTUNREACH);
328		INCSTAT(cns_cantforward);
329		goto done;
330	}
331	ifp = ia->ia_ifp;
332
333#ifdef ARGO_DEBUG
334	if (argo_debug[D_FORWARD]) {
335		printf("clnp_forward: packet routed to %s\n",
336		       clnp_iso_addrp(&satocsiso(next_hop)->siso_addr));
337	}
338#endif
339
340	INCSTAT(cns_forward);
341
342	/*
343	 *	If we are an intermediate system and
344	 *	we are routing outbound on the same ifp that the packet
345	 *	arrived upon, and we know the next hop snpa,
346	 *	then generate a redirect request
347	 */
348	if ((iso_systype & SNPA_IS) && (inbound_shp) &&
349	    (ifp == inbound_shp->snh_ifp))
350		esis_rdoutput(inbound_shp, m, oidx, dst, rtcache_validate(&route));
351	/*
352	 *	If options are present, update them
353	 */
354	if (oidx) {
355		struct iso_addr *mysrc = &ia->ia_addr.siso_addr;
356		if (mysrc == NULL) {
357			clnp_discard(m, ADDR_DESTUNREACH);
358			INCSTAT(cns_cantforward);
359			clnp_stat.cns_forward--;
360			goto done;
361		} else {
362			(void) clnp_dooptions(m, oidx, ifp, mysrc);
363		}
364	}
365#ifdef	DECBIT
366	if (ifp->if_snd.ifq_len > congest_threshold) {
367		/*
368		 *	Congestion! Set the Dec Bit and thank Dave Oran
369		 */
370#ifdef ARGO_DEBUG
371		if (argo_debug[D_FORWARD]) {
372			printf("clnp_forward: congestion experienced\n");
373		}
374#endif
375		if ((oidx) && (oidx->cni_qos_formatp)) {
376			char *         qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
377			u_char          qos = *qosp;
378#ifdef ARGO_DEBUG
379			if (argo_debug[D_FORWARD]) {
380				printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
381			}
382#endif
383			if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
384				qos |= CLNPOVAL_CONGESTED;
385				INCSTAT(cns_congest_set);
386				*qosp = qos;
387			}
388		}
389	}
390#endif				/* DECBIT */
391
392	/*
393	 *	Dispatch the datagram if it is small enough, otherwise fragment
394	 */
395	if ((rt = rtcache_validate(&route)) == NULL)
396		;
397	else if (len <= SN_MTU(ifp, rt)) {
398		iso_gen_csum(m, CLNP_CKSUM_OFF, (int) clnp->cnf_hdr_len);
399		(void) (*ifp->if_output) (ifp, m, next_hop, rt);
400	} else {
401		(void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */ 0, rt);
402	}
403
404done:
405	/*
406	 *	Free route
407	 */
408	rtcache_free(&route);
409}
410
411#ifdef	notdef
412/*
413 * FUNCTION:		clnp_insert_addr
414 *
415 * PURPOSE:			Insert the address part into a clnp datagram.
416 *
417 * RETURNS:			Address of first byte after address part in datagram.
418 *
419 * SIDE EFFECTS:
420 *
421 * NOTES:			Assume that there is enough space for the address part.
422 */
423void *
424clnp_insert_addr(
425	void *        bufp,	/* address of where addr part goes */
426	struct iso_addr *srcp,	/* ptr to src addr */
427	struct iso_addr *dstp)	/* ptr to dst addr */
428{
429	*bufp++ = dstp->isoa_len;
430	(void)memcpy(bufp, dstp, dstp->isoa_len);
431	bufp += dstp->isoa_len;
432
433	*bufp++ = srcp->isoa_len;
434	(void)memcpy(bufp, srcp, srcp->isoa_len);
435	bufp += srcp->isoa_len;
436
437	return bufp;
438}
439
440#endif				/* notdef */
441
442/*
443 * FUNCTION:		clnp_route
444 *
445 * PURPOSE:		Route a clnp datagram to the first hop toward its
446 *			destination. In many cases, the first hop will be
447 *			the destination. The address of a route
448 *			is specified. If a routing entry is present in
449 *			that route, and it is still up to the same destination,
450 *			then no further action is necessary. Otherwise, a
451 *			new routing entry will be allocated.
452 *
453 * RETURNS:		route found - 0
454 *			unix error code
455 *
456 * SIDE EFFECTS:
457 *
458 * NOTES:		It is up to the caller to free the routing entry
459 *			allocated in route.
460 */
461int
462clnp_route(
463	struct iso_addr *dst,		/* ptr to datagram destination */
464	struct route *ro,		/* existing route structure */
465	int             flags,		/* flags for routing */
466	const struct sockaddr **first_hop,	/* result: fill in with ptr to
467					 	 * firsthop */
468	struct iso_ifaddr **ifa)	/* result: fill in with ptr to ifa */
469{
470	struct rtentry *rt;
471	int rc;
472	union {
473		struct sockaddr		dst;
474		struct sockaddr_iso	dsti;
475	} u;
476
477	if (flags & SO_DONTROUTE) {
478		struct iso_ifaddr *ia;
479
480		if ((rc = sockaddr_iso_init(&u.dsti, dst)) != 0)
481			return rc;
482		rtcache_setdst(ro, &u.dst);
483
484		if (rtcache_getdst(ro) == NULL)
485			return EADDRNOTAVAIL;
486		ia = iso_localifa(satocsiso(rtcache_getdst(ro)));
487		if (ia == NULL)
488			return EADDRNOTAVAIL;
489		if (ifa != NULL)
490			*ifa = ia;
491		if (first_hop != NULL)
492			*first_hop = rtcache_getdst(ro);
493		return 0;
494	}
495
496	/* set up new route structure */
497	if ((rc = sockaddr_iso_init(&u.dsti, dst)) != 0)
498		return rc;
499	if ((rt = rtcache_lookup(ro, &u.dst)) == NULL) {
500		rtcache_free(ro);
501		return ENETUNREACH;
502	}
503	rt->rt_use++;
504	if (ifa != NULL)
505		if ((*ifa = (struct iso_ifaddr *)rt->rt_ifa) == NULL)
506			panic("clnp_route");
507	if (first_hop != NULL) {
508		if (rt->rt_flags & RTF_GATEWAY)
509			*first_hop = rt->rt_gateway;
510		else
511			*first_hop = rtcache_getdst(ro);
512	}
513	return 0;
514}
515
516/*
517 * FUNCTION:		clnp_srcroute
518 *
519 * PURPOSE:		Source route the datagram. If complete source
520 *			routing is specified but not possible, then
521 *			return an error. If src routing is terminated, then
522 *			try routing on destination.
523 *			Usage of first_hop,
524 *			ifp, and error return is identical to clnp_route.
525 *
526 * RETURNS:		0 or unix error code
527 *
528 * SIDE EFFECTS:
529 *
530 * NOTES:		Remember that option index pointers are really
531 *			offsets from the beginning of the mbuf.
532 */
533int
534clnp_srcroute(
535	struct mbuf *options,		/* ptr to options */
536	struct clnp_optidx *oidx,	/* index to options */
537	struct route *ro,		/* route structure */
538	const struct sockaddr **first_hop,	/* RETURN: fill in with ptr to
539						 * firsthop */
540	struct iso_ifaddr **ifa,	/* RETURN: fill in with ptr to ifa */
541	struct iso_addr *final_dst)	/* final destination */
542{
543	struct iso_addr dst;	/* first hop specified by src rt */
544	int             error = 0;	/* return code */
545
546	/*
547	 *	Check if we have run out of routes
548	 *	If so, then try to route on destination.
549	 */
550	if CLNPSRCRT_TERM
551		(oidx, options) {
552		dst.isoa_len = final_dst->isoa_len;
553		if (sizeof(dst.isoa_genaddr) < (size_t)dst.isoa_len)
554			return EINVAL;
555		(void)memcpy(dst.isoa_genaddr, final_dst->isoa_genaddr,
556		    (size_t)dst.isoa_len);
557	} else {
558		/*
559		 * setup dst based on src rt specified
560		 */
561		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
562		if (sizeof(dst.isoa_genaddr) < (unsigned)dst.isoa_len)
563			return EINVAL;
564		(void)memcpy(dst.isoa_genaddr, CLNPSRCRT_CADDR(oidx, options),
565		    (size_t)dst.isoa_len);
566	}
567
568	/*
569	 *	try to route it
570	 */
571	error = clnp_route(&dst, ro, 0, first_hop, ifa);
572	if (error != 0)
573		return error;
574
575	/*
576	 *	If complete src rt, first hop must be equal to dst
577	 */
578	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
579	    (!iso_addrmatch1(&satocsiso(*first_hop)->siso_addr, &dst))) {
580#ifdef ARGO_DEBUG
581		if (argo_debug[D_OPTIONS]) {
582			printf("clnp_srcroute: complete src route failed\n");
583		}
584#endif
585		return EHOSTUNREACH;	/* RAH? would like ESRCRTFAILED */
586	}
587	return error;
588}
589
590/*
591 * FUNCTION:		clnp_echoreply
592 *
593 * PURPOSE:			generate an echo reply packet and transmit
594 *
595 * RETURNS:			result of clnp_output
596 *
597 * SIDE EFFECTS:
598 */
599int
600clnp_echoreply(
601    struct mbuf    *ec_m,		/* echo request */
602    int             ec_len,		/* length of ec */
603    struct sockaddr_iso *ec_src,	/* src of ec */
604    struct sockaddr_iso *ec_dst,	/* destination of ec (i.e., us) */
605    struct clnp_optidx *ec_oidxp) /* options index to ec packet */
606{
607	struct isopcb   isopcb;
608	int             flags = CLNP_NOCACHE | CLNP_ECHOR;
609	int             ret;
610
611	/* fill in fake isopcb to pass to output function */
612	memset(&isopcb, 0, sizeof(isopcb));
613	isopcb.isop_laddr = ec_dst;
614	isopcb.isop_faddr = ec_src;
615
616	/*
617	 * forget copying the options for now. If implemented, need only copy
618	 * record route option, but it must be reset to zero length
619	 */
620
621	ret = clnp_output(ec_m, &isopcb, ec_len, flags);
622
623#ifdef ARGO_DEBUG
624	if (argo_debug[D_OUTPUT]) {
625		printf("clnp_echoreply: output returns %d\n", ret);
626	}
627#endif
628	return ret;
629}
630
631/*
632 * FUNCTION:		clnp_badmtu
633 *
634 * PURPOSE:		print notice of route with mtu not initialized.
635 *
636 * RETURNS:		mtu of ifp.
637 *
638 * SIDE EFFECTS:	prints notice, slows down system.
639 */
640int
641clnp_badmtu(
642	struct ifnet   *ifp,	/* outgoing interface */
643	struct rtentry *rt,	/* dst route */
644	int             line,	/* where the dirty deed occurred */
645	const char     *file)	/* where the dirty deed occurred */
646{
647	printf("sending on route %p with no mtu, line %d of file %s\n",
648	    rt, line, file);
649#ifdef ARGO_DEBUG
650	printf("route dst is ");
651	dump_isoaddr(satocsiso(rt_getkey(rt)));
652#endif
653	return ifp->if_mtu;
654}
655
656/*
657 * FUNCTION:		clnp_ypocb - backwards bcopy
658 *
659 * PURPOSE:		bcopy starting at end of src rather than beginning.
660 *
661 * RETURNS:		none
662 *
663 * SIDE EFFECTS:
664 *
665 * NOTES:		No attempt has been made to make this efficient
666 */
667void
668clnp_ypocb(
669	void *        from,	/* src buffer */
670	void *        to,	/* dst buffer */
671	u_int           len)	/* number of bytes */
672{
673	while (len--)
674		*((char *)to + len) = *((char *)from + len);
675}
676#endif				/* ISO */
677