xref: /csrg-svn/sys/netiso/clnp_subr.c (revision 38476)
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 $ */
2936375Ssklower 
3036375Ssklower #ifndef lint
3136770Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $";
3236375Ssklower #endif lint
3336375Ssklower 
3436375Ssklower #ifdef ISO
3536375Ssklower 
3637469Ssklower #include "types.h"
3737469Ssklower #include "param.h"
3837469Ssklower #include "mbuf.h"
3937469Ssklower #include "domain.h"
4037469Ssklower #include "protosw.h"
4137469Ssklower #include "socket.h"
4237469Ssklower #include "socketvar.h"
4337469Ssklower #include "errno.h"
4437469Ssklower #include "time.h"
4536375Ssklower 
4636375Ssklower #include "../net/if.h"
4736375Ssklower #include "../net/route.h"
4836375Ssklower 
4937469Ssklower #include "iso.h"
5037469Ssklower #include "iso_var.h"
5137469Ssklower #include "iso_pcb.h"
5237469Ssklower #include "iso_snpac.h"
5337469Ssklower #include "clnp.h"
5437469Ssklower #include "clnp_stat.h"
5537469Ssklower #include "argo_debug.h"
5636375Ssklower 
5736375Ssklower /*
5836375Ssklower  * FUNCTION:		clnp_data_ck
5936375Ssklower  *
6036375Ssklower  * PURPOSE:			Check that the amount of data in the mbuf chain is
6136375Ssklower  *					at least as much as the clnp header would have us
6236375Ssklower  *					expect. Trim mbufs if longer than expected, drop
6336375Ssklower  *					packet if shorter than expected.
6436375Ssklower  *
6536375Ssklower  * RETURNS:			success - ptr to mbuf chain
6636375Ssklower  *					failure - 0
6736375Ssklower  *
6836375Ssklower  * SIDE EFFECTS:
6936375Ssklower  *
7036375Ssklower  * NOTES:
7136375Ssklower  */
7236375Ssklower struct mbuf *
7336375Ssklower clnp_data_ck(m, length)
7436375Ssklower register struct mbuf	*m;		/* ptr to mbuf chain containing hdr & data */
7536375Ssklower int						length;	/* length (in bytes) of packet */
7636375Ssklower  {
7736375Ssklower 	register int 			len;		/* length of data */
7836375Ssklower 	register struct mbuf	*mhead;		/* ptr to head of chain */
7936375Ssklower 
8036375Ssklower 	len = -length;
8136375Ssklower 	mhead = m;
8236375Ssklower 	for (;;) {
8336375Ssklower 		len += m->m_len;
8436375Ssklower 		if (m->m_next == 0)
8536375Ssklower 			break;
8636375Ssklower 		m = m->m_next;
8736375Ssklower 	}
8836375Ssklower 	if (len != 0) {
8936375Ssklower 		if (len < 0) {
9036375Ssklower 			INCSTAT(cns_toosmall);
9136375Ssklower 			clnp_discard(mhead, GEN_INCOMPLETE);
9236375Ssklower 			return 0;
9336375Ssklower 		}
9436375Ssklower 		if (len <= m->m_len)
9536375Ssklower 			m->m_len -= len;
9636375Ssklower 		else
9736375Ssklower 			m_adj(mhead, -len);
9836375Ssklower 	}
9936375Ssklower 	return mhead;
10036375Ssklower }
10136375Ssklower 
10236375Ssklower #ifdef ndef
10336375Ssklower /*
10436375Ssklower  * FUNCTION:		clnp_extract_addr
10536375Ssklower  *
10636375Ssklower  * PURPOSE:			Extract the source and destination address from the
10736375Ssklower  *					supplied buffer. Place them in the supplied address buffers.
10836375Ssklower  *					If insufficient data is supplied, then fail.
10936375Ssklower  *
11036375Ssklower  * RETURNS:			success - Address of first byte in the packet past
11136375Ssklower  *						the address part.
11236375Ssklower  *					failure - 0
11336375Ssklower  *
11436375Ssklower  * SIDE EFFECTS:
11536375Ssklower  *
11636375Ssklower  * NOTES:
11736375Ssklower  */
11836375Ssklower caddr_t
11936375Ssklower clnp_extract_addr(bufp, buflen, srcp, destp)
12036375Ssklower caddr_t					bufp;		/* ptr to buffer containing addresses */
12136375Ssklower int						buflen;		/* length of buffer */
12236375Ssklower register struct iso_addr	*srcp;		/* ptr to source address buffer */
12336375Ssklower register struct iso_addr	*destp;		/* ptr to destination address buffer */
12436375Ssklower  {
12536375Ssklower 	int	len;		/* argument to bcopy */
12636375Ssklower 
12736375Ssklower 	/*
12836375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
12936375Ssklower 	 */
13036375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
13136375Ssklower 		return((caddr_t)0);
13236375Ssklower 	}
13336375Ssklower 	len = destp->isoa_len = (u_char)*bufp++;
13436375Ssklower 	(void) bcopy(bufp, (caddr_t)destp, len);
13536375Ssklower 	buflen -= len;
13636375Ssklower 	bufp += len;
13736375Ssklower 
13836375Ssklower 	/*
13936375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
14036375Ssklower 	 */
14136375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
14236375Ssklower 		return((caddr_t)0);
14336375Ssklower 	}
14436375Ssklower 	len = srcp->isoa_len = (u_char)* bufp++;
14536375Ssklower 	(void) bcopy(bufp, (caddr_t)srcp, len);
14636375Ssklower 	bufp += len;
14736375Ssklower 
14836375Ssklower 	/*
14936375Ssklower 	 *	Insure that the addresses make sense
15036375Ssklower 	 */
15136375Ssklower 	if (iso_ck_addr(srcp) && iso_ck_addr(destp))
15236375Ssklower 		return bufp;
15336375Ssklower 	else
15436375Ssklower 		return (caddr_t) 0;
15536375Ssklower }
15636375Ssklower #endif	ndef
15736375Ssklower 
15836375Ssklower /*
15936375Ssklower  * FUNCTION:		clnp_ours
16036375Ssklower  *
16136375Ssklower  * PURPOSE:			Decide whether the supplied packet is destined for
16236375Ssklower  *					us, or that it should be forwarded on.
16336375Ssklower  *
16436375Ssklower  * RETURNS:			packet is for us - 1
16536375Ssklower  *					packet is not for us - 0
16636375Ssklower  *
16736375Ssklower  * SIDE EFFECTS:
16836375Ssklower  *
16936375Ssklower  * NOTES:
17036375Ssklower  */
17136375Ssklower clnp_ours(dst)
17236375Ssklower register struct iso_addr *dst;		/* ptr to destination address */
17336375Ssklower {
17436375Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
17536375Ssklower 
17636375Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
17736375Ssklower 		IFDEBUG(D_ROUTE)
17836375Ssklower 			printf("clnp_ours: ia_sis x%x, dst x%x\n", &IA_SIS(ia)->siso_addr,
17936375Ssklower 				dst);
18036375Ssklower 		ENDDEBUG
18136375Ssklower 		/* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */
18236375Ssklower 		if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst))
18336375Ssklower 			return 1;
18436375Ssklower 	}
18536375Ssklower 	return 0;
18636375Ssklower }
18736375Ssklower 
18836770Ssklower /* Dec bit set if ifp qlen is greater than congest_threshold */
18936770Ssklower int congest_threshold = 0;
19036770Ssklower 
19136375Ssklower /*
19236375Ssklower  * FUNCTION:		clnp_forward
19336375Ssklower  *
19436375Ssklower  * PURPOSE:			Forward the datagram passed
19536375Ssklower  *					clnpintr guarantees that the header will be
19636375Ssklower  *					contigious (a cluster mbuf will be used if necessary).
19736375Ssklower  *
19836375Ssklower  *					If oidx is NULL, no options are present.
19936375Ssklower  *
20036375Ssklower  * RETURNS:			nothing
20136375Ssklower  *
20236375Ssklower  * SIDE EFFECTS:
20336375Ssklower  *
20436375Ssklower  * NOTES:
20536375Ssklower  */
20636375Ssklower clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
20736375Ssklower struct mbuf			*m;		/* pkt to forward */
20836375Ssklower int					len;	/* length of pkt */
20936375Ssklower struct iso_addr		*dst;	/* destination address */
21036375Ssklower struct clnp_optidx	*oidx;	/* option index */
21136375Ssklower int					seg_off;/* offset of segmentation part */
21236375Ssklower struct snpa_hdr		*inbound_shp;	/* subnetwork header of inbound packet */
21336375Ssklower {
21436375Ssklower 	struct clnp_fixed		*clnp;	/* ptr to fixed part of header */
21536375Ssklower 	int						error;	/* return value of route function */
21636375Ssklower 	struct sockaddr			*next_hop;	/* next hop for dgram */
21736375Ssklower 	struct ifnet			*ifp;	/* ptr to outgoing interface */
21837469Ssklower 	struct iso_ifaddr		*ia = 0;/* ptr to iso name for ifp */
21936769Ssklower 	struct route_iso		route;	/* filled in by clnp_route */
22036375Ssklower 	extern int				iso_systype;
22136375Ssklower 
22236375Ssklower 	clnp = mtod(m, struct clnp_fixed *);
22336375Ssklower 	bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
22436375Ssklower 
22536375Ssklower 	/*
22636375Ssklower 	 *	Don't forward multicast or broadcast packets
22736375Ssklower 	 */
22836375Ssklower 	if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
22936375Ssklower 		IFDEBUG(D_FORWARD)
23036375Ssklower 			printf("clnp_forward: dropping multicast packet\n");
23136375Ssklower 		ENDDEBUG
23237469Ssklower 		clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */
23336375Ssklower 		clnp_discard(m, 0);
23436375Ssklower 		goto done;
23536375Ssklower 	}
23636375Ssklower 
23736375Ssklower 	IFDEBUG(D_FORWARD)
23836375Ssklower 		printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
23936375Ssklower 			clnp_iso_addrp(dst), oidx);
24036375Ssklower 	ENDDEBUG
24136375Ssklower 
24236375Ssklower 	/*
24336375Ssklower 	 *	Decrement ttl, and if zero drop datagram
24436375Ssklower 	 *	Can't compare ttl as less than zero 'cause its a unsigned
24536375Ssklower 	 */
24636375Ssklower 	if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
24736375Ssklower 		IFDEBUG(D_FORWARD)
24836375Ssklower 			printf("clnp_forward: discarding datagram because ttl is zero\n");
24936375Ssklower 		ENDDEBUG
25036375Ssklower 		INCSTAT(cns_ttlexpired);
25136375Ssklower 		clnp_discard(m, TTL_EXPTRANSIT);
25236375Ssklower 		goto done;
25336375Ssklower 	}
25436375Ssklower 	/*
25536375Ssklower 	 *	Route packet; special case for source rt
25636375Ssklower 	 */
25736375Ssklower 	if CLNPSRCRT_VALID(oidx) {
25836375Ssklower 		/*
25936375Ssklower 		 *	Update src route first
26036375Ssklower 		 */
26136375Ssklower 		clnp_update_srcrt(m, oidx);
26237469Ssklower 		error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
26336375Ssklower 	} else {
26437469Ssklower 		error = clnp_route(dst, &route, 0, &next_hop, &ia);
26536375Ssklower 	}
26637469Ssklower 	if (error || ia == 0) {
26736375Ssklower 		IFDEBUG(D_FORWARD)
26836375Ssklower 			printf("clnp_forward: can't route packet (errno %d)\n", error);
26936375Ssklower 		ENDDEBUG
27036375Ssklower 		clnp_discard(m, ADDR_DESTUNREACH);
27136375Ssklower 		goto done;
27236375Ssklower 	}
27337469Ssklower 	ifp = ia->ia_ifp;
27436375Ssklower 
27536375Ssklower 	IFDEBUG(D_FORWARD)
27636375Ssklower 		printf("clnp_forward: packet routed to %s\n",
27736375Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
27836375Ssklower 	ENDDEBUG
27936375Ssklower 
28036375Ssklower 	INCSTAT(cns_forward);
28136375Ssklower 
28236375Ssklower 	/*
28336375Ssklower 	 *	If we are an intermediate system and
28436375Ssklower 	 *	we are routing outbound on the same ifp that the packet
28536375Ssklower 	 *	arrived upon, and we know the next hop snpa,
28636375Ssklower 	 *	then generate a redirect request
28736375Ssklower 	 */
28836375Ssklower 	if ((iso_systype & SNPA_IS) && (inbound_shp) &&
28936375Ssklower 		(ifp == inbound_shp->snh_ifp)) {
29036375Ssklower 		struct snpa_cache 			*sc;
29136375Ssklower 
29236375Ssklower 		sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr);
29336375Ssklower 		if (sc != NULL) {
29436375Ssklower 			esis_rdoutput(inbound_shp, m, oidx, dst, sc);
29536375Ssklower 		}
29636375Ssklower 	}
29736375Ssklower 
29836375Ssklower 	/*
29936375Ssklower 	 *	If options are present, update them
30036375Ssklower 	 */
30136375Ssklower 	if (oidx) {
30237469Ssklower 		struct iso_addr	*mysrc = &ia->ia_addr.siso_addr;
30336375Ssklower 		if (mysrc == NULL) {
30436375Ssklower 			clnp_discard(m, ADDR_DESTUNREACH);
30536375Ssklower 			goto done;
30636375Ssklower 		} else {
30736770Ssklower 			(void) clnp_dooptions(m, oidx, ifp, mysrc);
30836375Ssklower 		}
30936375Ssklower 	}
31036770Ssklower 
31136770Ssklower #ifdef	DECBIT
31236770Ssklower 	if (ifp->if_snd.ifq_len > congest_threshold) {
31336770Ssklower 		/*
31436770Ssklower 		 *	Congestion! Set the Dec Bit and thank Dave Oran
31536770Ssklower 		 */
31636770Ssklower 		IFDEBUG(D_FORWARD)
31736770Ssklower 			printf("clnp_forward: congestion experienced\n");
31836770Ssklower 		ENDDEBUG
31936770Ssklower 		if ((oidx) && (oidx->cni_qos_formatp)) {
32036770Ssklower 			caddr_t	qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
32136770Ssklower 			u_char	qos = *qosp;
32236770Ssklower 			IFDEBUG(D_FORWARD)
32336770Ssklower 				printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
32436770Ssklower 			ENDDEBUG
32536770Ssklower 			if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
32636770Ssklower 				qos |= CLNPOVAL_CONGESTED;
32736770Ssklower 				INCSTAT(cns_congest_set);
32836770Ssklower 				*qosp = qos;
32936770Ssklower 			}
33036770Ssklower 		}
33136770Ssklower 	}
33236770Ssklower #endif	DECBIT
33336375Ssklower 
33436375Ssklower 	/*
33536375Ssklower 	 *	Dispatch the datagram if it is small enough, otherwise fragment
33636375Ssklower 	 */
33736375Ssklower 	if (len <= SN_MTU(ifp)) {
33836375Ssklower 		iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
33936375Ssklower 		(void) (*ifp->if_output)(ifp, m, next_hop);
34036375Ssklower 	} else {
34136375Ssklower 		(void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0);
34236375Ssklower 	}
34336375Ssklower 
34436375Ssklower done:
34536375Ssklower 	/*
34636375Ssklower 	 *	Free route
34736375Ssklower 	 */
34836375Ssklower 	if (route.ro_rt != NULL) {
34936375Ssklower 		RTFREE(route.ro_rt);
35036375Ssklower 	}
35136375Ssklower }
35236375Ssklower 
35336375Ssklower #ifdef	ndef
35436375Ssklower /*
35536375Ssklower  * FUNCTION:		clnp_insert_addr
35636375Ssklower  *
35736375Ssklower  * PURPOSE:			Insert the address part into a clnp datagram.
35836375Ssklower  *
35936375Ssklower  * RETURNS:			Address of first byte after address part in datagram.
36036375Ssklower  *
36136375Ssklower  * SIDE EFFECTS:
36236375Ssklower  *
36336375Ssklower  * NOTES:			Assume that there is enough space for the address part.
36436375Ssklower  */
36536375Ssklower caddr_t
36636375Ssklower clnp_insert_addr(bufp, srcp, dstp)
36736375Ssklower caddr_t						bufp;	/* address of where addr part goes */
36836375Ssklower register struct iso_addr	*srcp;	/* ptr to src addr */
36936375Ssklower register struct iso_addr	*dstp;	/* ptr to dst addr */
37036375Ssklower {
37136375Ssklower 	*bufp++ = dstp->isoa_len;
37236375Ssklower 	(void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
37336375Ssklower 	bufp += dstp->isoa_len;
37436375Ssklower 
37536375Ssklower 	*bufp++ = srcp->isoa_len;
37636375Ssklower 	(void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
37736375Ssklower 	bufp += srcp->isoa_len;
37836375Ssklower 
37936375Ssklower 	return bufp;
38036375Ssklower }
38136375Ssklower 
38236375Ssklower #endif	ndef
38336375Ssklower 
38436375Ssklower /*
38536375Ssklower  * FUNCTION:		clnp_route
38636375Ssklower  *
38736375Ssklower  * PURPOSE:			Route a clnp datagram to the first hop toward its
38836375Ssklower  *					destination. In many cases, the first hop will be
38936375Ssklower  *					the destination. The address of a route
39036375Ssklower  *					is specified. If a routing entry is present in
39136375Ssklower  *					that route, and it is still up to the same destination,
39236375Ssklower  *					then no further action is necessary. Otherwise, a
39336375Ssklower  *					new routing entry will be allocated.
39436375Ssklower  *
39536375Ssklower  * RETURNS:			route found - 0
39636375Ssklower  *					unix error code
39736375Ssklower  *
39836375Ssklower  * SIDE EFFECTS:
39936375Ssklower  *
40036375Ssklower  * NOTES:			It is up to the caller to free the routing entry
40136375Ssklower  *					allocated in route.
40236375Ssklower  */
40337469Ssklower clnp_route(dst, ro, flags, first_hop, ifa)
40437469Ssklower 	struct iso_addr	*dst;			/* ptr to datagram destination */
40537469Ssklower 	register struct	route_iso *ro;	/* existing route structure */
40637469Ssklower 	int flags;						/* flags for routing */
40737469Ssklower 	struct sockaddr **first_hop;	/* result: fill in with ptr to firsthop */
40837469Ssklower 	struct iso_ifaddr **ifa;		/* result: fill in with ptr to interface */
40936375Ssklower {
41037469Ssklower 	if (flags & SO_DONTROUTE) {
41137469Ssklower 		struct iso_ifaddr *ia;
41236375Ssklower 
413*38476Ssklower 		if (ro->ro_rt) {
414*38476Ssklower 			RTFREE(ro->ro_rt);
415*38476Ssklower 			ro->ro_rt = 0;
416*38476Ssklower 		}
417*38476Ssklower 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
418*38476Ssklower 		bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr,
41937469Ssklower 			1 + (unsigned)dst->isoa_len);
420*38476Ssklower 		ro->ro_dst.siso_family = AF_ISO;
421*38476Ssklower 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
422*38476Ssklower 		ia = iso_localifa(&ro->ro_dst);
42337469Ssklower 		if (ia == 0)
42437469Ssklower 			return EADDRNOTAVAIL;
42537469Ssklower 		if (ifa)
426*38476Ssklower 			*ifa = ia;
427*38476Ssklower 		if (first_hop)
428*38476Ssklower 			*first_hop = (struct sockaddr *)&ro->ro_dst;
42937469Ssklower 		return 0;
43037469Ssklower 	}
43136375Ssklower 	/*
43236375Ssklower 	 *	If there is a cached route, check that it is still up and to
43336375Ssklower 	 *	the same destination. If not, free it and try again.
43436375Ssklower 	 */
43536375Ssklower 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
43637469Ssklower 		(Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
43736375Ssklower 		IFDEBUG(D_ROUTE)
43836375Ssklower 			printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
43936375Ssklower 				ro->ro_rt);
44036375Ssklower 			printf("clnp_route: old route refcnt: 0x%x\n",
44136375Ssklower 				ro->ro_rt->rt_refcnt);
44236375Ssklower 		ENDDEBUG
44336375Ssklower 
44436375Ssklower 		/* free old route entry */
44536375Ssklower 		RTFREE(ro->ro_rt);
44636375Ssklower 		ro->ro_rt = (struct rtentry *)0;
44736375Ssklower 	} else {
44836375Ssklower 		IFDEBUG(D_ROUTE)
44936375Ssklower 			printf("clnp_route: OK route exists\n");
45036375Ssklower 		ENDDEBUG
45136375Ssklower 	}
45236375Ssklower 
45336375Ssklower 	if (ro->ro_rt == 0) {
45436375Ssklower 		/* set up new route structure */
45537469Ssklower 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
45637469Ssklower 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
45737469Ssklower 		ro->ro_dst.siso_family = AF_ISO;
45837469Ssklower 		Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len);
45936375Ssklower 		/* allocate new route */
46036375Ssklower 		IFDEBUG(D_ROUTE)
46136375Ssklower 			printf("clnp_route: allocating new route to %s\n",
46236375Ssklower 				clnp_iso_addrp(dst));
46336375Ssklower 		ENDDEBUG
46437469Ssklower 		rtalloc((struct route *)ro);
46536375Ssklower 	}
46637469Ssklower 	if (ro->ro_rt == 0)
46736375Ssklower 		return(ENETUNREACH);	/* rtalloc failed */
46837469Ssklower 	ro->ro_rt->rt_use++;
46937469Ssklower 	if (ifa)
47037469Ssklower 		if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
47137469Ssklower 			panic("clnp_route");
47237469Ssklower 	if (first_hop) {
47337469Ssklower 		if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
47437469Ssklower 			*first_hop = ro->ro_rt->rt_gateway;
47537469Ssklower 		else
47637469Ssklower 			*first_hop = (struct sockaddr *)&ro->ro_dst;
47736375Ssklower 	}
47836375Ssklower 	return(0);
47936375Ssklower }
48036375Ssklower 
48136375Ssklower /*
48236375Ssklower  * FUNCTION:		clnp_srcroute
48336375Ssklower  *
48436375Ssklower  * PURPOSE:			Source route the datagram. If complete source
48536375Ssklower  *					routing is specified but not possible, then
48636375Ssklower  *					return an error. If src routing is terminated, then
48736375Ssklower  *					try routing on destination.
48836375Ssklower  *					Usage of first_hop,
48936375Ssklower  *					ifp, and error return is identical to clnp_route.
49036375Ssklower  *
49136375Ssklower  * RETURNS:			0 or unix error code
49236375Ssklower  *
49336375Ssklower  * SIDE EFFECTS:
49436375Ssklower  *
49536375Ssklower  * NOTES:			Remember that option index pointers are really
49636375Ssklower  *					offsets from the beginning of the mbuf.
49736375Ssklower  */
49837469Ssklower clnp_srcroute(options, oidx, route, first_hop, ifa, final_dst)
49936375Ssklower struct mbuf			*options;		/* ptr to options */
50036375Ssklower struct clnp_optidx	*oidx;			/* index to options */
50137469Ssklower struct route_iso	*route;			/* route structure */
50236375Ssklower struct sockaddr		**first_hop;	/* RETURN: fill in with ptr to firsthop */
50337469Ssklower struct iso_ifaddr	**ifa;			/* RETURN: fill in with ptr to interface */
50436375Ssklower struct iso_addr		*final_dst;		/* final destination */
50536375Ssklower {
50636375Ssklower 	struct iso_addr	dst;		/* first hop specified by src rt */
50736375Ssklower 	int				error = 0;	/* return code */
50836375Ssklower 
50936375Ssklower 	/*
51036375Ssklower 	 *	Check if we have run out of routes
51136375Ssklower 	 *	If so, then try to route on destination.
51236375Ssklower 	 */
51336375Ssklower 	if CLNPSRCRT_TERM(oidx, options) {
51436375Ssklower 		dst.isoa_len = final_dst->isoa_len;
51537469Ssklower 		bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len);
51636375Ssklower 	} else {
51736375Ssklower 		/*
51836375Ssklower 		 * setup dst based on src rt specified
51936375Ssklower 		 */
52036375Ssklower 		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
52137469Ssklower 		bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len);
52236375Ssklower 	}
52336375Ssklower 
52436375Ssklower 	/*
52536375Ssklower 	 *	try to route it
52636375Ssklower 	 */
52737469Ssklower 	error = clnp_route(&dst, route, 0, first_hop, ifa);
52836375Ssklower 	if (error != 0)
52936375Ssklower 		return error;
53036375Ssklower 
53136375Ssklower 	/*
53236375Ssklower 	 *	If complete src rt, first hop must be equal to dst
53336375Ssklower 	 */
53436375Ssklower 	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
53536375Ssklower 	 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
53636375Ssklower 		IFDEBUG(D_OPTIONS)
53736375Ssklower 			printf("clnp_srcroute: complete src route failed\n");
53836375Ssklower 		ENDDEBUG
53936375Ssklower 		return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
54036375Ssklower 	}
54136375Ssklower 
54236375Ssklower 	return error;
54336375Ssklower }
54436375Ssklower 
54536375Ssklower /*
54636375Ssklower  * FUNCTION:		clnp_ypocb - backwards bcopy
54736375Ssklower  *
54836375Ssklower  * PURPOSE:			bcopy starting at end of src rather than beginning.
54936375Ssklower  *
55036375Ssklower  * RETURNS:			none
55136375Ssklower  *
55236375Ssklower  * SIDE EFFECTS:
55336375Ssklower  *
55436375Ssklower  * NOTES:			No attempt has been made to make this efficient
55536375Ssklower  */
55636375Ssklower clnp_ypocb(from, to, len)
55736375Ssklower caddr_t from;		/* src buffer */
55836375Ssklower caddr_t to;			/* dst buffer */
55936375Ssklower u_int	len;		/* number of bytes */
56036375Ssklower {
56136375Ssklower 	while (len--)
56236375Ssklower 		*(to + len) = *(from + len);
56336375Ssklower }
56436375Ssklower 
56536375Ssklower /*
56636375Ssklower  * FUNCTION:		clnp_hdrsize
56736375Ssklower  *
56836375Ssklower  * PURPOSE:			Return the size of a typical clnp hdr.
56936375Ssklower  *
57036375Ssklower  * RETURNS:			Size of hdr in bytes.
57136375Ssklower  *
57236375Ssklower  * SIDE EFFECTS:
57336375Ssklower  *
57436375Ssklower  * NOTES:			Assumes segmenting subset. If addrlen is
57536375Ssklower  *					zero, default to largest nsap address size.
57636375Ssklower  */
57736375Ssklower clnp_hdrsize(addrlen)
57836375Ssklower u_char	addrlen;		/* length of nsap address */
57936375Ssklower {
58036375Ssklower 	if (addrlen == 0)
58136375Ssklower 		addrlen = 20;
58236375Ssklower 
58336375Ssklower 	addrlen++;			/* length of address byte */
58436375Ssklower 	addrlen *= 2;		/* src and dst addresses */
58536375Ssklower 	addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
58636375Ssklower 
58736375Ssklower 	return(addrlen);
58836375Ssklower }
58936375Ssklower #endif	ISO
590