xref: /csrg-svn/sys/netiso/clnp_subr.c (revision 36770)
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  */
27*36770Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */
28*36770Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */
2936375Ssklower 
3036375Ssklower #ifndef lint
31*36770Ssklower 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 
3636375Ssklower #include "../h/types.h"
3736375Ssklower #include "../h/param.h"
3836375Ssklower #include "../h/mbuf.h"
3936375Ssklower #include "../h/domain.h"
4036375Ssklower #include "../h/protosw.h"
4136375Ssklower #include "../h/socket.h"
4236375Ssklower #include "../h/socketvar.h"
4336375Ssklower #include "../h/errno.h"
4436375Ssklower #include "../h/time.h"
4536375Ssklower 
4636375Ssklower #include "../net/if.h"
4736375Ssklower #include "../net/route.h"
4836375Ssklower 
4936375Ssklower #include "../netiso/iso.h"
5036375Ssklower #include "../netiso/iso_var.h"
5136375Ssklower #include "../netiso/clnp.h"
5236375Ssklower #include "../netiso/clnp_stat.h"
5336375Ssklower #include "../netiso/argo_debug.h"
5436375Ssklower #include "../netiso/iso_snpac.h"
5536375Ssklower 
5636375Ssklower /*
5736375Ssklower  * FUNCTION:		clnp_data_ck
5836375Ssklower  *
5936375Ssklower  * PURPOSE:			Check that the amount of data in the mbuf chain is
6036375Ssklower  *					at least as much as the clnp header would have us
6136375Ssklower  *					expect. Trim mbufs if longer than expected, drop
6236375Ssklower  *					packet if shorter than expected.
6336375Ssklower  *
6436375Ssklower  * RETURNS:			success - ptr to mbuf chain
6536375Ssklower  *					failure - 0
6636375Ssklower  *
6736375Ssklower  * SIDE EFFECTS:
6836375Ssklower  *
6936375Ssklower  * NOTES:
7036375Ssklower  */
7136375Ssklower struct mbuf *
7236375Ssklower clnp_data_ck(m, length)
7336375Ssklower register struct mbuf	*m;		/* ptr to mbuf chain containing hdr & data */
7436375Ssklower int						length;	/* length (in bytes) of packet */
7536375Ssklower  {
7636375Ssklower 	register int 			len;		/* length of data */
7736375Ssklower 	register struct mbuf	*mhead;		/* ptr to head of chain */
7836375Ssklower 
7936375Ssklower 	len = -length;
8036375Ssklower 	mhead = m;
8136375Ssklower 	for (;;) {
8236375Ssklower 		len += m->m_len;
8336375Ssklower 		if (m->m_next == 0)
8436375Ssklower 			break;
8536375Ssklower 		m = m->m_next;
8636375Ssklower 	}
8736375Ssklower 	if (len != 0) {
8836375Ssklower 		if (len < 0) {
8936375Ssklower 			INCSTAT(cns_toosmall);
9036375Ssklower 			clnp_discard(mhead, GEN_INCOMPLETE);
9136375Ssklower 			return 0;
9236375Ssklower 		}
9336375Ssklower 		if (len <= m->m_len)
9436375Ssklower 			m->m_len -= len;
9536375Ssklower 		else
9636375Ssklower 			m_adj(mhead, -len);
9736375Ssklower 	}
9836375Ssklower 	return mhead;
9936375Ssklower }
10036375Ssklower 
10136375Ssklower #ifdef ndef
10236375Ssklower /*
10336375Ssklower  * FUNCTION:		clnp_extract_addr
10436375Ssklower  *
10536375Ssklower  * PURPOSE:			Extract the source and destination address from the
10636375Ssklower  *					supplied buffer. Place them in the supplied address buffers.
10736375Ssklower  *					If insufficient data is supplied, then fail.
10836375Ssklower  *
10936375Ssklower  * RETURNS:			success - Address of first byte in the packet past
11036375Ssklower  *						the address part.
11136375Ssklower  *					failure - 0
11236375Ssklower  *
11336375Ssklower  * SIDE EFFECTS:
11436375Ssklower  *
11536375Ssklower  * NOTES:
11636375Ssklower  */
11736375Ssklower caddr_t
11836375Ssklower clnp_extract_addr(bufp, buflen, srcp, destp)
11936375Ssklower caddr_t					bufp;		/* ptr to buffer containing addresses */
12036375Ssklower int						buflen;		/* length of buffer */
12136375Ssklower register struct iso_addr	*srcp;		/* ptr to source address buffer */
12236375Ssklower register struct iso_addr	*destp;		/* ptr to destination address buffer */
12336375Ssklower  {
12436375Ssklower 	int	len;		/* argument to bcopy */
12536375Ssklower 
12636375Ssklower 	/*
12736375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
12836375Ssklower 	 */
12936375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
13036375Ssklower 		return((caddr_t)0);
13136375Ssklower 	}
13236375Ssklower 	len = destp->isoa_len = (u_char)*bufp++;
13336375Ssklower 	(void) bcopy(bufp, (caddr_t)destp, len);
13436375Ssklower 	buflen -= len;
13536375Ssklower 	bufp += len;
13636375Ssklower 
13736375Ssklower 	/*
13836375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
13936375Ssklower 	 */
14036375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
14136375Ssklower 		return((caddr_t)0);
14236375Ssklower 	}
14336375Ssklower 	len = srcp->isoa_len = (u_char)* bufp++;
14436375Ssklower 	(void) bcopy(bufp, (caddr_t)srcp, len);
14536375Ssklower 	bufp += len;
14636375Ssklower 
14736375Ssklower 	/*
14836375Ssklower 	 *	Insure that the addresses make sense
14936375Ssklower 	 */
15036375Ssklower 	if (iso_ck_addr(srcp) && iso_ck_addr(destp))
15136375Ssklower 		return bufp;
15236375Ssklower 	else
15336375Ssklower 		return (caddr_t) 0;
15436375Ssklower }
15536375Ssklower #endif	ndef
15636375Ssklower 
15736375Ssklower /*
15836375Ssklower  * FUNCTION:		clnp_ours
15936375Ssklower  *
16036375Ssklower  * PURPOSE:			Decide whether the supplied packet is destined for
16136375Ssklower  *					us, or that it should be forwarded on.
16236375Ssklower  *
16336375Ssklower  * RETURNS:			packet is for us - 1
16436375Ssklower  *					packet is not for us - 0
16536375Ssklower  *
16636375Ssklower  * SIDE EFFECTS:
16736375Ssklower  *
16836375Ssklower  * NOTES:
16936375Ssklower  */
17036375Ssklower clnp_ours(dst)
17136375Ssklower register struct iso_addr *dst;		/* ptr to destination address */
17236375Ssklower {
17336375Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
17436375Ssklower 
17536375Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
17636375Ssklower 		IFDEBUG(D_ROUTE)
17736375Ssklower 			printf("clnp_ours: ia_sis x%x, dst x%x\n", &IA_SIS(ia)->siso_addr,
17836375Ssklower 				dst);
17936375Ssklower 		ENDDEBUG
18036375Ssklower 		/* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */
18136375Ssklower 		if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst))
18236375Ssklower 			return 1;
18336375Ssklower 	}
18436375Ssklower 	return 0;
18536375Ssklower }
18636375Ssklower 
187*36770Ssklower /* Dec bit set if ifp qlen is greater than congest_threshold */
188*36770Ssklower int congest_threshold = 0;
189*36770Ssklower 
19036375Ssklower /*
19136375Ssklower  * FUNCTION:		clnp_forward
19236375Ssklower  *
19336375Ssklower  * PURPOSE:			Forward the datagram passed
19436375Ssklower  *					clnpintr guarantees that the header will be
19536375Ssklower  *					contigious (a cluster mbuf will be used if necessary).
19636375Ssklower  *
19736375Ssklower  *					If oidx is NULL, no options are present.
19836375Ssklower  *
19936375Ssklower  * RETURNS:			nothing
20036375Ssklower  *
20136375Ssklower  * SIDE EFFECTS:
20236375Ssklower  *
20336375Ssklower  * NOTES:
20436375Ssklower  */
20536375Ssklower clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
20636375Ssklower struct mbuf			*m;		/* pkt to forward */
20736375Ssklower int					len;	/* length of pkt */
20836375Ssklower struct iso_addr		*dst;	/* destination address */
20936375Ssklower struct clnp_optidx	*oidx;	/* option index */
21036375Ssklower int					seg_off;/* offset of segmentation part */
21136375Ssklower struct snpa_hdr		*inbound_shp;	/* subnetwork header of inbound packet */
21236375Ssklower {
21336375Ssklower 	struct clnp_fixed		*clnp;	/* ptr to fixed part of header */
21436375Ssklower 	int						error;	/* return value of route function */
21536375Ssklower 	struct sockaddr			*next_hop;	/* next hop for dgram */
21636375Ssklower 	struct ifnet			*ifp;	/* ptr to outgoing interface */
21736769Ssklower 	struct route_iso		route;	/* filled in by clnp_route */
21836375Ssklower 	extern int				iso_systype;
21936375Ssklower 
22036375Ssklower 	clnp = mtod(m, struct clnp_fixed *);
22136375Ssklower 	bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
22236375Ssklower 
22336375Ssklower 	/*
22436375Ssklower 	 *	Don't forward multicast or broadcast packets
22536375Ssklower 	 */
22636375Ssklower 	if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
22736375Ssklower 		IFDEBUG(D_FORWARD)
22836375Ssklower 			printf("clnp_forward: dropping multicast packet\n");
22936375Ssklower 		ENDDEBUG
23036375Ssklower 		clnp->cnf_err_ok = 0;	/* so we don't generate an ER */
23136375Ssklower 		clnp_discard(m, 0);
23236375Ssklower 		goto done;
23336375Ssklower 	}
23436375Ssklower 
23536375Ssklower 	IFDEBUG(D_FORWARD)
23636375Ssklower 		printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
23736375Ssklower 			clnp_iso_addrp(dst), oidx);
23836375Ssklower 	ENDDEBUG
23936375Ssklower 
24036375Ssklower 	/*
24136375Ssklower 	 *	Decrement ttl, and if zero drop datagram
24236375Ssklower 	 *	Can't compare ttl as less than zero 'cause its a unsigned
24336375Ssklower 	 */
24436375Ssklower 	if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
24536375Ssklower 		IFDEBUG(D_FORWARD)
24636375Ssklower 			printf("clnp_forward: discarding datagram because ttl is zero\n");
24736375Ssklower 		ENDDEBUG
24836375Ssklower 		INCSTAT(cns_ttlexpired);
24936375Ssklower 		clnp_discard(m, TTL_EXPTRANSIT);
25036375Ssklower 		goto done;
25136375Ssklower 	}
25236375Ssklower 
25336375Ssklower 	/*
25436375Ssklower 	 *	Route packet; special case for source rt
25536375Ssklower 	 */
25636375Ssklower 	if CLNPSRCRT_VALID(oidx) {
25736375Ssklower 		/*
25836375Ssklower 		 *	Update src route first
25936375Ssklower 		 */
26036375Ssklower 		clnp_update_srcrt(m, oidx);
26136375Ssklower 		error = clnp_srcroute(m, oidx, &route, &next_hop, &ifp, dst);
26236375Ssklower 	} else {
26336375Ssklower 		error = clnp_route(dst, &route, 0, &next_hop, &ifp);
26436375Ssklower 	}
26536375Ssklower 	if (error) {
26636375Ssklower 		IFDEBUG(D_FORWARD)
26736375Ssklower 			printf("clnp_forward: can't route packet (errno %d)\n", error);
26836375Ssklower 		ENDDEBUG
26936375Ssklower 		clnp_discard(m, ADDR_DESTUNREACH);
27036375Ssklower 		goto done;
27136375Ssklower 	}
27236375Ssklower 
27336375Ssklower 	IFDEBUG(D_FORWARD)
27436375Ssklower 		printf("clnp_forward: packet routed to %s\n",
27536375Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
27636375Ssklower 	ENDDEBUG
27736375Ssklower 
27836375Ssklower 	INCSTAT(cns_forward);
27936375Ssklower 
28036375Ssklower 	/*
28136375Ssklower 	 *	If we are an intermediate system and
28236375Ssklower 	 *	we are routing outbound on the same ifp that the packet
28336375Ssklower 	 *	arrived upon, and we know the next hop snpa,
28436375Ssklower 	 *	then generate a redirect request
28536375Ssklower 	 */
28636375Ssklower 	if ((iso_systype & SNPA_IS) && (inbound_shp) &&
28736375Ssklower 		(ifp == inbound_shp->snh_ifp)) {
28836375Ssklower 		struct snpa_cache 			*sc;
28936375Ssklower 
29036375Ssklower 		sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr);
29136375Ssklower 		if (sc != NULL) {
29236375Ssklower 			esis_rdoutput(inbound_shp, m, oidx, dst, sc);
29336375Ssklower 		}
29436375Ssklower 	}
29536375Ssklower 
29636375Ssklower 	/*
29736375Ssklower 	 *	If options are present, update them
29836375Ssklower 	 */
29936375Ssklower 	if (oidx) {
30036375Ssklower 		struct iso_addr	*mysrc =
30136375Ssklower 			clnp_srcaddr(ifp, &((struct sockaddr_iso *)next_hop)->siso_addr);
30236375Ssklower 		if (mysrc == NULL) {
30336375Ssklower 			clnp_discard(m, ADDR_DESTUNREACH);
30436375Ssklower 			goto done;
30536375Ssklower 		} else {
306*36770Ssklower 			(void) clnp_dooptions(m, oidx, ifp, mysrc);
30736375Ssklower 		}
30836375Ssklower 	}
309*36770Ssklower 
310*36770Ssklower #ifdef	DECBIT
311*36770Ssklower 	if (ifp->if_snd.ifq_len > congest_threshold) {
312*36770Ssklower 		/*
313*36770Ssklower 		 *	Congestion! Set the Dec Bit and thank Dave Oran
314*36770Ssklower 		 */
315*36770Ssklower 		IFDEBUG(D_FORWARD)
316*36770Ssklower 			printf("clnp_forward: congestion experienced\n");
317*36770Ssklower 		ENDDEBUG
318*36770Ssklower 		if ((oidx) && (oidx->cni_qos_formatp)) {
319*36770Ssklower 			caddr_t	qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
320*36770Ssklower 			u_char	qos = *qosp;
321*36770Ssklower 			IFDEBUG(D_FORWARD)
322*36770Ssklower 				printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
323*36770Ssklower 			ENDDEBUG
324*36770Ssklower 			if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
325*36770Ssklower 				qos |= CLNPOVAL_CONGESTED;
326*36770Ssklower 				INCSTAT(cns_congest_set);
327*36770Ssklower 				*qosp = qos;
328*36770Ssklower 			}
329*36770Ssklower 		}
330*36770Ssklower 	}
331*36770Ssklower #endif	DECBIT
33236375Ssklower 
33336375Ssklower 	/*
33436375Ssklower 	 *	Dispatch the datagram if it is small enough, otherwise fragment
33536375Ssklower 	 */
33636375Ssklower 	if (len <= SN_MTU(ifp)) {
33736375Ssklower 		iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
33836375Ssklower 		(void) (*ifp->if_output)(ifp, m, next_hop);
33936375Ssklower 	} else {
34036375Ssklower 		(void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0);
34136375Ssklower 	}
34236375Ssklower 
34336375Ssklower done:
34436375Ssklower 	/*
34536375Ssklower 	 *	Free route
34636375Ssklower 	 */
34736375Ssklower 	if (route.ro_rt != NULL) {
34836375Ssklower 		RTFREE(route.ro_rt);
34936375Ssklower 	}
35036375Ssklower }
35136375Ssklower 
35236375Ssklower #ifdef	ndef
35336375Ssklower /*
35436375Ssklower  * FUNCTION:		clnp_insert_addr
35536375Ssklower  *
35636375Ssklower  * PURPOSE:			Insert the address part into a clnp datagram.
35736375Ssklower  *
35836375Ssklower  * RETURNS:			Address of first byte after address part in datagram.
35936375Ssklower  *
36036375Ssklower  * SIDE EFFECTS:
36136375Ssklower  *
36236375Ssklower  * NOTES:			Assume that there is enough space for the address part.
36336375Ssklower  */
36436375Ssklower caddr_t
36536375Ssklower clnp_insert_addr(bufp, srcp, dstp)
36636375Ssklower caddr_t						bufp;	/* address of where addr part goes */
36736375Ssklower register struct iso_addr	*srcp;	/* ptr to src addr */
36836375Ssklower register struct iso_addr	*dstp;	/* ptr to dst addr */
36936375Ssklower {
37036375Ssklower 	*bufp++ = dstp->isoa_len;
37136375Ssklower 	(void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
37236375Ssklower 	bufp += dstp->isoa_len;
37336375Ssklower 
37436375Ssklower 	*bufp++ = srcp->isoa_len;
37536375Ssklower 	(void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
37636375Ssklower 	bufp += srcp->isoa_len;
37736375Ssklower 
37836375Ssklower 	return bufp;
37936375Ssklower }
38036375Ssklower 
38136375Ssklower #endif	ndef
38236375Ssklower 
38336375Ssklower /*
38436375Ssklower  * FUNCTION:		clnp_route
38536375Ssklower  *
38636375Ssklower  * PURPOSE:			Route a clnp datagram to the first hop toward its
38736375Ssklower  *					destination. In many cases, the first hop will be
38836375Ssklower  *					the destination. The address of a route
38936375Ssklower  *					is specified. If a routing entry is present in
39036375Ssklower  *					that route, and it is still up to the same destination,
39136375Ssklower  *					then no further action is necessary. Otherwise, a
39236375Ssklower  *					new routing entry will be allocated.
39336375Ssklower  *
39436375Ssklower  * RETURNS:			route found - 0
39536375Ssklower  *					unix error code
39636375Ssklower  *
39736375Ssklower  * SIDE EFFECTS:
39836375Ssklower  *
39936375Ssklower  * NOTES:			It is up to the caller to free the routing entry
40036375Ssklower  *					allocated in route.
40136375Ssklower  */
40236375Ssklower clnp_route(dst, ro, flags, first_hop, ifp)
40336375Ssklower struct iso_addr		*dst;			/* ptr to datagram destination */
40436769Ssklower struct route_iso	*ro;			/* existing route structure */
40536375Ssklower int					flags;			/* flags for routing */
40636375Ssklower struct sockaddr		**first_hop;	/* result: fill in with ptr to firsthop */
40736375Ssklower struct ifnet		**ifp;			/* result: fill in with ptr to interface */
40836375Ssklower {
40936375Ssklower 	register struct sockaddr_iso	*ro_dst;	/* ptr to route's destination */
41036375Ssklower 
41136375Ssklower 	ro_dst = (struct sockaddr_iso *)&ro->ro_dst;
41236375Ssklower 
41336375Ssklower 	/*
41436375Ssklower 	 *	If there is a cached route, check that it is still up and to
41536375Ssklower 	 *	the same destination. If not, free it and try again.
41636375Ssklower 	 */
41736375Ssklower 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
41836375Ssklower 		(!iso_addrmatch1(&ro_dst->siso_addr, dst)))) {
41936375Ssklower 		IFDEBUG(D_ROUTE)
42036375Ssklower 			printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
42136375Ssklower 				ro->ro_rt);
42236375Ssklower 			printf("clnp_route: old route refcnt: 0x%x\n",
42336375Ssklower 				ro->ro_rt->rt_refcnt);
42436375Ssklower 		ENDDEBUG
42536375Ssklower 
42636375Ssklower 		/* free old route entry */
42736375Ssklower 		RTFREE(ro->ro_rt);
42836375Ssklower 		ro->ro_rt = (struct rtentry *)0;
42936375Ssklower 	} else {
43036375Ssklower 		IFDEBUG(D_ROUTE)
43136375Ssklower 			printf("clnp_route: OK route exists\n");
43236375Ssklower 		ENDDEBUG
43336375Ssklower 	}
43436375Ssklower 
43536375Ssklower 	if (ro->ro_rt == 0) {
43636375Ssklower 		/* set up new route structure */
43736375Ssklower 		ro_dst->siso_family = AF_ISO;
43836375Ssklower 		ro_dst->siso_addr = *dst;
43936375Ssklower 
44036375Ssklower 		/* allocate new route */
44136375Ssklower 		IFDEBUG(D_ROUTE)
44236375Ssklower 			printf("clnp_route: allocating new route to %s\n",
44336375Ssklower 				clnp_iso_addrp(dst));
44436375Ssklower 		ENDDEBUG
44536375Ssklower 		rtalloc(ro);
44636375Ssklower 	}
44736375Ssklower 
44836375Ssklower 	if ((ro->ro_rt == 0) || ((*ifp = ro->ro_rt->rt_ifp) == 0)) {
44936375Ssklower 		return(ENETUNREACH);	/* rtalloc failed */
45036375Ssklower 	}
45136375Ssklower 
45236375Ssklower 	ro->ro_rt->rt_use++;
45336375Ssklower 	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
45436375Ssklower 		*first_hop = &ro->ro_rt->rt_gateway;
45536375Ssklower 	else
45636375Ssklower 		*first_hop = (struct sockaddr *)ro_dst;
45736375Ssklower 
45836375Ssklower 	return(0);
45936375Ssklower }
46036375Ssklower 
46136375Ssklower /*
46236375Ssklower  * FUNCTION:		clnp_srcroute
46336375Ssklower  *
46436375Ssklower  * PURPOSE:			Source route the datagram. If complete source
46536375Ssklower  *					routing is specified but not possible, then
46636375Ssklower  *					return an error. If src routing is terminated, then
46736375Ssklower  *					try routing on destination.
46836375Ssklower  *					Usage of first_hop,
46936375Ssklower  *					ifp, and error return is identical to clnp_route.
47036375Ssklower  *
47136375Ssklower  * RETURNS:			0 or unix error code
47236375Ssklower  *
47336375Ssklower  * SIDE EFFECTS:
47436375Ssklower  *
47536375Ssklower  * NOTES:			Remember that option index pointers are really
47636375Ssklower  *					offsets from the beginning of the mbuf.
47736375Ssklower  */
47836375Ssklower clnp_srcroute(options, oidx, route, first_hop, ifp, final_dst)
47936375Ssklower struct mbuf			*options;		/* ptr to options */
48036375Ssklower struct clnp_optidx	*oidx;			/* index to options */
48136375Ssklower struct route		*route;			/* route structure */
48236375Ssklower struct sockaddr		**first_hop;	/* RETURN: fill in with ptr to firsthop */
48336375Ssklower struct ifnet		**ifp;			/* RETURN: fill in with ptr to interface */
48436375Ssklower struct iso_addr		*final_dst;		/* final destination */
48536375Ssklower {
48636375Ssklower 	struct iso_addr	dst;		/* first hop specified by src rt */
48736375Ssklower 	int				error = 0;	/* return code */
48836375Ssklower 
48936375Ssklower 	/*
49036375Ssklower 	 *	Check if we have run out of routes
49136375Ssklower 	 *	If so, then try to route on destination.
49236375Ssklower 	 */
49336375Ssklower 	if CLNPSRCRT_TERM(oidx, options) {
49436375Ssklower 		dst.isoa_len = final_dst->isoa_len;
49536375Ssklower 		bcopy((caddr_t)final_dst, (caddr_t)&dst, dst.isoa_len);
49636375Ssklower 	} else {
49736375Ssklower 		/*
49836375Ssklower 		 * setup dst based on src rt specified
49936375Ssklower 		 */
50036375Ssklower 		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
50136375Ssklower 		bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&dst, dst.isoa_len);
50236375Ssklower 	}
50336375Ssklower 
50436375Ssklower 	/*
50536375Ssklower 	 *	try to route it
50636375Ssklower 	 */
50736375Ssklower 	error = clnp_route(&dst, route, 0, first_hop, ifp);
50836375Ssklower 	if (error != 0)
50936375Ssklower 		return error;
51036375Ssklower 
51136375Ssklower 	/*
51236375Ssklower 	 *	If complete src rt, first hop must be equal to dst
51336375Ssklower 	 */
51436375Ssklower 	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
51536375Ssklower 	 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
51636375Ssklower 		IFDEBUG(D_OPTIONS)
51736375Ssklower 			printf("clnp_srcroute: complete src route failed\n");
51836375Ssklower 		ENDDEBUG
51936375Ssklower 		return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
52036375Ssklower 	}
52136375Ssklower 
52236375Ssklower 	return error;
52336375Ssklower }
52436375Ssklower 
52536375Ssklower /*
52636375Ssklower  * FUNCTION:		clnp_srcaddr
52736375Ssklower  *
52836375Ssklower  * PURPOSE:			Build the correct source address for a datagram based on the
52936375Ssklower  *					outgoing interface and firsthop. The firsthop information
53036375Ssklower  *					is needed inorder to decide which addr to use if
53136375Ssklower  *					>1 ISO addr is present for an ifp.
53236375Ssklower  *
53336375Ssklower  * RETURNS:			a ptr to a static copy of the source address.
53436375Ssklower  *					or NULL
53536375Ssklower  *
53636375Ssklower  * SIDE EFFECTS:
53736375Ssklower  *
53836375Ssklower  * NOTES:			The ifp must be valid, or we will return NULL
53936375Ssklower  */
54036375Ssklower static struct iso_addr mysrc;
54136375Ssklower struct iso_addr *
54236375Ssklower clnp_srcaddr(ifp, firsthop)
54336375Ssklower struct ifnet	*ifp;		/* ptr to interface to send packet on */
54436375Ssklower struct iso_addr	*firsthop;	/* ptr to first hop for packet */
54536375Ssklower {
54636375Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
54736375Ssklower 	struct iso_addr				*maybe = NULL;
54836375Ssklower 
54936375Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
55036375Ssklower 		if (ia->ia_ifp == ifp) {
55136375Ssklower 			struct iso_addr	*isoa = &IA_SIS(ia)->siso_addr;
55236375Ssklower 
55336375Ssklower 			IFDEBUG(D_ROUTE)
55436375Ssklower 				printf("clnp_srcaddr: isoa is %s\n", clnp_iso_addrp(isoa));
55536375Ssklower 			ENDDEBUG
55636375Ssklower 
55736375Ssklower 			if (iso_eqtype(isoa, firsthop)) {
55836375Ssklower 				mysrc.isoa_len = isoa->isoa_len;
55936375Ssklower 				bcopy((caddr_t)isoa, (caddr_t)&mysrc, mysrc.isoa_len);
56036375Ssklower 				return(&mysrc);
56136375Ssklower 			} else
56236375Ssklower 				maybe = isoa;
56336375Ssklower 		}
56436375Ssklower 	}
56536375Ssklower 
56636375Ssklower 	if (maybe != NULL) {
56736375Ssklower 		mysrc.isoa_len = maybe->isoa_len;
56836375Ssklower 		bcopy((caddr_t)maybe, (caddr_t)&mysrc, mysrc.isoa_len);
56936375Ssklower 		return(&mysrc);
57036375Ssklower 	} else {
57136375Ssklower 		/*
57236375Ssklower 		 *	This will only happen if there are routes involving
57336375Ssklower 		 *	an interface that has just had all iso addresses deleted
57436375Ssklower 		 *	from it. This will happen if esisd has added a default
57536375Ssklower 		 *	route to an interface, and then the interface was
57636375Ssklower 		 *	marked down. As soon as esisd tries to send a pdu on that
57736375Ssklower 		 *	interface, it will discover it is down, and remove the
57836375Ssklower 		 *	route.  Nonetheless, there is a window for this discrepancy,
57936375Ssklower 		 *	so we will return null here rather than panicing.
58036375Ssklower 		 */
58136375Ssklower 		return(NULL);
58236375Ssklower 	}
58336375Ssklower }
58436375Ssklower 
58536375Ssklower /*
58636375Ssklower  * FUNCTION:		clnp_ypocb - backwards bcopy
58736375Ssklower  *
58836375Ssklower  * PURPOSE:			bcopy starting at end of src rather than beginning.
58936375Ssklower  *
59036375Ssklower  * RETURNS:			none
59136375Ssklower  *
59236375Ssklower  * SIDE EFFECTS:
59336375Ssklower  *
59436375Ssklower  * NOTES:			No attempt has been made to make this efficient
59536375Ssklower  */
59636375Ssklower clnp_ypocb(from, to, len)
59736375Ssklower caddr_t from;		/* src buffer */
59836375Ssklower caddr_t to;			/* dst buffer */
59936375Ssklower u_int	len;		/* number of bytes */
60036375Ssklower {
60136375Ssklower 	while (len--)
60236375Ssklower 		*(to + len) = *(from + len);
60336375Ssklower }
60436375Ssklower 
60536375Ssklower /*
60636375Ssklower  * FUNCTION:		clnp_hdrsize
60736375Ssklower  *
60836375Ssklower  * PURPOSE:			Return the size of a typical clnp hdr.
60936375Ssklower  *
61036375Ssklower  * RETURNS:			Size of hdr in bytes.
61136375Ssklower  *
61236375Ssklower  * SIDE EFFECTS:
61336375Ssklower  *
61436375Ssklower  * NOTES:			Assumes segmenting subset. If addrlen is
61536375Ssklower  *					zero, default to largest nsap address size.
61636375Ssklower  */
61736375Ssklower clnp_hdrsize(addrlen)
61836375Ssklower u_char	addrlen;		/* length of nsap address */
61936375Ssklower {
62036375Ssklower 	if (addrlen == 0)
62136375Ssklower 		addrlen = 20;
62236375Ssklower 
62336375Ssklower 	addrlen++;			/* length of address byte */
62436375Ssklower 	addrlen *= 2;		/* src and dst addresses */
62536375Ssklower 	addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
62636375Ssklower 
62736375Ssklower 	return(addrlen);
62836375Ssklower }
62936375Ssklower #endif	ISO
630