xref: /csrg-svn/sys/netiso/iso.c (revision 58601)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*58601Ssklower  *	@(#)iso.c	7.22 (Berkeley) 03/09/93
849268Sbostic  */
949268Sbostic 
1036384Ssklower /***********************************************************
1136384Ssklower 		Copyright IBM Corporation 1987
1236384Ssklower 
1336384Ssklower                       All Rights Reserved
1436384Ssklower 
1536384Ssklower Permission to use, copy, modify, and distribute this software and its
1636384Ssklower documentation for any purpose and without fee is hereby granted,
1736384Ssklower provided that the above copyright notice appear in all copies and that
1836384Ssklower both that copyright notice and this permission notice appear in
1936384Ssklower supporting documentation, and that the name of IBM not be
2036384Ssklower used in advertising or publicity pertaining to distribution of the
2136384Ssklower software without specific, written prior permission.
2236384Ssklower 
2336384Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436384Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536384Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636384Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736384Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836384Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936384Ssklower SOFTWARE.
3036384Ssklower 
3136384Ssklower ******************************************************************/
3236384Ssklower 
3336384Ssklower /*
3436384Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536384Ssklower  */
3636384Ssklower /*
3736384Ssklower  * $Header: iso.c,v 4.11 88/09/19 14:58:35 root Exp $
3836384Ssklower  * $Source: /usr/argo/sys/netiso/RCS/iso.c,v $
3936384Ssklower  *
4036384Ssklower  * iso.c: miscellaneous routines to support the iso address family
4136384Ssklower  */
4236384Ssklower 
4356533Sbostic #include <sys/param.h>
4456533Sbostic #include <sys/systm.h>
4556533Sbostic #include <sys/ioctl.h>
4656533Sbostic #include <sys/mbuf.h>
4756533Sbostic #include <sys/domain.h>
4856533Sbostic #include <sys/protosw.h>
4956533Sbostic #include <sys/socket.h>
5056533Sbostic #include <sys/socketvar.h>
5156533Sbostic #include <sys/errno.h>
5236384Ssklower 
5356533Sbostic #include <net/if.h>
5456533Sbostic #include <net/route.h>
5556533Sbostic #include <net/af.h>
5636384Ssklower 
5756533Sbostic #include <netiso/iso.h>
5856533Sbostic #include <netiso/iso_var.h>
5956533Sbostic #include <netiso/iso_snpac.h>
6056533Sbostic #include <netiso/iso_pcb.h>
6156533Sbostic #include <netiso/clnp.h>
6256533Sbostic #include <netiso/argo_debug.h>
6356913Ssklower #ifdef TUBA
6456913Ssklower #include <netiso/tuba_table.h>
6556913Ssklower #endif
6636384Ssklower 
6736384Ssklower #ifdef ISO
6836384Ssklower 
6936384Ssklower int	iso_interfaces = 0;		/* number of external interfaces */
7036384Ssklower extern	struct ifnet loif;	/* loopback interface */
7154823Ssklower int	ether_output();
7254823Ssklower void	llc_rtrequest();
7336384Ssklower 
7436384Ssklower /*
7536384Ssklower  * FUNCTION:		iso_addrmatch1
7636384Ssklower  *
7736384Ssklower  * PURPOSE:			decide if the two iso_addrs passed are equal
7836384Ssklower  *
7936384Ssklower  * RETURNS:			true if the addrs match, false if they do not
8036384Ssklower  *
8136384Ssklower  * SIDE EFFECTS:
8236384Ssklower  *
8336384Ssklower  * NOTES:
8436384Ssklower  */
8536384Ssklower iso_addrmatch1(isoaa, isoab)
8637469Ssklower register struct iso_addr *isoaa, *isoab;		/* addresses to check */
8736384Ssklower {
8837469Ssklower 	u_int	compare_len;
8936384Ssklower 
9036384Ssklower 	IFDEBUG(D_ROUTE)
9136384Ssklower 		printf("iso_addrmatch1: comparing lengths: %d to %d\n", isoaa->isoa_len,
9236384Ssklower 			isoab->isoa_len);
9336384Ssklower 		printf("a:\n");
9437469Ssklower 		dump_buf(isoaa->isoa_genaddr, isoaa->isoa_len);
9536384Ssklower 		printf("b:\n");
9637469Ssklower 		dump_buf(isoab->isoa_genaddr, isoab->isoa_len);
9736384Ssklower 	ENDDEBUG
9836384Ssklower 
9936384Ssklower 	if ((compare_len = isoaa->isoa_len) != isoab->isoa_len) {
10036384Ssklower 		IFDEBUG(D_ROUTE)
10136384Ssklower 			printf("iso_addrmatch1: returning false because of lengths\n");
10236384Ssklower 		ENDDEBUG
10336384Ssklower 		return 0;
10436384Ssklower 	}
10536384Ssklower 
10637469Ssklower #ifdef notdef
10736384Ssklower 	/* TODO : generalize this to all afis with masks */
10836384Ssklower 	if(	isoaa->isoa_afi == AFI_37 ) {
10936384Ssklower 		/* must not compare 2 least significant digits, or for
11036384Ssklower 		 * that matter, the DSP
11136384Ssklower 		 */
11236384Ssklower 		compare_len = ADDR37_IDI_LEN - 1;
11336384Ssklower 	}
11437469Ssklower #endif
11536384Ssklower 
11636384Ssklower 	IFDEBUG(D_ROUTE)
11736384Ssklower 		int i;
11836384Ssklower 		char *a, *b;
11936384Ssklower 
12037469Ssklower 		a = isoaa->isoa_genaddr;
12137469Ssklower 		b = isoab->isoa_genaddr;
12236384Ssklower 
12336384Ssklower 		for (i=0; i<compare_len; i++) {
12436384Ssklower 			printf("<%x=%x>", a[i]&0xff, b[i]&0xff);
12536384Ssklower 			if (a[i] != b[i]) {
12636384Ssklower 				printf("\naddrs are not equal at byte %d\n", i);
12736384Ssklower 				return(0);
12836384Ssklower 			}
12936384Ssklower 		}
13036384Ssklower 		printf("\n");
13136384Ssklower 		printf("addrs are equal\n");
13236384Ssklower 		return (1);
13336384Ssklower 	ENDDEBUG
13437469Ssklower 	return (!bcmp(isoaa->isoa_genaddr, isoab->isoa_genaddr, compare_len));
13536384Ssklower }
13636384Ssklower 
13736384Ssklower /*
13836384Ssklower  * FUNCTION:		iso_addrmatch
13936384Ssklower  *
14036384Ssklower  * PURPOSE:			decide if the two sockadrr_isos passed are equal
14136384Ssklower  *
14236384Ssklower  * RETURNS:			true if the addrs match, false if they do not
14336384Ssklower  *
14436384Ssklower  * SIDE EFFECTS:
14536384Ssklower  *
14636384Ssklower  * NOTES:
14736384Ssklower  */
14836384Ssklower iso_addrmatch(sisoa, sisob)
14936384Ssklower struct sockaddr_iso	*sisoa, *sisob;		/* addresses to check */
15036384Ssklower {
15136384Ssklower 	return(iso_addrmatch1(&sisoa->siso_addr, &sisob->siso_addr));
15236384Ssklower }
15337469Ssklower #ifdef notdef
15436384Ssklower /*
15536384Ssklower  * FUNCTION:		iso_netmatch
15636384Ssklower  *
15736384Ssklower  * PURPOSE:			similar to iso_addrmatch but takes sockaddr_iso
15836384Ssklower  *					as argument.
15936384Ssklower  *
16036384Ssklower  * RETURNS:			true if same net, false if not
16136384Ssklower  *
16236384Ssklower  * SIDE EFFECTS:
16336384Ssklower  *
16436384Ssklower  * NOTES:
16536384Ssklower  */
16636384Ssklower iso_netmatch(sisoa, sisob)
16736384Ssklower struct sockaddr_iso *sisoa, *sisob;
16836384Ssklower {
16936384Ssklower 	u_char			bufa[sizeof(struct sockaddr_iso)];
17036384Ssklower 	u_char			bufb[sizeof(struct sockaddr_iso)];
17136384Ssklower 	register int	lena, lenb;
17236384Ssklower 
17336384Ssklower 	lena = iso_netof(&sisoa->siso_addr, bufa);
17436384Ssklower 	lenb = iso_netof(&sisob->siso_addr, bufb);
17536384Ssklower 
17636384Ssklower 	IFDEBUG(D_ROUTE)
17736384Ssklower 		printf("iso_netmatch: comparing lengths: %d to %d\n", lena, lenb);
17836384Ssklower 		printf("a:\n");
17936384Ssklower 		dump_buf(bufa, lena);
18036384Ssklower 		printf("b:\n");
18136384Ssklower 		dump_buf(bufb, lenb);
18236384Ssklower 	ENDDEBUG
18336384Ssklower 
18436384Ssklower 	return ((lena == lenb) && (!bcmp(bufa, bufb, lena)));
18536384Ssklower }
18637469Ssklower #endif notdef
18736384Ssklower 
18836384Ssklower /*
18936384Ssklower  * FUNCTION:		iso_hashchar
19036384Ssklower  *
19136384Ssklower  * PURPOSE:			Hash all character in the buffer specified into
19236384Ssklower  *					a long. Return the long.
19336384Ssklower  *
19436384Ssklower  * RETURNS:			The hash value.
19536384Ssklower  *
19636384Ssklower  * SIDE EFFECTS:
19736384Ssklower  *
19836384Ssklower  * NOTES:			The hash is achieved by exclusive ORing 4 byte
19936384Ssklower  *					quantities.
20036384Ssklower  */
20136384Ssklower u_long
20236384Ssklower iso_hashchar(buf, len)
20336384Ssklower register caddr_t	buf;		/* buffer to pack from */
20436384Ssklower register int		len;		/* length of buffer */
20536384Ssklower {
20636384Ssklower 	register u_long	h = 0;
20736384Ssklower 	register int	i;
20836384Ssklower 
20936384Ssklower 	for (i=0; i<len; i+=4) {
21036384Ssklower 		register u_long	l = 0;
21136384Ssklower 
21236384Ssklower 		if ((len - i) < 4) {
21336384Ssklower 			/* buffer not multiple of 4 */
21436384Ssklower 			switch (len - i) {
21536384Ssklower 				case 3:
21636384Ssklower 					l |= buf[i+2] << 8;
21736384Ssklower 				case 2:
21836384Ssklower 					l |= buf[i+1] << 16;
21936384Ssklower 				case 1:
22036384Ssklower 					l |= buf[i] << 24;
22136384Ssklower 					break;
22236384Ssklower 				default:
22336384Ssklower 					printf("iso_hashchar: unexpected value x%x\n", len - i);
22436384Ssklower 					break;
22536384Ssklower 			}
22636384Ssklower 		} else {
22736384Ssklower 			l |= buf[i] << 24;
22836384Ssklower 			l |= buf[i+1] << 16;
22936384Ssklower 			l |= buf[i+2] << 8;
23036384Ssklower 			l |= buf[i+3];
23136384Ssklower 		}
23236384Ssklower 
23336384Ssklower 		h ^= l;
23436384Ssklower 	}
23536384Ssklower 
23636384Ssklower 	h ^= (u_long) (len % 4);
23736384Ssklower 
23836384Ssklower 	return(h);
23936384Ssklower }
24037469Ssklower #ifdef notdef
24136384Ssklower /*
24236384Ssklower  * FUNCTION:		iso_hash
24336384Ssklower  *
24436384Ssklower  * PURPOSE:			Fill in fields of afhash structure based upon addr passed.
24536384Ssklower  *
24636384Ssklower  * RETURNS:			none
24736384Ssklower  *
24836384Ssklower  * SIDE EFFECTS:
24936384Ssklower  *
25036384Ssklower  * NOTES:
25136384Ssklower  */
25236384Ssklower iso_hash(siso, hp)
25336384Ssklower struct sockaddr_iso	*siso;		/* address to perform hash on */
25436384Ssklower struct afhash		*hp;		/* RETURN: hash info here */
25536384Ssklower {
25636384Ssklower 	u_long			buf[sizeof(struct sockaddr_iso)+1/4];
25736384Ssklower 	register int	bufsize;
25836384Ssklower 
25936384Ssklower 
26036384Ssklower 	bzero(buf, sizeof(buf));
26136384Ssklower 
26236384Ssklower 	bufsize = iso_netof(&siso->siso_addr, buf);
26336384Ssklower 	hp->afh_nethash = iso_hashchar((caddr_t)buf, bufsize);
26436384Ssklower 
26536384Ssklower 	IFDEBUG(D_ROUTE)
26636384Ssklower 		printf("iso_hash: iso_netof: bufsize = %d\n", bufsize);
26736384Ssklower 	ENDDEBUG
26836384Ssklower 
26936384Ssklower 	hp->afh_hosthash = iso_hashchar((caddr_t)&siso->siso_addr,
27036384Ssklower 		siso->siso_addr.isoa_len);
27136384Ssklower 
27236384Ssklower 	IFDEBUG(D_ROUTE)
27336384Ssklower 		printf("iso_hash: %s: nethash = x%x, hosthash = x%x\n",
27436384Ssklower 			clnp_iso_addrp(&siso->siso_addr), hp->afh_nethash,
27536384Ssklower 			hp->afh_hosthash);
27636384Ssklower 	ENDDEBUG
27736384Ssklower }
27836384Ssklower /*
27936384Ssklower  * FUNCTION:		iso_netof
28036384Ssklower  *
28136384Ssklower  * PURPOSE:			Extract the network portion of the iso address.
28236384Ssklower  *					The network portion of the iso address varies depending
28336384Ssklower  *					on the type of address. The network portion of the
28436384Ssklower  *					address will include the IDP. The network portion is:
28536384Ssklower  *
28636384Ssklower  *						TYPE			DESC
28736384Ssklower  *					t37					The AFI and x.121 (IDI)
28836384Ssklower  *					osinet				The AFI, orgid, snetid
28936384Ssklower  *					rfc986				The AFI, vers and network part of
29036384Ssklower  *										internet address.
29136384Ssklower  *
29236384Ssklower  * RETURNS:			number of bytes placed into buf.
29336384Ssklower  *
29436384Ssklower  * SIDE EFFECTS:
29536384Ssklower  *
29636384Ssklower  * NOTES:			Buf is assumed to be big enough
29736384Ssklower  */
29836384Ssklower iso_netof(isoa, buf)
29936384Ssklower struct iso_addr	*isoa;		/* address */
30036384Ssklower caddr_t			buf;		/* RESULT: network portion of address here */
30136384Ssklower {
30236384Ssklower 	u_int		len = 1;	/* length of afi */
30336384Ssklower 
30436384Ssklower 	switch (isoa->isoa_afi) {
30536384Ssklower 		case AFI_37:
30636384Ssklower 			/*
30736384Ssklower 			 * Due to classic x.25 tunnel vision, there is no
30836384Ssklower 			 * net portion of an x.121 address.  For our purposes
30936384Ssklower 			 * the AFI will do, so that all x.25 -type addresses
31036384Ssklower 			 * map to the single x.25 SNPA. (Cannot have more than
31136384Ssklower 			 * one, obviously).
31236384Ssklower 			 */
31336384Ssklower 
31436384Ssklower 			break;
31536384Ssklower 
31636384Ssklower /* 		case AFI_OSINET:*/
31736384Ssklower 		case AFI_RFC986: {
31836384Ssklower 			u_short	idi;	/* value of idi */
31936384Ssklower 
32036384Ssklower 			/* osinet and rfc986 have idi in the same place */
32136384Ssklower 			CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi);
32236384Ssklower 
32336384Ssklower 			if (idi == IDI_OSINET)
32436384Ssklower /*
32536384Ssklower  *	Network portion of OSINET address can only be the IDI. Clearly,
32636384Ssklower  *	with one x25 interface, one could get to several orgids, and
32736384Ssklower  *	several snetids.
32836384Ssklower 				len += (ADDROSINET_IDI_LEN + OVLOSINET_ORGID_LEN +
32936384Ssklower 						OVLOSINET_SNETID_LEN);
33036384Ssklower  */
33136384Ssklower 				len += ADDROSINET_IDI_LEN;
33236384Ssklower 			else if (idi == IDI_RFC986) {
33336384Ssklower 				u_long				inetaddr;
33436384Ssklower 				struct ovl_rfc986	*o986 = (struct ovl_rfc986 *)isoa;
33536384Ssklower 
33636384Ssklower 				/* bump len to include idi and version (1 byte) */
33736384Ssklower 				len += ADDRRFC986_IDI_LEN + 1;
33836384Ssklower 
33936384Ssklower 				/* get inet addr long aligned */
34036384Ssklower 				bcopy(o986->o986_inetaddr, &inetaddr, sizeof(inetaddr));
34136384Ssklower 				inetaddr = ntohl(inetaddr);	/* convert to host byte order */
34236384Ssklower 
34336384Ssklower 				IFDEBUG(D_ROUTE)
34436384Ssklower 					printf("iso_netof: isoa ");
34536384Ssklower 					dump_buf(isoa, sizeof(*isoa));
34636384Ssklower 					printf("iso_netof: inetaddr 0x%x ", inetaddr);
34736384Ssklower 				ENDDEBUG
34836384Ssklower 
34936384Ssklower 				/* bump len by size of network portion of inet address */
35036384Ssklower 				if (IN_CLASSA(inetaddr)) {
35136384Ssklower 					len += 4-IN_CLASSA_NSHIFT/8;
35236384Ssklower 					IFDEBUG(D_ROUTE)
35336384Ssklower 						printf("iso_netof: class A net len is now %d\n", len);
35436384Ssklower 					ENDDEBUG
35536384Ssklower 				} else if (IN_CLASSB(inetaddr)) {
35636384Ssklower 					len += 4-IN_CLASSB_NSHIFT/8;
35736384Ssklower 					IFDEBUG(D_ROUTE)
35836384Ssklower 						printf("iso_netof: class B net len is now %d\n", len);
35936384Ssklower 					ENDDEBUG
36036384Ssklower 				} else {
36136384Ssklower 					len += 4-IN_CLASSC_NSHIFT/8;
36236384Ssklower 					IFDEBUG(D_ROUTE)
36336384Ssklower 						printf("iso_netof: class C net len is now %d\n", len);
36436384Ssklower 					ENDDEBUG
36536384Ssklower 				}
36636384Ssklower 			} else
36736384Ssklower 				len = 0;
36836384Ssklower 		} break;
36936384Ssklower 
37036384Ssklower 		default:
37136384Ssklower 			len = 0;
37236384Ssklower 	}
37336384Ssklower 
37436384Ssklower 	bcopy((caddr_t)isoa, buf, len);
37536384Ssklower 	IFDEBUG(D_ROUTE)
376*58601Ssklower 		printf("iso_netof: isoa ");
37736384Ssklower 		dump_buf(isoa, len);
378*58601Ssklower 		printf("iso_netof: net ");
37936384Ssklower 		dump_buf(buf, len);
38036384Ssklower 	ENDDEBUG
38136384Ssklower 	return len;
38236384Ssklower }
38337469Ssklower #endif notdef
38436384Ssklower /*
38537469Ssklower  * Generic iso control operations (ioctl's).
38637469Ssklower  * Ifp is 0 if not an interface-specific ioctl.
38736384Ssklower  */
38837469Ssklower /* ARGSUSED */
38936384Ssklower iso_control(so, cmd, data, ifp)
39037469Ssklower 	struct socket *so;
39137469Ssklower 	int cmd;
39237469Ssklower 	caddr_t data;
39337469Ssklower 	register struct ifnet *ifp;
39436384Ssklower {
39537469Ssklower 	register struct iso_ifreq *ifr = (struct iso_ifreq *)data;
39637469Ssklower 	register struct iso_ifaddr *ia = 0;
39737469Ssklower 	register struct ifaddr *ifa;
39837469Ssklower 	struct iso_ifaddr *oia;
39937469Ssklower 	struct iso_aliasreq *ifra = (struct iso_aliasreq *)data;
40037469Ssklower 	int error, hostIsNew, maskIsNew;
40136384Ssklower 
40237469Ssklower 	/*
40337469Ssklower 	 * Find address for this interface, if it exists.
40437469Ssklower 	 */
40537469Ssklower 	if (ifp)
40637469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next)
40737469Ssklower 			if (ia->ia_ifp == ifp)
40837469Ssklower 				break;
40936384Ssklower 
41036384Ssklower 	switch (cmd) {
41137469Ssklower 
41237469Ssklower 	case SIOCAIFADDR_ISO:
41337469Ssklower 	case SIOCDIFADDR_ISO:
41437469Ssklower 		if (ifra->ifra_addr.siso_family == AF_ISO)
41537469Ssklower 		    for (oia = ia; ia; ia = ia->ia_next) {
41637469Ssklower 			if (ia->ia_ifp == ifp  &&
41737469Ssklower 			    SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr))
41837469Ssklower 				break;
41937469Ssklower 		}
42050232Ssklower 		if ((so->so_state & SS_PRIV) == 0)
42150232Ssklower 			return (EPERM);
42236384Ssklower 		if (ifp == 0)
42337469Ssklower 			panic("iso_control");
42437469Ssklower 		if (ia == (struct iso_ifaddr *)0) {
42537469Ssklower 			struct iso_ifaddr *nia;
42637469Ssklower 			if (cmd == SIOCDIFADDR_ISO)
42737469Ssklower 				return (EADDRNOTAVAIL);
42856913Ssklower #ifdef TUBA
42956913Ssklower 			/* XXXXXX can't be done in the proto init routines */
43056913Ssklower 			if (tuba_tree == 0)
43156913Ssklower 				tuba_table_init();
43256913Ssklower #endif
43337469Ssklower 			MALLOC(nia, struct iso_ifaddr *, sizeof(*nia),
43437469Ssklower 				       M_IFADDR, M_WAITOK);
43537469Ssklower 			if (nia == (struct iso_ifaddr *)0)
43637469Ssklower 				return (ENOBUFS);
43737469Ssklower 			bzero((caddr_t)nia, sizeof(*nia));
43837469Ssklower 			if (ia = iso_ifaddr) {
43937469Ssklower 				for ( ; ia->ia_next; ia = ia->ia_next)
44037469Ssklower 					;
44137469Ssklower 				ia->ia_next = nia;
44237469Ssklower 			} else
44337469Ssklower 				iso_ifaddr = nia;
44437469Ssklower 			ia = nia;
44537469Ssklower 			if (ifa = ifp->if_addrlist) {
44637469Ssklower 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
44737469Ssklower 					;
44837469Ssklower 				ifa->ifa_next = (struct ifaddr *) ia;
44937469Ssklower 			} else
45037469Ssklower 				ifp->if_addrlist = (struct ifaddr *) ia;
45137469Ssklower 			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
45237469Ssklower 			ia->ia_ifa.ifa_dstaddr
45337469Ssklower 					= (struct sockaddr *)&ia->ia_dstaddr;
45437469Ssklower 			ia->ia_ifa.ifa_netmask
45537469Ssklower 					= (struct sockaddr *)&ia->ia_sockmask;
45637469Ssklower 			ia->ia_ifp = ifp;
45737469Ssklower 			if (ifp != &loif)
45837469Ssklower 				iso_interfaces++;
45937469Ssklower 		}
46037469Ssklower 		break;
46136384Ssklower 
46237469Ssklower #define cmdbyte(x)	(((x) >> 8) & 0xff)
46337469Ssklower 	default:
46437469Ssklower 		if (cmdbyte(cmd) == 'a')
46550232Ssklower 			return (snpac_ioctl(so, cmd, data));
46637469Ssklower 		if (ia == (struct iso_ifaddr *)0)
46737469Ssklower 			return (EADDRNOTAVAIL);
46837469Ssklower 		break;
46937469Ssklower 	}
47037469Ssklower 	switch (cmd) {
47136384Ssklower 
47237469Ssklower 	case SIOCGIFADDR_ISO:
47337469Ssklower 		ifr->ifr_Addr = ia->ia_addr;
47437469Ssklower 		break;
47536384Ssklower 
47637469Ssklower 	case SIOCGIFDSTADDR_ISO:
47737469Ssklower 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
47837469Ssklower 			return (EINVAL);
47937469Ssklower 		ifr->ifr_Addr = ia->ia_dstaddr;
48037469Ssklower 		break;
48136384Ssklower 
48237469Ssklower 	case SIOCGIFNETMASK_ISO:
48337469Ssklower 		ifr->ifr_Addr = ia->ia_sockmask;
48437469Ssklower 		break;
48536384Ssklower 
48637469Ssklower 	case SIOCAIFADDR_ISO:
48743428Ssklower 		maskIsNew = 0; hostIsNew = 1; error = 0;
48837469Ssklower 		if (ia->ia_addr.siso_family == AF_ISO) {
48937469Ssklower 			if (ifra->ifra_addr.siso_len == 0) {
49037469Ssklower 				ifra->ifra_addr = ia->ia_addr;
49137469Ssklower 				hostIsNew = 0;
49237469Ssklower 			} else if (SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr))
49337469Ssklower 				hostIsNew = 0;
49437469Ssklower 		}
49537469Ssklower 		if (ifra->ifra_mask.siso_len) {
49637469Ssklower 			iso_ifscrub(ifp, ia);
49737469Ssklower 			ia->ia_sockmask = ifra->ifra_mask;
49837469Ssklower 			maskIsNew = 1;
49937469Ssklower 		}
50037469Ssklower 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
50137469Ssklower 		    (ifra->ifra_dstaddr.siso_family == AF_ISO)) {
50237469Ssklower 			iso_ifscrub(ifp, ia);
50337469Ssklower 			ia->ia_dstaddr = ifra->ifra_dstaddr;
50437469Ssklower 			maskIsNew  = 1; /* We lie; but the effect's the same */
50537469Ssklower 		}
50637469Ssklower 		if (ifra->ifra_addr.siso_family == AF_ISO &&
50737469Ssklower 					    (hostIsNew || maskIsNew)) {
50837469Ssklower 			error = iso_ifinit(ifp, ia, &ifra->ifra_addr, 0);
50937469Ssklower 		}
51037469Ssklower 		if (ifra->ifra_snpaoffset)
51137469Ssklower 			ia->ia_snpaoffset = ifra->ifra_snpaoffset;
51237469Ssklower 		return (error);
51337469Ssklower 
51437469Ssklower 	case SIOCDIFADDR_ISO:
51537469Ssklower 		iso_ifscrub(ifp, ia);
51637469Ssklower 		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
51737469Ssklower 			ifp->if_addrlist = ifa->ifa_next;
51837469Ssklower 		else {
51937469Ssklower 			while (ifa->ifa_next &&
52037469Ssklower 			       (ifa->ifa_next != (struct ifaddr *)ia))
52137469Ssklower 				    ifa = ifa->ifa_next;
52237469Ssklower 			if (ifa->ifa_next)
52337469Ssklower 			    ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
52437469Ssklower 			else
52537469Ssklower 				printf("Couldn't unlink isoifaddr from ifp\n");
52637469Ssklower 		}
52737469Ssklower 		oia = ia;
52837469Ssklower 		if (oia == (ia = iso_ifaddr)) {
52937469Ssklower 			iso_ifaddr = ia->ia_next;
53037469Ssklower 		} else {
53137469Ssklower 			while (ia->ia_next && (ia->ia_next != oia)) {
53237469Ssklower 				ia = ia->ia_next;
53336384Ssklower 			}
53437469Ssklower 			if (ia->ia_next)
53537469Ssklower 			    ia->ia_next = oia->ia_next;
53637469Ssklower 			else
53737469Ssklower 				printf("Didn't unlink isoifadr from list\n");
53836384Ssklower 		}
53952030Ssklower 		IFAFREE((&oia->ia_ifa));
54037469Ssklower 		break;
54136384Ssklower 
54236384Ssklower 	default:
54336384Ssklower 		if (ifp == 0 || ifp->if_ioctl == 0)
54436384Ssklower 			return (EOPNOTSUPP);
54536384Ssklower 		return ((*ifp->if_ioctl)(ifp, cmd, data));
54636384Ssklower 	}
54737469Ssklower 	return (0);
54836384Ssklower }
54936384Ssklower 
55037469Ssklower /*
55137469Ssklower  * Delete any existing route for an interface.
55237469Ssklower  */
55337469Ssklower iso_ifscrub(ifp, ia)
55437469Ssklower 	register struct ifnet *ifp;
55537469Ssklower 	register struct iso_ifaddr *ia;
55637469Ssklower {
55743333Ssklower 	int nsellength = ia->ia_addr.siso_tlen;
55837469Ssklower 	if ((ia->ia_flags & IFA_ROUTE) == 0)
55937469Ssklower 		return;
56043333Ssklower 	ia->ia_addr.siso_tlen = 0;
56137469Ssklower 	if (ifp->if_flags & IFF_LOOPBACK)
56237469Ssklower 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
56337469Ssklower 	else if (ifp->if_flags & IFF_POINTOPOINT)
56437469Ssklower 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
56537469Ssklower 	else {
56637469Ssklower 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
56737469Ssklower 	}
56843333Ssklower 	ia->ia_addr.siso_tlen = nsellength;
56937469Ssklower 	ia->ia_flags &= ~IFA_ROUTE;
57037469Ssklower }
57137469Ssklower 
57237469Ssklower /*
57337469Ssklower  * Initialize an interface's internet address
57437469Ssklower  * and routing table entry.
57537469Ssklower  */
57637469Ssklower iso_ifinit(ifp, ia, siso, scrub)
57737469Ssklower 	register struct ifnet *ifp;
57837469Ssklower 	register struct iso_ifaddr *ia;
57937469Ssklower 	struct sockaddr_iso *siso;
58037469Ssklower {
58137469Ssklower 	struct sockaddr_iso oldaddr;
58243333Ssklower 	int s = splimp(), error, nsellength;
58337469Ssklower 
58437469Ssklower 	oldaddr = ia->ia_addr;
58537469Ssklower 	ia->ia_addr = *siso;
58637469Ssklower 	/*
58737469Ssklower 	 * Give the interface a chance to initialize
58837469Ssklower 	 * if this is its first address,
58937469Ssklower 	 * and to validate the address if necessary.
59037469Ssklower 	 */
59154823Ssklower 	if (ifp->if_ioctl &&
59254823Ssklower 				(error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
59337469Ssklower 		splx(s);
59437469Ssklower 		ia->ia_addr = oldaddr;
59537469Ssklower 		return (error);
59637469Ssklower 	}
59737469Ssklower 	if (scrub) {
59837469Ssklower 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
59937469Ssklower 		iso_ifscrub(ifp, ia);
60037469Ssklower 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
60137469Ssklower 	}
60243333Ssklower 	/* XXX -- The following is here temporarily out of laziness
60343333Ssklower 	   in not changing every ethernet driver's if_ioctl routine */
60443333Ssklower 	if (ifp->if_output == ether_output) {
60543333Ssklower 		ia->ia_ifa.ifa_rtrequest = llc_rtrequest;
60643333Ssklower 		ia->ia_ifa.ifa_flags |= RTF_CLONING;
60743333Ssklower 	}
60837469Ssklower 	/*
60937469Ssklower 	 * Add route for the network.
61037469Ssklower 	 */
61143333Ssklower 	nsellength = ia->ia_addr.siso_tlen;
61243333Ssklower 	ia->ia_addr.siso_tlen = 0;
61337469Ssklower 	if (ifp->if_flags & IFF_LOOPBACK) {
61437469Ssklower 		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
61540894Ssklower 		error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
61637469Ssklower 	} else if (ifp->if_flags & IFF_POINTOPOINT &&
61737469Ssklower 		 ia->ia_dstaddr.siso_family == AF_ISO)
61840894Ssklower 		error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
61937469Ssklower 	else {
62040894Ssklower 		rt_maskedcopy(ia->ia_ifa.ifa_addr, ia->ia_ifa.ifa_dstaddr,
62140894Ssklower 			ia->ia_ifa.ifa_netmask);
62249936Ssklower 		ia->ia_dstaddr.siso_nlen =
62349936Ssklower 			min(ia->ia_addr.siso_nlen, (ia->ia_sockmask.siso_len - 6));
62440894Ssklower 		error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
62537469Ssklower 	}
62643333Ssklower 	ia->ia_addr.siso_tlen = nsellength;
62737469Ssklower 	ia->ia_flags |= IFA_ROUTE;
62837469Ssklower 	splx(s);
62940894Ssklower 	return (error);
63037469Ssklower }
63137469Ssklower #ifdef notdef
63237469Ssklower 
63336384Ssklower struct ifaddr *
63436384Ssklower iso_ifwithidi(addr)
63536384Ssklower 	register struct sockaddr *addr;
63636384Ssklower {
63736384Ssklower 	register struct ifnet *ifp;
63836384Ssklower 	register struct ifaddr *ifa;
63936384Ssklower 	register u_int af = addr->sa_family;
64036384Ssklower 
64136384Ssklower 	if (af != AF_ISO)
64236384Ssklower 		return (0);
64336384Ssklower 	IFDEBUG(D_ROUTE)
64436384Ssklower 		printf(">>> iso_ifwithidi addr\n");
64536384Ssklower 		dump_isoaddr( (struct sockaddr_iso *)(addr));
64636384Ssklower 		printf("\n");
64736384Ssklower 	ENDDEBUG
64836384Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
64936384Ssklower 		IFDEBUG(D_ROUTE)
65036384Ssklower 			printf("iso_ifwithidi ifnet %s\n", ifp->if_name);
65136384Ssklower 		ENDDEBUG
65236384Ssklower 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
65336384Ssklower 			IFDEBUG(D_ROUTE)
65436384Ssklower 				printf("iso_ifwithidi address ");
65537469Ssklower 				dump_isoaddr( (struct sockaddr_iso *)(ifa->ifa_addr));
65636384Ssklower 			ENDDEBUG
65737469Ssklower 			if (ifa->ifa_addr->sa_family != addr->sa_family)
65836384Ssklower 				continue;
65936384Ssklower 
66036384Ssklower #define	IFA_SIS(ifa)\
66137469Ssklower 	((struct sockaddr_iso *)((ifa)->ifa_addr))
66236384Ssklower 
66336384Ssklower 			IFDEBUG(D_ROUTE)
66436384Ssklower 				printf(" af same, args to iso_eqtype:\n");
66536384Ssklower 				printf("0x%x ", IFA_SIS(ifa)->siso_addr);
66636384Ssklower 				printf(" 0x%x\n",
66736384Ssklower 				&(((struct sockaddr_iso *)addr)->siso_addr));
66836384Ssklower 			ENDDEBUG
66936384Ssklower 
67036384Ssklower 			if (iso_eqtype(&(IFA_SIS(ifa)->siso_addr),
67136384Ssklower 				&(((struct sockaddr_iso *)addr)->siso_addr))) {
67236384Ssklower 				IFDEBUG(D_ROUTE)
67336384Ssklower 					printf("ifa_ifwithidi: ifa found\n");
67436384Ssklower 				ENDDEBUG
67536384Ssklower 				return (ifa);
67636384Ssklower 			}
67736384Ssklower 			IFDEBUG(D_ROUTE)
67836384Ssklower 				printf(" iso_eqtype failed\n");
67936384Ssklower 			ENDDEBUG
68036384Ssklower 		}
68136384Ssklower 	}
68236384Ssklower 	return ((struct ifaddr *)0);
68336384Ssklower }
68436384Ssklower 
68537469Ssklower #endif notdef
68636384Ssklower /*
68736384Ssklower  * FUNCTION:		iso_ck_addr
68836384Ssklower  *
68936384Ssklower  * PURPOSE:			return true if the iso_addr passed is
69036384Ssklower  *					within the legal size limit for an iso address.
69136384Ssklower  *
69236384Ssklower  * RETURNS:			true or false
69336384Ssklower  *
69436384Ssklower  * SIDE EFFECTS:
69536384Ssklower  *
69636384Ssklower  */
69736384Ssklower iso_ck_addr(isoa)
69836384Ssklower struct iso_addr	*isoa;	/* address to check */
69936384Ssklower {
70036384Ssklower 	return (isoa->isoa_len <= 20);
70136384Ssklower 
70236384Ssklower }
70336384Ssklower 
70437469Ssklower #ifdef notdef
70536384Ssklower /*
70636384Ssklower  * FUNCTION:		iso_eqtype
70736384Ssklower  *
70836384Ssklower  * PURPOSE:			Determine if two iso addresses are of the same type.
70936384Ssklower  *  This is flaky.  Really we should consider all type 47 addrs to be the
71036384Ssklower  *  same - but there do exist different structures for 47 addrs.
71136384Ssklower  *  Gosip adds a 3rd.
71236384Ssklower  *
71336384Ssklower  * RETURNS:			true if the addresses are the same type
71436384Ssklower  *
71536384Ssklower  * SIDE EFFECTS:
71636384Ssklower  *
71736384Ssklower  * NOTES:			By type, I mean rfc986, t37, or osinet
71836384Ssklower  *
71936384Ssklower  *					This will first compare afis. If they match, then
72036384Ssklower  *					if the addr is not t37, the idis must be compared.
72136384Ssklower  */
72236384Ssklower iso_eqtype(isoaa, isoab)
72336384Ssklower struct iso_addr	*isoaa;		/* first addr to check */
72436384Ssklower struct iso_addr	*isoab;		/* other addr to check */
72536384Ssklower {
72636384Ssklower 	if (isoaa->isoa_afi == isoab->isoa_afi) {
72736384Ssklower 		if (isoaa->isoa_afi == AFI_37)
72836384Ssklower 			return(1);
72936384Ssklower 		else
73036384Ssklower 			return (!bcmp(&isoaa->isoa_u, &isoab->isoa_u, 2));
73136384Ssklower 	}
73236384Ssklower 	return(0);
73336384Ssklower }
73437469Ssklower #endif notdef
73536384Ssklower /*
73637469Ssklower  * FUNCTION:		iso_localifa()
73736384Ssklower  *
73837469Ssklower  * PURPOSE:			Find an interface addresss having a given destination
73937469Ssklower  *					or at least matching the net.
74036384Ssklower  *
74136384Ssklower  * RETURNS:			ptr to an interface address
74236384Ssklower  *
74336384Ssklower  * SIDE EFFECTS:
74436384Ssklower  *
74536384Ssklower  * NOTES:
74636384Ssklower  */
74736384Ssklower struct iso_ifaddr *
74837469Ssklower iso_localifa(siso)
74937469Ssklower 	register struct sockaddr_iso *siso;
75036384Ssklower {
75136384Ssklower 	register struct iso_ifaddr *ia;
75237469Ssklower 	register char *cp1, *cp2, *cp3;
75337469Ssklower 	register struct ifnet *ifp;
75437469Ssklower 	struct iso_ifaddr *ia_maybe = 0;
75537469Ssklower 	/*
75637469Ssklower 	 * We make one pass looking for both net matches and an exact
75737469Ssklower 	 * dst addr.
75837469Ssklower 	 */
75937469Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
76037469Ssklower 		if ((ifp = ia->ia_ifp) == 0 || ((ifp->if_flags & IFF_UP) == 0))
76137469Ssklower 			continue;
76237469Ssklower 		if (ifp->if_flags & IFF_POINTOPOINT) {
76337469Ssklower 			if ((ia->ia_dstaddr.siso_family == AF_ISO) &&
76437469Ssklower 				SAME_ISOADDR(&ia->ia_dstaddr, siso))
76537469Ssklower 				return (ia);
76637469Ssklower 			else
76737469Ssklower 				if (SAME_ISOADDR(&ia->ia_addr, siso))
76837469Ssklower 					ia_maybe = ia;
76937469Ssklower 			continue;
77037469Ssklower 		}
77137469Ssklower 		if (ia->ia_sockmask.siso_len) {
77237469Ssklower 			char *cplim = ia->ia_sockmask.siso_len + (char *)&ia->ia_sockmask;
77337469Ssklower 			cp1 = ia->ia_sockmask.siso_data;
77437469Ssklower 			cp2 = siso->siso_data;
77537469Ssklower 			cp3 = ia->ia_addr.siso_data;
77639936Ssklower 			while (cp1 < cplim)
77737469Ssklower 				if (*cp1++ & (*cp2++ ^ *cp3++))
77837469Ssklower 					goto next;
77937469Ssklower 			ia_maybe = ia;
78037469Ssklower 		}
78137469Ssklower 		if (SAME_ISOADDR(&ia->ia_addr, siso))
78237469Ssklower 			return ia;
78337469Ssklower 	next:;
78437469Ssklower 	}
78537469Ssklower 	return ia_maybe;
78636384Ssklower }
78736384Ssklower 
78847272Ssklower #ifdef	TPCONS
78956533Sbostic #include <netiso/cons.h>
79047272Ssklower #endif	TPCONS
79136384Ssklower /*
79236384Ssklower  * FUNCTION:		iso_nlctloutput
79336384Ssklower  *
79436384Ssklower  * PURPOSE:			Set options at the network level
79536384Ssklower  *
79636384Ssklower  * RETURNS:			E*
79736384Ssklower  *
79836384Ssklower  * SIDE EFFECTS:
79936384Ssklower  *
80036384Ssklower  * NOTES:			This could embody some of the functions of
80136384Ssklower  *					rclnp_ctloutput and cons_ctloutput.
80236384Ssklower  */
80336384Ssklower iso_nlctloutput(cmd, optname, pcb, m)
80436384Ssklower int			cmd;		/* command:set or get */
80536384Ssklower int			optname;	/* option of interest */
80636384Ssklower caddr_t		pcb;		/* nl pcb */
80736384Ssklower struct mbuf	*m;			/* data for set, buffer for get */
80836384Ssklower {
80936384Ssklower 	struct isopcb	*isop = (struct isopcb *)pcb;
81036384Ssklower 	int				error = 0;	/* return value */
81136384Ssklower 	caddr_t			data;		/* data for option */
81236384Ssklower 	int				data_len;	/* data's length */
81336384Ssklower 
81436384Ssklower 	IFDEBUG(D_ISO)
81536384Ssklower 		printf("iso_nlctloutput: cmd %x, opt %x, pcb %x, m %x\n",
81636384Ssklower 			cmd, optname, pcb, m);
81736384Ssklower 	ENDDEBUG
81836384Ssklower 
81936384Ssklower 	if ((cmd != PRCO_GETOPT) && (cmd != PRCO_SETOPT))
82036384Ssklower 		return(EOPNOTSUPP);
82136384Ssklower 
82236384Ssklower 	data = mtod(m, caddr_t);
82336384Ssklower 	data_len = (m)->m_len;
82436384Ssklower 
82536384Ssklower 	IFDEBUG(D_ISO)
82636384Ssklower 		printf("iso_nlctloutput: data is:\n");
82736384Ssklower 		dump_buf(data, data_len);
82836384Ssklower 	ENDDEBUG
82936384Ssklower 
83036384Ssklower 	switch (optname) {
83136384Ssklower 
83247272Ssklower #ifdef	TPCONS
83336384Ssklower 		case CONSOPT_X25CRUD:
83436384Ssklower 			if (cmd == PRCO_GETOPT) {
83536384Ssklower 				error = EOPNOTSUPP;
83636384Ssklower 				break;
83736384Ssklower 			}
83836384Ssklower 
83936384Ssklower 			if (data_len > MAXX25CRUDLEN) {
84036384Ssklower 				error = EINVAL;
84136384Ssklower 				break;
84236384Ssklower 			}
84336384Ssklower 
84436384Ssklower 			IFDEBUG(D_ISO)
84536384Ssklower 				printf("iso_nlctloutput: setting x25 crud\n");
84636384Ssklower 			ENDDEBUG
84736384Ssklower 
84837469Ssklower 			bcopy(data, (caddr_t)isop->isop_x25crud, (unsigned)data_len);
84936384Ssklower 			isop->isop_x25crud_len = data_len;
85036384Ssklower 			break;
85147272Ssklower #endif	TPCONS
85236384Ssklower 
85336384Ssklower 		default:
85436384Ssklower 			error = EOPNOTSUPP;
85536384Ssklower 	}
85650972Ssklower 	if (cmd == PRCO_SETOPT)
85750972Ssklower 		m_freem(m);
85836384Ssklower 	return error;
85936384Ssklower }
86036384Ssklower #endif ISO
86136384Ssklower 
86236384Ssklower #ifdef ARGO_DEBUG
86336384Ssklower 
86436384Ssklower /*
86536384Ssklower  * FUNCTION:		dump_isoaddr
86636384Ssklower  *
86736384Ssklower  * PURPOSE:			debugging
86836384Ssklower  *
86936384Ssklower  * RETURNS:			nada
87036384Ssklower  *
87136384Ssklower  */
87236384Ssklower dump_isoaddr(s)
87336384Ssklower 	struct sockaddr_iso *s;
87436384Ssklower {
87537469Ssklower 	char *clnp_saddr_isop();
87636384Ssklower 	register int i;
87736384Ssklower 
87836384Ssklower 	if( s->siso_family == AF_ISO) {
87937469Ssklower 		printf("ISO address: suffixlen %d, %s\n",
88038841Ssklower 			s->siso_tlen, clnp_saddr_isop(s));
88136384Ssklower 	} else if( s->siso_family == AF_INET) {
88236384Ssklower 		/* hack */
88336384Ssklower 		struct sockaddr_in *sin = (struct sockaddr_in *)s;
88436384Ssklower 
88536384Ssklower 		printf("%d.%d.%d.%d: %d",
88636384Ssklower 			(sin->sin_addr.s_addr>>24)&0xff,
88736384Ssklower 			(sin->sin_addr.s_addr>>16)&0xff,
88836384Ssklower 			(sin->sin_addr.s_addr>>8)&0xff,
88936384Ssklower 			(sin->sin_addr.s_addr)&0xff,
89036384Ssklower 			sin->sin_port);
89136384Ssklower 	}
89236384Ssklower }
89336384Ssklower 
89436384Ssklower #endif ARGO_DEBUG
895