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