xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 39950)
136392Ssklower /***********************************************************
236392Ssklower 		Copyright IBM Corporation 1987
336392Ssklower 
436392Ssklower                       All Rights Reserved
536392Ssklower 
636392Ssklower Permission to use, copy, modify, and distribute this software and its
736392Ssklower documentation for any purpose and without fee is hereby granted,
836392Ssklower provided that the above copyright notice appear in all copies and that
936392Ssklower both that copyright notice and this permission notice appear in
1036392Ssklower supporting documentation, and that the name of IBM not be
1136392Ssklower used in advertising or publicity pertaining to distribution of the
1236392Ssklower software without specific, written prior permission.
1336392Ssklower 
1436392Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536392Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636392Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736392Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836392Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936392Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036392Ssklower SOFTWARE.
2136392Ssklower 
2236392Ssklower ******************************************************************/
2336392Ssklower 
2436392Ssklower /*
2536392Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636392Ssklower  */
2736392Ssklower /* $Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $ */
2836392Ssklower /* $Source: /usr/argo/sys/netiso/RCS/iso_snpac.c,v $ */
29*39950Ssklower /*	@(#)iso_snpac.c	7.6 (Berkeley) 01/25/90 */
3036392Ssklower 
3136392Ssklower #ifndef lint
3236392Ssklower static char *rcsid = "$Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $";
3336392Ssklower #endif lint
3436392Ssklower 
3536392Ssklower #ifdef ISO
3636392Ssklower 
3737469Ssklower #include "types.h"
3837469Ssklower #include "param.h"
3937551Smckusick #include "user.h"
4037469Ssklower #include "mbuf.h"
4137469Ssklower #include "domain.h"
4237469Ssklower #include "protosw.h"
4337469Ssklower #include "socket.h"
4437469Ssklower #include "socketvar.h"
4537469Ssklower #include "errno.h"
4637469Ssklower #include "ioctl.h"
4737469Ssklower #include "kernel.h"
4836392Ssklower 
4936392Ssklower #include "../net/if.h"
5036392Ssklower #include "../net/route.h"
5136392Ssklower 
5237469Ssklower #include "iso.h"
5337469Ssklower #include "iso_var.h"
5437469Ssklower #include "iso_snpac.h"
5537469Ssklower #include "clnp.h"
5637469Ssklower #include "clnp_stat.h"
5738841Ssklower #include "esis.h"
5837469Ssklower #include "argo_debug.h"
5936392Ssklower 
6036392Ssklower #define	SNPAC_BSIZ	20		/* bucket size */
6136392Ssklower #define	SNPAC_NB	13		/* number of buckets */
6236392Ssklower #define	SNPAC_SIZE	(SNPAC_BSIZ * SNPAC_NB)
6336392Ssklower struct	snpa_cache	iso_snpac[SNPAC_SIZE];
6437469Ssklower u_int				iso_snpac_size = SNPAC_SIZE;/* for iso_map command */
6536392Ssklower int 				iso_systype = SNPA_ES;	/* default to be an ES */
6636392Ssklower 
6737469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
6837469Ssklower extern u_long iso_hashchar();
6937469Ssklower static struct sockaddr_iso
7037469Ssklower 	dst	= {sizeof(dst), AF_ISO},
7137469Ssklower 	gte	= {sizeof(dst), AF_ISO},
7237469Ssklower 	src	= {sizeof(dst), AF_ISO},
7337469Ssklower 	msk	= {sizeof(dst), AF_ISO},
7437469Ssklower 	zmk = {1};
7537469Ssklower #define zsi blank_siso
7637469Ssklower #define zero_isoa	zsi.siso_addr
7737469Ssklower #define zap_isoaddr(a, b) (bzero((caddr_t)&a.siso_addr, sizeof(*r)), \
7837469Ssklower 	   ((r = b) && bcopy((caddr_t)r, (caddr_t)&a.siso_addr, 1 + (r)->isoa_len)))
7937469Ssklower #define S(x) ((struct sockaddr *)&(x))
8037469Ssklower 
8136392Ssklower #define	SNPAC_HASH(addr) \
8237469Ssklower 	(((u_long) iso_hashchar((caddr_t)addr, (int)addr->isoa_len)) % SNPAC_NB)
8336392Ssklower 
8436392Ssklower #define	SNPAC_LOOK(sc,addr) { \
8536392Ssklower 	register n; \
8636392Ssklower 	sc = &iso_snpac[SNPAC_HASH(addr) * SNPAC_BSIZ]; \
8736392Ssklower 	for (n = 0 ; n < SNPAC_BSIZ ; n++,sc++) \
8836392Ssklower 		if ((sc->sc_flags & SNPA_VALID) && \
8936392Ssklower 			(iso_addrmatch1(&sc->sc_nsap, addr))) \
9036392Ssklower 			break; \
9136392Ssklower 	if (n >= SNPAC_BSIZ) \
9236392Ssklower 		sc = 0; \
9336392Ssklower }
9436392Ssklower 
9536392Ssklower struct snpa_cache	*snpac_new();
9636392Ssklower 
9736392Ssklower /*
9836392Ssklower  *	We only keep track of a single IS at a time.
9936392Ssklower  */
10036392Ssklower struct snpa_cache	*known_is;
10136392Ssklower 
10236392Ssklower /*
10336392Ssklower  *	Addresses taken from NBS agreements, December 1987.
10436392Ssklower  *
10536392Ssklower  *	These addresses assume on-the-wire transmission of least significant
10636392Ssklower  *	bit first. This is the method used by 802.3. When these
10736392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
10836392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
10936392Ssklower  *
11036392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
11136392Ssklower  *	true token ring multicast addresses. More work is necessary
11236392Ssklower  *	to get multicast to work right on token ring.
11336392Ssklower  *
11436392Ssklower  *	Currently, the token ring driver does not handle multicast, so
11536392Ssklower  *	these addresses are converted into the broadcast address in
11636392Ssklower  *	lan_output() That means that if these multicast addresses change
11736392Ssklower  *	the token ring driver must be altered.
11836392Ssklower  */
11936392Ssklower struct snpa_cache	all_es = {
12036392Ssklower 	{ { 0x0 },							/* sc_nsap */
12136392Ssklower 	6,									/* sc_len */
12236392Ssklower 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }, /* sc_snpa */
12336392Ssklower 	SNPA_VALID,							/* sc_flags */
12436392Ssklower 	0	}								/* sc_ht */
12536392Ssklower };
12636392Ssklower struct snpa_cache	all_is = {
12736392Ssklower 	{ { 0x0 },							/* sc_nsap */
12836392Ssklower 	6,									/* sc_len */
12936392Ssklower 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }, /* sc_snpa */
13036392Ssklower 	SNPA_VALID,							/* sc_flags */
13136392Ssklower 	0	}								/* sc_ht */
13236392Ssklower };
13336392Ssklower 
13436392Ssklower 
13536392Ssklower /*
13636392Ssklower  * FUNCTION:		iso_snparesolve
13736392Ssklower  *
13836392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
13936392Ssklower  *
14036392Ssklower  * RETURNS:			0 if addr is resolved
14136392Ssklower  *					errno if addr is unknown
14236392Ssklower  *
14336392Ssklower  * SIDE EFFECTS:
14436392Ssklower  *
14536392Ssklower  * NOTES:			If an entry is found that matches the address, that
14636392Ssklower  *					snpa is returned. If no entry is found, but an IS is
14736392Ssklower  *					known, then the address of the IS is returned. If
14836392Ssklower  *					neither an address is found that matches or an IS is
14936392Ssklower  *					known, then the multi-cast address for "all ES" for
15036392Ssklower  *					this interface is returned.
15136392Ssklower  *
15236392Ssklower  *					NB: the last case described above constitutes the
15336392Ssklower  *					query configuration function 9542, sec 6.5
15436392Ssklower  *					A mechanism is needed to prevent this function from
15536392Ssklower  *					being invoked if the system is an IS.
15636392Ssklower  */
15737469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
15836392Ssklower struct ifnet 		*ifp;	/* outgoing interface */
15937469Ssklower struct sockaddr_iso *dest;	/* destination */
16036392Ssklower char				*snpa;	/* RESULT: snpa to be used */
16136392Ssklower int					*snpa_len;	/* RESULT: length of snpa */
16236392Ssklower {
16336392Ssklower 	extern struct ifnet 	loif;		/* loopback interface */
16436392Ssklower 	struct snpa_cache		*sc;		/* ptr to snpa table entry */
16536392Ssklower 	struct iso_addr			*destiso;	/* destination iso addr */
16636392Ssklower 
16737469Ssklower  	destiso = &dest->siso_addr;
16836392Ssklower 
16936392Ssklower 	/*
17036392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
17136392Ssklower 	 *	addresss embedded in the destination nsap address
17236392Ssklower 	 */
17337469Ssklower 	if (destiso->isoa_genaddr[0] == AFI_SNA) {
17436392Ssklower 		/*
17536392Ssklower 		 *	This is a subnetwork address. Return it immediately
17636392Ssklower 		 */
17736392Ssklower 		IFDEBUG(D_SNPA)
17836392Ssklower 			printf("iso_snparesolve: return SN address\n");
17936392Ssklower 		ENDDEBUG
18036392Ssklower 
18136392Ssklower 		*snpa_len = destiso->isoa_len - 1;	/* subtract size of AFI */
18237469Ssklower 		bcopy((caddr_t) destiso->isoa_genaddr + 1, (caddr_t)snpa,
18337469Ssklower 			  (unsigned)*snpa_len);
18436392Ssklower 		return (0);
18536392Ssklower 	}
18636392Ssklower 
18736392Ssklower 	IFDEBUG(D_SNPA)
18836392Ssklower 		printf("iso_snparesolve: resolving %s\n", clnp_iso_addrp(destiso));
18936392Ssklower 	ENDDEBUG
19036392Ssklower 
19136392Ssklower 	/*
19236392Ssklower 	 *	packet is not for us, check cache for an entry
19336392Ssklower 	 */
19436392Ssklower 	SNPAC_LOOK(sc, destiso);
19536392Ssklower 	if (sc == 0) {			/* not found */
19636392Ssklower 		/* If we are an IS, we can't do much with the packet */
19736392Ssklower 		if (iso_systype == SNPA_IS)
19836392Ssklower 			goto bad;
19936392Ssklower 
20036392Ssklower 		/*
20136392Ssklower 		 *	Check if we know about an IS
20236392Ssklower 		 */
20336392Ssklower 		if ((known_is) && (known_is->sc_flags & SNPA_VALID)) {
20436392Ssklower 			sc = known_is;
20536392Ssklower 		} else if (ifp->if_flags & IFF_BROADCAST) {
20636392Ssklower 			/*
20736392Ssklower 			 *	no IS, no match. Return "all es" multicast address for this
20836392Ssklower 			 *	interface, as per Query Configuration Function (9542 sec 6.5)
20936392Ssklower 			 *
21036392Ssklower 			 *	Note: there is a potential problem here. If the destination
21136392Ssklower 			 *	is on the subnet and it does not respond with a ESH, but
21236392Ssklower 			 *	does send back a TP CC, a connection could be established
21336392Ssklower 			 *	where we always transmit the CLNP packet to "all es"
21436392Ssklower 			 */
21536392Ssklower 			sc = &all_es;
21636392Ssklower 		} else {
21736392Ssklower 			goto bad;
21836392Ssklower 		}
21936392Ssklower 	}
22036392Ssklower 
22136392Ssklower 	bcopy((caddr_t)sc->sc_snpa, (caddr_t)snpa, sc->sc_len);
22236392Ssklower 	*snpa_len = sc->sc_len;
22336392Ssklower 	return (0);
22436392Ssklower 
22536392Ssklower bad:
22636392Ssklower 	return(ENETUNREACH);
22736392Ssklower }
22836392Ssklower 
22936392Ssklower 
23036392Ssklower /*
23136392Ssklower  * FUNCTION:		snpac_look
23236392Ssklower  *
23336392Ssklower  * PURPOSE:			Look up an entry in the snpa cache
23436392Ssklower  *
23536392Ssklower  * RETURNS:			Pointer to snpa_cache structure, or null
23636392Ssklower  *
23736392Ssklower  * SIDE EFFECTS:
23836392Ssklower  *
23936392Ssklower  * NOTES:			This is simply SNPAC_LOOK as a procedure.
24036392Ssklower  */
24136392Ssklower struct snpa_cache *
24236392Ssklower snpac_look(isoa)
24336392Ssklower struct iso_addr *isoa;	/* destination nsap */
24436392Ssklower {
24536392Ssklower 	struct snpa_cache	*sc;
24636392Ssklower 	int 				s = splimp();
24736392Ssklower 
24836392Ssklower 	SNPAC_LOOK(sc, isoa);
24936392Ssklower 
25036392Ssklower 	splx(s);
25136392Ssklower 	return(sc);
25236392Ssklower }
25336392Ssklower 
25436392Ssklower /*
25536392Ssklower  * FUNCTION:		iso_8208snparesolve
25636392Ssklower  *
25736392Ssklower  * PURPOSE:			Find the X.121 address that corresponds to an NSAP addr
25836392Ssklower  *
25936392Ssklower  * RETURNS:			0 or unix errno
26036392Ssklower  *
26136392Ssklower  * SIDE EFFECTS:
26236392Ssklower  *
26336392Ssklower  * NOTES:			This ought to invoke the 8208 ES-IS function
26436392Ssklower  */
26537469Ssklower iso_8208snparesolve(dest, snpa, snpa_len)
26637469Ssklower struct sockaddr_iso *dest;	/* destination */
26736392Ssklower char				*snpa;	/* RESULT: snpa to be used */
26836392Ssklower int					*snpa_len;	/* RESULT: length of snpa */
26936392Ssklower {
27036392Ssklower 	struct snpa_cache		*sc;		/* ptr to snpa table entry */
27136392Ssklower 	struct iso_addr			*destiso;	/* destination iso addr */
27236392Ssklower 	int						s;
27336392Ssklower 	int						err = 0;
27436392Ssklower 
27537469Ssklower  	destiso = &dest->siso_addr;
27636392Ssklower 
27736392Ssklower 	s = splimp();
27836392Ssklower 	SNPAC_LOOK(sc, destiso);
27936392Ssklower 	if (sc) {
28036392Ssklower 		bcopy((caddr_t)sc->sc_snpa, (caddr_t)snpa, sc->sc_len);
28136392Ssklower 		*snpa_len = sc->sc_len;
28236392Ssklower 	} else {
28336392Ssklower 		err = ENETUNREACH;
28436392Ssklower 	}
28536392Ssklower 	splx(s);
28636392Ssklower 	return (err);
28736392Ssklower }
28836392Ssklower 
28936392Ssklower /*
29036392Ssklower  * FUNCTION:		iso_8208snpaadd
29136392Ssklower  *
29236392Ssklower  * PURPOSE:			Add an entry to the snpa cache
29336392Ssklower  *
29436392Ssklower  * RETURNS:
29536392Ssklower  *
29636392Ssklower  * SIDE EFFECTS:
29736392Ssklower  *
29836392Ssklower  * NOTES:			used by cons
29936392Ssklower  */
30036392Ssklower iso_8208snpaadd(ifp, nsap, snpa, snpalen, ht)
30136392Ssklower struct ifnet		*ifp;		/* interface info is related to */
30236392Ssklower struct iso_addr		*nsap;		/* nsap to add */
30336392Ssklower caddr_t				snpa;		/* translation */
30436392Ssklower int					snpalen;	/* length in bytes */
30536392Ssklower short				ht;			/* holding time (in seconds) */
30636392Ssklower {
30737469Ssklower 	snpac_add(ifp, nsap, snpa, snpalen, SNPA_ES, (u_short)ht);
30836392Ssklower }
30936392Ssklower 
31036392Ssklower /*
31136392Ssklower  * FUNCTION:		iso_8208snpadelete
31236392Ssklower  *
31336392Ssklower  * PURPOSE:			Delete an entry from the snpa cache
31436392Ssklower  *
31536392Ssklower  * RETURNS:			nothing
31636392Ssklower  *
31736392Ssklower  * SIDE EFFECTS:
31836392Ssklower  *
31936392Ssklower  * NOTES:			used by CONS
32036392Ssklower  */
32136392Ssklower iso_8208snpadelete(nsap)
32236392Ssklower struct iso_addr	*nsap;
32336392Ssklower {
32436392Ssklower 	struct snpa_cache	*sc = snpac_look(nsap);
32536392Ssklower 
32636392Ssklower 	if (sc != NULL)
32736392Ssklower 		snpac_free(sc);
32836392Ssklower }
32936392Ssklower 
33036392Ssklower /*
33136392Ssklower  * FUNCTION:		snpac_new
33236392Ssklower  *
33336392Ssklower  * PURPOSE:			create a new entry in the iso address to ethernet
33436392Ssklower  *					address table
33536392Ssklower  *
33636392Ssklower  * RETURNS:			pointer to newest entry
33736392Ssklower  *
33836392Ssklower  * SIDE EFFECTS:	times out old entries if no new entries are found
33936392Ssklower  *
34036392Ssklower  * NOTES:			If the bucket is full, then timeout the oldest entry
34136392Ssklower  *					(ie. the one with the youngest holding time)
34236392Ssklower  */
34336392Ssklower struct snpa_cache *
34436392Ssklower snpac_new(isoa)
34536392Ssklower struct iso_addr *isoa;		/* iso address to enter into table */
34636392Ssklower {
34736392Ssklower 	register struct snpa_cache	*sc;
34836392Ssklower 	register int 				n;
34936392Ssklower 	int							smallest_ht = 1000000;
35036392Ssklower 	struct snpa_cache			*maybe;
35136392Ssklower 
35236392Ssklower 	sc = &iso_snpac[SNPAC_HASH(isoa) * SNPAC_BSIZ];
35336392Ssklower 	for (n = 0 ; n < SNPAC_BSIZ ; n++,sc++) {
35436392Ssklower 
35536392Ssklower 		IFDEBUG (D_IOCTL)
35636392Ssklower 			printf("snpac_new: sc x%x ", sc);
35736392Ssklower 
35836392Ssklower 			if (sc->sc_flags & SNPA_VALID) {
35936392Ssklower 				int i;
36036392Ssklower 
36136392Ssklower 				printf("(valid) %s ", clnp_iso_addrp(&sc->sc_nsap));
36236392Ssklower 				for (i=0; i<sc->sc_len; i++)
36336392Ssklower 					printf("%x%c", sc->sc_snpa[i], i < (sc->sc_len-1) ? ':'
36436392Ssklower 						: '\n');
36536392Ssklower 			} else {
36636392Ssklower 				printf("invalid\n");
36736392Ssklower 			}
36836392Ssklower 		ENDDEBUG
36936392Ssklower 
37036392Ssklower 		if (sc->sc_flags & SNPA_VALID) {
37136392Ssklower 			if (sc->sc_ht < smallest_ht) {
37236392Ssklower 				smallest_ht = sc->sc_ht;
37336392Ssklower 				maybe = sc;
37436392Ssklower 			}
37536392Ssklower 		} else {
37636392Ssklower 			return sc; /* found unused slot */
37736392Ssklower 		}
37836392Ssklower 	}
37936392Ssklower 	snpac_free(maybe);
38036392Ssklower 	return maybe;
38136392Ssklower }
38236392Ssklower /*
38336392Ssklower  * FUNCTION:		snpac_free
38436392Ssklower  *
38536392Ssklower  * PURPOSE:			free an entry in the iso address map table
38636392Ssklower  *
38736392Ssklower  * RETURNS:			nothing
38836392Ssklower  *
38936392Ssklower  * SIDE EFFECTS:
39036392Ssklower  *
39136392Ssklower  * NOTES:			If there is a route entry associated with cache
39236392Ssklower  *					entry, then delete that as well
39336392Ssklower  */
39436392Ssklower snpac_free(sc)
39536392Ssklower register struct snpa_cache *sc;		/* entry to free */
39636392Ssklower {
39737469Ssklower 	register struct rtentry *rt;
39837469Ssklower 	register struct iso_addr *r;
39936392Ssklower 
40036392Ssklower 	if (known_is == sc) {
40136392Ssklower 		known_is = NULL;
40236392Ssklower 	}
40337469Ssklower 	if (sc->sc_rt) {
40437469Ssklower 		zap_isoaddr(dst, (&(sc->sc_da)));
40537469Ssklower 		rt = rtalloc1((struct sockaddr *)&dst, 0);
40637469Ssklower 		if ((sc->sc_rt == rt) && (rt->rt_flags & RTF_UP)
40737469Ssklower 			&& (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
40837469Ssklower 			RTFREE(rt);
40937469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
41037469Ssklower 						rt->rt_flags, (struct rtentry **)0);
41137469Ssklower 		}
41237469Ssklower 		RTFREE(rt);
41336392Ssklower 	}
41436392Ssklower 	bzero((caddr_t)sc, sizeof(struct snpa_cache));
41536392Ssklower }
41636392Ssklower 
41736392Ssklower /*
41836392Ssklower  * FUNCTION:		snpac_add
41936392Ssklower  *
42036392Ssklower  * PURPOSE:			Add an entry to the snpa cache
42136392Ssklower  *
42236392Ssklower  * RETURNS:
42336392Ssklower  *
42436392Ssklower  * SIDE EFFECTS:
42536392Ssklower  *
42636392Ssklower  * NOTES:			If entry already exists, then update holding time.
42736392Ssklower  */
42836392Ssklower snpac_add(ifp, nsap, snpa, snpalen, type, ht)
42936392Ssklower struct ifnet		*ifp;		/* interface info is related to */
43036392Ssklower struct iso_addr		*nsap;		/* nsap to add */
43136392Ssklower caddr_t				snpa;		/* translation */
43237469Ssklower int					snpalen;	/* translation length */
43336392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
43437469Ssklower u_short				ht;			/* holding time (in seconds) */
43536392Ssklower {
43636392Ssklower 	struct snpa_cache	*sc;
43736392Ssklower 
43836392Ssklower 	SNPAC_LOOK(sc, nsap);
43936392Ssklower 	if (sc == NULL) {
44036392Ssklower 		sc = snpac_new(nsap);
44136392Ssklower 		sc->sc_nsap = *nsap;
44236392Ssklower 	}
44336392Ssklower 
44436392Ssklower 	sc->sc_ht = ht;
44536392Ssklower 
44636392Ssklower 	sc->sc_len = min(snpalen, MAX_SNPALEN);
44737469Ssklower 	bcopy(snpa, (caddr_t)sc->sc_snpa, sc->sc_len);
44836392Ssklower 	sc->sc_flags = SNPA_VALID | type;
44936392Ssklower 	sc->sc_ifp = ifp;
45036392Ssklower 
45136392Ssklower 	if (type & SNPA_IS)
45236392Ssklower 		snpac_logdefis(sc);
45336392Ssklower }
45436392Ssklower 
45536392Ssklower /*
45636392Ssklower  * FUNCTION:		snpac_ioctl
45736392Ssklower  *
45836392Ssklower  * PURPOSE:			handle ioctls to change the iso address map
45936392Ssklower  *
46036392Ssklower  * RETURNS:			unix error code
46136392Ssklower  *
46236392Ssklower  * SIDE EFFECTS:	changes the snpa_cache table declared above.
46336392Ssklower  *
46436392Ssklower  * NOTES:
46536392Ssklower  */
46636392Ssklower snpac_ioctl(cmd, data)
46736392Ssklower int		cmd;		/* ioctl to process */
46836392Ssklower caddr_t	data;	/* data for the cmd */
46936392Ssklower {
47036392Ssklower 	register struct snpa_req	*rq = (struct snpa_req *)data;
47136392Ssklower 	register struct snpa_cache	*sc;
47236392Ssklower 	register struct iso_addr	*isoa;
47336392Ssklower 	int							s;
47437469Ssklower 	char						*type;
47536392Ssklower 
47637469Ssklower 	switch(cmd) {
47737469Ssklower 		case SIOCSISOMAP: type = "set"; break;
47837469Ssklower 		case SIOCDISOMAP: type = "delete"; break;
47937469Ssklower 		case SIOCGISOMAP: type = "get"; break;
48037469Ssklower 		default: return(snpac_systype(cmd, data));
48137469Ssklower 	}
48236392Ssklower 
48336392Ssklower 	/* sanity check */
48436392Ssklower 	if (rq->sr_len > MAX_SNPALEN)
48536392Ssklower 		return(EINVAL);
48636392Ssklower 
48736392Ssklower 	IFDEBUG (D_IOCTL)
48836392Ssklower 		int i;
48936392Ssklower 
49037469Ssklower 		printf("snpac_ioctl: %s %s to ", type, clnp_iso_addrp(isoa));
49136392Ssklower 		for (i=0; i<rq->sr_len; i++)
49236392Ssklower 			printf("%x%c", rq->sr_snpa[i], i < (rq->sr_len-1) ? ':' : '\n');
49336392Ssklower 	ENDDEBUG
49436392Ssklower 
49537469Ssklower 	/* look up this address in table */
49637469Ssklower 	isoa = &rq->sr_isoa;
49737469Ssklower 
49836392Ssklower 	SNPAC_LOOK(sc, isoa);
49936392Ssklower 	if (sc == NULL) {	 /* not found */
50036392Ssklower 		if (cmd != SIOCSISOMAP)
50136392Ssklower 			return(ENXIO);
50236392Ssklower 	}
50336392Ssklower 
50436392Ssklower 	switch(cmd) {
50536392Ssklower 		case SIOCSISOMAP:	/* set entry */
50637469Ssklower 			snpac_add((struct ifnet *)NULL, isoa, (caddr_t)rq->sr_snpa,
50737469Ssklower 					  (int)rq->sr_len,
50837469Ssklower 					  (char)(rq->sr_flags & (SNPA_ES|SNPA_IS|SNPA_PERM)),
50937469Ssklower 					  rq->sr_ht);
51036392Ssklower 			break;
51136392Ssklower 
51236392Ssklower 		case SIOCDISOMAP:	/* delete entry */
51336392Ssklower 			snpac_free(sc);
51436392Ssklower 			break;
51536392Ssklower 
51636392Ssklower 		case SIOCGISOMAP:	/* get entry */
51737469Ssklower 			bcopy((caddr_t)&sc->sc_sr, (caddr_t)rq, sizeof(struct snpa_req));
51836392Ssklower 			break;
51936392Ssklower 	}
52036392Ssklower 	return(0);
52136392Ssklower }
52236392Ssklower 
52336392Ssklower /*
52436392Ssklower  * FUNCTION:		iso_tryloopback
52536392Ssklower  *
52636392Ssklower  * PURPOSE:			Attempt to use the software loopback interface for pkt
52736392Ssklower  *
52836392Ssklower  * RETURNS:			0		if packet was sent successfully
52936392Ssklower  *					errno	if there was a problem sending the packet
53036392Ssklower  *							Ie. the return value of looutput
53136392Ssklower  *					-1 		if software loopback is not appropriate
53236392Ssklower  *
53336392Ssklower  * SIDE EFFECTS:
53436392Ssklower  *
53536392Ssklower  * NOTES:
53636392Ssklower  */
53737469Ssklower iso_tryloopback(m, dest)
53836392Ssklower struct mbuf			*m;		/* pkt */
53937469Ssklower struct sockaddr_iso *dest;	/* destination */
54036392Ssklower {
54136392Ssklower 	struct iso_addr			*destiso;	/* destination iso addr */
54236392Ssklower 
54337469Ssklower  	destiso = &dest->siso_addr;
54436392Ssklower 
54536392Ssklower 	if (clnp_ours(destiso)) {
54636392Ssklower 		IFDEBUG(D_SNPA)
54736392Ssklower 			printf("iso_tryloopback: local destination\n");
54836392Ssklower 		ENDDEBUG
54936392Ssklower 		if (loif.if_flags & IFF_UP) {
55036392Ssklower 			IFDEBUG(D_SNPA)
55136392Ssklower 				printf("iso_tryloopback: calling looutput\n");
55236392Ssklower 			ENDDEBUG
55337469Ssklower 			return (looutput(&loif, m, (struct sockaddr *)dest));
55436392Ssklower 		}
55536392Ssklower 	}
55636392Ssklower 	return (-1);
55736392Ssklower }
55836392Ssklower 
55936392Ssklower /*
56036392Ssklower  * FUNCTION:		snpac_systype
56136392Ssklower  *
56236392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
56336392Ssklower  *
56436392Ssklower  * RETURNS:			0 on success, or unix error code
56536392Ssklower  *
56636392Ssklower  * SIDE EFFECTS:
56736392Ssklower  *
56836392Ssklower  * NOTES:
56936392Ssklower  */
57036392Ssklower snpac_systype (cmd, data)
57136392Ssklower int		cmd;	/* ioctl to process */
57236392Ssklower caddr_t	data;	/* data for the cmd */
57336392Ssklower {
57436392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
57536392Ssklower 	extern short	esis_holding_time, esis_config_time;
57636392Ssklower 
57736392Ssklower 	IFDEBUG (D_IOCTL)
57836392Ssklower 		if (cmd == SIOCSSTYPE)
57936392Ssklower 			printf("snpac_systype: cmd set, type x%x, ht %d, ct %d\n",
58036392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
58136392Ssklower 		else
58236392Ssklower 			printf("snpac_systype: cmd get\n");
58336392Ssklower 	ENDDEBUG
58436392Ssklower 
58536392Ssklower 	if (cmd == SIOCSSTYPE) {
58637551Smckusick 		if (suser(u.u_cred, &u.u_acflag))
58736392Ssklower 			return(EACCES);
58836392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
58936392Ssklower 			return(EINVAL);
59036392Ssklower 		if (rq->sr_type & SNPA_ES) {
59136392Ssklower 			iso_systype = SNPA_ES;
59236392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
59336392Ssklower 			iso_systype = SNPA_IS;
59436392Ssklower 		} else {
59536392Ssklower 			return(EINVAL);
59636392Ssklower 		}
59736392Ssklower 		esis_holding_time = rq->sr_holdt;
59836392Ssklower 		esis_config_time = rq->sr_configt;
59936392Ssklower 	} else if (cmd == SIOCGSTYPE) {
60036392Ssklower 		rq->sr_type = iso_systype;
60136392Ssklower 		rq->sr_holdt = esis_holding_time;
60236392Ssklower 		rq->sr_configt = esis_config_time;
60336392Ssklower 	} else {
60436392Ssklower 		return(EINVAL);
60536392Ssklower 	}
60636392Ssklower 	return(0);
60736392Ssklower }
60836392Ssklower 
60936392Ssklower /*
61036392Ssklower  * FUNCTION:		snpac_logdefis
61136392Ssklower  *
61236392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
61336392Ssklower  *
61436392Ssklower  * RETURNS:			nothing
61536392Ssklower  *
61636392Ssklower  * SIDE EFFECTS:
61736392Ssklower  *
61836392Ssklower  * NOTES:
61936392Ssklower  */
62036392Ssklower snpac_logdefis(sc)
62137469Ssklower register struct snpa_cache	*sc;
62236392Ssklower {
62337469Ssklower 	register struct iso_addr *r;
62437469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
62537469Ssklower 	if (known_is == 0)
62637469Ssklower 		known_is = sc;
62737469Ssklower 	if (known_is != sc) {
62837469Ssklower 		if (known_is->sc_rt) {
62937469Ssklower 			rtfree(known_is->sc_rt);
63037469Ssklower 			known_is->sc_rt = 0;
63137469Ssklower 		}
63237469Ssklower 		known_is = sc;
63336392Ssklower 	}
63437469Ssklower 	if (rt == 0) {
63537469Ssklower 		zap_isoaddr(dst, &(sc->sc_nsap));
63637469Ssklower 		rtrequest(RTM_ADD, S(zsi), S(dst), S(zmk),
63737469Ssklower 						RTF_DYNAMIC|RTF_GATEWAY, &sc->sc_rt);
63837469Ssklower 		return;
63937469Ssklower 	}
64037469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
64137469Ssklower 		((struct sockaddr_iso *)rt->rt_gateway)->siso_addr = sc->sc_nsap;
64237469Ssklower 		known_is = sc;
64337469Ssklower 		sc->sc_rt = rt;
64437469Ssklower 	}
64536392Ssklower }
64636392Ssklower 
64736392Ssklower /*
64836392Ssklower  * FUNCTION:		snpac_age
64936392Ssklower  *
65036392Ssklower  * PURPOSE:			Time out snpac entries
65136392Ssklower  *
65236392Ssklower  * RETURNS:
65336392Ssklower  *
65436392Ssklower  * SIDE EFFECTS:
65536392Ssklower  *
65636392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
65736392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
65836392Ssklower  *					if the entry is added a moment before snpac_age is
65936392Ssklower  *					called, the entry will immediately have SNPAC_AGE
66036392Ssklower  *					seconds taken off the holding time, even though
66136392Ssklower  *					it has only been held a brief moment.
66236392Ssklower  *
66336392Ssklower  *					The proper way to do this is set an expiry timeval
66436392Ssklower  *					equal to current time + holding time. Then snpac_age
66536392Ssklower  *					would time out entries where expiry date is older
66636392Ssklower  *					than the current time.
66736392Ssklower  */
66836392Ssklower snpac_age()
66936392Ssklower {
67036392Ssklower 	register struct snpa_cache	*sc;
67136392Ssklower 	register int 				i;
67236392Ssklower 
67336392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
67436392Ssklower 
67536392Ssklower 	sc = &iso_snpac[0];
67636392Ssklower 	for (i=0; i<SNPAC_SIZE; i++, sc++) {
67736392Ssklower 		if (((sc->sc_flags & SNPA_PERM) == 0) && (sc->sc_flags & SNPA_VALID)) {
67836392Ssklower 			sc->sc_ht -= SNPAC_AGE;
67936392Ssklower 			if (sc->sc_ht > 0)
68036392Ssklower 				continue;
68136392Ssklower 			else
68236392Ssklower 				snpac_free(sc);
68336392Ssklower 		}
68436392Ssklower 	}
68536392Ssklower }
68636392Ssklower 
68736392Ssklower /*
68836392Ssklower  * FUNCTION:		snpac_ownmulti
68936392Ssklower  *
69036392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
69136392Ssklower  *					of the same type as the system.
69236392Ssklower  *
69336392Ssklower  * RETURNS:			true or false
69436392Ssklower  *
69536392Ssklower  * SIDE EFFECTS:
69636392Ssklower  *
69736392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
69836392Ssklower  *					as interm kludge until
69936392Ssklower  *					real multicast addresses can be configured
70036392Ssklower  */
70136392Ssklower snpac_ownmulti(snpa, len)
70236392Ssklower char	*snpa;
70336392Ssklower int		len;
70436392Ssklower {
70537469Ssklower 	return (((iso_systype & SNPA_ES) &&
70637469Ssklower 			 (!bcmp((caddr_t)snpa, (caddr_t)all_es.sc_snpa, (unsigned)len))) ||
70737469Ssklower 			((iso_systype & SNPA_IS) &&
70837469Ssklower 			 (!bcmp((caddr_t)snpa, (caddr_t)all_is.sc_snpa, (unsigned)len))));
70936392Ssklower }
71036392Ssklower 
71136392Ssklower /*
71236392Ssklower  * FUNCTION:		snpac_flushifp
71336392Ssklower  *
71436392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
71536392Ssklower  *
71636392Ssklower  * RETURNS:			nothing
71736392Ssklower  *
71836392Ssklower  * SIDE EFFECTS:
71936392Ssklower  *
72036392Ssklower  * NOTES:
72136392Ssklower  */
72236392Ssklower snpac_flushifp(ifp)
72336392Ssklower struct ifnet	*ifp;
72436392Ssklower {
72536392Ssklower 	register struct snpa_cache	*sc;
72636392Ssklower 	register int 				i;
72736392Ssklower 
72836392Ssklower 	sc = &iso_snpac[0];
72936392Ssklower 	for (i=0; i<SNPAC_SIZE; i++, sc++) {
73036392Ssklower 		if ((sc->sc_ifp == ifp) && (sc->sc_flags & SNPA_VALID)) {
73136392Ssklower 			snpac_free(sc);
73236392Ssklower 		}
73336392Ssklower 	}
73436392Ssklower }
73536392Ssklower 
73636392Ssklower /*
73736392Ssklower  * FUNCTION:		snpac_rtrequest
73836392Ssklower  *
73936392Ssklower  * PURPOSE:			Make a routing request
74036392Ssklower  *
74136392Ssklower  * RETURNS:			nothing
74236392Ssklower  *
74336392Ssklower  * SIDE EFFECTS:
74436392Ssklower  *
74536392Ssklower  * NOTES:			In the future, this should make a request of a user
74636392Ssklower  *					level routing daemon.
74736392Ssklower  */
74837469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
74936392Ssklower int				req;
75037469Ssklower struct iso_addr	*host;
75136392Ssklower struct iso_addr	*gateway;
75237469Ssklower struct iso_addr	*netmask;
75336392Ssklower short			flags;
75437469Ssklower struct rtentry	**ret_nrt;
75536392Ssklower {
75637469Ssklower 	register struct iso_addr *r;
75736392Ssklower 
75836392Ssklower 	IFDEBUG(D_SNPA)
75936392Ssklower 		printf("snpac_rtrequest: ");
76037469Ssklower 		if (req == RTM_ADD)
76136392Ssklower 			printf("add");
76237469Ssklower 		else if (req == RTM_DELETE)
76336392Ssklower 			printf("delete");
76436392Ssklower 		else
76536392Ssklower 			printf("unknown command");
76637469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
76736392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
76836392Ssklower 	ENDDEBUG
76936392Ssklower 
77036392Ssklower 
77137469Ssklower 	zap_isoaddr(dst, host);
77237469Ssklower 	zap_isoaddr(gte, gateway);
77337469Ssklower 	zap_isoaddr(msk, netmask);
77437469Ssklower 
77537469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
77637469Ssklower 		flags, ret_nrt);
77736392Ssklower }
77836392Ssklower 
77936392Ssklower /*
78036392Ssklower  * FUNCTION:		snpac_addrt
78136392Ssklower  *
78236392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
78336392Ssklower  *
78436392Ssklower  * RETURNS:			nothing
78536392Ssklower  *
78636392Ssklower  * SIDE EFFECTS:
78736392Ssklower  *
78836392Ssklower  * NOTES:			If a cache entry exists for gateway, then
78936392Ssklower  *					make a routing entry (host, gateway) and associate
79036392Ssklower  *					with gateway.
79136392Ssklower  *
79236392Ssklower  *					If a route already exists and is different, first delete
79336392Ssklower  *					it.
79436392Ssklower  *
79536392Ssklower  *					This could be made more efficient by checking
79636392Ssklower  *					the existing route before adding a new one.
79736392Ssklower  */
798*39950Ssklower snpac_addrt(ifp, host, gateway, netmask)
799*39950Ssklower struct ifnet *ifp;
800*39950Ssklower struct iso_addr	*host, *gateway, *netmask;
80136392Ssklower {
80237469Ssklower 	register struct snpa_cache	*sc;
80337469Ssklower 	register struct iso_addr *r;
80436392Ssklower 
80536392Ssklower 	SNPAC_LOOK(sc, gateway);
80636392Ssklower 	if (sc != NULL) {
80737469Ssklower 		bcopy((caddr_t)host, (caddr_t)&sc->sc_da, sizeof(struct iso_addr));
80837469Ssklower 		zap_isoaddr(dst, host);
80937469Ssklower 		zap_isoaddr(gte, gateway);
81037469Ssklower 		zap_isoaddr(msk, netmask);
81137469Ssklower 		if (netmask) {
812*39950Ssklower 			rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), &sc->sc_rt);
81337469Ssklower 		} else
81437469Ssklower 			rtredirect(S(dst), S(gte), (struct sockaddr *)0,
815*39950Ssklower 									RTF_DONE | RTF_HOST, S(gte), &sc->sc_rt);
81636392Ssklower 	}
81736392Ssklower }
81836392Ssklower #endif	ISO
819