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