xref: /original-bsd/sys/netiso/clnp_subr.c (revision 87febec0)
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 sockaddr_iso dest;
412 		struct iso_ifaddr *ia;
413 
414 		bzero((caddr_t)&dest, sizeof(dest));
415 		bcopy((caddr_t)dst, (caddr_t)&dest.siso_addr,
416 			1 + (unsigned)dst->isoa_len);
417 		dest.siso_family = AF_ISO;
418 		dest.siso_len = sizeof(dest);
419 		ia = iso_localifa(&dest);
420 		if (ia == 0)
421 			return EADDRNOTAVAIL;
422 		if (ifa)
423 			*ifa = (struct iso_ifaddr *)ia;
424 		return 0;
425 	}
426 	/*
427 	 *	If there is a cached route, check that it is still up and to
428 	 *	the same destination. If not, free it and try again.
429 	 */
430 	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
431 		(Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
432 		IFDEBUG(D_ROUTE)
433 			printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
434 				ro->ro_rt);
435 			printf("clnp_route: old route refcnt: 0x%x\n",
436 				ro->ro_rt->rt_refcnt);
437 		ENDDEBUG
438 
439 		/* free old route entry */
440 		RTFREE(ro->ro_rt);
441 		ro->ro_rt = (struct rtentry *)0;
442 	} else {
443 		IFDEBUG(D_ROUTE)
444 			printf("clnp_route: OK route exists\n");
445 		ENDDEBUG
446 	}
447 
448 	if (ro->ro_rt == 0) {
449 		/* set up new route structure */
450 		bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
451 		ro->ro_dst.siso_len = sizeof(ro->ro_dst);
452 		ro->ro_dst.siso_family = AF_ISO;
453 		Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len);
454 		/* allocate new route */
455 		IFDEBUG(D_ROUTE)
456 			printf("clnp_route: allocating new route to %s\n",
457 				clnp_iso_addrp(dst));
458 		ENDDEBUG
459 		rtalloc((struct route *)ro);
460 	}
461 	if (ro->ro_rt == 0)
462 		return(ENETUNREACH);	/* rtalloc failed */
463 	ro->ro_rt->rt_use++;
464 	if (ifa)
465 		if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
466 			panic("clnp_route");
467 	if (first_hop) {
468 		if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
469 			*first_hop = ro->ro_rt->rt_gateway;
470 		else
471 			*first_hop = (struct sockaddr *)&ro->ro_dst;
472 	}
473 	return(0);
474 }
475 
476 /*
477  * FUNCTION:		clnp_srcroute
478  *
479  * PURPOSE:			Source route the datagram. If complete source
480  *					routing is specified but not possible, then
481  *					return an error. If src routing is terminated, then
482  *					try routing on destination.
483  *					Usage of first_hop,
484  *					ifp, and error return is identical to clnp_route.
485  *
486  * RETURNS:			0 or unix error code
487  *
488  * SIDE EFFECTS:
489  *
490  * NOTES:			Remember that option index pointers are really
491  *					offsets from the beginning of the mbuf.
492  */
493 clnp_srcroute(options, oidx, route, first_hop, ifa, final_dst)
494 struct mbuf			*options;		/* ptr to options */
495 struct clnp_optidx	*oidx;			/* index to options */
496 struct route_iso	*route;			/* route structure */
497 struct sockaddr		**first_hop;	/* RETURN: fill in with ptr to firsthop */
498 struct iso_ifaddr	**ifa;			/* RETURN: fill in with ptr to interface */
499 struct iso_addr		*final_dst;		/* final destination */
500 {
501 	struct iso_addr	dst;		/* first hop specified by src rt */
502 	int				error = 0;	/* return code */
503 
504 	/*
505 	 *	Check if we have run out of routes
506 	 *	If so, then try to route on destination.
507 	 */
508 	if CLNPSRCRT_TERM(oidx, options) {
509 		dst.isoa_len = final_dst->isoa_len;
510 		bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len);
511 	} else {
512 		/*
513 		 * setup dst based on src rt specified
514 		 */
515 		dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
516 		bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len);
517 	}
518 
519 	/*
520 	 *	try to route it
521 	 */
522 	error = clnp_route(&dst, route, 0, first_hop, ifa);
523 	if (error != 0)
524 		return error;
525 
526 	/*
527 	 *	If complete src rt, first hop must be equal to dst
528 	 */
529 	if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
530 	 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
531 		IFDEBUG(D_OPTIONS)
532 			printf("clnp_srcroute: complete src route failed\n");
533 		ENDDEBUG
534 		return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
535 	}
536 
537 	return error;
538 }
539 
540 /*
541  * FUNCTION:		clnp_ypocb - backwards bcopy
542  *
543  * PURPOSE:			bcopy starting at end of src rather than beginning.
544  *
545  * RETURNS:			none
546  *
547  * SIDE EFFECTS:
548  *
549  * NOTES:			No attempt has been made to make this efficient
550  */
551 clnp_ypocb(from, to, len)
552 caddr_t from;		/* src buffer */
553 caddr_t to;			/* dst buffer */
554 u_int	len;		/* number of bytes */
555 {
556 	while (len--)
557 		*(to + len) = *(from + len);
558 }
559 
560 /*
561  * FUNCTION:		clnp_hdrsize
562  *
563  * PURPOSE:			Return the size of a typical clnp hdr.
564  *
565  * RETURNS:			Size of hdr in bytes.
566  *
567  * SIDE EFFECTS:
568  *
569  * NOTES:			Assumes segmenting subset. If addrlen is
570  *					zero, default to largest nsap address size.
571  */
572 clnp_hdrsize(addrlen)
573 u_char	addrlen;		/* length of nsap address */
574 {
575 	if (addrlen == 0)
576 		addrlen = 20;
577 
578 	addrlen++;			/* length of address byte */
579 	addrlen *= 2;		/* src and dst addresses */
580 	addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
581 
582 	return(addrlen);
583 }
584 #endif	ISO
585