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