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