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