xref: /original-bsd/sys/netiso/iso.c (revision 87a44d1b)
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 /*
28  * $Header: iso.c,v 4.11 88/09/19 14:58:35 root Exp $
29  * $Source: /usr/argo/sys/netiso/RCS/iso.c,v $
30  *
31  * iso.c: miscellaneous routines to support the iso address family
32  */
33 
34 #ifndef lint
35 static char *rcsid = "$Header: iso.c,v 4.11 88/09/19 14:58:35 root Exp $";
36 #endif
37 
38 
39 #include "../h/types.h"
40 #include "../h/param.h"
41 #include "../h/ioctl.h"
42 #include "../h/mbuf.h"
43 #include "../h/domain.h"
44 #include "../h/protosw.h"
45 #include "../h/socket.h"
46 #include "../h/socketvar.h"
47 #include "../h/uio.h"
48 #include "../h/dir.h"
49 #include "../h/user.h"
50 #include "../h/errno.h"
51 
52 #include "../net/if.h"
53 #include "../net/route.h"
54 #include "../net/af.h"
55 
56 #include "../netiso/iso.h"
57 #include "../netiso/iso_var.h"
58 #include "../netiso/iso_snpac.h"
59 #include "../netiso/iso_pcb.h"
60 #include "../netiso/clnp.h"
61 #include "../netiso/argo_debug.h"
62 
63 #ifdef ISO
64 
65 int	iso_interfaces = 0;		/* number of external interfaces */
66 extern	struct ifnet loif;	/* loopback interface */
67 
68 
69 /*
70  * FUNCTION:		iso_init
71  *
72  * PURPOSE:			initialize the iso address family
73  *
74  * RETURNS:			nothing
75  *
76  * SIDE EFFECTS:	1) zeros the maptab table.
77  *
78  * NOTES:
79  */
80 iso_init()
81 {
82 	extern struct maptab	iso_snpac[];
83 	extern int 				iso_snpac_size;
84 
85  	bzero((caddr_t)iso_snpac, iso_snpac_size * sizeof(struct snpa_cache));
86 }
87 
88 /*
89  * FUNCTION:		iso_addrmatch1
90  *
91  * PURPOSE:			decide if the two iso_addrs passed are equal
92  *
93  * RETURNS:			true if the addrs match, false if they do not
94  *
95  * SIDE EFFECTS:
96  *
97  * NOTES:
98  */
99 iso_addrmatch1(isoaa, isoab)
100 struct iso_addr	*isoaa, *isoab;		/* addresses to check */
101 {
102 	int	compare_len;
103 
104 	IFDEBUG(D_ROUTE)
105 		printf("iso_addrmatch1: comparing lengths: %d to %d\n", isoaa->isoa_len,
106 			isoab->isoa_len);
107 		printf("a:\n");
108 		dump_buf((caddr_t)isoaa, isoaa->isoa_len);
109 		printf("b:\n");
110 		dump_buf((caddr_t)isoab, isoab->isoa_len);
111 	ENDDEBUG
112 
113 	if ((compare_len = isoaa->isoa_len) != isoab->isoa_len) {
114 		IFDEBUG(D_ROUTE)
115 			printf("iso_addrmatch1: returning false because of lengths\n");
116 		ENDDEBUG
117 		return 0;
118 	}
119 
120 	/* TODO : generalize this to all afis with masks */
121 	if(	isoaa->isoa_afi == AFI_37 ) {
122 		/* must not compare 2 least significant digits, or for
123 		 * that matter, the DSP
124 		 */
125 		compare_len = ADDR37_IDI_LEN - 1;
126 	}
127 
128 	IFDEBUG(D_ROUTE)
129 		int i;
130 		char *a, *b;
131 
132 		a = (char *) isoaa;
133 		b = (char *) isoab;
134 
135 		for (i=0; i<compare_len; i++) {
136 			printf("<%x=%x>", a[i]&0xff, b[i]&0xff);
137 			if (a[i] != b[i]) {
138 				printf("\naddrs are not equal at byte %d\n", i);
139 				return(0);
140 			}
141 		}
142 		printf("\n");
143 		printf("addrs are equal\n");
144 		return (1);
145 	ENDDEBUG
146 	return (!bcmp((caddr_t)isoaa, (caddr_t)isoab, compare_len));
147 }
148 
149 /*
150  * FUNCTION:		iso_addrmatch
151  *
152  * PURPOSE:			decide if the two sockadrr_isos passed are equal
153  *
154  * RETURNS:			true if the addrs match, false if they do not
155  *
156  * SIDE EFFECTS:
157  *
158  * NOTES:
159  */
160 iso_addrmatch(sisoa, sisob)
161 struct sockaddr_iso	*sisoa, *sisob;		/* addresses to check */
162 {
163 	return(iso_addrmatch1(&sisoa->siso_addr, &sisob->siso_addr));
164 }
165 
166 /*
167  * FUNCTION:		iso_netmatch
168  *
169  * PURPOSE:			similar to iso_addrmatch but takes sockaddr_iso
170  *					as argument.
171  *
172  * RETURNS:			true if same net, false if not
173  *
174  * SIDE EFFECTS:
175  *
176  * NOTES:
177  */
178 iso_netmatch(sisoa, sisob)
179 struct sockaddr_iso *sisoa, *sisob;
180 {
181 	u_char			bufa[sizeof(struct sockaddr_iso)];
182 	u_char			bufb[sizeof(struct sockaddr_iso)];
183 	register int	lena, lenb;
184 
185 	lena = iso_netof(&sisoa->siso_addr, bufa);
186 	lenb = iso_netof(&sisob->siso_addr, bufb);
187 
188 	IFDEBUG(D_ROUTE)
189 		printf("iso_netmatch: comparing lengths: %d to %d\n", lena, lenb);
190 		printf("a:\n");
191 		dump_buf(bufa, lena);
192 		printf("b:\n");
193 		dump_buf(bufb, lenb);
194 	ENDDEBUG
195 
196 	return ((lena == lenb) && (!bcmp(bufa, bufb, lena)));
197 }
198 
199 /*
200  * FUNCTION:		iso_hashchar
201  *
202  * PURPOSE:			Hash all character in the buffer specified into
203  *					a long. Return the long.
204  *
205  * RETURNS:			The hash value.
206  *
207  * SIDE EFFECTS:
208  *
209  * NOTES:			The hash is achieved by exclusive ORing 4 byte
210  *					quantities.
211  */
212 u_long
213 iso_hashchar(buf, len)
214 register caddr_t	buf;		/* buffer to pack from */
215 register int		len;		/* length of buffer */
216 {
217 	register u_long	h = 0;
218 	register int	i;
219 
220 	for (i=0; i<len; i+=4) {
221 		register u_long	l = 0;
222 
223 		if ((len - i) < 4) {
224 			/* buffer not multiple of 4 */
225 			switch (len - i) {
226 				case 3:
227 					l |= buf[i+2] << 8;
228 				case 2:
229 					l |= buf[i+1] << 16;
230 				case 1:
231 					l |= buf[i] << 24;
232 					break;
233 				default:
234 					printf("iso_hashchar: unexpected value x%x\n", len - i);
235 					break;
236 			}
237 		} else {
238 			l |= buf[i] << 24;
239 			l |= buf[i+1] << 16;
240 			l |= buf[i+2] << 8;
241 			l |= buf[i+3];
242 		}
243 
244 		h ^= l;
245 	}
246 
247 	h ^= (u_long) (len % 4);
248 
249 	return(h);
250 }
251 
252 /*
253  * FUNCTION:		iso_hash
254  *
255  * PURPOSE:			Fill in fields of afhash structure based upon addr passed.
256  *
257  * RETURNS:			none
258  *
259  * SIDE EFFECTS:
260  *
261  * NOTES:
262  */
263 iso_hash(siso, hp)
264 struct sockaddr_iso	*siso;		/* address to perform hash on */
265 struct afhash		*hp;		/* RETURN: hash info here */
266 {
267 	u_long			buf[sizeof(struct sockaddr_iso)+1/4];
268 	register int	bufsize;
269 
270 
271 	bzero(buf, sizeof(buf));
272 
273 	bufsize = iso_netof(&siso->siso_addr, buf);
274 	hp->afh_nethash = iso_hashchar((caddr_t)buf, bufsize);
275 
276 	IFDEBUG(D_ROUTE)
277 		printf("iso_hash: iso_netof: bufsize = %d\n", bufsize);
278 	ENDDEBUG
279 
280 	hp->afh_hosthash = iso_hashchar((caddr_t)&siso->siso_addr,
281 		siso->siso_addr.isoa_len);
282 
283 	IFDEBUG(D_ROUTE)
284 		printf("iso_hash: %s: nethash = x%x, hosthash = x%x\n",
285 			clnp_iso_addrp(&siso->siso_addr), hp->afh_nethash,
286 			hp->afh_hosthash);
287 	ENDDEBUG
288 }
289 
290 /*
291  * FUNCTION:		iso_netof
292  *
293  * PURPOSE:			Extract the network portion of the iso address.
294  *					The network portion of the iso address varies depending
295  *					on the type of address. The network portion of the
296  *					address will include the IDP. The network portion is:
297  *
298  *						TYPE			DESC
299  *					t37					The AFI and x.121 (IDI)
300  *					osinet				The AFI, orgid, snetid
301  *					rfc986				The AFI, vers and network part of
302  *										internet address.
303  *
304  * RETURNS:			number of bytes placed into buf.
305  *
306  * SIDE EFFECTS:
307  *
308  * NOTES:			Buf is assumed to be big enough
309  */
310 iso_netof(isoa, buf)
311 struct iso_addr	*isoa;		/* address */
312 caddr_t			buf;		/* RESULT: network portion of address here */
313 {
314 	u_int		len = 1;	/* length of afi */
315 
316 	switch (isoa->isoa_afi) {
317 		case AFI_37:
318 			/*
319 			 * Due to classic x.25 tunnel vision, there is no
320 			 * net portion of an x.121 address.  For our purposes
321 			 * the AFI will do, so that all x.25 -type addresses
322 			 * map to the single x.25 SNPA. (Cannot have more than
323 			 * one, obviously).
324 			 */
325 
326 			break;
327 
328 /* 		case AFI_OSINET:*/
329 		case AFI_RFC986: {
330 			u_short	idi;	/* value of idi */
331 
332 			/* osinet and rfc986 have idi in the same place */
333 			CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi);
334 
335 			if (idi == IDI_OSINET)
336 /*
337  *	Network portion of OSINET address can only be the IDI. Clearly,
338  *	with one x25 interface, one could get to several orgids, and
339  *	several snetids.
340 				len += (ADDROSINET_IDI_LEN + OVLOSINET_ORGID_LEN +
341 						OVLOSINET_SNETID_LEN);
342  */
343 				len += ADDROSINET_IDI_LEN;
344 			else if (idi == IDI_RFC986) {
345 				u_long				inetaddr;
346 				struct ovl_rfc986	*o986 = (struct ovl_rfc986 *)isoa;
347 
348 				/* bump len to include idi and version (1 byte) */
349 				len += ADDRRFC986_IDI_LEN + 1;
350 
351 				/* get inet addr long aligned */
352 				bcopy(o986->o986_inetaddr, &inetaddr, sizeof(inetaddr));
353 				inetaddr = ntohl(inetaddr);	/* convert to host byte order */
354 
355 				IFDEBUG(D_ROUTE)
356 					printf("iso_netof: isoa ");
357 					dump_buf(isoa, sizeof(*isoa));
358 					printf("iso_netof: inetaddr 0x%x ", inetaddr);
359 				ENDDEBUG
360 
361 				/* bump len by size of network portion of inet address */
362 				if (IN_CLASSA(inetaddr)) {
363 					len += 4-IN_CLASSA_NSHIFT/8;
364 					IFDEBUG(D_ROUTE)
365 						printf("iso_netof: class A net len is now %d\n", len);
366 					ENDDEBUG
367 				} else if (IN_CLASSB(inetaddr)) {
368 					len += 4-IN_CLASSB_NSHIFT/8;
369 					IFDEBUG(D_ROUTE)
370 						printf("iso_netof: class B net len is now %d\n", len);
371 					ENDDEBUG
372 				} else {
373 					len += 4-IN_CLASSC_NSHIFT/8;
374 					IFDEBUG(D_ROUTE)
375 						printf("iso_netof: class C net len is now %d\n", len);
376 					ENDDEBUG
377 				}
378 			} else
379 				len = 0;
380 		} break;
381 
382 		default:
383 			len = 0;
384 	}
385 
386 	bcopy((caddr_t)isoa, buf, len);
387 	IFDEBUG(D_ROUTE)
388 		printf("in_netof: isoa ");
389 		dump_buf(isoa, len);
390 		printf("in_netof: net ");
391 		dump_buf(buf, len);
392 	ENDDEBUG
393 	return len;
394 }
395 
396 /*
397  *	The following is a kludge until I figure something out. Since AFISO
398  *	allows >1 addr/ifp, SIOCGIFADDR can possibly return more than one
399  *	address. Rather than changing the ifreq structure, I have set up
400  *	the ioctl so it will return the address in sequential calls. When
401  *	all addresses have been read, EADDRNOTAVAIL will be returned.
402  *
403  *	A call to delete or set an addr will cause a subsequent get to
404  *	retrieve the first addr, even if the first had already been read.
405  *
406  *	The static pointer iso_ia keeps track of which addrs have been read.
407  */
408 static struct iso_ifaddr *iso_iap = NULL;
409 
410 /*
411  * FUNCTION:		iso_control
412  *
413  * PURPOSE:			Generic iso control operations (ioctl's).
414  *					Ifp is 0 if this is not an interface-specific ioctl.
415  *
416  * RETURNS:			unix error code
417  *
418  * SIDE EFFECTS:
419  *
420  * NOTES:			The iso address family will allow more than one
421  *					iso address per interface as long as they are different
422  *					iso address types. The three types currently supported
423  *					are rfc986, t37, and osinet.
424  */
425 iso_control(so, cmd, data, ifp)
426 struct socket	*so;		/* socket ioctl arrived on */
427 int				cmd;		/* ioctl to perform */
428 caddr_t			data;		/* data for the ioctl */
429 struct ifnet	*ifp;		/* optional interface ptr */
430 {
431 	register struct ifreq		*ifr = (struct ifreq *)data;
432 	register struct iso_ifaddr	*ia = 0;
433 	struct ifaddr				*ifa;
434 	struct mbuf					*m;
435 
436 
437 	switch (cmd) {
438 	case SIOCSIFADDR:
439 		if (!suser())
440 			return (u.u_error);
441 
442 		if (ifp == 0)
443 			panic("iso_control: SIOCSIFADDR");
444 
445 		/*
446 		 *	Check if a iso address of same type exists for ifp
447 		 *	If it does, then return an error.
448 		 */
449 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
450 			if (ia->ia_ifp == ifp) {
451 				struct sockaddr_iso *siso;
452 
453 				siso = (struct sockaddr_iso *)&ifr->ifr_addr;
454 				if (iso_eqtype(&IA_SIS(ia)->siso_addr, &siso->siso_addr))
455 					return(EADDRNOTAVAIL);
456 			}
457 		}
458 
459 		/*
460 		 *	Go ahead and create new ifaddr
461 		 *
462 		 *	Link addr into list of iso addresses
463 		 */
464 		m = m_getclr(M_WAIT, MT_IFADDR);
465 		if (m == (struct mbuf *)NULL)
466 			return (ENOBUFS);
467 		if (ia = iso_ifaddr) {
468 			for ( ; ia->ia_next; ia = ia->ia_next)
469 				;
470 			ia->ia_next = mtod(m, struct iso_ifaddr *);
471 		} else
472 			iso_ifaddr = mtod(m, struct iso_ifaddr *);
473 		iso_iap = iso_ifaddr;
474 
475 		/*
476 		 *	Link addr into list on interface
477 		 */
478 		ia = mtod(m, struct iso_ifaddr *);
479 		if (ifa = ifp->if_addrlist) {
480 			for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
481 				;
482 			ifa->ifa_next = (struct ifaddr *) ia;
483 		} else
484 			ifp->if_addrlist = (struct ifaddr *) ia;
485 
486 		ia->ia_ifp = ifp;
487 		IA_SIS(ia)->siso_family = AF_ISO;
488 		if (ifp != &loif)
489 			iso_interfaces++;
490 		return (iso_ifinit(ifp, ia, &ifr->ifr_addr));
491 
492 	case SIOCGIFADDR:
493 		for (ia = iso_iap; ia; ia = ia->ia_next) {
494 			if (ia->ia_ifp == ifp) {
495 				ifr->ifr_addr = ia->ia_addr;
496 				iso_iap = ia->ia_next;
497 				return (0);
498 			}
499 		}
500 		iso_iap = iso_ifaddr;
501 		return(EADDRNOTAVAIL);
502 
503 	case SIOCDIFADDR: /* TODO: what about this ioctl on other families */
504 		if (!suser())
505 			return (u.u_error);
506 		iso_iap = iso_ifaddr;
507 
508 		if (ifp == 0)
509 			panic("iso_control: SIOCDIFADDR");
510 
511 		return (iso_ifdelete(ifp, &ifr->ifr_addr));
512 
513 	default:
514 		if (ifp == 0 || ifp->if_ioctl == 0)
515 			return (EOPNOTSUPP);
516 		return ((*ifp->if_ioctl)(ifp, cmd, data));
517 	}
518 }
519 
520 struct ifaddr *
521 iso_ifwithidi(addr)
522 	register struct sockaddr *addr;
523 {
524 	register struct ifnet *ifp;
525 	register struct ifaddr *ifa;
526 	register u_int af = addr->sa_family;
527 
528 	if (af != AF_ISO)
529 		return (0);
530 	IFDEBUG(D_ROUTE)
531 		printf(">>> iso_ifwithidi addr\n");
532 		dump_isoaddr( (struct sockaddr_iso *)(addr));
533 		printf("\n");
534 	ENDDEBUG
535 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
536 		IFDEBUG(D_ROUTE)
537 			printf("iso_ifwithidi ifnet %s\n", ifp->if_name);
538 		ENDDEBUG
539 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
540 			IFDEBUG(D_ROUTE)
541 				printf("iso_ifwithidi address ");
542 				dump_isoaddr( (struct sockaddr_iso *)(&ifa->ifa_addr));
543 			ENDDEBUG
544 			if (ifa->ifa_addr.sa_family != addr->sa_family)
545 				continue;
546 
547 #define	IFA_SIS(ifa)\
548 	((struct sockaddr_iso *)&((ifa)->ifa_addr))
549 
550 			IFDEBUG(D_ROUTE)
551 				printf(" af same, args to iso_eqtype:\n");
552 				printf("0x%x ", IFA_SIS(ifa)->siso_addr);
553 				printf(" 0x%x\n",
554 				&(((struct sockaddr_iso *)addr)->siso_addr));
555 			ENDDEBUG
556 
557 			if (iso_eqtype(&(IFA_SIS(ifa)->siso_addr),
558 				&(((struct sockaddr_iso *)addr)->siso_addr))) {
559 				IFDEBUG(D_ROUTE)
560 					printf("ifa_ifwithidi: ifa found\n");
561 				ENDDEBUG
562 				return (ifa);
563 			}
564 			IFDEBUG(D_ROUTE)
565 				printf(" iso_eqtype failed\n");
566 			ENDDEBUG
567 		}
568 	}
569 	return ((struct ifaddr *)0);
570 }
571 
572 /*
573  * FUNCTION:		iso_ifinit
574  *
575  * PURPOSE:			Initialize an interface's iso address and
576  *					routing table entry.
577  *
578  * RETURNS:			unix error code
579  *
580  * SIDE EFFECTS:
581  *
582  * NOTES:
583  */
584 iso_ifinit(ifp, ia, siso)
585 register struct ifnet		*ifp;	/* interface to initialize */
586 register struct iso_ifaddr	*ia;	/* addr on ifnet list */
587 struct sockaddr_iso			*siso;	/* address to use */
588 {
589 	struct sockaddr oldaddr;
590 	struct sockaddr_iso netaddr;
591 	int s = splimp(), error;
592 
593 	/*
594 	 *	Make sure the address make sense
595 	 */
596 	if (!iso_ck_addr(&siso->siso_addr))
597 		return(EINVAL);
598 	IFDEBUG(D_ROUTE)
599 		int i;
600 		char *ptr;
601 
602 		ptr = (char *) siso;
603 		printf("The size of sockaddr_iso is %d\n",
604 			sizeof(struct sockaddr_iso));
605 		for(i=0; i< sizeof(struct sockaddr_iso); i++) {
606 			printf("sockaddr[%d] = 0x%x\n", i, *ptr++ & 0xff);
607 		}
608 	ENDDEBUG
609 
610 	oldaddr = ia->ia_addr;
611 	ia->ia_addr = *(struct sockaddr *)siso;
612 	bzero((caddr_t)&netaddr, sizeof (netaddr));
613 	netaddr.siso_family = AF_ISO;
614 
615 	/*
616 	 * Give the interface a chance to initialize
617 	 */
618 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
619 		splx(s);
620 		ia->ia_addr = oldaddr;
621 		return (error);
622 	}
623 	splx(s);
624 
625 	/*
626 	 * Add route for the network.
627 	 */
628 	if (ifp->if_flags & IFF_LOOPBACK)
629 		rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT, RTF_HOST|RTF_UP);
630 	else {
631 		int len;
632 
633 		len = iso_netof(&siso->siso_addr, (caddr_t)&netaddr.siso_addr);
634 		netaddr.siso_addr.isoa_len = len;
635 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
636 		    (int)SIOCADDRT, RTF_UP);
637 	}
638 	ia->ia_flags |= IFA_ROUTE;
639 	return (0);
640 }
641 
642 
643 /*
644  * FUNCTION:		iso_ifdelete
645  *
646  * PURPOSE:			Delete an iso address from an interface.
647  *
648  * RETURNS:			0 or unix error code
649  *
650  * SIDE EFFECTS:
651  *
652  * NOTES:
653  */
654 iso_ifdelete(ifp, siso)
655 struct ifnet		*ifp;	/* interface to delete addr from */
656 struct sockaddr_iso	*siso;	/* address to delete */
657 {
658 	struct iso_addr 			*isoa = &siso->siso_addr;
659 	register struct iso_ifaddr	*ia, *prev = 0;
660 	register struct ifaddr		*ifa;
661 	int 						s;
662 	struct sockaddr_iso 		netaddr;
663 
664 	/*
665 	 *	Find the iso address of same type as specified and delete it.
666 	 */
667 	for (ia = iso_ifaddr; ia; prev = ia, ia = ia->ia_next) {
668 		if (ia->ia_ifp == ifp) {
669 			if (iso_eqtype(&IA_SIS(ia)->siso_addr, isoa)) {
670 				/*
671 				 * Delete any previous route for the address.
672 				 */
673 				IFDEBUG(D_IOCTL)
674 					printf("iso_ifdelete: delete %s\n", clnp_iso_addrp(isoa))
675 				ENDDEBUG
676 				s = splimp();
677 				bzero((caddr_t)&netaddr, sizeof (netaddr));
678 				netaddr.siso_family = AF_ISO;
679 				if (ia->ia_flags & IFA_ROUTE) {
680 					if (ifp->if_flags & IFF_LOOPBACK)
681 						rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCDELRT,
682 							RTF_HOST);
683 					else {
684 						(void) iso_netof(&siso->siso_addr,
685 							(caddr_t)&netaddr.siso_addr);
686 						rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
687 							(int)SIOCDELRT, 0);
688 					}
689 					ia->ia_flags &= ~IFA_ROUTE;
690 				}
691 				splx(s);
692 
693 				/*
694 				 *	Remove from list of iso addresses
695 				 */
696 				if (prev == 0)
697 					iso_ifaddr = ia->ia_next;
698 				else
699 					prev->ia_next = ia->ia_next;
700 				if (ifp != &loif)
701 					iso_interfaces--;
702 
703 				/*
704 				 *	Remove from list of addrs on ifnet structure
705 				 */
706 				if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
707 					ifp->if_addrlist = ia->ia_ifa.ifa_next;
708 				else {
709 					for (; ifa; ifa = ifa->ifa_next) {
710 						if (ifa->ifa_next == (struct ifaddr *)ia) {
711 							ifa->ifa_next = ia->ia_ifa.ifa_next;
712 							break;
713 						}
714 					}
715 				}
716 
717 				/*
718 				 *	Free the iso_ifaddr mbuf
719 				 */
720 				m_free(dtom(ia));
721 				return (0);
722 			}
723 		}
724 	}
725 	return(EADDRNOTAVAIL);
726 }
727 
728 /*
729  * FUNCTION:		iso_ck_addr
730  *
731  * PURPOSE:			return true if the iso_addr passed is
732  *					within the legal size limit for an iso address.
733  *
734  * RETURNS:			true or false
735  *
736  * SIDE EFFECTS:
737  *
738  */
739 iso_ck_addr(isoa)
740 struct iso_addr	*isoa;	/* address to check */
741 {
742 	return (isoa->isoa_len <= 20);
743 
744 }
745 
746 
747 /*
748  * FUNCTION:		iso_eqtype
749  *
750  * PURPOSE:			Determine if two iso addresses are of the same type.
751  *  This is flaky.  Really we should consider all type 47 addrs to be the
752  *  same - but there do exist different structures for 47 addrs.
753  *  Gosip adds a 3rd.
754  *
755  * RETURNS:			true if the addresses are the same type
756  *
757  * SIDE EFFECTS:
758  *
759  * NOTES:			By type, I mean rfc986, t37, or osinet
760  *
761  *					This will first compare afis. If they match, then
762  *					if the addr is not t37, the idis must be compared.
763  */
764 iso_eqtype(isoaa, isoab)
765 struct iso_addr	*isoaa;		/* first addr to check */
766 struct iso_addr	*isoab;		/* other addr to check */
767 {
768 	if (isoaa->isoa_afi == isoab->isoa_afi) {
769 		if (isoaa->isoa_afi == AFI_37)
770 			return(1);
771 		else
772 			return (!bcmp(&isoaa->isoa_u, &isoab->isoa_u, 2));
773 	}
774 	return(0);
775 }
776 
777 /*
778  * FUNCTION:		iso_iaonnetof()
779  *
780  * PURPOSE:			Find and interface addresss based on the network
781  *					portion of an address.
782  *
783  * RETURNS:			ptr to an interface address
784  *
785  * SIDE EFFECTS:
786  *
787  * NOTES:
788  */
789 struct iso_ifaddr *
790 iso_iaonnetof(siso)
791 	struct sockaddr_iso *siso;
792 {
793 	register struct iso_ifaddr *ia;
794 
795 	for (ia = iso_ifaddr; ia; ia = ia->ia_next)
796 		if (iso_netmatch( (struct sockaddr_iso *)(&ia->ia_ifa.ifa_addr), siso) )
797 			return (ia);
798 	return ((struct iso_ifaddr *)0);
799 }
800 
801 #ifdef	NARGOXTWENTYFIVE > 0
802 #include "cons.h"
803 #endif	NARGOXTWENTYFIVE > 0
804 /*
805  * FUNCTION:		iso_nlctloutput
806  *
807  * PURPOSE:			Set options at the network level
808  *
809  * RETURNS:			E*
810  *
811  * SIDE EFFECTS:
812  *
813  * NOTES:			This could embody some of the functions of
814  *					rclnp_ctloutput and cons_ctloutput.
815  */
816 iso_nlctloutput(cmd, optname, pcb, m)
817 int			cmd;		/* command:set or get */
818 int			optname;	/* option of interest */
819 caddr_t		pcb;		/* nl pcb */
820 struct mbuf	*m;			/* data for set, buffer for get */
821 {
822 	struct isopcb	*isop = (struct isopcb *)pcb;
823 	int				error = 0;	/* return value */
824 	caddr_t			data;		/* data for option */
825 	int				data_len;	/* data's length */
826 
827 	IFDEBUG(D_ISO)
828 		printf("iso_nlctloutput: cmd %x, opt %x, pcb %x, m %x\n",
829 			cmd, optname, pcb, m);
830 	ENDDEBUG
831 
832 	if ((cmd != PRCO_GETOPT) && (cmd != PRCO_SETOPT))
833 		return(EOPNOTSUPP);
834 
835 	data = mtod(m, caddr_t);
836 	data_len = (m)->m_len;
837 
838 	IFDEBUG(D_ISO)
839 		printf("iso_nlctloutput: data is:\n");
840 		dump_buf(data, data_len);
841 	ENDDEBUG
842 
843 	switch (optname) {
844 
845 #ifdef	NARGOXTWENTYFIVE > 0
846 		case CONSOPT_X25CRUD:
847 			if (cmd == PRCO_GETOPT) {
848 				error = EOPNOTSUPP;
849 				break;
850 			}
851 
852 			if (data_len > MAXX25CRUDLEN) {
853 				error = EINVAL;
854 				break;
855 			}
856 
857 			IFDEBUG(D_ISO)
858 				printf("iso_nlctloutput: setting x25 crud\n");
859 			ENDDEBUG
860 
861 			bcopy(data, (caddr_t)&isop->isop_x25crud, data_len);
862 			isop->isop_x25crud_len = data_len;
863 			break;
864 #endif	NARGOXTWENTYFIVE > 0
865 
866 		default:
867 			error = EOPNOTSUPP;
868 	}
869 
870 	return error;
871 }
872 
873 /*
874  * FUNCTION:		iso_routeifp
875  *
876  * PURPOSE:			Route on a sockaddr and return ifp
877  *
878  * RETURNS:			ifp of outgoing interface, or null
879  *
880  * SIDE EFFECTS:
881  *
882  * NOTES:
883  */
884 struct ifnet *
885 iso_routeifp(dst)
886 struct sockaddr	*dst;		/* destination to route to */
887 {
888 	struct route	ro;
889 	struct ifnet	*ifp = NULL;
890 
891 	ro.ro_dst = *dst;
892 	ro.ro_rt = NULL;
893 
894 	IFDEBUG(D_ROUTE)
895 		printf("iso_routeifp: dst:");
896 		dump_isoaddr(dst);
897 	ENDDEBUG
898 
899 	rtalloc(&ro);
900 
901 	if (ro.ro_rt) {
902 		ifp = ro.ro_rt->rt_ifp;
903 		RTFREE(ro.ro_rt);
904 	}
905 
906 	IFDEBUG(D_ROUTE)
907 		printf("iso_routeifp: ifp x%x", ifp);
908 		if (ifp)
909 			printf(" (%s%d)\n", ifp->if_name, ifp->if_unit);
910 		else
911 			printf("\n");
912 	ENDDEBUG
913 
914 	return(ifp);
915 }
916 #endif ISO
917 
918 #ifdef ARGO_DEBUG
919 
920 /*
921  * FUNCTION:		dump_isoaddr
922  *
923  * PURPOSE:			debugging
924  *
925  * RETURNS:			nada
926  *
927  */
928 dump_isoaddr(s)
929 	struct sockaddr_iso *s;
930 {
931 	caddr_t c = (caddr_t)&(s->siso_addr.isoa_u);
932 	register int i;
933 
934 	if( s->siso_family == AF_ISO) {
935 		printf("len %d family: 0x%x  suffix 0x%x, afi 0x%x,",
936 			(int)s->siso_addr.isoa_len,
937 			(int)s->siso_family,
938 			s->siso_tsuffix, (int)s->siso_addr.isoa_afi);
939 		if( s->siso_addr.isoa_len > sizeof(struct sockaddr) )
940 			printf("ERROR-ADDR TOO BIG %d\n", s->siso_addr.isoa_len);
941 		else  {
942 			if (s->siso_addr.isoa_len != 0) {
943 			/* -2 because we already skipped the afi */
944 					for (i=0; i<s->siso_addr.isoa_len-2; i++)
945 						printf("0x%x.", *(c+i)&0xff);
946 					printf("0x%x\n", *(c+i)&0xff);
947 			}
948 		}
949 	} else if( s->siso_family == AF_INET) {
950 		/* hack */
951 		struct sockaddr_in *sin = (struct sockaddr_in *)s;
952 
953 		printf("%d.%d.%d.%d: %d",
954 			(sin->sin_addr.s_addr>>24)&0xff,
955 			(sin->sin_addr.s_addr>>16)&0xff,
956 			(sin->sin_addr.s_addr>>8)&0xff,
957 			(sin->sin_addr.s_addr)&0xff,
958 			sin->sin_port);
959 	}
960 }
961 
962 #endif ARGO_DEBUG
963