xref: /csrg-svn/sys/netiso/clnp_subr.c (revision 42949)
136375Ssklower /***********************************************************
236375Ssklower 		Copyright IBM Corporation 1987
336375Ssklower 
436375Ssklower                       All Rights Reserved
536375Ssklower 
636375Ssklower Permission to use, copy, modify, and distribute this software and its
736375Ssklower documentation for any purpose and without fee is hereby granted,
836375Ssklower provided that the above copyright notice appear in all copies and that
936375Ssklower both that copyright notice and this permission notice appear in
1036375Ssklower supporting documentation, and that the name of IBM not be
1136375Ssklower used in advertising or publicity pertaining to distribution of the
1236375Ssklower software without specific, written prior permission.
1336375Ssklower 
1436375Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536375Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636375Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736375Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836375Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936375Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036375Ssklower SOFTWARE.
2136375Ssklower 
2236375Ssklower ******************************************************************/
2336375Ssklower 
2436375Ssklower /*
2536375Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636375Ssklower  */
2736770Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */
2836770Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */
29*42949Ssklower /*	@(#)clnp_subr.c	7.9 (Berkeley) 06/06/90 */
3036375Ssklower 
3136375Ssklower #ifndef lint
3236770Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $";
3336375Ssklower #endif lint
3436375Ssklower 
3536375Ssklower #ifdef ISO
3636375Ssklower 
3737469Ssklower #include "types.h"
3837469Ssklower #include "param.h"
3937469Ssklower #include "mbuf.h"
4037469Ssklower #include "domain.h"
4137469Ssklower #include "protosw.h"
4237469Ssklower #include "socket.h"
4337469Ssklower #include "socketvar.h"
4437469Ssklower #include "errno.h"
4537469Ssklower #include "time.h"
4636375Ssklower 
4736375Ssklower #include "../net/if.h"
4836375Ssklower #include "../net/route.h"
4936375Ssklower 
5037469Ssklower #include "iso.h"
5137469Ssklower #include "iso_var.h"
5237469Ssklower #include "iso_pcb.h"
5337469Ssklower #include "iso_snpac.h"
5437469Ssklower #include "clnp.h"
5537469Ssklower #include "clnp_stat.h"
5637469Ssklower #include "argo_debug.h"
5736375Ssklower 
5836375Ssklower /*
5936375Ssklower  * FUNCTION:		clnp_data_ck
6036375Ssklower  *
6136375Ssklower  * PURPOSE:			Check that the amount of data in the mbuf chain is
6236375Ssklower  *					at least as much as the clnp header would have us
6336375Ssklower  *					expect. Trim mbufs if longer than expected, drop
6436375Ssklower  *					packet if shorter than expected.
6536375Ssklower  *
6636375Ssklower  * RETURNS:			success - ptr to mbuf chain
6736375Ssklower  *					failure - 0
6836375Ssklower  *
6936375Ssklower  * SIDE EFFECTS:
7036375Ssklower  *
7136375Ssklower  * NOTES:
7236375Ssklower  */
7336375Ssklower struct mbuf *
7436375Ssklower clnp_data_ck(m, length)
7536375Ssklower register struct mbuf	*m;		/* ptr to mbuf chain containing hdr & data */
7636375Ssklower int						length;	/* length (in bytes) of packet */
7736375Ssklower  {
7836375Ssklower 	register int 			len;		/* length of data */
7936375Ssklower 	register struct mbuf	*mhead;		/* ptr to head of chain */
8036375Ssklower 
8136375Ssklower 	len = -length;
8236375Ssklower 	mhead = m;
8336375Ssklower 	for (;;) {
8436375Ssklower 		len += m->m_len;
8536375Ssklower 		if (m->m_next == 0)
8636375Ssklower 			break;
8736375Ssklower 		m = m->m_next;
8836375Ssklower 	}
8936375Ssklower 	if (len != 0) {
9036375Ssklower 		if (len < 0) {
9136375Ssklower 			INCSTAT(cns_toosmall);
9236375Ssklower 			clnp_discard(mhead, GEN_INCOMPLETE);
9336375Ssklower 			return 0;
9436375Ssklower 		}
9536375Ssklower 		if (len <= m->m_len)
9636375Ssklower 			m->m_len -= len;
9736375Ssklower 		else
9836375Ssklower 			m_adj(mhead, -len);
9936375Ssklower 	}
10036375Ssklower 	return mhead;
10136375Ssklower }
10236375Ssklower 
10336375Ssklower #ifdef ndef
10436375Ssklower /*
10536375Ssklower  * FUNCTION:		clnp_extract_addr
10636375Ssklower  *
10736375Ssklower  * PURPOSE:			Extract the source and destination address from the
10836375Ssklower  *					supplied buffer. Place them in the supplied address buffers.
10936375Ssklower  *					If insufficient data is supplied, then fail.
11036375Ssklower  *
11136375Ssklower  * RETURNS:			success - Address of first byte in the packet past
11236375Ssklower  *						the address part.
11336375Ssklower  *					failure - 0
11436375Ssklower  *
11536375Ssklower  * SIDE EFFECTS:
11636375Ssklower  *
11736375Ssklower  * NOTES:
11836375Ssklower  */
11936375Ssklower caddr_t
12036375Ssklower clnp_extract_addr(bufp, buflen, srcp, destp)
12136375Ssklower caddr_t					bufp;		/* ptr to buffer containing addresses */
12236375Ssklower int						buflen;		/* length of buffer */
12336375Ssklower register struct iso_addr	*srcp;		/* ptr to source address buffer */
12436375Ssklower register struct iso_addr	*destp;		/* ptr to destination address buffer */
12536375Ssklower  {
12636375Ssklower 	int	len;		/* argument to bcopy */
12736375Ssklower 
12836375Ssklower 	/*
12936375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
13036375Ssklower 	 */
13136375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
13236375Ssklower 		return((caddr_t)0);
13336375Ssklower 	}
13436375Ssklower 	len = destp->isoa_len = (u_char)*bufp++;
13536375Ssklower 	(void) bcopy(bufp, (caddr_t)destp, len);
13636375Ssklower 	buflen -= len;
13736375Ssklower 	bufp += len;
13836375Ssklower 
13936375Ssklower 	/*
14036375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
14136375Ssklower 	 */
14236375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
14336375Ssklower 		return((caddr_t)0);
14436375Ssklower 	}
14536375Ssklower 	len = srcp->isoa_len = (u_char)* bufp++;
14636375Ssklower 	(void) bcopy(bufp, (caddr_t)srcp, len);
14736375Ssklower 	bufp += len;
14836375Ssklower 
14936375Ssklower 	/*
15036375Ssklower 	 *	Insure that the addresses make sense
15136375Ssklower 	 */
15236375Ssklower 	if (iso_ck_addr(srcp) && iso_ck_addr(destp))
15336375Ssklower 		return bufp;
15436375Ssklower 	else
15536375Ssklower 		return (caddr_t) 0;
15636375Ssklower }
15736375Ssklower #endif	ndef
15836375Ssklower 
15936375Ssklower /*
16036375Ssklower  * FUNCTION:		clnp_ours
16136375Ssklower  *
16236375Ssklower  * PURPOSE:			Decide whether the supplied packet is destined for
16336375Ssklower  *					us, or that it should be forwarded on.
16436375Ssklower  *
16536375Ssklower  * RETURNS:			packet is for us - 1
16636375Ssklower  *					packet is not for us - 0
16736375Ssklower  *
16836375Ssklower  * SIDE EFFECTS:
16936375Ssklower  *
17036375Ssklower  * NOTES:
17136375Ssklower  */
17236375Ssklower clnp_ours(dst)
17336375Ssklower register struct iso_addr *dst;		/* ptr to destination address */
17436375Ssklower {
17536375Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
17636375Ssklower 
17736375Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
17836375Ssklower 		IFDEBUG(D_ROUTE)
179*42949Ssklower 			printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia->ia_addr,
18036375Ssklower 				dst);
18136375Ssklower 		ENDDEBUG
182*42949Ssklower 		/*
183*42949Ssklower 		 * XXX Warning:
184*42949Ssklower 		 * We are overloading siso_tlen in the if's address, as an nsel length.
185*42949Ssklower 		 */
186*42949Ssklower 		if (dst->isoa_len == ia->ia_addr.siso_tlen + ia->ia_addr.siso_nlen &&
187*42949Ssklower 			bcmp((caddr_t)ia->ia_addr.siso_addr.isoa_genaddr,
188*42949Ssklower 				 (caddr_t)dst->isoa_genaddr, ia->ia_addr.siso_nlen) == 0)
189*42949Ssklower 					return 1;
19036375Ssklower 	}
19136375Ssklower 	return 0;
19236375Ssklower }
19336375Ssklower 
19436770Ssklower /* Dec bit set if ifp qlen is greater than congest_threshold */
19536770Ssklower int congest_threshold = 0;
19636770Ssklower 
19736375Ssklower /*
19836375Ssklower  * FUNCTION:		clnp_forward
19936375Ssklower  *
20036375Ssklower  * PURPOSE:			Forward the datagram passed
20136375Ssklower  *					clnpintr guarantees that the header will be
20236375Ssklower  *					contigious (a cluster mbuf will be used if necessary).
20336375Ssklower  *
20436375Ssklower  *					If oidx is NULL, no options are present.
20536375Ssklower  *
20636375Ssklower  * RETURNS:			nothing
20736375Ssklower  *
20836375Ssklower  * SIDE EFFECTS:
20936375Ssklower  *
21036375Ssklower  * NOTES:
21136375Ssklower  */
21236375Ssklower clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
21336375Ssklower struct mbuf			*m;		/* pkt to forward */
21436375Ssklower int					len;	/* length of pkt */
21536375Ssklower struct iso_addr		*dst;	/* destination address */
21636375Ssklower struct clnp_optidx	*oidx;	/* option index */
21736375Ssklower int					seg_off;/* offset of segmentation part */
21836375Ssklower struct snpa_hdr		*inbound_shp;	/* subnetwork header of inbound packet */
21936375Ssklower {
22036375Ssklower 	struct clnp_fixed		*clnp;	/* ptr to fixed part of header */
22136375Ssklower 	int						error;	/* return value of route function */
22236375Ssklower 	struct sockaddr			*next_hop;	/* next hop for dgram */
22336375Ssklower 	struct ifnet			*ifp;	/* ptr to outgoing interface */
22437469Ssklower 	struct iso_ifaddr		*ia = 0;/* ptr to iso name for ifp */
22536769Ssklower 	struct route_iso		route;	/* filled in by clnp_route */
22636375Ssklower 	extern int				iso_systype;
22736375Ssklower 
22836375Ssklower 	clnp = mtod(m, struct clnp_fixed *);
22936375Ssklower 	bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
23036375Ssklower 
23136375Ssklower 	/*
23236375Ssklower 	 *	Don't forward multicast or broadcast packets
23336375Ssklower 	 */
23436375Ssklower 	if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
23536375Ssklower 		IFDEBUG(D_FORWARD)
23636375Ssklower 			printf("clnp_forward: dropping multicast packet\n");
23736375Ssklower 		ENDDEBUG
23837469Ssklower 		clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */
23936375Ssklower 		clnp_discard(m, 0);
24039198Ssklower 		INCSTAT(cns_cantforward);
24136375Ssklower 		goto done;
24236375Ssklower 	}
24336375Ssklower 
24436375Ssklower 	IFDEBUG(D_FORWARD)
24536375Ssklower 		printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
24636375Ssklower 			clnp_iso_addrp(dst), oidx);
24736375Ssklower 	ENDDEBUG
24836375Ssklower 
24936375Ssklower 	/*
25036375Ssklower 	 *	Decrement ttl, and if zero drop datagram
25136375Ssklower 	 *	Can't compare ttl as less than zero 'cause its a unsigned
25236375Ssklower 	 */
25336375Ssklower 	if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
25436375Ssklower 		IFDEBUG(D_FORWARD)
25536375Ssklower 			printf("clnp_forward: discarding datagram because ttl is zero\n");
25636375Ssklower 		ENDDEBUG
25736375Ssklower 		INCSTAT(cns_ttlexpired);
25836375Ssklower 		clnp_discard(m, TTL_EXPTRANSIT);
25936375Ssklower 		goto done;
26036375Ssklower 	}
26136375Ssklower 	/*
26236375Ssklower 	 *	Route packet; special case for source rt
26336375Ssklower 	 */
26436375Ssklower 	if CLNPSRCRT_VALID(oidx) {
26536375Ssklower 		/*
26636375Ssklower 		 *	Update src route first
26736375Ssklower 		 */
26836375Ssklower 		clnp_update_srcrt(m, oidx);
26937469Ssklower 		error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
27036375Ssklower 	} else {
27137469Ssklower 		error = clnp_route(dst, &route, 0, &next_hop, &ia);
27236375Ssklower 	}
27337469Ssklower 	if (error || ia == 0) {
27436375Ssklower 		IFDEBUG(D_FORWARD)
27536375Ssklower 			printf("clnp_forward: can't route packet (errno %d)\n", error);
27636375Ssklower 		ENDDEBUG
27736375Ssklower 		clnp_discard(m, ADDR_DESTUNREACH);
27839198Ssklower 		INCSTAT(cns_cantforward);
27936375Ssklower 		goto done;
28036375Ssklower 	}
28137469Ssklower 	ifp = ia->ia_ifp;
28236375Ssklower 
28336375Ssklower 	IFDEBUG(D_FORWARD)
28436375Ssklower 		printf("clnp_forward: packet routed to %s\n",
28536375Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
28636375Ssklower 	ENDDEBUG
28736375Ssklower 
28836375Ssklower 	INCSTAT(cns_forward);
28936375Ssklower 
29036375Ssklower 	/*
29136375Ssklower 	 *	If we are an intermediate system and
29236375Ssklower 	 *	we are routing outbound on the same ifp that the packet
29336375Ssklower 	 *	arrived upon, and we know the next hop snpa,
29436375Ssklower 	 *	then generate a redirect request
29536375Ssklower 	 */
29636375Ssklower 	if ((iso_systype & SNPA_IS) && (inbound_shp) &&
29736375Ssklower 		(ifp == inbound_shp->snh_ifp)) {
29836375Ssklower 		struct snpa_cache 			*sc;
29936375Ssklower 
30036375Ssklower 		sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr);
30136375Ssklower 		if (sc != NULL) {
30236375Ssklower 			esis_rdoutput(inbound_shp, m, oidx, dst, sc);
30336375Ssklower 		}
30436375Ssklower 	}
30536375Ssklower 
30636375Ssklower 	/*
30736375Ssklower 	 *	If options are present, update them
30836375Ssklower 	 */
30936375Ssklower 	if (oidx) {
31037469Ssklower 		struct iso_addr	*mysrc = &ia->ia_addr.siso_addr;
31136375Ssklower 		if (mysrc == NULL) {
31236375Ssklower 			clnp_discard(m, ADDR_DESTUNREACH);
31339198Ssklower 			INCSTAT(cns_cantforward);
31439198Ssklower 			clnp_stat.cns_forward--;
31536375Ssklower 			goto done;
31636375Ssklower 		} else {
31736770Ssklower 			(void) clnp_dooptions(m, oidx, ifp, mysrc);
31836375Ssklower 		}
31936375Ssklower 	}
32036770Ssklower 
32136770Ssklower #ifdef	DECBIT
32236770Ssklower 	if (ifp->if_snd.ifq_len > congest_threshold) {
32336770Ssklower 		/*
32436770Ssklower 		 *	Congestion! Set the Dec Bit and thank Dave Oran
32536770Ssklower 		 */
32636770Ssklower 		IFDEBUG(D_FORWARD)
32736770Ssklower 			printf("clnp_forward: congestion experienced\n");
32836770Ssklower 		ENDDEBUG
32936770Ssklower 		if ((oidx) && (oidx->cni_qos_formatp)) {
33036770Ssklower 			caddr_t	qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
33136770Ssklower 			u_char	qos = *qosp;
33236770Ssklower 			IFDEBUG(D_FORWARD)
33336770Ssklower 				printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
33436770Ssklower 			ENDDEBUG
33536770Ssklower 			if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
33636770Ssklower 				qos |= CLNPOVAL_CONGESTED;
33736770Ssklower 				INCSTAT(cns_congest_set);
33836770Ssklower 				*qosp = qos;
33936770Ssklower 			}
34036770Ssklower 		}
34136770Ssklower 	}
34236770Ssklower #endif	DECBIT
34336375Ssklower 
34436375Ssklower 	/*
34536375Ssklower 	 *	Dispatch the datagram if it is small enough, otherwise fragment
34636375Ssklower 	 */
34736375Ssklower 	if (len <= SN_MTU(ifp)) {
34836375Ssklower 		iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
34940776Ssklower 		(void) (*ifp->if_output)(ifp, m, next_hop, route.ro_rt);
35036375Ssklower 	} else {
35140776Ssklower 		(void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0, route.ro_rt);
35236375Ssklower 	}
35336375Ssklower 
35436375Ssklower done:
35536375Ssklower 	/*
35636375Ssklower 	 *	Free route
35736375Ssklower 	 */
35836375Ssklower 	if (route.ro_rt != NULL) {
35936375Ssklower 		RTFREE(route.ro_rt);
36036375Ssklower 	}
36136375Ssklower }
36236375Ssklower 
36336375Ssklower #ifdef	ndef
36436375Ssklower /*
36536375Ssklower  * FUNCTION:		clnp_insert_addr
36636375Ssklower  *
36736375Ssklower  * PURPOSE:			Insert the address part into a clnp datagram.
36836375Ssklower  *
36936375Ssklower  * RETURNS:			Address of first byte after address part in datagram.
37036375Ssklower  *
37136375Ssklower  * SIDE EFFECTS:
37236375Ssklower  *
37336375Ssklower  * NOTES:			Assume that there is enough space for the address part.
37436375Ssklower  */
37536375Ssklower caddr_t
37636375Ssklower clnp_insert_addr(bufp, srcp, dstp)
37736375Ssklower caddr_t						bufp;	/* address of where addr part goes */
37836375Ssklower register struct iso_addr	*srcp;	/* ptr to src addr */
37936375Ssklower register struct iso_addr	*dstp;	/* ptr to dst addr */
38036375Ssklower {
38136375Ssklower 	*bufp++ = dstp->isoa_len;
38236375Ssklower 	(void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
38336375Ssklower 	bufp += dstp->isoa_len;
38436375Ssklower 
38536375Ssklower 	*bufp++ = srcp->isoa_len;
38636375Ssklower 	(void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
38736375Ssklower 	bufp += srcp->isoa_len;
38836375Ssklower 
38936375Ssklower 	return bufp;
39036375Ssklower }
39136375Ssklower 
39236375Ssklower #endif	ndef
39336375Ssklower 
39436375Ssklower /*
39536375Ssklower  * FUNCTION:		clnp_route
39636375Ssklower  *
39736375Ssklower  * PURPOSE:			Route a clnp datagram to the first hop toward its
39836375Ssklower  *					destination. In many cases, the first hop will be
39936375Ssklower  *					the destination. The address of a route
40036375Ssklower  *					is specified. If a routing entry is present in
40136375Ssklower  *					that route, and it is still up to the same destination,
40236375Ssklower  *					then no further action is necessary. Otherwise, a
40336375Ssklower  *					new routing entry will be allocated.
40436375Ssklower  *
40536375Ssklower  * RETURNS:			route found - 0
40636375Ssklower  *					unix error code
40736375Ssklower  *
40836375Ssklower  * SIDE EFFECTS:
40936375Ssklower  *
41036375Ssklower  * NOTES:			It is up to the caller to free the routing entry
41136375Ssklower  *					allocated in route.
41236375Ssklower  */
41337469Ssklower clnp_route(dst, ro, flags, first_hop, ifa)
41437469Ssklower 	struct iso_addr	*dst;			/* ptr to datagram destination */
41537469Ssklower 	register struct	route_iso *ro;	/* existing route structure */
41637469Ssklower 	int flags;						/* flags for routing */
41737469Ssklower 	struct sockaddr **first_hop;	/* result: fill in with ptr to firsthop */
41837469Ssklower 	struct iso_ifaddr **ifa;		/* result: fill in with ptr to interface */
41936375Ssklower {
42037469Ssklower 	if (flags & SO_DONTROUTE) {
42137469Ssklower 		struct iso_ifaddr *ia;
42236375Ssklower 
42338476Ssklower 		if (ro->ro_rt) {
42438476Ssklower 			RTFREE(ro->ro_rt);
42538476Ssklower 			ro->ro_rt = 0;
42638476Ssklower 		}
42738476Ssklower 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
42838476Ssklower 		bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr,
42937469Ssklower 			1 + (unsigned)dst->isoa_len);
43038476Ssklower 		ro->ro_dst.siso_family = AF_ISO;
43138476Ssklower 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
43238476Ssklower 		ia = iso_localifa(&ro->ro_dst);
43337469Ssklower 		if (ia == 0)
43437469Ssklower 			return EADDRNOTAVAIL;
43537469Ssklower 		if (ifa)
43638476Ssklower 			*ifa = ia;
43738476Ssklower 		if (first_hop)
43838476Ssklower 			*first_hop = (struct sockaddr *)&ro->ro_dst;
43937469Ssklower 		return 0;
44037469Ssklower 	}
44136375Ssklower 	/*
44236375Ssklower 	 *	If there is a cached route, check that it is still up and to
44336375Ssklower 	 *	the same destination. If not, free it and try again.
44436375Ssklower 	 */
44536375Ssklower 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
44637469Ssklower 		(Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
44736375Ssklower 		IFDEBUG(D_ROUTE)
44836375Ssklower 			printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
44936375Ssklower 				ro->ro_rt);
45036375Ssklower 			printf("clnp_route: old route refcnt: 0x%x\n",
45136375Ssklower 				ro->ro_rt->rt_refcnt);
45236375Ssklower 		ENDDEBUG
45336375Ssklower 
45436375Ssklower 		/* free old route entry */
45536375Ssklower 		RTFREE(ro->ro_rt);
45636375Ssklower 		ro->ro_rt = (struct rtentry *)0;
45736375Ssklower 	} else {
45836375Ssklower 		IFDEBUG(D_ROUTE)
45936375Ssklower 			printf("clnp_route: OK route exists\n");
46036375Ssklower 		ENDDEBUG
46136375Ssklower 	}
46236375Ssklower 
46336375Ssklower 	if (ro->ro_rt == 0) {
46436375Ssklower 		/* set up new route structure */
46537469Ssklower 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
46637469Ssklower 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
46737469Ssklower 		ro->ro_dst.siso_family = AF_ISO;
46837469Ssklower 		Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len);
46936375Ssklower 		/* allocate new route */
47036375Ssklower 		IFDEBUG(D_ROUTE)
47136375Ssklower 			printf("clnp_route: allocating new route to %s\n",
47236375Ssklower 				clnp_iso_addrp(dst));
47336375Ssklower 		ENDDEBUG
47437469Ssklower 		rtalloc((struct route *)ro);
47536375Ssklower 	}
47637469Ssklower 	if (ro->ro_rt == 0)
47736375Ssklower 		return(ENETUNREACH);	/* rtalloc failed */
47837469Ssklower 	ro->ro_rt->rt_use++;
47937469Ssklower 	if (ifa)
48037469Ssklower 		if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
48137469Ssklower 			panic("clnp_route");
48237469Ssklower 	if (first_hop) {
48340776Ssklower 		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
48437469Ssklower 			*first_hop = ro->ro_rt->rt_gateway;
48537469Ssklower 		else
48637469Ssklower 			*first_hop = (struct sockaddr *)&ro->ro_dst;
48736375Ssklower 	}
48836375Ssklower 	return(0);
48936375Ssklower }
49036375Ssklower 
49136375Ssklower /*
49236375Ssklower  * FUNCTION:		clnp_srcroute
49336375Ssklower  *
49436375Ssklower  * PURPOSE:			Source route the datagram. If complete source
49536375Ssklower  *					routing is specified but not possible, then
49636375Ssklower  *					return an error. If src routing is terminated, then
49736375Ssklower  *					try routing on destination.
49836375Ssklower  *					Usage of first_hop,
49936375Ssklower  *					ifp, and error return is identical to clnp_route.
50036375Ssklower  *
50136375Ssklower  * RETURNS:			0 or unix error code
50236375Ssklower  *
50336375Ssklower  * SIDE EFFECTS:
50436375Ssklower  *
50536375Ssklower  * NOTES:			Remember that option index pointers are really
50636375Ssklower  *					offsets from the beginning of the mbuf.
50736375Ssklower  */
50837469Ssklower clnp_srcroute(options, oidx, route, first_hop, ifa, final_dst)
50936375Ssklower struct mbuf			*options;		/* ptr to options */
51036375Ssklower struct clnp_optidx	*oidx;			/* index to options */
51137469Ssklower struct route_iso	*route;			/* route structure */
51236375Ssklower struct sockaddr		**first_hop;	/* RETURN: fill in with ptr to firsthop */
51337469Ssklower struct iso_ifaddr	**ifa;			/* RETURN: fill in with ptr to interface */
51436375Ssklower struct iso_addr		*final_dst;		/* final destination */
51536375Ssklower {
51636375Ssklower 	struct iso_addr	dst;		/* first hop specified by src rt */
51736375Ssklower 	int				error = 0;	/* return code */
51836375Ssklower 
51936375Ssklower 	/*
52036375Ssklower 	 *	Check if we have run out of routes
52136375Ssklower 	 *	If so, then try to route on destination.
52236375Ssklower 	 */
52336375Ssklower 	if CLNPSRCRT_TERM(oidx, options) {
52436375Ssklower 		dst.isoa_len = final_dst->isoa_len;
52537469Ssklower 		bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len);
52636375Ssklower 	} else {
52736375Ssklower 		/*
52836375Ssklower 		 * setup dst based on src rt specified
52936375Ssklower 		 */
53036375Ssklower 		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
53137469Ssklower 		bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len);
53236375Ssklower 	}
53336375Ssklower 
53436375Ssklower 	/*
53536375Ssklower 	 *	try to route it
53636375Ssklower 	 */
53737469Ssklower 	error = clnp_route(&dst, route, 0, first_hop, ifa);
53836375Ssklower 	if (error != 0)
53936375Ssklower 		return error;
54036375Ssklower 
54136375Ssklower 	/*
54236375Ssklower 	 *	If complete src rt, first hop must be equal to dst
54336375Ssklower 	 */
54436375Ssklower 	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
54536375Ssklower 	 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
54636375Ssklower 		IFDEBUG(D_OPTIONS)
54736375Ssklower 			printf("clnp_srcroute: complete src route failed\n");
54836375Ssklower 		ENDDEBUG
54936375Ssklower 		return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
55036375Ssklower 	}
55136375Ssklower 
55236375Ssklower 	return error;
55336375Ssklower }
55436375Ssklower 
55536375Ssklower /*
55636375Ssklower  * FUNCTION:		clnp_ypocb - backwards bcopy
55736375Ssklower  *
55836375Ssklower  * PURPOSE:			bcopy starting at end of src rather than beginning.
55936375Ssklower  *
56036375Ssklower  * RETURNS:			none
56136375Ssklower  *
56236375Ssklower  * SIDE EFFECTS:
56336375Ssklower  *
56436375Ssklower  * NOTES:			No attempt has been made to make this efficient
56536375Ssklower  */
56636375Ssklower clnp_ypocb(from, to, len)
56736375Ssklower caddr_t from;		/* src buffer */
56836375Ssklower caddr_t to;			/* dst buffer */
56936375Ssklower u_int	len;		/* number of bytes */
57036375Ssklower {
57136375Ssklower 	while (len--)
57236375Ssklower 		*(to + len) = *(from + len);
57336375Ssklower }
57436375Ssklower 
57536375Ssklower /*
57636375Ssklower  * FUNCTION:		clnp_hdrsize
57736375Ssklower  *
57836375Ssklower  * PURPOSE:			Return the size of a typical clnp hdr.
57936375Ssklower  *
58036375Ssklower  * RETURNS:			Size of hdr in bytes.
58136375Ssklower  *
58236375Ssklower  * SIDE EFFECTS:
58336375Ssklower  *
58436375Ssklower  * NOTES:			Assumes segmenting subset. If addrlen is
58536375Ssklower  *					zero, default to largest nsap address size.
58636375Ssklower  */
58736375Ssklower clnp_hdrsize(addrlen)
58836375Ssklower u_char	addrlen;		/* length of nsap address */
58936375Ssklower {
59036375Ssklower 	if (addrlen == 0)
59136375Ssklower 		addrlen = 20;
59236375Ssklower 
59336375Ssklower 	addrlen++;			/* length of address byte */
59436375Ssklower 	addrlen *= 2;		/* src and dst addresses */
59536375Ssklower 	addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
59636375Ssklower 
59736375Ssklower 	return(addrlen);
59836375Ssklower }
59936375Ssklower #endif	ISO
600