xref: /csrg-svn/sys/netiso/clnp_subr.c (revision 63222)
149267Sbostic /*-
2*63222Sbostic  * Copyright (c) 1991, 1993
3*63222Sbostic  *	The Regents of the University of California.  All rights reserved.
449267Sbostic  *
549267Sbostic  * %sccs.include.redist.c%
649267Sbostic  *
7*63222Sbostic  *	@(#)clnp_subr.c	8.1 (Berkeley) 06/10/93
849267Sbostic  */
949267Sbostic 
1036375Ssklower /***********************************************************
1136375Ssklower 		Copyright IBM Corporation 1987
1236375Ssklower 
1336375Ssklower                       All Rights Reserved
1436375Ssklower 
1536375Ssklower Permission to use, copy, modify, and distribute this software and its
1636375Ssklower documentation for any purpose and without fee is hereby granted,
1736375Ssklower provided that the above copyright notice appear in all copies and that
1836375Ssklower both that copyright notice and this permission notice appear in
1936375Ssklower supporting documentation, and that the name of IBM not be
2036375Ssklower used in advertising or publicity pertaining to distribution of the
2136375Ssklower software without specific, written prior permission.
2236375Ssklower 
2336375Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436375Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536375Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636375Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736375Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836375Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936375Ssklower SOFTWARE.
3036375Ssklower 
3136375Ssklower ******************************************************************/
3236375Ssklower 
3336375Ssklower /*
3436375Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536375Ssklower  */
3636770Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */
3736770Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */
3836375Ssklower 
3936375Ssklower #ifdef ISO
4036375Ssklower 
4156533Sbostic #include <sys/param.h>
4256533Sbostic #include <sys/mbuf.h>
4356533Sbostic #include <sys/domain.h>
4456533Sbostic #include <sys/protosw.h>
4556533Sbostic #include <sys/socket.h>
4656533Sbostic #include <sys/socketvar.h>
4756533Sbostic #include <sys/errno.h>
4856533Sbostic #include <sys/time.h>
4936375Ssklower 
5056533Sbostic #include <net/if.h>
5156533Sbostic #include <net/route.h>
5256533Sbostic #include <net/if_dl.h>
5336375Ssklower 
5456533Sbostic #include <netiso/iso.h>
5556533Sbostic #include <netiso/iso_var.h>
5656533Sbostic #include <netiso/iso_pcb.h>
5756533Sbostic #include <netiso/iso_snpac.h>
5856533Sbostic #include <netiso/clnp.h>
5956533Sbostic #include <netiso/clnp_stat.h>
6056533Sbostic #include <netiso/argo_debug.h>
6136375Ssklower 
6236375Ssklower /*
6336375Ssklower  * FUNCTION:		clnp_data_ck
6436375Ssklower  *
6536375Ssklower  * PURPOSE:			Check that the amount of data in the mbuf chain is
6636375Ssklower  *					at least as much as the clnp header would have us
6736375Ssklower  *					expect. Trim mbufs if longer than expected, drop
6836375Ssklower  *					packet if shorter than expected.
6936375Ssklower  *
7036375Ssklower  * RETURNS:			success - ptr to mbuf chain
7136375Ssklower  *					failure - 0
7236375Ssklower  *
7336375Ssklower  * SIDE EFFECTS:
7436375Ssklower  *
7536375Ssklower  * NOTES:
7636375Ssklower  */
7736375Ssklower struct mbuf *
clnp_data_ck(m,length)7836375Ssklower clnp_data_ck(m, length)
7936375Ssklower register struct mbuf	*m;		/* ptr to mbuf chain containing hdr & data */
8036375Ssklower int						length;	/* length (in bytes) of packet */
8136375Ssklower  {
8236375Ssklower 	register int 			len;		/* length of data */
8336375Ssklower 	register struct mbuf	*mhead;		/* ptr to head of chain */
8436375Ssklower 
8536375Ssklower 	len = -length;
8636375Ssklower 	mhead = m;
8736375Ssklower 	for (;;) {
8836375Ssklower 		len += m->m_len;
8936375Ssklower 		if (m->m_next == 0)
9036375Ssklower 			break;
9136375Ssklower 		m = m->m_next;
9236375Ssklower 	}
9336375Ssklower 	if (len != 0) {
9436375Ssklower 		if (len < 0) {
9536375Ssklower 			INCSTAT(cns_toosmall);
9636375Ssklower 			clnp_discard(mhead, GEN_INCOMPLETE);
9736375Ssklower 			return 0;
9836375Ssklower 		}
9936375Ssklower 		if (len <= m->m_len)
10036375Ssklower 			m->m_len -= len;
10136375Ssklower 		else
10236375Ssklower 			m_adj(mhead, -len);
10336375Ssklower 	}
10436375Ssklower 	return mhead;
10536375Ssklower }
10636375Ssklower 
10748740Ssklower #ifdef notdef
10836375Ssklower /*
10936375Ssklower  * FUNCTION:		clnp_extract_addr
11036375Ssklower  *
11136375Ssklower  * PURPOSE:			Extract the source and destination address from the
11236375Ssklower  *					supplied buffer. Place them in the supplied address buffers.
11336375Ssklower  *					If insufficient data is supplied, then fail.
11436375Ssklower  *
11536375Ssklower  * RETURNS:			success - Address of first byte in the packet past
11636375Ssklower  *						the address part.
11736375Ssklower  *					failure - 0
11836375Ssklower  *
11936375Ssklower  * SIDE EFFECTS:
12036375Ssklower  *
12136375Ssklower  * NOTES:
12236375Ssklower  */
12336375Ssklower caddr_t
clnp_extract_addr(bufp,buflen,srcp,destp)12436375Ssklower clnp_extract_addr(bufp, buflen, srcp, destp)
12536375Ssklower caddr_t					bufp;		/* ptr to buffer containing addresses */
12636375Ssklower int						buflen;		/* length of buffer */
12736375Ssklower register struct iso_addr	*srcp;		/* ptr to source address buffer */
12836375Ssklower register struct iso_addr	*destp;		/* ptr to destination address buffer */
12936375Ssklower  {
13036375Ssklower 	int	len;		/* argument to bcopy */
13136375Ssklower 
13236375Ssklower 	/*
13336375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
13436375Ssklower 	 */
13536375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
13636375Ssklower 		return((caddr_t)0);
13736375Ssklower 	}
13836375Ssklower 	len = destp->isoa_len = (u_char)*bufp++;
13936375Ssklower 	(void) bcopy(bufp, (caddr_t)destp, len);
14036375Ssklower 	buflen -= len;
14136375Ssklower 	bufp += len;
14236375Ssklower 
14336375Ssklower 	/*
14436375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
14536375Ssklower 	 */
14636375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
14736375Ssklower 		return((caddr_t)0);
14836375Ssklower 	}
14936375Ssklower 	len = srcp->isoa_len = (u_char)* bufp++;
15036375Ssklower 	(void) bcopy(bufp, (caddr_t)srcp, len);
15136375Ssklower 	bufp += len;
15236375Ssklower 
15336375Ssklower 	/*
15436375Ssklower 	 *	Insure that the addresses make sense
15536375Ssklower 	 */
15636375Ssklower 	if (iso_ck_addr(srcp) && iso_ck_addr(destp))
15736375Ssklower 		return bufp;
15836375Ssklower 	else
15936375Ssklower 		return (caddr_t) 0;
16036375Ssklower }
16161290Ssklower #endif	/* notdef */
16236375Ssklower 
16336375Ssklower /*
16436375Ssklower  * FUNCTION:		clnp_ours
16536375Ssklower  *
16636375Ssklower  * PURPOSE:			Decide whether the supplied packet is destined for
16736375Ssklower  *					us, or that it should be forwarded on.
16836375Ssklower  *
16936375Ssklower  * RETURNS:			packet is for us - 1
17036375Ssklower  *					packet is not for us - 0
17136375Ssklower  *
17236375Ssklower  * SIDE EFFECTS:
17336375Ssklower  *
17436375Ssklower  * NOTES:
17536375Ssklower  */
clnp_ours(dst)17636375Ssklower clnp_ours(dst)
17736375Ssklower register struct iso_addr *dst;		/* ptr to destination address */
17836375Ssklower {
17936375Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
18036375Ssklower 
18136375Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
18236375Ssklower 		IFDEBUG(D_ROUTE)
18342949Ssklower 			printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia->ia_addr,
18436375Ssklower 				dst);
18536375Ssklower 		ENDDEBUG
18642949Ssklower 		/*
18742949Ssklower 		 * XXX Warning:
18842949Ssklower 		 * We are overloading siso_tlen in the if's address, as an nsel length.
18942949Ssklower 		 */
19043332Ssklower 		if (dst->isoa_len == ia->ia_addr.siso_nlen &&
19142949Ssklower 			bcmp((caddr_t)ia->ia_addr.siso_addr.isoa_genaddr,
19243332Ssklower 				 (caddr_t)dst->isoa_genaddr,
19343332Ssklower 				 ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0)
19442949Ssklower 					return 1;
19536375Ssklower 	}
19636375Ssklower 	return 0;
19736375Ssklower }
19836375Ssklower 
19936770Ssklower /* Dec bit set if ifp qlen is greater than congest_threshold */
20036770Ssklower int congest_threshold = 0;
20136770Ssklower 
20236375Ssklower /*
20336375Ssklower  * FUNCTION:		clnp_forward
20436375Ssklower  *
20536375Ssklower  * PURPOSE:			Forward the datagram passed
20636375Ssklower  *					clnpintr guarantees that the header will be
20736375Ssklower  *					contigious (a cluster mbuf will be used if necessary).
20836375Ssklower  *
20936375Ssklower  *					If oidx is NULL, no options are present.
21036375Ssklower  *
21136375Ssklower  * RETURNS:			nothing
21236375Ssklower  *
21336375Ssklower  * SIDE EFFECTS:
21436375Ssklower  *
21536375Ssklower  * NOTES:
21636375Ssklower  */
21736375Ssklower clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
21836375Ssklower struct mbuf			*m;		/* pkt to forward */
21936375Ssklower int					len;	/* length of pkt */
22036375Ssklower struct iso_addr		*dst;	/* destination address */
22136375Ssklower struct clnp_optidx	*oidx;	/* option index */
22236375Ssklower int					seg_off;/* offset of segmentation part */
22336375Ssklower struct snpa_hdr		*inbound_shp;	/* subnetwork header of inbound packet */
22436375Ssklower {
22536375Ssklower 	struct clnp_fixed		*clnp;	/* ptr to fixed part of header */
22636375Ssklower 	int						error;	/* return value of route function */
22736375Ssklower 	struct sockaddr			*next_hop;	/* next hop for dgram */
22836375Ssklower 	struct ifnet			*ifp;	/* ptr to outgoing interface */
22937469Ssklower 	struct iso_ifaddr		*ia = 0;/* ptr to iso name for ifp */
23036769Ssklower 	struct route_iso		route;	/* filled in by clnp_route */
23136375Ssklower 	extern int				iso_systype;
23236375Ssklower 
23336375Ssklower 	clnp = mtod(m, struct clnp_fixed *);
23436375Ssklower 	bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
23536375Ssklower 
23636375Ssklower 	/*
23736375Ssklower 	 *	Don't forward multicast or broadcast packets
23836375Ssklower 	 */
23936375Ssklower 	if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
24036375Ssklower 		IFDEBUG(D_FORWARD)
24136375Ssklower 			printf("clnp_forward: dropping multicast packet\n");
24236375Ssklower 		ENDDEBUG
24337469Ssklower 		clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */
24436375Ssklower 		clnp_discard(m, 0);
24539198Ssklower 		INCSTAT(cns_cantforward);
24636375Ssklower 		goto done;
24736375Ssklower 	}
24836375Ssklower 
24936375Ssklower 	IFDEBUG(D_FORWARD)
25036375Ssklower 		printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
25136375Ssklower 			clnp_iso_addrp(dst), oidx);
25236375Ssklower 	ENDDEBUG
25336375Ssklower 
25436375Ssklower 	/*
25536375Ssklower 	 *	Decrement ttl, and if zero drop datagram
25636375Ssklower 	 *	Can't compare ttl as less than zero 'cause its a unsigned
25736375Ssklower 	 */
25836375Ssklower 	if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
25936375Ssklower 		IFDEBUG(D_FORWARD)
26036375Ssklower 			printf("clnp_forward: discarding datagram because ttl is zero\n");
26136375Ssklower 		ENDDEBUG
26236375Ssklower 		INCSTAT(cns_ttlexpired);
26336375Ssklower 		clnp_discard(m, TTL_EXPTRANSIT);
26436375Ssklower 		goto done;
26536375Ssklower 	}
26636375Ssklower 	/*
26736375Ssklower 	 *	Route packet; special case for source rt
26836375Ssklower 	 */
26936375Ssklower 	if CLNPSRCRT_VALID(oidx) {
27036375Ssklower 		/*
27136375Ssklower 		 *	Update src route first
27236375Ssklower 		 */
27336375Ssklower 		clnp_update_srcrt(m, oidx);
27437469Ssklower 		error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
27536375Ssklower 	} else {
27637469Ssklower 		error = clnp_route(dst, &route, 0, &next_hop, &ia);
27736375Ssklower 	}
27837469Ssklower 	if (error || ia == 0) {
27936375Ssklower 		IFDEBUG(D_FORWARD)
28036375Ssklower 			printf("clnp_forward: can't route packet (errno %d)\n", error);
28136375Ssklower 		ENDDEBUG
28236375Ssklower 		clnp_discard(m, ADDR_DESTUNREACH);
28339198Ssklower 		INCSTAT(cns_cantforward);
28436375Ssklower 		goto done;
28536375Ssklower 	}
28637469Ssklower 	ifp = ia->ia_ifp;
28736375Ssklower 
28836375Ssklower 	IFDEBUG(D_FORWARD)
28936375Ssklower 		printf("clnp_forward: packet routed to %s\n",
29036375Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
29136375Ssklower 	ENDDEBUG
29236375Ssklower 
29336375Ssklower 	INCSTAT(cns_forward);
29436375Ssklower 
29536375Ssklower 	/*
29636375Ssklower 	 *	If we are an intermediate system and
29736375Ssklower 	 *	we are routing outbound on the same ifp that the packet
29836375Ssklower 	 *	arrived upon, and we know the next hop snpa,
29936375Ssklower 	 *	then generate a redirect request
30036375Ssklower 	 */
30136375Ssklower 	if ((iso_systype & SNPA_IS) && (inbound_shp) &&
30243332Ssklower 		(ifp == inbound_shp->snh_ifp))
30343332Ssklower 		    esis_rdoutput(inbound_shp, m, oidx, dst, route.ro_rt);
30436375Ssklower 	/*
30536375Ssklower 	 *	If options are present, update them
30636375Ssklower 	 */
30736375Ssklower 	if (oidx) {
30837469Ssklower 		struct iso_addr	*mysrc = &ia->ia_addr.siso_addr;
30936375Ssklower 		if (mysrc == NULL) {
31036375Ssklower 			clnp_discard(m, ADDR_DESTUNREACH);
31139198Ssklower 			INCSTAT(cns_cantforward);
31239198Ssklower 			clnp_stat.cns_forward--;
31336375Ssklower 			goto done;
31436375Ssklower 		} else {
31536770Ssklower 			(void) clnp_dooptions(m, oidx, ifp, mysrc);
31636375Ssklower 		}
31736375Ssklower 	}
31836770Ssklower 
31936770Ssklower #ifdef	DECBIT
32036770Ssklower 	if (ifp->if_snd.ifq_len > congest_threshold) {
32136770Ssklower 		/*
32236770Ssklower 		 *	Congestion! Set the Dec Bit and thank Dave Oran
32336770Ssklower 		 */
32436770Ssklower 		IFDEBUG(D_FORWARD)
32536770Ssklower 			printf("clnp_forward: congestion experienced\n");
32636770Ssklower 		ENDDEBUG
32736770Ssklower 		if ((oidx) && (oidx->cni_qos_formatp)) {
32836770Ssklower 			caddr_t	qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
32936770Ssklower 			u_char	qos = *qosp;
33036770Ssklower 			IFDEBUG(D_FORWARD)
33136770Ssklower 				printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
33236770Ssklower 			ENDDEBUG
33336770Ssklower 			if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
33436770Ssklower 				qos |= CLNPOVAL_CONGESTED;
33536770Ssklower 				INCSTAT(cns_congest_set);
33636770Ssklower 				*qosp = qos;
33736770Ssklower 			}
33836770Ssklower 		}
33936770Ssklower 	}
34061290Ssklower #endif	/* DECBIT */
34136375Ssklower 
34236375Ssklower 	/*
34336375Ssklower 	 *	Dispatch the datagram if it is small enough, otherwise fragment
34436375Ssklower 	 */
34548740Ssklower 	if (len <= SN_MTU(ifp, route.ro_rt)) {
34636375Ssklower 		iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
34740776Ssklower 		(void) (*ifp->if_output)(ifp, m, next_hop, route.ro_rt);
34836375Ssklower 	} else {
34940776Ssklower 		(void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0, route.ro_rt);
35036375Ssklower 	}
35136375Ssklower 
35236375Ssklower done:
35336375Ssklower 	/*
35436375Ssklower 	 *	Free route
35536375Ssklower 	 */
35636375Ssklower 	if (route.ro_rt != NULL) {
35736375Ssklower 		RTFREE(route.ro_rt);
35836375Ssklower 	}
35936375Ssklower }
36036375Ssklower 
36148740Ssklower #ifdef	notdef
36236375Ssklower /*
36336375Ssklower  * FUNCTION:		clnp_insert_addr
36436375Ssklower  *
36536375Ssklower  * PURPOSE:			Insert the address part into a clnp datagram.
36636375Ssklower  *
36736375Ssklower  * RETURNS:			Address of first byte after address part in datagram.
36836375Ssklower  *
36936375Ssklower  * SIDE EFFECTS:
37036375Ssklower  *
37136375Ssklower  * NOTES:			Assume that there is enough space for the address part.
37236375Ssklower  */
37336375Ssklower caddr_t
clnp_insert_addr(bufp,srcp,dstp)37436375Ssklower clnp_insert_addr(bufp, srcp, dstp)
37536375Ssklower caddr_t						bufp;	/* address of where addr part goes */
37636375Ssklower register struct iso_addr	*srcp;	/* ptr to src addr */
37736375Ssklower register struct iso_addr	*dstp;	/* ptr to dst addr */
37836375Ssklower {
37936375Ssklower 	*bufp++ = dstp->isoa_len;
38036375Ssklower 	(void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
38136375Ssklower 	bufp += dstp->isoa_len;
38236375Ssklower 
38336375Ssklower 	*bufp++ = srcp->isoa_len;
38436375Ssklower 	(void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
38536375Ssklower 	bufp += srcp->isoa_len;
38636375Ssklower 
38736375Ssklower 	return bufp;
38836375Ssklower }
38936375Ssklower 
39061290Ssklower #endif	/* notdef */
39136375Ssklower 
39236375Ssklower /*
39336375Ssklower  * FUNCTION:		clnp_route
39436375Ssklower  *
39536375Ssklower  * PURPOSE:			Route a clnp datagram to the first hop toward its
39636375Ssklower  *					destination. In many cases, the first hop will be
39736375Ssklower  *					the destination. The address of a route
39836375Ssklower  *					is specified. If a routing entry is present in
39936375Ssklower  *					that route, and it is still up to the same destination,
40036375Ssklower  *					then no further action is necessary. Otherwise, a
40136375Ssklower  *					new routing entry will be allocated.
40236375Ssklower  *
40336375Ssklower  * RETURNS:			route found - 0
40436375Ssklower  *					unix error code
40536375Ssklower  *
40636375Ssklower  * SIDE EFFECTS:
40736375Ssklower  *
40836375Ssklower  * NOTES:			It is up to the caller to free the routing entry
40936375Ssklower  *					allocated in route.
41036375Ssklower  */
41137469Ssklower clnp_route(dst, ro, flags, first_hop, ifa)
41237469Ssklower 	struct iso_addr	*dst;			/* ptr to datagram destination */
41337469Ssklower 	register struct	route_iso *ro;	/* existing route structure */
41437469Ssklower 	int flags;						/* flags for routing */
41537469Ssklower 	struct sockaddr **first_hop;	/* result: fill in with ptr to firsthop */
41637469Ssklower 	struct iso_ifaddr **ifa;		/* result: fill in with ptr to interface */
41736375Ssklower {
41837469Ssklower 	if (flags & SO_DONTROUTE) {
41937469Ssklower 		struct iso_ifaddr *ia;
42036375Ssklower 
42138476Ssklower 		if (ro->ro_rt) {
42238476Ssklower 			RTFREE(ro->ro_rt);
42338476Ssklower 			ro->ro_rt = 0;
42438476Ssklower 		}
42538476Ssklower 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
42638476Ssklower 		bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr,
42737469Ssklower 			1 + (unsigned)dst->isoa_len);
42838476Ssklower 		ro->ro_dst.siso_family = AF_ISO;
42938476Ssklower 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
43038476Ssklower 		ia = iso_localifa(&ro->ro_dst);
43137469Ssklower 		if (ia == 0)
43237469Ssklower 			return EADDRNOTAVAIL;
43337469Ssklower 		if (ifa)
43438476Ssklower 			*ifa = ia;
43538476Ssklower 		if (first_hop)
43638476Ssklower 			*first_hop = (struct sockaddr *)&ro->ro_dst;
43737469Ssklower 		return 0;
43837469Ssklower 	}
43936375Ssklower 	/*
44036375Ssklower 	 *	If there is a cached route, check that it is still up and to
44136375Ssklower 	 *	the same destination. If not, free it and try again.
44236375Ssklower 	 */
44336375Ssklower 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
44437469Ssklower 		(Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
44536375Ssklower 		IFDEBUG(D_ROUTE)
44636375Ssklower 			printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
44736375Ssklower 				ro->ro_rt);
44836375Ssklower 			printf("clnp_route: old route refcnt: 0x%x\n",
44936375Ssklower 				ro->ro_rt->rt_refcnt);
45036375Ssklower 		ENDDEBUG
45136375Ssklower 
45236375Ssklower 		/* free old route entry */
45336375Ssklower 		RTFREE(ro->ro_rt);
45436375Ssklower 		ro->ro_rt = (struct rtentry *)0;
45536375Ssklower 	} else {
45636375Ssklower 		IFDEBUG(D_ROUTE)
45736375Ssklower 			printf("clnp_route: OK route exists\n");
45836375Ssklower 		ENDDEBUG
45936375Ssklower 	}
46036375Ssklower 
46136375Ssklower 	if (ro->ro_rt == 0) {
46236375Ssklower 		/* set up new route structure */
46337469Ssklower 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
46437469Ssklower 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
46537469Ssklower 		ro->ro_dst.siso_family = AF_ISO;
46637469Ssklower 		Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len);
46736375Ssklower 		/* allocate new route */
46836375Ssklower 		IFDEBUG(D_ROUTE)
46936375Ssklower 			printf("clnp_route: allocating new route to %s\n",
47036375Ssklower 				clnp_iso_addrp(dst));
47136375Ssklower 		ENDDEBUG
47237469Ssklower 		rtalloc((struct route *)ro);
47336375Ssklower 	}
47437469Ssklower 	if (ro->ro_rt == 0)
47536375Ssklower 		return(ENETUNREACH);	/* rtalloc failed */
47637469Ssklower 	ro->ro_rt->rt_use++;
47737469Ssklower 	if (ifa)
47837469Ssklower 		if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
47937469Ssklower 			panic("clnp_route");
48037469Ssklower 	if (first_hop) {
48140776Ssklower 		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
48237469Ssklower 			*first_hop = ro->ro_rt->rt_gateway;
48337469Ssklower 		else
48437469Ssklower 			*first_hop = (struct sockaddr *)&ro->ro_dst;
48536375Ssklower 	}
48636375Ssklower 	return(0);
48736375Ssklower }
48836375Ssklower 
48936375Ssklower /*
49036375Ssklower  * FUNCTION:		clnp_srcroute
49136375Ssklower  *
49236375Ssklower  * PURPOSE:			Source route the datagram. If complete source
49336375Ssklower  *					routing is specified but not possible, then
49436375Ssklower  *					return an error. If src routing is terminated, then
49536375Ssklower  *					try routing on destination.
49636375Ssklower  *					Usage of first_hop,
49736375Ssklower  *					ifp, and error return is identical to clnp_route.
49836375Ssklower  *
49936375Ssklower  * RETURNS:			0 or unix error code
50036375Ssklower  *
50136375Ssklower  * SIDE EFFECTS:
50236375Ssklower  *
50336375Ssklower  * NOTES:			Remember that option index pointers are really
50436375Ssklower  *					offsets from the beginning of the mbuf.
50536375Ssklower  */
50643332Ssklower clnp_srcroute(options, oidx, ro, first_hop, ifa, final_dst)
50736375Ssklower struct mbuf			*options;		/* ptr to options */
50836375Ssklower struct clnp_optidx	*oidx;			/* index to options */
50943332Ssklower struct route_iso	*ro;			/* route structure */
51036375Ssklower struct sockaddr		**first_hop;	/* RETURN: fill in with ptr to firsthop */
51137469Ssklower struct iso_ifaddr	**ifa;			/* RETURN: fill in with ptr to interface */
51236375Ssklower struct iso_addr		*final_dst;		/* final destination */
51336375Ssklower {
51436375Ssklower 	struct iso_addr	dst;		/* first hop specified by src rt */
51536375Ssklower 	int				error = 0;	/* return code */
51636375Ssklower 
51736375Ssklower 	/*
51836375Ssklower 	 *	Check if we have run out of routes
51936375Ssklower 	 *	If so, then try to route on destination.
52036375Ssklower 	 */
52136375Ssklower 	if CLNPSRCRT_TERM(oidx, options) {
52236375Ssklower 		dst.isoa_len = final_dst->isoa_len;
52337469Ssklower 		bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len);
52436375Ssklower 	} else {
52536375Ssklower 		/*
52636375Ssklower 		 * setup dst based on src rt specified
52736375Ssklower 		 */
52836375Ssklower 		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
52937469Ssklower 		bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len);
53036375Ssklower 	}
53136375Ssklower 
53236375Ssklower 	/*
53336375Ssklower 	 *	try to route it
53436375Ssklower 	 */
53543332Ssklower 	error = clnp_route(&dst, ro, 0, first_hop, ifa);
53636375Ssklower 	if (error != 0)
53736375Ssklower 		return error;
53836375Ssklower 
53936375Ssklower 	/*
54036375Ssklower 	 *	If complete src rt, first hop must be equal to dst
54136375Ssklower 	 */
54236375Ssklower 	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
54336375Ssklower 	 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
54436375Ssklower 		IFDEBUG(D_OPTIONS)
54536375Ssklower 			printf("clnp_srcroute: complete src route failed\n");
54636375Ssklower 		ENDDEBUG
54736375Ssklower 		return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
54836375Ssklower 	}
54936375Ssklower 
55036375Ssklower 	return error;
55136375Ssklower }
55236375Ssklower 
55336375Ssklower /*
55452487Ssklower  * FUNCTION:		clnp_echoreply
55552487Ssklower  *
55652487Ssklower  * PURPOSE:			generate an echo reply packet and transmit
55752487Ssklower  *
55852487Ssklower  * RETURNS:			result of clnp_output
55952487Ssklower  *
56052487Ssklower  * SIDE EFFECTS:
56152487Ssklower  */
56252487Ssklower clnp_echoreply(ec_m, ec_len, ec_src, ec_dst, ec_oidxp)
56352487Ssklower struct mbuf			*ec_m;		/* echo request */
56452487Ssklower int					ec_len;		/* length of ec */
56552487Ssklower struct sockaddr_iso	*ec_src;		/* src of ec */
56652487Ssklower struct sockaddr_iso	*ec_dst; 	/* destination of ec (i.e., us) */
56752487Ssklower struct clnp_optidx	*ec_oidxp;	/* options index to ec packet */
56852487Ssklower {
56952487Ssklower 	struct isopcb	isopcb;
57052487Ssklower 	int				flags = CLNP_NOCACHE|CLNP_ECHOR;
57152487Ssklower 	int				ret;
57252487Ssklower 
57352487Ssklower 	/* fill in fake isopcb to pass to output function */
57452487Ssklower 	bzero(&isopcb, sizeof(isopcb));
57552487Ssklower 	isopcb.isop_laddr = ec_dst;
57652487Ssklower 	isopcb.isop_faddr = ec_src;
57752487Ssklower 
57852487Ssklower 	/* forget copying the options for now. If implemented, need only
57952487Ssklower 	 * copy record route option, but it must be reset to zero length */
58052487Ssklower 
58152487Ssklower 	ret = clnp_output(ec_m, &isopcb, ec_len, flags);
58252487Ssklower 
58352487Ssklower 	IFDEBUG(D_OUTPUT)
58452487Ssklower 		printf("clnp_echoreply: output returns %d\n", ret);
58552487Ssklower 	ENDDEBUG
58652487Ssklower 	return ret;
58752487Ssklower }
58852487Ssklower 
58952487Ssklower /*
59048740Ssklower  * FUNCTION:		clnp_badmtu
59148740Ssklower  *
59248740Ssklower  * PURPOSE:			print notice of route with mtu not initialized.
59348740Ssklower  *
59448740Ssklower  * RETURNS:			mtu of ifp.
59548740Ssklower  *
59648740Ssklower  * SIDE EFFECTS:	prints notice, slows down system.
59748740Ssklower  */
59848740Ssklower clnp_badmtu(ifp, rt, line, file)
59948740Ssklower struct ifnet *ifp;	/* outgoing interface */
60048740Ssklower struct rtentry *rt; /* dst route */
60148740Ssklower int line;			/* where the dirty deed occured */
60248740Ssklower char *file;			/* where the dirty deed occured */
60348740Ssklower {
60457951Ssklower 	printf("sending on route 0x%x with no mtu, line %d of file %s\n",
60548740Ssklower 		rt, line, file);
60648740Ssklower #ifdef ARGO_DEBUG
60757951Ssklower 	printf("route dst is ");
60848740Ssklower 	dump_isoaddr(rt_key(rt));
60948740Ssklower #endif
61048740Ssklower 	return ifp->if_mtu;
61148740Ssklower }
61248740Ssklower 
61348740Ssklower /*
61436375Ssklower  * FUNCTION:		clnp_ypocb - backwards bcopy
61536375Ssklower  *
61636375Ssklower  * PURPOSE:			bcopy starting at end of src rather than beginning.
61736375Ssklower  *
61836375Ssklower  * RETURNS:			none
61936375Ssklower  *
62036375Ssklower  * SIDE EFFECTS:
62136375Ssklower  *
62236375Ssklower  * NOTES:			No attempt has been made to make this efficient
62336375Ssklower  */
clnp_ypocb(from,to,len)62436375Ssklower clnp_ypocb(from, to, len)
62536375Ssklower caddr_t from;		/* src buffer */
62636375Ssklower caddr_t to;			/* dst buffer */
62736375Ssklower u_int	len;		/* number of bytes */
62836375Ssklower {
62936375Ssklower 	while (len--)
63036375Ssklower 		*(to + len) = *(from + len);
63136375Ssklower }
63261290Ssklower #endif	/* ISO */
633