xref: /csrg-svn/sys/netiso/clnp_subr.c (revision 36375)
1*36375Ssklower /***********************************************************
2*36375Ssklower 		Copyright IBM Corporation 1987
3*36375Ssklower 
4*36375Ssklower                       All Rights Reserved
5*36375Ssklower 
6*36375Ssklower Permission to use, copy, modify, and distribute this software and its
7*36375Ssklower documentation for any purpose and without fee is hereby granted,
8*36375Ssklower provided that the above copyright notice appear in all copies and that
9*36375Ssklower both that copyright notice and this permission notice appear in
10*36375Ssklower supporting documentation, and that the name of IBM not be
11*36375Ssklower used in advertising or publicity pertaining to distribution of the
12*36375Ssklower software without specific, written prior permission.
13*36375Ssklower 
14*36375Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36375Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36375Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36375Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36375Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36375Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36375Ssklower SOFTWARE.
21*36375Ssklower 
22*36375Ssklower ******************************************************************/
23*36375Ssklower 
24*36375Ssklower /*
25*36375Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36375Ssklower  */
27*36375Ssklower /* $Header: clnp_subr.c,v 4.10 88/09/14 11:31:33 hagens Exp $ */
28*36375Ssklower /* $Source: /usr/argo/sys/netiso/RCS/clnp_subr.c,v $ */
29*36375Ssklower 
30*36375Ssklower #ifndef lint
31*36375Ssklower static char *rcsid = "$Header: clnp_subr.c,v 4.10 88/09/14 11:31:33 hagens Exp $";
32*36375Ssklower #endif lint
33*36375Ssklower 
34*36375Ssklower #ifdef ISO
35*36375Ssklower 
36*36375Ssklower #include "../h/types.h"
37*36375Ssklower #include "../h/param.h"
38*36375Ssklower #include "../h/mbuf.h"
39*36375Ssklower #include "../h/domain.h"
40*36375Ssklower #include "../h/protosw.h"
41*36375Ssklower #include "../h/socket.h"
42*36375Ssklower #include "../h/socketvar.h"
43*36375Ssklower #include "../h/errno.h"
44*36375Ssklower #include "../h/time.h"
45*36375Ssklower 
46*36375Ssklower #include "../net/if.h"
47*36375Ssklower #include "../net/route.h"
48*36375Ssklower 
49*36375Ssklower #include "../netiso/iso.h"
50*36375Ssklower #include "../netiso/iso_var.h"
51*36375Ssklower #include "../netiso/clnp.h"
52*36375Ssklower #include "../netiso/clnp_stat.h"
53*36375Ssklower #include "../netiso/argo_debug.h"
54*36375Ssklower #include "../netiso/iso_snpac.h"
55*36375Ssklower 
56*36375Ssklower /*
57*36375Ssklower  * FUNCTION:		clnp_data_ck
58*36375Ssklower  *
59*36375Ssklower  * PURPOSE:			Check that the amount of data in the mbuf chain is
60*36375Ssklower  *					at least as much as the clnp header would have us
61*36375Ssklower  *					expect. Trim mbufs if longer than expected, drop
62*36375Ssklower  *					packet if shorter than expected.
63*36375Ssklower  *
64*36375Ssklower  * RETURNS:			success - ptr to mbuf chain
65*36375Ssklower  *					failure - 0
66*36375Ssklower  *
67*36375Ssklower  * SIDE EFFECTS:
68*36375Ssklower  *
69*36375Ssklower  * NOTES:
70*36375Ssklower  */
71*36375Ssklower struct mbuf *
72*36375Ssklower clnp_data_ck(m, length)
73*36375Ssklower register struct mbuf	*m;		/* ptr to mbuf chain containing hdr & data */
74*36375Ssklower int						length;	/* length (in bytes) of packet */
75*36375Ssklower  {
76*36375Ssklower 	register int 			len;		/* length of data */
77*36375Ssklower 	register struct mbuf	*mhead;		/* ptr to head of chain */
78*36375Ssklower 
79*36375Ssklower 	len = -length;
80*36375Ssklower 	mhead = m;
81*36375Ssklower 	for (;;) {
82*36375Ssklower 		len += m->m_len;
83*36375Ssklower 		if (m->m_next == 0)
84*36375Ssklower 			break;
85*36375Ssklower 		m = m->m_next;
86*36375Ssklower 	}
87*36375Ssklower 	if (len != 0) {
88*36375Ssklower 		if (len < 0) {
89*36375Ssklower 			INCSTAT(cns_toosmall);
90*36375Ssklower 			clnp_discard(mhead, GEN_INCOMPLETE);
91*36375Ssklower 			return 0;
92*36375Ssklower 		}
93*36375Ssklower 		if (len <= m->m_len)
94*36375Ssklower 			m->m_len -= len;
95*36375Ssklower 		else
96*36375Ssklower 			m_adj(mhead, -len);
97*36375Ssklower 	}
98*36375Ssklower 	return mhead;
99*36375Ssklower }
100*36375Ssklower 
101*36375Ssklower #ifdef ndef
102*36375Ssklower /*
103*36375Ssklower  * FUNCTION:		clnp_extract_addr
104*36375Ssklower  *
105*36375Ssklower  * PURPOSE:			Extract the source and destination address from the
106*36375Ssklower  *					supplied buffer. Place them in the supplied address buffers.
107*36375Ssklower  *					If insufficient data is supplied, then fail.
108*36375Ssklower  *
109*36375Ssklower  * RETURNS:			success - Address of first byte in the packet past
110*36375Ssklower  *						the address part.
111*36375Ssklower  *					failure - 0
112*36375Ssklower  *
113*36375Ssklower  * SIDE EFFECTS:
114*36375Ssklower  *
115*36375Ssklower  * NOTES:
116*36375Ssklower  */
117*36375Ssklower caddr_t
118*36375Ssklower clnp_extract_addr(bufp, buflen, srcp, destp)
119*36375Ssklower caddr_t					bufp;		/* ptr to buffer containing addresses */
120*36375Ssklower int						buflen;		/* length of buffer */
121*36375Ssklower register struct iso_addr	*srcp;		/* ptr to source address buffer */
122*36375Ssklower register struct iso_addr	*destp;		/* ptr to destination address buffer */
123*36375Ssklower  {
124*36375Ssklower 	int	len;		/* argument to bcopy */
125*36375Ssklower 
126*36375Ssklower 	/*
127*36375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
128*36375Ssklower 	 */
129*36375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
130*36375Ssklower 		return((caddr_t)0);
131*36375Ssklower 	}
132*36375Ssklower 	len = destp->isoa_len = (u_char)*bufp++;
133*36375Ssklower 	(void) bcopy(bufp, (caddr_t)destp, len);
134*36375Ssklower 	buflen -= len;
135*36375Ssklower 	bufp += len;
136*36375Ssklower 
137*36375Ssklower 	/*
138*36375Ssklower 	 *	check that we have enough data. Plus1 is for length octet
139*36375Ssklower 	 */
140*36375Ssklower 	if ((u_char)*bufp + 1 > buflen) {
141*36375Ssklower 		return((caddr_t)0);
142*36375Ssklower 	}
143*36375Ssklower 	len = srcp->isoa_len = (u_char)* bufp++;
144*36375Ssklower 	(void) bcopy(bufp, (caddr_t)srcp, len);
145*36375Ssklower 	bufp += len;
146*36375Ssklower 
147*36375Ssklower 	/*
148*36375Ssklower 	 *	Insure that the addresses make sense
149*36375Ssklower 	 */
150*36375Ssklower 	if (iso_ck_addr(srcp) && iso_ck_addr(destp))
151*36375Ssklower 		return bufp;
152*36375Ssklower 	else
153*36375Ssklower 		return (caddr_t) 0;
154*36375Ssklower }
155*36375Ssklower #endif	ndef
156*36375Ssklower 
157*36375Ssklower /*
158*36375Ssklower  * FUNCTION:		clnp_ours
159*36375Ssklower  *
160*36375Ssklower  * PURPOSE:			Decide whether the supplied packet is destined for
161*36375Ssklower  *					us, or that it should be forwarded on.
162*36375Ssklower  *
163*36375Ssklower  * RETURNS:			packet is for us - 1
164*36375Ssklower  *					packet is not for us - 0
165*36375Ssklower  *
166*36375Ssklower  * SIDE EFFECTS:
167*36375Ssklower  *
168*36375Ssklower  * NOTES:
169*36375Ssklower  */
170*36375Ssklower clnp_ours(dst)
171*36375Ssklower register struct iso_addr *dst;		/* ptr to destination address */
172*36375Ssklower {
173*36375Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
174*36375Ssklower 
175*36375Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
176*36375Ssklower 		IFDEBUG(D_ROUTE)
177*36375Ssklower 			printf("clnp_ours: ia_sis x%x, dst x%x\n", &IA_SIS(ia)->siso_addr,
178*36375Ssklower 				dst);
179*36375Ssklower 		ENDDEBUG
180*36375Ssklower 		/* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */
181*36375Ssklower 		if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst))
182*36375Ssklower 			return 1;
183*36375Ssklower 	}
184*36375Ssklower 	return 0;
185*36375Ssklower }
186*36375Ssklower 
187*36375Ssklower /*
188*36375Ssklower  * FUNCTION:		clnp_forward
189*36375Ssklower  *
190*36375Ssklower  * PURPOSE:			Forward the datagram passed
191*36375Ssklower  *					clnpintr guarantees that the header will be
192*36375Ssklower  *					contigious (a cluster mbuf will be used if necessary).
193*36375Ssklower  *
194*36375Ssklower  *					If oidx is NULL, no options are present.
195*36375Ssklower  *
196*36375Ssklower  * RETURNS:			nothing
197*36375Ssklower  *
198*36375Ssklower  * SIDE EFFECTS:
199*36375Ssklower  *
200*36375Ssklower  * NOTES:
201*36375Ssklower  */
202*36375Ssklower clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
203*36375Ssklower struct mbuf			*m;		/* pkt to forward */
204*36375Ssklower int					len;	/* length of pkt */
205*36375Ssklower struct iso_addr		*dst;	/* destination address */
206*36375Ssklower struct clnp_optidx	*oidx;	/* option index */
207*36375Ssklower int					seg_off;/* offset of segmentation part */
208*36375Ssklower struct snpa_hdr		*inbound_shp;	/* subnetwork header of inbound packet */
209*36375Ssklower {
210*36375Ssklower 	struct clnp_fixed		*clnp;	/* ptr to fixed part of header */
211*36375Ssklower 	int						error;	/* return value of route function */
212*36375Ssklower 	struct sockaddr			*next_hop;	/* next hop for dgram */
213*36375Ssklower 	struct ifnet			*ifp;	/* ptr to outgoing interface */
214*36375Ssklower 	struct route			route;	/* filled in by clnp_route */
215*36375Ssklower 	extern int				iso_systype;
216*36375Ssklower 
217*36375Ssklower 	clnp = mtod(m, struct clnp_fixed *);
218*36375Ssklower 	bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
219*36375Ssklower 
220*36375Ssklower 	/*
221*36375Ssklower 	 *	Don't forward multicast or broadcast packets
222*36375Ssklower 	 */
223*36375Ssklower 	if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
224*36375Ssklower 		IFDEBUG(D_FORWARD)
225*36375Ssklower 			printf("clnp_forward: dropping multicast packet\n");
226*36375Ssklower 		ENDDEBUG
227*36375Ssklower 		clnp->cnf_err_ok = 0;	/* so we don't generate an ER */
228*36375Ssklower 		clnp_discard(m, 0);
229*36375Ssklower 		goto done;
230*36375Ssklower 	}
231*36375Ssklower 
232*36375Ssklower 	IFDEBUG(D_FORWARD)
233*36375Ssklower 		printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
234*36375Ssklower 			clnp_iso_addrp(dst), oidx);
235*36375Ssklower 	ENDDEBUG
236*36375Ssklower 
237*36375Ssklower 	/*
238*36375Ssklower 	 *	Decrement ttl, and if zero drop datagram
239*36375Ssklower 	 *	Can't compare ttl as less than zero 'cause its a unsigned
240*36375Ssklower 	 */
241*36375Ssklower 	if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
242*36375Ssklower 		IFDEBUG(D_FORWARD)
243*36375Ssklower 			printf("clnp_forward: discarding datagram because ttl is zero\n");
244*36375Ssklower 		ENDDEBUG
245*36375Ssklower 		INCSTAT(cns_ttlexpired);
246*36375Ssklower 		clnp_discard(m, TTL_EXPTRANSIT);
247*36375Ssklower 		goto done;
248*36375Ssklower 	}
249*36375Ssklower 
250*36375Ssklower 	/*
251*36375Ssklower 	 *	Route packet; special case for source rt
252*36375Ssklower 	 */
253*36375Ssklower 	if CLNPSRCRT_VALID(oidx) {
254*36375Ssklower 		/*
255*36375Ssklower 		 *	Update src route first
256*36375Ssklower 		 */
257*36375Ssklower 		clnp_update_srcrt(m, oidx);
258*36375Ssklower 		error = clnp_srcroute(m, oidx, &route, &next_hop, &ifp, dst);
259*36375Ssklower 	} else {
260*36375Ssklower 		error = clnp_route(dst, &route, 0, &next_hop, &ifp);
261*36375Ssklower 	}
262*36375Ssklower 	if (error) {
263*36375Ssklower 		IFDEBUG(D_FORWARD)
264*36375Ssklower 			printf("clnp_forward: can't route packet (errno %d)\n", error);
265*36375Ssklower 		ENDDEBUG
266*36375Ssklower 		clnp_discard(m, ADDR_DESTUNREACH);
267*36375Ssklower 		goto done;
268*36375Ssklower 	}
269*36375Ssklower 
270*36375Ssklower 	IFDEBUG(D_FORWARD)
271*36375Ssklower 		printf("clnp_forward: packet routed to %s\n",
272*36375Ssklower 			clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
273*36375Ssklower 	ENDDEBUG
274*36375Ssklower 
275*36375Ssklower 	INCSTAT(cns_forward);
276*36375Ssklower 
277*36375Ssklower 	/*
278*36375Ssklower 	 *	If we are an intermediate system and
279*36375Ssklower 	 *	we are routing outbound on the same ifp that the packet
280*36375Ssklower 	 *	arrived upon, and we know the next hop snpa,
281*36375Ssklower 	 *	then generate a redirect request
282*36375Ssklower 	 */
283*36375Ssklower 	if ((iso_systype & SNPA_IS) && (inbound_shp) &&
284*36375Ssklower 		(ifp == inbound_shp->snh_ifp)) {
285*36375Ssklower 		struct snpa_cache 			*sc;
286*36375Ssklower 
287*36375Ssklower 		sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr);
288*36375Ssklower 		if (sc != NULL) {
289*36375Ssklower 			esis_rdoutput(inbound_shp, m, oidx, dst, sc);
290*36375Ssklower 		}
291*36375Ssklower 	}
292*36375Ssklower 
293*36375Ssklower 	/*
294*36375Ssklower 	 *	If options are present, update them
295*36375Ssklower 	 */
296*36375Ssklower 	if (oidx) {
297*36375Ssklower 		struct iso_addr	*mysrc =
298*36375Ssklower 			clnp_srcaddr(ifp, &((struct sockaddr_iso *)next_hop)->siso_addr);
299*36375Ssklower 		if (mysrc == NULL) {
300*36375Ssklower 			clnp_discard(m, ADDR_DESTUNREACH);
301*36375Ssklower 			goto done;
302*36375Ssklower 		} else {
303*36375Ssklower 		(void) clnp_dooptions(m, oidx, ifp, mysrc);
304*36375Ssklower 		}
305*36375Ssklower 	}
306*36375Ssklower 
307*36375Ssklower 	/*
308*36375Ssklower 	 *	Dispatch the datagram if it is small enough, otherwise fragment
309*36375Ssklower 	 */
310*36375Ssklower 	if (len <= SN_MTU(ifp)) {
311*36375Ssklower 		iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
312*36375Ssklower 		(void) (*ifp->if_output)(ifp, m, next_hop);
313*36375Ssklower 	} else {
314*36375Ssklower 		(void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0);
315*36375Ssklower 	}
316*36375Ssklower 
317*36375Ssklower done:
318*36375Ssklower 	/*
319*36375Ssklower 	 *	Free route
320*36375Ssklower 	 */
321*36375Ssklower 	if (route.ro_rt != NULL) {
322*36375Ssklower 		RTFREE(route.ro_rt);
323*36375Ssklower 	}
324*36375Ssklower }
325*36375Ssklower 
326*36375Ssklower #ifdef	ndef
327*36375Ssklower /*
328*36375Ssklower  * FUNCTION:		clnp_insert_addr
329*36375Ssklower  *
330*36375Ssklower  * PURPOSE:			Insert the address part into a clnp datagram.
331*36375Ssklower  *
332*36375Ssklower  * RETURNS:			Address of first byte after address part in datagram.
333*36375Ssklower  *
334*36375Ssklower  * SIDE EFFECTS:
335*36375Ssklower  *
336*36375Ssklower  * NOTES:			Assume that there is enough space for the address part.
337*36375Ssklower  */
338*36375Ssklower caddr_t
339*36375Ssklower clnp_insert_addr(bufp, srcp, dstp)
340*36375Ssklower caddr_t						bufp;	/* address of where addr part goes */
341*36375Ssklower register struct iso_addr	*srcp;	/* ptr to src addr */
342*36375Ssklower register struct iso_addr	*dstp;	/* ptr to dst addr */
343*36375Ssklower {
344*36375Ssklower 	*bufp++ = dstp->isoa_len;
345*36375Ssklower 	(void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
346*36375Ssklower 	bufp += dstp->isoa_len;
347*36375Ssklower 
348*36375Ssklower 	*bufp++ = srcp->isoa_len;
349*36375Ssklower 	(void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
350*36375Ssklower 	bufp += srcp->isoa_len;
351*36375Ssklower 
352*36375Ssklower 	return bufp;
353*36375Ssklower }
354*36375Ssklower 
355*36375Ssklower #endif	ndef
356*36375Ssklower 
357*36375Ssklower /*
358*36375Ssklower  * FUNCTION:		clnp_route
359*36375Ssklower  *
360*36375Ssklower  * PURPOSE:			Route a clnp datagram to the first hop toward its
361*36375Ssklower  *					destination. In many cases, the first hop will be
362*36375Ssklower  *					the destination. The address of a route
363*36375Ssklower  *					is specified. If a routing entry is present in
364*36375Ssklower  *					that route, and it is still up to the same destination,
365*36375Ssklower  *					then no further action is necessary. Otherwise, a
366*36375Ssklower  *					new routing entry will be allocated.
367*36375Ssklower  *
368*36375Ssklower  * RETURNS:			route found - 0
369*36375Ssklower  *					unix error code
370*36375Ssklower  *
371*36375Ssklower  * SIDE EFFECTS:
372*36375Ssklower  *
373*36375Ssklower  * NOTES:			It is up to the caller to free the routing entry
374*36375Ssklower  *					allocated in route.
375*36375Ssklower  */
376*36375Ssklower clnp_route(dst, ro, flags, first_hop, ifp)
377*36375Ssklower struct iso_addr		*dst;			/* ptr to datagram destination */
378*36375Ssklower struct route		*ro;			/* existing route structure */
379*36375Ssklower int					flags;			/* flags for routing */
380*36375Ssklower struct sockaddr		**first_hop;	/* result: fill in with ptr to firsthop */
381*36375Ssklower struct ifnet		**ifp;			/* result: fill in with ptr to interface */
382*36375Ssklower {
383*36375Ssklower 	register struct sockaddr_iso	*ro_dst;	/* ptr to route's destination */
384*36375Ssklower 
385*36375Ssklower 	ro_dst = (struct sockaddr_iso *)&ro->ro_dst;
386*36375Ssklower 
387*36375Ssklower 	/*
388*36375Ssklower 	 *	If there is a cached route, check that it is still up and to
389*36375Ssklower 	 *	the same destination. If not, free it and try again.
390*36375Ssklower 	 */
391*36375Ssklower 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
392*36375Ssklower 		(!iso_addrmatch1(&ro_dst->siso_addr, dst)))) {
393*36375Ssklower 		IFDEBUG(D_ROUTE)
394*36375Ssklower 			printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
395*36375Ssklower 				ro->ro_rt);
396*36375Ssklower 			printf("clnp_route: old route refcnt: 0x%x\n",
397*36375Ssklower 				ro->ro_rt->rt_refcnt);
398*36375Ssklower 		ENDDEBUG
399*36375Ssklower 
400*36375Ssklower 		/* free old route entry */
401*36375Ssklower 		RTFREE(ro->ro_rt);
402*36375Ssklower 		ro->ro_rt = (struct rtentry *)0;
403*36375Ssklower 	} else {
404*36375Ssklower 		IFDEBUG(D_ROUTE)
405*36375Ssklower 			printf("clnp_route: OK route exists\n");
406*36375Ssklower 		ENDDEBUG
407*36375Ssklower 	}
408*36375Ssklower 
409*36375Ssklower 	if (ro->ro_rt == 0) {
410*36375Ssklower 		/* set up new route structure */
411*36375Ssklower 		ro_dst->siso_family = AF_ISO;
412*36375Ssklower 		ro_dst->siso_addr = *dst;
413*36375Ssklower 
414*36375Ssklower 		/* allocate new route */
415*36375Ssklower 		IFDEBUG(D_ROUTE)
416*36375Ssklower 			printf("clnp_route: allocating new route to %s\n",
417*36375Ssklower 				clnp_iso_addrp(dst));
418*36375Ssklower 		ENDDEBUG
419*36375Ssklower 		rtalloc(ro);
420*36375Ssklower 	}
421*36375Ssklower 
422*36375Ssklower 	if ((ro->ro_rt == 0) || ((*ifp = ro->ro_rt->rt_ifp) == 0)) {
423*36375Ssklower 		return(ENETUNREACH);	/* rtalloc failed */
424*36375Ssklower 	}
425*36375Ssklower 
426*36375Ssklower 	ro->ro_rt->rt_use++;
427*36375Ssklower 	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
428*36375Ssklower 		*first_hop = &ro->ro_rt->rt_gateway;
429*36375Ssklower 	else
430*36375Ssklower 		*first_hop = (struct sockaddr *)ro_dst;
431*36375Ssklower 
432*36375Ssklower 	return(0);
433*36375Ssklower }
434*36375Ssklower 
435*36375Ssklower /*
436*36375Ssklower  * FUNCTION:		clnp_srcroute
437*36375Ssklower  *
438*36375Ssklower  * PURPOSE:			Source route the datagram. If complete source
439*36375Ssklower  *					routing is specified but not possible, then
440*36375Ssklower  *					return an error. If src routing is terminated, then
441*36375Ssklower  *					try routing on destination.
442*36375Ssklower  *					Usage of first_hop,
443*36375Ssklower  *					ifp, and error return is identical to clnp_route.
444*36375Ssklower  *
445*36375Ssklower  * RETURNS:			0 or unix error code
446*36375Ssklower  *
447*36375Ssklower  * SIDE EFFECTS:
448*36375Ssklower  *
449*36375Ssklower  * NOTES:			Remember that option index pointers are really
450*36375Ssklower  *					offsets from the beginning of the mbuf.
451*36375Ssklower  */
452*36375Ssklower clnp_srcroute(options, oidx, route, first_hop, ifp, final_dst)
453*36375Ssklower struct mbuf			*options;		/* ptr to options */
454*36375Ssklower struct clnp_optidx	*oidx;			/* index to options */
455*36375Ssklower struct route		*route;			/* route structure */
456*36375Ssklower struct sockaddr		**first_hop;	/* RETURN: fill in with ptr to firsthop */
457*36375Ssklower struct ifnet		**ifp;			/* RETURN: fill in with ptr to interface */
458*36375Ssklower struct iso_addr		*final_dst;		/* final destination */
459*36375Ssklower {
460*36375Ssklower 	struct iso_addr	dst;		/* first hop specified by src rt */
461*36375Ssklower 	int				error = 0;	/* return code */
462*36375Ssklower 
463*36375Ssklower 	/*
464*36375Ssklower 	 *	Check if we have run out of routes
465*36375Ssklower 	 *	If so, then try to route on destination.
466*36375Ssklower 	 */
467*36375Ssklower 	if CLNPSRCRT_TERM(oidx, options) {
468*36375Ssklower 		dst.isoa_len = final_dst->isoa_len;
469*36375Ssklower 		bcopy((caddr_t)final_dst, (caddr_t)&dst, dst.isoa_len);
470*36375Ssklower 	} else {
471*36375Ssklower 		/*
472*36375Ssklower 		 * setup dst based on src rt specified
473*36375Ssklower 		 */
474*36375Ssklower 		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
475*36375Ssklower 		bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&dst, dst.isoa_len);
476*36375Ssklower 	}
477*36375Ssklower 
478*36375Ssklower 	/*
479*36375Ssklower 	 *	try to route it
480*36375Ssklower 	 */
481*36375Ssklower 	error = clnp_route(&dst, route, 0, first_hop, ifp);
482*36375Ssklower 	if (error != 0)
483*36375Ssklower 		return error;
484*36375Ssklower 
485*36375Ssklower 	/*
486*36375Ssklower 	 *	If complete src rt, first hop must be equal to dst
487*36375Ssklower 	 */
488*36375Ssklower 	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
489*36375Ssklower 	 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
490*36375Ssklower 		IFDEBUG(D_OPTIONS)
491*36375Ssklower 			printf("clnp_srcroute: complete src route failed\n");
492*36375Ssklower 		ENDDEBUG
493*36375Ssklower 		return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
494*36375Ssklower 	}
495*36375Ssklower 
496*36375Ssklower 	return error;
497*36375Ssklower }
498*36375Ssklower 
499*36375Ssklower /*
500*36375Ssklower  * FUNCTION:		clnp_srcaddr
501*36375Ssklower  *
502*36375Ssklower  * PURPOSE:			Build the correct source address for a datagram based on the
503*36375Ssklower  *					outgoing interface and firsthop. The firsthop information
504*36375Ssklower  *					is needed inorder to decide which addr to use if
505*36375Ssklower  *					>1 ISO addr is present for an ifp.
506*36375Ssklower  *
507*36375Ssklower  * RETURNS:			a ptr to a static copy of the source address.
508*36375Ssklower  *					or NULL
509*36375Ssklower  *
510*36375Ssklower  * SIDE EFFECTS:
511*36375Ssklower  *
512*36375Ssklower  * NOTES:			The ifp must be valid, or we will return NULL
513*36375Ssklower  */
514*36375Ssklower static struct iso_addr mysrc;
515*36375Ssklower struct iso_addr *
516*36375Ssklower clnp_srcaddr(ifp, firsthop)
517*36375Ssklower struct ifnet	*ifp;		/* ptr to interface to send packet on */
518*36375Ssklower struct iso_addr	*firsthop;	/* ptr to first hop for packet */
519*36375Ssklower {
520*36375Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
521*36375Ssklower 	struct iso_addr				*maybe = NULL;
522*36375Ssklower 
523*36375Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
524*36375Ssklower 		if (ia->ia_ifp == ifp) {
525*36375Ssklower 			struct iso_addr	*isoa = &IA_SIS(ia)->siso_addr;
526*36375Ssklower 
527*36375Ssklower 			IFDEBUG(D_ROUTE)
528*36375Ssklower 				printf("clnp_srcaddr: isoa is %s\n", clnp_iso_addrp(isoa));
529*36375Ssklower 			ENDDEBUG
530*36375Ssklower 
531*36375Ssklower 			if (iso_eqtype(isoa, firsthop)) {
532*36375Ssklower 				mysrc.isoa_len = isoa->isoa_len;
533*36375Ssklower 				bcopy((caddr_t)isoa, (caddr_t)&mysrc, mysrc.isoa_len);
534*36375Ssklower 				return(&mysrc);
535*36375Ssklower 			} else
536*36375Ssklower 				maybe = isoa;
537*36375Ssklower 		}
538*36375Ssklower 	}
539*36375Ssklower 
540*36375Ssklower 	if (maybe != NULL) {
541*36375Ssklower 		mysrc.isoa_len = maybe->isoa_len;
542*36375Ssklower 		bcopy((caddr_t)maybe, (caddr_t)&mysrc, mysrc.isoa_len);
543*36375Ssklower 		return(&mysrc);
544*36375Ssklower 	} else {
545*36375Ssklower 		/*
546*36375Ssklower 		 *	This will only happen if there are routes involving
547*36375Ssklower 		 *	an interface that has just had all iso addresses deleted
548*36375Ssklower 		 *	from it. This will happen if esisd has added a default
549*36375Ssklower 		 *	route to an interface, and then the interface was
550*36375Ssklower 		 *	marked down. As soon as esisd tries to send a pdu on that
551*36375Ssklower 		 *	interface, it will discover it is down, and remove the
552*36375Ssklower 		 *	route.  Nonetheless, there is a window for this discrepancy,
553*36375Ssklower 		 *	so we will return null here rather than panicing.
554*36375Ssklower 		 */
555*36375Ssklower 		return(NULL);
556*36375Ssklower 	}
557*36375Ssklower }
558*36375Ssklower 
559*36375Ssklower /*
560*36375Ssklower  * FUNCTION:		clnp_ypocb - backwards bcopy
561*36375Ssklower  *
562*36375Ssklower  * PURPOSE:			bcopy starting at end of src rather than beginning.
563*36375Ssklower  *
564*36375Ssklower  * RETURNS:			none
565*36375Ssklower  *
566*36375Ssklower  * SIDE EFFECTS:
567*36375Ssklower  *
568*36375Ssklower  * NOTES:			No attempt has been made to make this efficient
569*36375Ssklower  */
570*36375Ssklower clnp_ypocb(from, to, len)
571*36375Ssklower caddr_t from;		/* src buffer */
572*36375Ssklower caddr_t to;			/* dst buffer */
573*36375Ssklower u_int	len;		/* number of bytes */
574*36375Ssklower {
575*36375Ssklower 	while (len--)
576*36375Ssklower 		*(to + len) = *(from + len);
577*36375Ssklower }
578*36375Ssklower 
579*36375Ssklower /*
580*36375Ssklower  * FUNCTION:		clnp_hdrsize
581*36375Ssklower  *
582*36375Ssklower  * PURPOSE:			Return the size of a typical clnp hdr.
583*36375Ssklower  *
584*36375Ssklower  * RETURNS:			Size of hdr in bytes.
585*36375Ssklower  *
586*36375Ssklower  * SIDE EFFECTS:
587*36375Ssklower  *
588*36375Ssklower  * NOTES:			Assumes segmenting subset. If addrlen is
589*36375Ssklower  *					zero, default to largest nsap address size.
590*36375Ssklower  */
591*36375Ssklower clnp_hdrsize(addrlen)
592*36375Ssklower u_char	addrlen;		/* length of nsap address */
593*36375Ssklower {
594*36375Ssklower 	if (addrlen == 0)
595*36375Ssklower 		addrlen = 20;
596*36375Ssklower 
597*36375Ssklower 	addrlen++;			/* length of address byte */
598*36375Ssklower 	addrlen *= 2;		/* src and dst addresses */
599*36375Ssklower 	addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
600*36375Ssklower 
601*36375Ssklower 	return(addrlen);
602*36375Ssklower }
603*36375Ssklower #endif	ISO
604