xref: /csrg-svn/sys/netiso/clnp_subr.c (revision 38841)
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.6 (Berkeley) 08/29/89 */
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_SIS(ia)->siso_addr,
180 				dst);
181 		ENDDEBUG
182 		/* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */
183 		if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst))
184 			return 1;
185 	}
186 	return 0;
187 }
188 
189 /* Dec bit set if ifp qlen is greater than congest_threshold */
190 int congest_threshold = 0;
191 
192 /*
193  * FUNCTION:		clnp_forward
194  *
195  * PURPOSE:			Forward the datagram passed
196  *					clnpintr guarantees that the header will be
197  *					contigious (a cluster mbuf will be used if necessary).
198  *
199  *					If oidx is NULL, no options are present.
200  *
201  * RETURNS:			nothing
202  *
203  * SIDE EFFECTS:
204  *
205  * NOTES:
206  */
207 clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
208 struct mbuf			*m;		/* pkt to forward */
209 int					len;	/* length of pkt */
210 struct iso_addr		*dst;	/* destination address */
211 struct clnp_optidx	*oidx;	/* option index */
212 int					seg_off;/* offset of segmentation part */
213 struct snpa_hdr		*inbound_shp;	/* subnetwork header of inbound packet */
214 {
215 	struct clnp_fixed		*clnp;	/* ptr to fixed part of header */
216 	int						error;	/* return value of route function */
217 	struct sockaddr			*next_hop;	/* next hop for dgram */
218 	struct ifnet			*ifp;	/* ptr to outgoing interface */
219 	struct iso_ifaddr		*ia = 0;/* ptr to iso name for ifp */
220 	struct route_iso		route;	/* filled in by clnp_route */
221 	extern int				iso_systype;
222 
223 	clnp = mtod(m, struct clnp_fixed *);
224 	bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
225 
226 	/*
227 	 *	Don't forward multicast or broadcast packets
228 	 */
229 	if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
230 		IFDEBUG(D_FORWARD)
231 			printf("clnp_forward: dropping multicast packet\n");
232 		ENDDEBUG
233 		clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */
234 		clnp_discard(m, 0);
235 		goto done;
236 	}
237 
238 	IFDEBUG(D_FORWARD)
239 		printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
240 			clnp_iso_addrp(dst), oidx);
241 	ENDDEBUG
242 
243 	/*
244 	 *	Decrement ttl, and if zero drop datagram
245 	 *	Can't compare ttl as less than zero 'cause its a unsigned
246 	 */
247 	if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
248 		IFDEBUG(D_FORWARD)
249 			printf("clnp_forward: discarding datagram because ttl is zero\n");
250 		ENDDEBUG
251 		INCSTAT(cns_ttlexpired);
252 		clnp_discard(m, TTL_EXPTRANSIT);
253 		goto done;
254 	}
255 	/*
256 	 *	Route packet; special case for source rt
257 	 */
258 	if CLNPSRCRT_VALID(oidx) {
259 		/*
260 		 *	Update src route first
261 		 */
262 		clnp_update_srcrt(m, oidx);
263 		error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
264 	} else {
265 		error = clnp_route(dst, &route, 0, &next_hop, &ia);
266 	}
267 	if (error || ia == 0) {
268 		IFDEBUG(D_FORWARD)
269 			printf("clnp_forward: can't route packet (errno %d)\n", error);
270 		ENDDEBUG
271 		clnp_discard(m, ADDR_DESTUNREACH);
272 		goto done;
273 	}
274 	ifp = ia->ia_ifp;
275 
276 	IFDEBUG(D_FORWARD)
277 		printf("clnp_forward: packet routed to %s\n",
278 			clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
279 	ENDDEBUG
280 
281 	INCSTAT(cns_forward);
282 
283 	/*
284 	 *	If we are an intermediate system and
285 	 *	we are routing outbound on the same ifp that the packet
286 	 *	arrived upon, and we know the next hop snpa,
287 	 *	then generate a redirect request
288 	 */
289 	if ((iso_systype & SNPA_IS) && (inbound_shp) &&
290 		(ifp == inbound_shp->snh_ifp)) {
291 		struct snpa_cache 			*sc;
292 
293 		sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr);
294 		if (sc != NULL) {
295 			esis_rdoutput(inbound_shp, m, oidx, dst, sc);
296 		}
297 	}
298 
299 	/*
300 	 *	If options are present, update them
301 	 */
302 	if (oidx) {
303 		struct iso_addr	*mysrc = &ia->ia_addr.siso_addr;
304 		if (mysrc == NULL) {
305 			clnp_discard(m, ADDR_DESTUNREACH);
306 			goto done;
307 		} else {
308 			(void) clnp_dooptions(m, oidx, ifp, mysrc);
309 		}
310 	}
311 
312 #ifdef	DECBIT
313 	if (ifp->if_snd.ifq_len > congest_threshold) {
314 		/*
315 		 *	Congestion! Set the Dec Bit and thank Dave Oran
316 		 */
317 		IFDEBUG(D_FORWARD)
318 			printf("clnp_forward: congestion experienced\n");
319 		ENDDEBUG
320 		if ((oidx) && (oidx->cni_qos_formatp)) {
321 			caddr_t	qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
322 			u_char	qos = *qosp;
323 			IFDEBUG(D_FORWARD)
324 				printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
325 			ENDDEBUG
326 			if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
327 				qos |= CLNPOVAL_CONGESTED;
328 				INCSTAT(cns_congest_set);
329 				*qosp = qos;
330 			}
331 		}
332 	}
333 #endif	DECBIT
334 
335 	/*
336 	 *	Dispatch the datagram if it is small enough, otherwise fragment
337 	 */
338 	if (len <= SN_MTU(ifp)) {
339 		iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
340 		(void) (*ifp->if_output)(ifp, m, next_hop);
341 	} else {
342 		(void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0);
343 	}
344 
345 done:
346 	/*
347 	 *	Free route
348 	 */
349 	if (route.ro_rt != NULL) {
350 		RTFREE(route.ro_rt);
351 	}
352 }
353 
354 #ifdef	ndef
355 /*
356  * FUNCTION:		clnp_insert_addr
357  *
358  * PURPOSE:			Insert the address part into a clnp datagram.
359  *
360  * RETURNS:			Address of first byte after address part in datagram.
361  *
362  * SIDE EFFECTS:
363  *
364  * NOTES:			Assume that there is enough space for the address part.
365  */
366 caddr_t
367 clnp_insert_addr(bufp, srcp, dstp)
368 caddr_t						bufp;	/* address of where addr part goes */
369 register struct iso_addr	*srcp;	/* ptr to src addr */
370 register struct iso_addr	*dstp;	/* ptr to dst addr */
371 {
372 	*bufp++ = dstp->isoa_len;
373 	(void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
374 	bufp += dstp->isoa_len;
375 
376 	*bufp++ = srcp->isoa_len;
377 	(void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
378 	bufp += srcp->isoa_len;
379 
380 	return bufp;
381 }
382 
383 #endif	ndef
384 
385 /*
386  * FUNCTION:		clnp_route
387  *
388  * PURPOSE:			Route a clnp datagram to the first hop toward its
389  *					destination. In many cases, the first hop will be
390  *					the destination. The address of a route
391  *					is specified. If a routing entry is present in
392  *					that route, and it is still up to the same destination,
393  *					then no further action is necessary. Otherwise, a
394  *					new routing entry will be allocated.
395  *
396  * RETURNS:			route found - 0
397  *					unix error code
398  *
399  * SIDE EFFECTS:
400  *
401  * NOTES:			It is up to the caller to free the routing entry
402  *					allocated in route.
403  */
404 clnp_route(dst, ro, flags, first_hop, ifa)
405 	struct iso_addr	*dst;			/* ptr to datagram destination */
406 	register struct	route_iso *ro;	/* existing route structure */
407 	int flags;						/* flags for routing */
408 	struct sockaddr **first_hop;	/* result: fill in with ptr to firsthop */
409 	struct iso_ifaddr **ifa;		/* result: fill in with ptr to interface */
410 {
411 	if (flags & SO_DONTROUTE) {
412 		struct iso_ifaddr *ia;
413 
414 		if (ro->ro_rt) {
415 			RTFREE(ro->ro_rt);
416 			ro->ro_rt = 0;
417 		}
418 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
419 		bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr,
420 			1 + (unsigned)dst->isoa_len);
421 		ro->ro_dst.siso_family = AF_ISO;
422 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
423 		ia = iso_localifa(&ro->ro_dst);
424 		if (ia == 0)
425 			return EADDRNOTAVAIL;
426 		if (ifa)
427 			*ifa = ia;
428 		if (first_hop)
429 			*first_hop = (struct sockaddr *)&ro->ro_dst;
430 		return 0;
431 	}
432 	/*
433 	 *	If there is a cached route, check that it is still up and to
434 	 *	the same destination. If not, free it and try again.
435 	 */
436 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
437 		(Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
438 		IFDEBUG(D_ROUTE)
439 			printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
440 				ro->ro_rt);
441 			printf("clnp_route: old route refcnt: 0x%x\n",
442 				ro->ro_rt->rt_refcnt);
443 		ENDDEBUG
444 
445 		/* free old route entry */
446 		RTFREE(ro->ro_rt);
447 		ro->ro_rt = (struct rtentry *)0;
448 	} else {
449 		IFDEBUG(D_ROUTE)
450 			printf("clnp_route: OK route exists\n");
451 		ENDDEBUG
452 	}
453 
454 	if (ro->ro_rt == 0) {
455 		/* set up new route structure */
456 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
457 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
458 		ro->ro_dst.siso_family = AF_ISO;
459 		Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len);
460 		/* allocate new route */
461 		IFDEBUG(D_ROUTE)
462 			printf("clnp_route: allocating new route to %s\n",
463 				clnp_iso_addrp(dst));
464 		ENDDEBUG
465 		rtalloc((struct route *)ro);
466 	}
467 	if (ro->ro_rt == 0)
468 		return(ENETUNREACH);	/* rtalloc failed */
469 	ro->ro_rt->rt_use++;
470 	if (ifa)
471 		if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
472 			panic("clnp_route");
473 	if (first_hop) {
474 		if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
475 			*first_hop = ro->ro_rt->rt_gateway;
476 		else
477 			*first_hop = (struct sockaddr *)&ro->ro_dst;
478 	}
479 	return(0);
480 }
481 
482 /*
483  * FUNCTION:		clnp_srcroute
484  *
485  * PURPOSE:			Source route the datagram. If complete source
486  *					routing is specified but not possible, then
487  *					return an error. If src routing is terminated, then
488  *					try routing on destination.
489  *					Usage of first_hop,
490  *					ifp, and error return is identical to clnp_route.
491  *
492  * RETURNS:			0 or unix error code
493  *
494  * SIDE EFFECTS:
495  *
496  * NOTES:			Remember that option index pointers are really
497  *					offsets from the beginning of the mbuf.
498  */
499 clnp_srcroute(options, oidx, route, first_hop, ifa, final_dst)
500 struct mbuf			*options;		/* ptr to options */
501 struct clnp_optidx	*oidx;			/* index to options */
502 struct route_iso	*route;			/* route structure */
503 struct sockaddr		**first_hop;	/* RETURN: fill in with ptr to firsthop */
504 struct iso_ifaddr	**ifa;			/* RETURN: fill in with ptr to interface */
505 struct iso_addr		*final_dst;		/* final destination */
506 {
507 	struct iso_addr	dst;		/* first hop specified by src rt */
508 	int				error = 0;	/* return code */
509 
510 	/*
511 	 *	Check if we have run out of routes
512 	 *	If so, then try to route on destination.
513 	 */
514 	if CLNPSRCRT_TERM(oidx, options) {
515 		dst.isoa_len = final_dst->isoa_len;
516 		bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len);
517 	} else {
518 		/*
519 		 * setup dst based on src rt specified
520 		 */
521 		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
522 		bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len);
523 	}
524 
525 	/*
526 	 *	try to route it
527 	 */
528 	error = clnp_route(&dst, route, 0, first_hop, ifa);
529 	if (error != 0)
530 		return error;
531 
532 	/*
533 	 *	If complete src rt, first hop must be equal to dst
534 	 */
535 	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
536 	 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
537 		IFDEBUG(D_OPTIONS)
538 			printf("clnp_srcroute: complete src route failed\n");
539 		ENDDEBUG
540 		return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
541 	}
542 
543 	return error;
544 }
545 
546 /*
547  * FUNCTION:		clnp_ypocb - backwards bcopy
548  *
549  * PURPOSE:			bcopy starting at end of src rather than beginning.
550  *
551  * RETURNS:			none
552  *
553  * SIDE EFFECTS:
554  *
555  * NOTES:			No attempt has been made to make this efficient
556  */
557 clnp_ypocb(from, to, len)
558 caddr_t from;		/* src buffer */
559 caddr_t to;			/* dst buffer */
560 u_int	len;		/* number of bytes */
561 {
562 	while (len--)
563 		*(to + len) = *(from + len);
564 }
565 
566 /*
567  * FUNCTION:		clnp_hdrsize
568  *
569  * PURPOSE:			Return the size of a typical clnp hdr.
570  *
571  * RETURNS:			Size of hdr in bytes.
572  *
573  * SIDE EFFECTS:
574  *
575  * NOTES:			Assumes segmenting subset. If addrlen is
576  *					zero, default to largest nsap address size.
577  */
578 clnp_hdrsize(addrlen)
579 u_char	addrlen;		/* length of nsap address */
580 {
581 	if (addrlen == 0)
582 		addrlen = 20;
583 
584 	addrlen++;			/* length of address byte */
585 	addrlen *= 2;		/* src and dst addresses */
586 	addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
587 
588 	return(addrlen);
589 }
590 #endif	ISO
591