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