xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 37469)
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 $ */
2936392Ssklower 
3036392Ssklower #ifndef lint
3136392Ssklower static char *rcsid = "$Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $";
3236392Ssklower #endif lint
3336392Ssklower 
3436392Ssklower #ifdef ISO
3536392Ssklower 
36*37469Ssklower #include "types.h"
37*37469Ssklower #include "param.h"
38*37469Ssklower #include "mbuf.h"
39*37469Ssklower #include "domain.h"
40*37469Ssklower #include "protosw.h"
41*37469Ssklower #include "socket.h"
42*37469Ssklower #include "socketvar.h"
43*37469Ssklower #include "errno.h"
44*37469Ssklower #include "ioctl.h"
45*37469Ssklower #include "time.h"
46*37469Ssklower #include "kernel.h"
4736392Ssklower 
4836392Ssklower #include "../net/if.h"
4936392Ssklower #include "../net/route.h"
5036392Ssklower 
51*37469Ssklower #include "iso.h"
52*37469Ssklower #include "iso_var.h"
53*37469Ssklower #include "iso_snpac.h"
54*37469Ssklower #include "clnp.h"
55*37469Ssklower #include "clnp_stat.h"
56*37469Ssklower #include "argo_debug.h"
57*37469Ssklower #include "esis.h"
5836392Ssklower 
5936392Ssklower #define	SNPAC_BSIZ	20		/* bucket size */
6036392Ssklower #define	SNPAC_NB	13		/* number of buckets */
6136392Ssklower #define	SNPAC_SIZE	(SNPAC_BSIZ * SNPAC_NB)
6236392Ssklower struct	snpa_cache	iso_snpac[SNPAC_SIZE];
63*37469Ssklower u_int				iso_snpac_size = SNPAC_SIZE;/* for iso_map command */
6436392Ssklower int 				iso_systype = SNPA_ES;	/* default to be an ES */
6536392Ssklower 
66*37469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
67*37469Ssklower extern u_long iso_hashchar();
68*37469Ssklower static struct sockaddr_iso
69*37469Ssklower 	dst	= {sizeof(dst), AF_ISO},
70*37469Ssklower 	gte	= {sizeof(dst), AF_ISO},
71*37469Ssklower 	src	= {sizeof(dst), AF_ISO},
72*37469Ssklower 	msk	= {sizeof(dst), AF_ISO},
73*37469Ssklower 	zmk = {1};
74*37469Ssklower #define zsi blank_siso
75*37469Ssklower #define zero_isoa	zsi.siso_addr
76*37469Ssklower #define zap_isoaddr(a, b) (bzero((caddr_t)&a.siso_addr, sizeof(*r)), \
77*37469Ssklower 	   ((r = b) && bcopy((caddr_t)r, (caddr_t)&a.siso_addr, 1 + (r)->isoa_len)))
78*37469Ssklower #define S(x) ((struct sockaddr *)&(x))
79*37469Ssklower 
8036392Ssklower #define	SNPAC_HASH(addr) \
81*37469Ssklower 	(((u_long) iso_hashchar((caddr_t)addr, (int)addr->isoa_len)) % SNPAC_NB)
8236392Ssklower 
8336392Ssklower #define	SNPAC_LOOK(sc,addr) { \
8436392Ssklower 	register n; \
8536392Ssklower 	sc = &iso_snpac[SNPAC_HASH(addr) * SNPAC_BSIZ]; \
8636392Ssklower 	for (n = 0 ; n < SNPAC_BSIZ ; n++,sc++) \
8736392Ssklower 		if ((sc->sc_flags & SNPA_VALID) && \
8836392Ssklower 			(iso_addrmatch1(&sc->sc_nsap, addr))) \
8936392Ssklower 			break; \
9036392Ssklower 	if (n >= SNPAC_BSIZ) \
9136392Ssklower 		sc = 0; \
9236392Ssklower }
9336392Ssklower 
9436392Ssklower struct snpa_cache	*snpac_new();
9536392Ssklower 
9636392Ssklower /*
9736392Ssklower  *	We only keep track of a single IS at a time.
9836392Ssklower  */
9936392Ssklower struct snpa_cache	*known_is;
10036392Ssklower 
10136392Ssklower /*
10236392Ssklower  *	Addresses taken from NBS agreements, December 1987.
10336392Ssklower  *
10436392Ssklower  *	These addresses assume on-the-wire transmission of least significant
10536392Ssklower  *	bit first. This is the method used by 802.3. When these
10636392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
10736392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
10836392Ssklower  *
10936392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
11036392Ssklower  *	true token ring multicast addresses. More work is necessary
11136392Ssklower  *	to get multicast to work right on token ring.
11236392Ssklower  *
11336392Ssklower  *	Currently, the token ring driver does not handle multicast, so
11436392Ssklower  *	these addresses are converted into the broadcast address in
11536392Ssklower  *	lan_output() That means that if these multicast addresses change
11636392Ssklower  *	the token ring driver must be altered.
11736392Ssklower  */
11836392Ssklower struct snpa_cache	all_es = {
11936392Ssklower 	{ { 0x0 },							/* sc_nsap */
12036392Ssklower 	6,									/* sc_len */
12136392Ssklower 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }, /* sc_snpa */
12236392Ssklower 	SNPA_VALID,							/* sc_flags */
12336392Ssklower 	0	}								/* sc_ht */
12436392Ssklower };
12536392Ssklower struct snpa_cache	all_is = {
12636392Ssklower 	{ { 0x0 },							/* sc_nsap */
12736392Ssklower 	6,									/* sc_len */
12836392Ssklower 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }, /* sc_snpa */
12936392Ssklower 	SNPA_VALID,							/* sc_flags */
13036392Ssklower 	0	}								/* sc_ht */
13136392Ssklower };
13236392Ssklower 
13336392Ssklower 
13436392Ssklower /*
13536392Ssklower  * FUNCTION:		iso_snparesolve
13636392Ssklower  *
13736392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
13836392Ssklower  *
13936392Ssklower  * RETURNS:			0 if addr is resolved
14036392Ssklower  *					errno if addr is unknown
14136392Ssklower  *
14236392Ssklower  * SIDE EFFECTS:
14336392Ssklower  *
14436392Ssklower  * NOTES:			If an entry is found that matches the address, that
14536392Ssklower  *					snpa is returned. If no entry is found, but an IS is
14636392Ssklower  *					known, then the address of the IS is returned. If
14736392Ssklower  *					neither an address is found that matches or an IS is
14836392Ssklower  *					known, then the multi-cast address for "all ES" for
14936392Ssklower  *					this interface is returned.
15036392Ssklower  *
15136392Ssklower  *					NB: the last case described above constitutes the
15236392Ssklower  *					query configuration function 9542, sec 6.5
15336392Ssklower  *					A mechanism is needed to prevent this function from
15436392Ssklower  *					being invoked if the system is an IS.
15536392Ssklower  */
156*37469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
15736392Ssklower struct ifnet 		*ifp;	/* outgoing interface */
158*37469Ssklower struct sockaddr_iso *dest;	/* destination */
15936392Ssklower char				*snpa;	/* RESULT: snpa to be used */
16036392Ssklower int					*snpa_len;	/* RESULT: length of snpa */
16136392Ssklower {
16236392Ssklower 	extern struct ifnet 	loif;		/* loopback interface */
16336392Ssklower 	struct snpa_cache		*sc;		/* ptr to snpa table entry */
16436392Ssklower 	struct iso_addr			*destiso;	/* destination iso addr */
16536392Ssklower 
166*37469Ssklower  	destiso = &dest->siso_addr;
16736392Ssklower 
16836392Ssklower 	/*
16936392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
17036392Ssklower 	 *	addresss embedded in the destination nsap address
17136392Ssklower 	 */
172*37469Ssklower 	if (destiso->isoa_genaddr[0] == AFI_SNA) {
17336392Ssklower 		/*
17436392Ssklower 		 *	This is a subnetwork address. Return it immediately
17536392Ssklower 		 */
17636392Ssklower 		IFDEBUG(D_SNPA)
17736392Ssklower 			printf("iso_snparesolve: return SN address\n");
17836392Ssklower 		ENDDEBUG
17936392Ssklower 
18036392Ssklower 		*snpa_len = destiso->isoa_len - 1;	/* subtract size of AFI */
181*37469Ssklower 		bcopy((caddr_t) destiso->isoa_genaddr + 1, (caddr_t)snpa,
182*37469Ssklower 			  (unsigned)*snpa_len);
18336392Ssklower 		return (0);
18436392Ssklower 	}
18536392Ssklower 
18636392Ssklower 	IFDEBUG(D_SNPA)
18736392Ssklower 		printf("iso_snparesolve: resolving %s\n", clnp_iso_addrp(destiso));
18836392Ssklower 	ENDDEBUG
18936392Ssklower 
19036392Ssklower 	/*
19136392Ssklower 	 *	packet is not for us, check cache for an entry
19236392Ssklower 	 */
19336392Ssklower 	SNPAC_LOOK(sc, destiso);
19436392Ssklower 	if (sc == 0) {			/* not found */
19536392Ssklower 		/* If we are an IS, we can't do much with the packet */
19636392Ssklower 		if (iso_systype == SNPA_IS)
19736392Ssklower 			goto bad;
19836392Ssklower 
19936392Ssklower 		/*
20036392Ssklower 		 *	Check if we know about an IS
20136392Ssklower 		 */
20236392Ssklower 		if ((known_is) && (known_is->sc_flags & SNPA_VALID)) {
20336392Ssklower 			sc = known_is;
20436392Ssklower 		} else if (ifp->if_flags & IFF_BROADCAST) {
20536392Ssklower 			/*
20636392Ssklower 			 *	no IS, no match. Return "all es" multicast address for this
20736392Ssklower 			 *	interface, as per Query Configuration Function (9542 sec 6.5)
20836392Ssklower 			 *
20936392Ssklower 			 *	Note: there is a potential problem here. If the destination
21036392Ssklower 			 *	is on the subnet and it does not respond with a ESH, but
21136392Ssklower 			 *	does send back a TP CC, a connection could be established
21236392Ssklower 			 *	where we always transmit the CLNP packet to "all es"
21336392Ssklower 			 */
21436392Ssklower 			sc = &all_es;
21536392Ssklower 		} else {
21636392Ssklower 			goto bad;
21736392Ssklower 		}
21836392Ssklower 	}
21936392Ssklower 
22036392Ssklower 	bcopy((caddr_t)sc->sc_snpa, (caddr_t)snpa, sc->sc_len);
22136392Ssklower 	*snpa_len = sc->sc_len;
22236392Ssklower 	return (0);
22336392Ssklower 
22436392Ssklower bad:
22536392Ssklower 	return(ENETUNREACH);
22636392Ssklower }
22736392Ssklower 
22836392Ssklower 
22936392Ssklower /*
23036392Ssklower  * FUNCTION:		snpac_look
23136392Ssklower  *
23236392Ssklower  * PURPOSE:			Look up an entry in the snpa cache
23336392Ssklower  *
23436392Ssklower  * RETURNS:			Pointer to snpa_cache structure, or null
23536392Ssklower  *
23636392Ssklower  * SIDE EFFECTS:
23736392Ssklower  *
23836392Ssklower  * NOTES:			This is simply SNPAC_LOOK as a procedure.
23936392Ssklower  */
24036392Ssklower struct snpa_cache *
24136392Ssklower snpac_look(isoa)
24236392Ssklower struct iso_addr *isoa;	/* destination nsap */
24336392Ssklower {
24436392Ssklower 	struct snpa_cache	*sc;
24536392Ssklower 	int 				s = splimp();
24636392Ssklower 
24736392Ssklower 	SNPAC_LOOK(sc, isoa);
24836392Ssklower 
24936392Ssklower 	splx(s);
25036392Ssklower 	return(sc);
25136392Ssklower }
25236392Ssklower 
25336392Ssklower /*
25436392Ssklower  * FUNCTION:		iso_8208snparesolve
25536392Ssklower  *
25636392Ssklower  * PURPOSE:			Find the X.121 address that corresponds to an NSAP addr
25736392Ssklower  *
25836392Ssklower  * RETURNS:			0 or unix errno
25936392Ssklower  *
26036392Ssklower  * SIDE EFFECTS:
26136392Ssklower  *
26236392Ssklower  * NOTES:			This ought to invoke the 8208 ES-IS function
26336392Ssklower  */
264*37469Ssklower iso_8208snparesolve(dest, snpa, snpa_len)
265*37469Ssklower struct sockaddr_iso *dest;	/* destination */
26636392Ssklower char				*snpa;	/* RESULT: snpa to be used */
26736392Ssklower int					*snpa_len;	/* RESULT: length of snpa */
26836392Ssklower {
26936392Ssklower 	struct snpa_cache		*sc;		/* ptr to snpa table entry */
27036392Ssklower 	struct iso_addr			*destiso;	/* destination iso addr */
27136392Ssklower 	int						s;
27236392Ssklower 	int						err = 0;
27336392Ssklower 
274*37469Ssklower  	destiso = &dest->siso_addr;
27536392Ssklower 
27636392Ssklower 	s = splimp();
27736392Ssklower 	SNPAC_LOOK(sc, destiso);
27836392Ssklower 	if (sc) {
27936392Ssklower 		bcopy((caddr_t)sc->sc_snpa, (caddr_t)snpa, sc->sc_len);
28036392Ssklower 		*snpa_len = sc->sc_len;
28136392Ssklower 	} else {
28236392Ssklower 		err = ENETUNREACH;
28336392Ssklower 	}
28436392Ssklower 	splx(s);
28536392Ssklower 	return (err);
28636392Ssklower }
28736392Ssklower 
28836392Ssklower /*
28936392Ssklower  * FUNCTION:		iso_8208snpaadd
29036392Ssklower  *
29136392Ssklower  * PURPOSE:			Add an entry to the snpa cache
29236392Ssklower  *
29336392Ssklower  * RETURNS:
29436392Ssklower  *
29536392Ssklower  * SIDE EFFECTS:
29636392Ssklower  *
29736392Ssklower  * NOTES:			used by cons
29836392Ssklower  */
29936392Ssklower iso_8208snpaadd(ifp, nsap, snpa, snpalen, ht)
30036392Ssklower struct ifnet		*ifp;		/* interface info is related to */
30136392Ssklower struct iso_addr		*nsap;		/* nsap to add */
30236392Ssklower caddr_t				snpa;		/* translation */
30336392Ssklower int					snpalen;	/* length in bytes */
30436392Ssklower short				ht;			/* holding time (in seconds) */
30536392Ssklower {
306*37469Ssklower 	snpac_add(ifp, nsap, snpa, snpalen, SNPA_ES, (u_short)ht);
30736392Ssklower }
30836392Ssklower 
30936392Ssklower /*
31036392Ssklower  * FUNCTION:		iso_8208snpadelete
31136392Ssklower  *
31236392Ssklower  * PURPOSE:			Delete an entry from the snpa cache
31336392Ssklower  *
31436392Ssklower  * RETURNS:			nothing
31536392Ssklower  *
31636392Ssklower  * SIDE EFFECTS:
31736392Ssklower  *
31836392Ssklower  * NOTES:			used by CONS
31936392Ssklower  */
32036392Ssklower iso_8208snpadelete(nsap)
32136392Ssklower struct iso_addr	*nsap;
32236392Ssklower {
32336392Ssklower 	struct snpa_cache	*sc = snpac_look(nsap);
32436392Ssklower 
32536392Ssklower 	if (sc != NULL)
32636392Ssklower 		snpac_free(sc);
32736392Ssklower }
32836392Ssklower 
32936392Ssklower /*
33036392Ssklower  * FUNCTION:		snpac_new
33136392Ssklower  *
33236392Ssklower  * PURPOSE:			create a new entry in the iso address to ethernet
33336392Ssklower  *					address table
33436392Ssklower  *
33536392Ssklower  * RETURNS:			pointer to newest entry
33636392Ssklower  *
33736392Ssklower  * SIDE EFFECTS:	times out old entries if no new entries are found
33836392Ssklower  *
33936392Ssklower  * NOTES:			If the bucket is full, then timeout the oldest entry
34036392Ssklower  *					(ie. the one with the youngest holding time)
34136392Ssklower  */
34236392Ssklower struct snpa_cache *
34336392Ssklower snpac_new(isoa)
34436392Ssklower struct iso_addr *isoa;		/* iso address to enter into table */
34536392Ssklower {
34636392Ssklower 	register struct snpa_cache	*sc;
34736392Ssklower 	register int 				n;
34836392Ssklower 	int							smallest_ht = 1000000;
34936392Ssklower 	struct snpa_cache			*maybe;
35036392Ssklower 
35136392Ssklower 	sc = &iso_snpac[SNPAC_HASH(isoa) * SNPAC_BSIZ];
35236392Ssklower 	for (n = 0 ; n < SNPAC_BSIZ ; n++,sc++) {
35336392Ssklower 
35436392Ssklower 		IFDEBUG (D_IOCTL)
35536392Ssklower 			printf("snpac_new: sc x%x ", sc);
35636392Ssklower 
35736392Ssklower 			if (sc->sc_flags & SNPA_VALID) {
35836392Ssklower 				int i;
35936392Ssklower 
36036392Ssklower 				printf("(valid) %s ", clnp_iso_addrp(&sc->sc_nsap));
36136392Ssklower 				for (i=0; i<sc->sc_len; i++)
36236392Ssklower 					printf("%x%c", sc->sc_snpa[i], i < (sc->sc_len-1) ? ':'
36336392Ssklower 						: '\n');
36436392Ssklower 			} else {
36536392Ssklower 				printf("invalid\n");
36636392Ssklower 			}
36736392Ssklower 		ENDDEBUG
36836392Ssklower 
36936392Ssklower 		if (sc->sc_flags & SNPA_VALID) {
37036392Ssklower 			if (sc->sc_ht < smallest_ht) {
37136392Ssklower 				smallest_ht = sc->sc_ht;
37236392Ssklower 				maybe = sc;
37336392Ssklower 			}
37436392Ssklower 		} else {
37536392Ssklower 			return sc; /* found unused slot */
37636392Ssklower 		}
37736392Ssklower 	}
37836392Ssklower 	snpac_free(maybe);
37936392Ssklower 	return maybe;
38036392Ssklower }
38136392Ssklower /*
38236392Ssklower  * FUNCTION:		snpac_free
38336392Ssklower  *
38436392Ssklower  * PURPOSE:			free an entry in the iso address map table
38536392Ssklower  *
38636392Ssklower  * RETURNS:			nothing
38736392Ssklower  *
38836392Ssklower  * SIDE EFFECTS:
38936392Ssklower  *
39036392Ssklower  * NOTES:			If there is a route entry associated with cache
39136392Ssklower  *					entry, then delete that as well
39236392Ssklower  */
39336392Ssklower snpac_free(sc)
39436392Ssklower register struct snpa_cache *sc;		/* entry to free */
39536392Ssklower {
396*37469Ssklower 	register struct rtentry *rt;
397*37469Ssklower 	register struct iso_addr *r;
39836392Ssklower 
39936392Ssklower 	if (known_is == sc) {
40036392Ssklower 		known_is = NULL;
40136392Ssklower 	}
402*37469Ssklower 	if (sc->sc_rt) {
403*37469Ssklower 		zap_isoaddr(dst, (&(sc->sc_da)));
404*37469Ssklower 		rt = rtalloc1((struct sockaddr *)&dst, 0);
405*37469Ssklower 		if ((sc->sc_rt == rt) && (rt->rt_flags & RTF_UP)
406*37469Ssklower 			&& (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
407*37469Ssklower 			RTFREE(rt);
408*37469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
409*37469Ssklower 						rt->rt_flags, (struct rtentry **)0);
410*37469Ssklower 		}
411*37469Ssklower 		RTFREE(rt);
41236392Ssklower 	}
41336392Ssklower 	bzero((caddr_t)sc, sizeof(struct snpa_cache));
41436392Ssklower }
41536392Ssklower 
41636392Ssklower /*
41736392Ssklower  * FUNCTION:		snpac_add
41836392Ssklower  *
41936392Ssklower  * PURPOSE:			Add an entry to the snpa cache
42036392Ssklower  *
42136392Ssklower  * RETURNS:
42236392Ssklower  *
42336392Ssklower  * SIDE EFFECTS:
42436392Ssklower  *
42536392Ssklower  * NOTES:			If entry already exists, then update holding time.
42636392Ssklower  */
42736392Ssklower snpac_add(ifp, nsap, snpa, snpalen, type, ht)
42836392Ssklower struct ifnet		*ifp;		/* interface info is related to */
42936392Ssklower struct iso_addr		*nsap;		/* nsap to add */
43036392Ssklower caddr_t				snpa;		/* translation */
431*37469Ssklower int					snpalen;	/* translation length */
43236392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
433*37469Ssklower u_short				ht;			/* holding time (in seconds) */
43436392Ssklower {
43536392Ssklower 	struct snpa_cache	*sc;
43636392Ssklower 
43736392Ssklower 	SNPAC_LOOK(sc, nsap);
43836392Ssklower 	if (sc == NULL) {
43936392Ssklower 		sc = snpac_new(nsap);
44036392Ssklower 		sc->sc_nsap = *nsap;
44136392Ssklower 	}
44236392Ssklower 
44336392Ssklower 	sc->sc_ht = ht;
44436392Ssklower 
44536392Ssklower 	sc->sc_len = min(snpalen, MAX_SNPALEN);
446*37469Ssklower 	bcopy(snpa, (caddr_t)sc->sc_snpa, sc->sc_len);
44736392Ssklower 	sc->sc_flags = SNPA_VALID | type;
44836392Ssklower 	sc->sc_ifp = ifp;
44936392Ssklower 
45036392Ssklower 	if (type & SNPA_IS)
45136392Ssklower 		snpac_logdefis(sc);
45236392Ssklower }
45336392Ssklower 
45436392Ssklower /*
45536392Ssklower  * FUNCTION:		snpac_ioctl
45636392Ssklower  *
45736392Ssklower  * PURPOSE:			handle ioctls to change the iso address map
45836392Ssklower  *
45936392Ssklower  * RETURNS:			unix error code
46036392Ssklower  *
46136392Ssklower  * SIDE EFFECTS:	changes the snpa_cache table declared above.
46236392Ssklower  *
46336392Ssklower  * NOTES:
46436392Ssklower  */
46536392Ssklower snpac_ioctl(cmd, data)
46636392Ssklower int		cmd;		/* ioctl to process */
46736392Ssklower caddr_t	data;	/* data for the cmd */
46836392Ssklower {
46936392Ssklower 	register struct snpa_req	*rq = (struct snpa_req *)data;
47036392Ssklower 	register struct snpa_cache	*sc;
47136392Ssklower 	register struct iso_addr	*isoa;
47236392Ssklower 	int							s;
473*37469Ssklower 	char						*type;
47436392Ssklower 
475*37469Ssklower 	switch(cmd) {
476*37469Ssklower 		case SIOCSISOMAP: type = "set"; break;
477*37469Ssklower 		case SIOCDISOMAP: type = "delete"; break;
478*37469Ssklower 		case SIOCGISOMAP: type = "get"; break;
479*37469Ssklower 		default: return(snpac_systype(cmd, data));
480*37469Ssklower 	}
48136392Ssklower 
48236392Ssklower 	/* sanity check */
48336392Ssklower 	if (rq->sr_len > MAX_SNPALEN)
48436392Ssklower 		return(EINVAL);
48536392Ssklower 
48636392Ssklower 	IFDEBUG (D_IOCTL)
48736392Ssklower 		int i;
48836392Ssklower 
489*37469Ssklower 		printf("snpac_ioctl: %s %s to ", type, clnp_iso_addrp(isoa));
49036392Ssklower 		for (i=0; i<rq->sr_len; i++)
49136392Ssklower 			printf("%x%c", rq->sr_snpa[i], i < (rq->sr_len-1) ? ':' : '\n');
49236392Ssklower 	ENDDEBUG
49336392Ssklower 
494*37469Ssklower 	/* look up this address in table */
495*37469Ssklower 	isoa = &rq->sr_isoa;
496*37469Ssklower 
49736392Ssklower 	SNPAC_LOOK(sc, isoa);
49836392Ssklower 	if (sc == NULL) {	 /* not found */
49936392Ssklower 		if (cmd != SIOCSISOMAP)
50036392Ssklower 			return(ENXIO);
50136392Ssklower 	}
50236392Ssklower 
50336392Ssklower 	switch(cmd) {
50436392Ssklower 		case SIOCSISOMAP:	/* set entry */
505*37469Ssklower 			snpac_add((struct ifnet *)NULL, isoa, (caddr_t)rq->sr_snpa,
506*37469Ssklower 					  (int)rq->sr_len,
507*37469Ssklower 					  (char)(rq->sr_flags & (SNPA_ES|SNPA_IS|SNPA_PERM)),
508*37469Ssklower 					  rq->sr_ht);
50936392Ssklower 			break;
51036392Ssklower 
51136392Ssklower 		case SIOCDISOMAP:	/* delete entry */
51236392Ssklower 			snpac_free(sc);
51336392Ssklower 			break;
51436392Ssklower 
51536392Ssklower 		case SIOCGISOMAP:	/* get entry */
516*37469Ssklower 			bcopy((caddr_t)&sc->sc_sr, (caddr_t)rq, sizeof(struct snpa_req));
51736392Ssklower 			break;
51836392Ssklower 	}
51936392Ssklower 	return(0);
52036392Ssklower }
52136392Ssklower 
52236392Ssklower /*
52336392Ssklower  * FUNCTION:		iso_tryloopback
52436392Ssklower  *
52536392Ssklower  * PURPOSE:			Attempt to use the software loopback interface for pkt
52636392Ssklower  *
52736392Ssklower  * RETURNS:			0		if packet was sent successfully
52836392Ssklower  *					errno	if there was a problem sending the packet
52936392Ssklower  *							Ie. the return value of looutput
53036392Ssklower  *					-1 		if software loopback is not appropriate
53136392Ssklower  *
53236392Ssklower  * SIDE EFFECTS:
53336392Ssklower  *
53436392Ssklower  * NOTES:
53536392Ssklower  */
536*37469Ssklower iso_tryloopback(m, dest)
53736392Ssklower struct mbuf			*m;		/* pkt */
538*37469Ssklower struct sockaddr_iso *dest;	/* destination */
53936392Ssklower {
54036392Ssklower 	struct iso_addr			*destiso;	/* destination iso addr */
54136392Ssklower 
542*37469Ssklower  	destiso = &dest->siso_addr;
54336392Ssklower 
54436392Ssklower 	if (clnp_ours(destiso)) {
54536392Ssklower 		IFDEBUG(D_SNPA)
54636392Ssklower 			printf("iso_tryloopback: local destination\n");
54736392Ssklower 		ENDDEBUG
54836392Ssklower 		if (loif.if_flags & IFF_UP) {
54936392Ssklower 			IFDEBUG(D_SNPA)
55036392Ssklower 				printf("iso_tryloopback: calling looutput\n");
55136392Ssklower 			ENDDEBUG
552*37469Ssklower 			return (looutput(&loif, m, (struct sockaddr *)dest));
55336392Ssklower 		}
55436392Ssklower 	}
55536392Ssklower 	return (-1);
55636392Ssklower }
55736392Ssklower 
55836392Ssklower /*
55936392Ssklower  * FUNCTION:		snpac_systype
56036392Ssklower  *
56136392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
56236392Ssklower  *
56336392Ssklower  * RETURNS:			0 on success, or unix error code
56436392Ssklower  *
56536392Ssklower  * SIDE EFFECTS:
56636392Ssklower  *
56736392Ssklower  * NOTES:
56836392Ssklower  */
56936392Ssklower snpac_systype (cmd, data)
57036392Ssklower int		cmd;	/* ioctl to process */
57136392Ssklower caddr_t	data;	/* data for the cmd */
57236392Ssklower {
57336392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
57436392Ssklower 	extern short	esis_holding_time, esis_config_time;
57536392Ssklower 
57636392Ssklower 	IFDEBUG (D_IOCTL)
57736392Ssklower 		if (cmd == SIOCSSTYPE)
57836392Ssklower 			printf("snpac_systype: cmd set, type x%x, ht %d, ct %d\n",
57936392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
58036392Ssklower 		else
58136392Ssklower 			printf("snpac_systype: cmd get\n");
58236392Ssklower 	ENDDEBUG
58336392Ssklower 
58436392Ssklower 	if (cmd == SIOCSSTYPE) {
58536392Ssklower 		if (!suser())
58636392Ssklower 			return(EACCES);
58736392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
58836392Ssklower 			return(EINVAL);
58936392Ssklower 		if (rq->sr_type & SNPA_ES) {
59036392Ssklower 			iso_systype = SNPA_ES;
59136392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
59236392Ssklower 			iso_systype = SNPA_IS;
59336392Ssklower 		} else {
59436392Ssklower 			return(EINVAL);
59536392Ssklower 		}
59636392Ssklower 		esis_holding_time = rq->sr_holdt;
59736392Ssklower 		esis_config_time = rq->sr_configt;
59836392Ssklower 	} else if (cmd == SIOCGSTYPE) {
59936392Ssklower 		rq->sr_type = iso_systype;
60036392Ssklower 		rq->sr_holdt = esis_holding_time;
60136392Ssklower 		rq->sr_configt = esis_config_time;
60236392Ssklower 	} else {
60336392Ssklower 		return(EINVAL);
60436392Ssklower 	}
60536392Ssklower 	return(0);
60636392Ssklower }
60736392Ssklower 
60836392Ssklower /*
60936392Ssklower  * FUNCTION:		snpac_logdefis
61036392Ssklower  *
61136392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
61236392Ssklower  *
61336392Ssklower  * RETURNS:			nothing
61436392Ssklower  *
61536392Ssklower  * SIDE EFFECTS:
61636392Ssklower  *
61736392Ssklower  * NOTES:
61836392Ssklower  */
61936392Ssklower snpac_logdefis(sc)
620*37469Ssklower register struct snpa_cache	*sc;
62136392Ssklower {
622*37469Ssklower 	register struct iso_addr *r;
623*37469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
624*37469Ssklower 	if (known_is == 0)
625*37469Ssklower 		known_is = sc;
626*37469Ssklower 	if (known_is != sc) {
627*37469Ssklower 		if (known_is->sc_rt) {
628*37469Ssklower 			rtfree(known_is->sc_rt);
629*37469Ssklower 			known_is->sc_rt = 0;
630*37469Ssklower 		}
631*37469Ssklower 		known_is = sc;
63236392Ssklower 	}
633*37469Ssklower 	if (rt == 0) {
634*37469Ssklower 		zap_isoaddr(dst, &(sc->sc_nsap));
635*37469Ssklower 		rtrequest(RTM_ADD, S(zsi), S(dst), S(zmk),
636*37469Ssklower 						RTF_DYNAMIC|RTF_GATEWAY, &sc->sc_rt);
637*37469Ssklower 		return;
638*37469Ssklower 	}
639*37469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
640*37469Ssklower 		((struct sockaddr_iso *)rt->rt_gateway)->siso_addr = sc->sc_nsap;
641*37469Ssklower 		known_is = sc;
642*37469Ssklower 		sc->sc_rt = rt;
643*37469Ssklower 	}
64436392Ssklower }
64536392Ssklower 
64636392Ssklower /*
64736392Ssklower  * FUNCTION:		snpac_age
64836392Ssklower  *
64936392Ssklower  * PURPOSE:			Time out snpac entries
65036392Ssklower  *
65136392Ssklower  * RETURNS:
65236392Ssklower  *
65336392Ssklower  * SIDE EFFECTS:
65436392Ssklower  *
65536392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
65636392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
65736392Ssklower  *					if the entry is added a moment before snpac_age is
65836392Ssklower  *					called, the entry will immediately have SNPAC_AGE
65936392Ssklower  *					seconds taken off the holding time, even though
66036392Ssklower  *					it has only been held a brief moment.
66136392Ssklower  *
66236392Ssklower  *					The proper way to do this is set an expiry timeval
66336392Ssklower  *					equal to current time + holding time. Then snpac_age
66436392Ssklower  *					would time out entries where expiry date is older
66536392Ssklower  *					than the current time.
66636392Ssklower  */
66736392Ssklower snpac_age()
66836392Ssklower {
66936392Ssklower 	register struct snpa_cache	*sc;
67036392Ssklower 	register int 				i;
67136392Ssklower 
67236392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
67336392Ssklower 
67436392Ssklower 	sc = &iso_snpac[0];
67536392Ssklower 	for (i=0; i<SNPAC_SIZE; i++, sc++) {
67636392Ssklower 		if (((sc->sc_flags & SNPA_PERM) == 0) && (sc->sc_flags & SNPA_VALID)) {
67736392Ssklower 			sc->sc_ht -= SNPAC_AGE;
67836392Ssklower 			if (sc->sc_ht > 0)
67936392Ssklower 				continue;
68036392Ssklower 			else
68136392Ssklower 				snpac_free(sc);
68236392Ssklower 		}
68336392Ssklower 	}
68436392Ssklower }
68536392Ssklower 
68636392Ssklower /*
68736392Ssklower  * FUNCTION:		snpac_ownmulti
68836392Ssklower  *
68936392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
69036392Ssklower  *					of the same type as the system.
69136392Ssklower  *
69236392Ssklower  * RETURNS:			true or false
69336392Ssklower  *
69436392Ssklower  * SIDE EFFECTS:
69536392Ssklower  *
69636392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
69736392Ssklower  *					as interm kludge until
69836392Ssklower  *					real multicast addresses can be configured
69936392Ssklower  */
70036392Ssklower snpac_ownmulti(snpa, len)
70136392Ssklower char	*snpa;
70236392Ssklower int		len;
70336392Ssklower {
704*37469Ssklower 	return (((iso_systype & SNPA_ES) &&
705*37469Ssklower 			 (!bcmp((caddr_t)snpa, (caddr_t)all_es.sc_snpa, (unsigned)len))) ||
706*37469Ssklower 			((iso_systype & SNPA_IS) &&
707*37469Ssklower 			 (!bcmp((caddr_t)snpa, (caddr_t)all_is.sc_snpa, (unsigned)len))));
70836392Ssklower }
70936392Ssklower 
71036392Ssklower /*
71136392Ssklower  * FUNCTION:		snpac_flushifp
71236392Ssklower  *
71336392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
71436392Ssklower  *
71536392Ssklower  * RETURNS:			nothing
71636392Ssklower  *
71736392Ssklower  * SIDE EFFECTS:
71836392Ssklower  *
71936392Ssklower  * NOTES:
72036392Ssklower  */
72136392Ssklower snpac_flushifp(ifp)
72236392Ssklower struct ifnet	*ifp;
72336392Ssklower {
72436392Ssklower 	register struct snpa_cache	*sc;
72536392Ssklower 	register int 				i;
72636392Ssklower 
72736392Ssklower 	sc = &iso_snpac[0];
72836392Ssklower 	for (i=0; i<SNPAC_SIZE; i++, sc++) {
72936392Ssklower 		if ((sc->sc_ifp == ifp) && (sc->sc_flags & SNPA_VALID)) {
73036392Ssklower 			snpac_free(sc);
73136392Ssklower 		}
73236392Ssklower 	}
73336392Ssklower }
73436392Ssklower 
73536392Ssklower /*
73636392Ssklower  * FUNCTION:		snpac_rtrequest
73736392Ssklower  *
73836392Ssklower  * PURPOSE:			Make a routing request
73936392Ssklower  *
74036392Ssklower  * RETURNS:			nothing
74136392Ssklower  *
74236392Ssklower  * SIDE EFFECTS:
74336392Ssklower  *
74436392Ssklower  * NOTES:			In the future, this should make a request of a user
74536392Ssklower  *					level routing daemon.
74636392Ssklower  */
747*37469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
74836392Ssklower int				req;
749*37469Ssklower struct iso_addr	*host;
75036392Ssklower struct iso_addr	*gateway;
751*37469Ssklower struct iso_addr	*netmask;
75236392Ssklower short			flags;
753*37469Ssklower struct rtentry	**ret_nrt;
75436392Ssklower {
755*37469Ssklower 	register struct iso_addr *r;
75636392Ssklower 
75736392Ssklower 	IFDEBUG(D_SNPA)
75836392Ssklower 		printf("snpac_rtrequest: ");
759*37469Ssklower 		if (req == RTM_ADD)
76036392Ssklower 			printf("add");
761*37469Ssklower 		else if (req == RTM_DELETE)
76236392Ssklower 			printf("delete");
76336392Ssklower 		else
76436392Ssklower 			printf("unknown command");
765*37469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
76636392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
76736392Ssklower 	ENDDEBUG
76836392Ssklower 
76936392Ssklower 
770*37469Ssklower 	zap_isoaddr(dst, host);
771*37469Ssklower 	zap_isoaddr(gte, gateway);
772*37469Ssklower 	zap_isoaddr(msk, netmask);
773*37469Ssklower 
774*37469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
775*37469Ssklower 		flags, ret_nrt);
77636392Ssklower }
77736392Ssklower 
77836392Ssklower /*
77936392Ssklower  * FUNCTION:		snpac_addrt
78036392Ssklower  *
78136392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
78236392Ssklower  *
78336392Ssklower  * RETURNS:			nothing
78436392Ssklower  *
78536392Ssklower  * SIDE EFFECTS:
78636392Ssklower  *
78736392Ssklower  * NOTES:			If a cache entry exists for gateway, then
78836392Ssklower  *					make a routing entry (host, gateway) and associate
78936392Ssklower  *					with gateway.
79036392Ssklower  *
79136392Ssklower  *					If a route already exists and is different, first delete
79236392Ssklower  *					it.
79336392Ssklower  *
79436392Ssklower  *					This could be made more efficient by checking
79536392Ssklower  *					the existing route before adding a new one.
79636392Ssklower  */
797*37469Ssklower snpac_addrt(host, gateway, source, netmask)
798*37469Ssklower struct iso_addr	*host, *gateway, *source, *netmask;
79936392Ssklower {
800*37469Ssklower 	register struct snpa_cache	*sc;
801*37469Ssklower 	register struct iso_addr *r;
80236392Ssklower 
80336392Ssklower 	SNPAC_LOOK(sc, gateway);
80436392Ssklower 	if (sc != NULL) {
805*37469Ssklower 		bcopy((caddr_t)host, (caddr_t)&sc->sc_da, sizeof(struct iso_addr));
806*37469Ssklower 		zap_isoaddr(dst, host);
807*37469Ssklower 		zap_isoaddr(gte, gateway);
808*37469Ssklower 		zap_isoaddr(src, source);
809*37469Ssklower 		zap_isoaddr(msk, netmask);
810*37469Ssklower 		if (netmask) {
811*37469Ssklower 			rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(src), &sc->sc_rt);
812*37469Ssklower 		} else
813*37469Ssklower 			rtredirect(S(dst), S(gte), (struct sockaddr *)0,
814*37469Ssklower 									RTF_DONE | RTF_HOST, S(src), &sc->sc_rt);
81536392Ssklower 	}
81636392Ssklower }
81736392Ssklower #endif	ISO
818