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