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