xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 50230)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*50230Ssklower  *	@(#)iso_snpac.c	7.14 (Berkeley) 06/27/91
849268Sbostic  */
949268Sbostic 
1036392Ssklower /***********************************************************
1136392Ssklower 		Copyright IBM Corporation 1987
1236392Ssklower 
1336392Ssklower                       All Rights Reserved
1436392Ssklower 
1536392Ssklower Permission to use, copy, modify, and distribute this software and its
1636392Ssklower documentation for any purpose and without fee is hereby granted,
1736392Ssklower provided that the above copyright notice appear in all copies and that
1836392Ssklower both that copyright notice and this permission notice appear in
1936392Ssklower supporting documentation, and that the name of IBM not be
2036392Ssklower used in advertising or publicity pertaining to distribution of the
2136392Ssklower software without specific, written prior permission.
2236392Ssklower 
2336392Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436392Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536392Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636392Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736392Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836392Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936392Ssklower SOFTWARE.
3036392Ssklower 
3136392Ssklower ******************************************************************/
3236392Ssklower 
3336392Ssklower /*
3436392Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536392Ssklower  */
3636392Ssklower /* $Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $ */
3736392Ssklower /* $Source: /usr/argo/sys/netiso/RCS/iso_snpac.c,v $ */
3836392Ssklower 
3936392Ssklower #ifdef ISO
4036392Ssklower 
4137469Ssklower #include "types.h"
4237469Ssklower #include "param.h"
4343071Ssklower #include "systm.h"
4437469Ssklower #include "mbuf.h"
4537469Ssklower #include "domain.h"
4637469Ssklower #include "protosw.h"
4737469Ssklower #include "socket.h"
4837469Ssklower #include "socketvar.h"
4937469Ssklower #include "errno.h"
5037469Ssklower #include "ioctl.h"
5147274Ssklower #include "syslog.h"
5236392Ssklower 
5336392Ssklower #include "../net/if.h"
5443071Ssklower #include "../net/if_dl.h"
5536392Ssklower #include "../net/route.h"
5636392Ssklower 
5737469Ssklower #include "iso.h"
5837469Ssklower #include "iso_var.h"
5937469Ssklower #include "iso_snpac.h"
6037469Ssklower #include "clnp.h"
6137469Ssklower #include "clnp_stat.h"
6238841Ssklower #include "esis.h"
6337469Ssklower #include "argo_debug.h"
6436392Ssklower 
6536392Ssklower int 				iso_systype = SNPA_ES;	/* default to be an ES */
6643423Ssklower extern short	esis_holding_time, esis_config_time, esis_esconfig_time;
67*50230Ssklower extern struct	timeval time;
68*50230Ssklower extern int esis_config(), hz;
69*50230Ssklower static void snpac_fixdstandmask();
7036392Ssklower 
7137469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
7237469Ssklower extern u_long iso_hashchar();
7337469Ssklower static struct sockaddr_iso
7437469Ssklower 	dst	= {sizeof(dst), AF_ISO},
7537469Ssklower 	gte	= {sizeof(dst), AF_ISO},
7637469Ssklower 	src	= {sizeof(dst), AF_ISO},
7737469Ssklower 	msk	= {sizeof(dst), AF_ISO},
7837469Ssklower 	zmk = {1};
7937469Ssklower #define zsi blank_siso
8037469Ssklower #define zero_isoa	zsi.siso_addr
81*50230Ssklower #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \
82*50230Ssklower 	   Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);}
8337469Ssklower #define S(x) ((struct sockaddr *)&(x))
8437469Ssklower 
8543071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
8643071Ssklower static struct sockaddr_dl gte_dl;
8743071Ssklower #define zap_linkaddr(a, b, c, i) \
8843071Ssklower 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
8936392Ssklower 
9036392Ssklower /*
9136392Ssklower  *	We only keep track of a single IS at a time.
9236392Ssklower  */
9343071Ssklower struct rtentry	*known_is;
9436392Ssklower 
9536392Ssklower /*
9636392Ssklower  *	Addresses taken from NBS agreements, December 1987.
9736392Ssklower  *
9836392Ssklower  *	These addresses assume on-the-wire transmission of least significant
9936392Ssklower  *	bit first. This is the method used by 802.3. When these
10036392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
10136392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
10236392Ssklower  *
10336392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
10436392Ssklower  *	true token ring multicast addresses. More work is necessary
10536392Ssklower  *	to get multicast to work right on token ring.
10636392Ssklower  *
10736392Ssklower  *	Currently, the token ring driver does not handle multicast, so
10836392Ssklower  *	these addresses are converted into the broadcast address in
10936392Ssklower  *	lan_output() That means that if these multicast addresses change
11036392Ssklower  *	the token ring driver must be altered.
11136392Ssklower  */
11243334Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 };
11343334Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 };
11445898Ssklower char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14};
11545898Ssklower char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15};
11636392Ssklower 
11743071Ssklower union sockunion {
11843071Ssklower 	struct sockaddr_iso siso;
11943071Ssklower 	struct sockaddr_dl	sdl;
12043071Ssklower 	struct sockaddr		sa;
12143071Ssklower };
12236392Ssklower 
12336392Ssklower /*
12443071Ssklower  * FUNCTION:		llc_rtrequest
12543071Ssklower  *
12643071Ssklower  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
12743071Ssklower  *
12843071Ssklower  * NOTES:			This does a lot of obscure magic;
12943071Ssklower  */
13043071Ssklower llc_rtrequest(req, rt, sa)
13143071Ssklower int req;
13243071Ssklower register struct rtentry *rt;
13343071Ssklower struct sockaddr *sa;
13443071Ssklower {
13543071Ssklower 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
13643071Ssklower 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
13743071Ssklower 	struct rtentry *rt2;
13843071Ssklower 	struct ifnet *ifp = rt->rt_ifp;
13943071Ssklower 	int addrlen = ifp->if_addrlen;
14043334Ssklower 	static struct rtentry *recursing = 0;
14148732Ssklower #define LLC_SIZE 3 /* XXXXXX do this right later */
14243071Ssklower 
14343334Ssklower 	IFDEBUG (D_SNPA)
14443334Ssklower 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
14543334Ssklower 	ENDDEBUG
14643334Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
14743334Ssklower 		if (recursing) {
14847274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: gateway route points to same type %x %x\n",
14943334Ssklower 				recursing, rt);
15043334Ssklower 		} else switch (req) {
15143334Ssklower 		case RTM_RESOLVE:
15243334Ssklower 		case RTM_ADD:
15343334Ssklower 			recursing = rt;
15443334Ssklower 			rt->rt_llinfo = (caddr_t)rtalloc1(&gate->sa, 1);
15543334Ssklower 			recursing = 0;
15648732Ssklower 			if (rt->rt_rmx.rmx_mtu == 0) {
15748732Ssklower 				rt->rt_rmx.rmx_mtu =
15848732Ssklower 				    ((rt2 = (struct rtentry *)rt->rt_llinfo) &&
15948732Ssklower 					    (rt2->rt_rmx.rmx_mtu)) ?
16048732Ssklower 				    rt2->rt_rmx.rmx_mtu :
16148732Ssklower 				    rt->rt_ifp->if_mtu - LLC_SIZE;
16248732Ssklower 			}
16343334Ssklower 			return;
16443334Ssklower 
16543334Ssklower 		case RTM_DELETE:
16643334Ssklower 			if (lc)
16743334Ssklower 				RTFREE((struct rtentry *)lc);
16843334Ssklower 			rt->rt_llinfo = 0;
16943071Ssklower 		}
17043334Ssklower 	} else switch (req) {
17143071Ssklower 	case RTM_ADD:
17243334Ssklower 		/*
17343334Ssklower 		 * Case 1: This route may come from a route to iface with mask
17443334Ssklower 		 * or from a default route.
17543334Ssklower 		 */
17643071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
17743334Ssklower 			register struct ifaddr *ifa;
17843334Ssklower 			register struct sockaddr *sa;
17943334Ssklower 			for (ifa = ifp->if_addrlist; ifa; ifa->ifa_next)
18043334Ssklower 				if ((sa = ifa->ifa_addr)->sa_family == AF_LINK) {
18143334Ssklower 					if (sa->sa_len > gate->sa.sa_len)
18247274Ssklower 						log(LOG_DEBUG, "llc_rtrequest: cloning address too small\n");
18343334Ssklower 					else {
18443334Ssklower 						Bcopy(sa, gate, gate->sa.sa_len);
18543334Ssklower 						gate->sdl.sdl_alen = 0;
18643334Ssklower 					}
18748732Ssklower 					break;
18843071Ssklower 				}
18943334Ssklower 			if (ifa == 0)
19047274Ssklower 				log(LOG_DEBUG, "llc_rtrequest: can't find LL ifaddr for iface\n");
19148732Ssklower 			break;
19243071Ssklower 		}
19343334Ssklower 		/* FALLTHROUGH */
19443334Ssklower 	case RTM_RESOLVE:
19543334Ssklower 		/*
19643334Ssklower 		 * Case 2:  This route may come from cloning, or a manual route
19743334Ssklower 		 * add with a LL address.
19843334Ssklower 		 */
19943334Ssklower 		if (gate->sdl.sdl_family != AF_LINK) {
20047274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
20148732Ssklower 			break;
20243334Ssklower 		}
20343334Ssklower 		if (lc != 0)
204*50230Ssklower 			return; /* happens on a route change */
20543334Ssklower 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
20643334Ssklower 		rt->rt_llinfo = (caddr_t)lc;
20743334Ssklower 		if (lc == 0) {
20847274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
20948732Ssklower 			break;
21043334Ssklower 		}
21143334Ssklower 		Bzero(lc, sizeof(*lc));
21243334Ssklower 		lc->lc_rt = rt;
21343334Ssklower 		rt->rt_flags |= RTF_LLINFO;
21443334Ssklower 		insque(lc, &llinfo_llc);
21543334Ssklower 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
21643334Ssklower 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
21743334Ssklower 			bcopy(addrlen + LLADDR(&gate->sdl),
21843334Ssklower 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
21943334Ssklower 		} else if (gate->sdl.sdl_alen == addrlen)
22043334Ssklower 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
22143071Ssklower 		break;
22243071Ssklower 	case RTM_DELETE:
22343334Ssklower 		if (lc == 0 || (rt->rt_flags & RTF_CLONING))
22443334Ssklower 			return;
22543334Ssklower 		remque(lc);
22643334Ssklower 		Free(lc);
22743334Ssklower 		rt->rt_llinfo = 0;
22843334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
22943071Ssklower 		break;
23043071Ssklower 	}
23148732Ssklower 	if (rt->rt_rmx.rmx_mtu == 0) {
23248732Ssklower 			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
23348732Ssklower 	}
23443071Ssklower }
23543071Ssklower /*
23636392Ssklower  * FUNCTION:		iso_snparesolve
23736392Ssklower  *
23836392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
23936392Ssklower  *
24036392Ssklower  * RETURNS:			0 if addr is resolved
24136392Ssklower  *					errno if addr is unknown
24236392Ssklower  *
24336392Ssklower  * SIDE EFFECTS:
24436392Ssklower  *
24543071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
24643071Ssklower  *					table, we know there is no snpa address known for this
24743071Ssklower  *					destination.  If we know of a default IS, then the address
24843071Ssklower  *					of the IS is returned.  If no IS is known, then return the
24943071Ssklower  *					multi-cast address for "all ES" for this interface.
25036392Ssklower  *
25136392Ssklower  *					NB: the last case described above constitutes the
25236392Ssklower  *					query configuration function 9542, sec 6.5
25336392Ssklower  *					A mechanism is needed to prevent this function from
25436392Ssklower  *					being invoked if the system is an IS.
25536392Ssklower  */
25637469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
25743071Ssklower struct	ifnet *ifp;			/* outgoing interface */
25843071Ssklower struct	sockaddr_iso *dest;	/* destination */
25943071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
26043071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
26136392Ssklower {
26243071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
26343071Ssklower 	caddr_t	found_snpa;
26443071Ssklower 	int 	addrlen;
26536392Ssklower 
26636392Ssklower 	/*
26736392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
26836392Ssklower 	 *	addresss embedded in the destination nsap address
26936392Ssklower 	 */
27043071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
27136392Ssklower 		/*
27236392Ssklower 		 *	This is a subnetwork address. Return it immediately
27336392Ssklower 		 */
27436392Ssklower 		IFDEBUG(D_SNPA)
27536392Ssklower 			printf("iso_snparesolve: return SN address\n");
27636392Ssklower 		ENDDEBUG
27743071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
27843071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
27936392Ssklower 	/*
28043071Ssklower 	 * If we are an IS, we can't do much with the packet;
28143071Ssklower 	 *	Check if we know about an IS.
28236392Ssklower 	 */
28343071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
28443071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
28543071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
28643071Ssklower 		register struct sockaddr_dl *sdl =
28743071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
28843071Ssklower 		found_snpa = LLADDR(sdl);
28943071Ssklower 		addrlen = sdl->sdl_alen;
29043071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
29143071Ssklower 		/*
29243071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
29343071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
29443071Ssklower 		 *
29543071Ssklower 		 *	Note: there is a potential problem here. If the destination
29643071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
29743071Ssklower 		 *	does send back a TP CC, a connection could be established
29843071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
29936392Ssklower 		 */
30043071Ssklower 		addrlen = ifp->if_addrlen;
30143071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
30243071Ssklower 	} else
30343071Ssklower 		return (ENETUNREACH);
30443071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
30536392Ssklower 	return (0);
30636392Ssklower }
30736392Ssklower 
30836392Ssklower 
30936392Ssklower /*
31036392Ssklower  * FUNCTION:		snpac_free
31136392Ssklower  *
31236392Ssklower  * PURPOSE:			free an entry in the iso address map table
31336392Ssklower  *
31436392Ssklower  * RETURNS:			nothing
31536392Ssklower  *
31636392Ssklower  * SIDE EFFECTS:
31736392Ssklower  *
31836392Ssklower  * NOTES:			If there is a route entry associated with cache
31936392Ssklower  *					entry, then delete that as well
32036392Ssklower  */
32143071Ssklower snpac_free(lc)
32243071Ssklower register struct llinfo_llc *lc;		/* entry to free */
32336392Ssklower {
32443071Ssklower 	register struct rtentry *rt = lc->lc_rt;
32537469Ssklower 	register struct iso_addr *r;
32636392Ssklower 
32743071Ssklower 	if (known_is == rt)
32843071Ssklower 		known_is = 0;
32943071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
33043071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
33137469Ssklower 			RTFREE(rt);
33237469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
33337469Ssklower 						rt->rt_flags, (struct rtentry **)0);
33437469Ssklower 		RTFREE(rt);
33536392Ssklower 	}
33636392Ssklower }
33736392Ssklower 
33836392Ssklower /*
33936392Ssklower  * FUNCTION:		snpac_add
34036392Ssklower  *
34136392Ssklower  * PURPOSE:			Add an entry to the snpa cache
34236392Ssklower  *
34336392Ssklower  * RETURNS:
34436392Ssklower  *
34536392Ssklower  * SIDE EFFECTS:
34636392Ssklower  *
34736392Ssklower  * NOTES:			If entry already exists, then update holding time.
34836392Ssklower  */
34943334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
35036392Ssklower struct ifnet		*ifp;		/* interface info is related to */
35136392Ssklower struct iso_addr		*nsap;		/* nsap to add */
35236392Ssklower caddr_t				snpa;		/* translation */
35336392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
35437469Ssklower u_short				ht;			/* holding time (in seconds) */
35543334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
35636392Ssklower {
35743071Ssklower 	register struct	llinfo_llc *lc;
35843334Ssklower 	register struct rtentry *rt;
35943334Ssklower 	struct	rtentry *mrt = 0;
36043071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
36143071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
36243071Ssklower 	int		new_entry = 0, index = ifp->if_index;
36336392Ssklower 
36443334Ssklower 	IFDEBUG(D_SNPA)
36543334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
36643334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
36743334Ssklower 	ENDDEBUG
36843071Ssklower 	zap_isoaddr(dst, nsap);
36943071Ssklower 	rt = rtalloc1(S(dst), 0);
37043334Ssklower 	IFDEBUG(D_SNPA)
37143334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
37243334Ssklower 	ENDDEBUG
37343071Ssklower 	if (rt == 0) {
37443334Ssklower 		struct sockaddr *netmask;
37543334Ssklower 		int flags;
37643334Ssklower 		add:
37743334Ssklower 		if (nsellength) {
37843334Ssklower 			netmask = S(msk); flags = RTF_UP;
37943334Ssklower 			snpac_fixdstandmask(nsellength);
38043334Ssklower 		} else {
38143334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
38243334Ssklower 		}
38343071Ssklower 		new_entry = 1;
38443071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
38543334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
38643334Ssklower 			mrt == 0)
38743071Ssklower 			return (0);
38843334Ssklower 		rt = mrt;
38943334Ssklower 		rt->rt_refcnt--;
39043071Ssklower 	} else {
39143071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
39243334Ssklower 		rt->rt_refcnt--;
39343334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
39443334Ssklower 			goto add;
39543334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
39643334Ssklower 			if (rt->rt_refcnt == 0) {
39743334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
39843334Ssklower 					(struct sockaddr *)0, 0, (struct rtentry *)0);
39943334Ssklower 				rt = 0;
40043334Ssklower 				goto add;
40143334Ssklower 			} else {
40243334Ssklower 				static struct iso_addr nsap2; register char *cp;
40343334Ssklower 				nsap2 = *nsap;
40443334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
40543334Ssklower 				while (cp < (char *)(1 + &nsap2))
40643334Ssklower 					*cp++ = 0;
40743334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
40843334Ssklower 			}
40943334Ssklower 		}
41043071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
41143071Ssklower 			int old_sdl_len = sdl->sdl_len;
41243334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
41347274Ssklower 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
41443071Ssklower 				return (0);
41543334Ssklower 			}
41643071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
41743071Ssklower 			sdl->sdl_len = old_sdl_len;
41843071Ssklower 			new_entry = 1;
41943071Ssklower 		}
42036392Ssklower 	}
42143334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
42243334Ssklower 		panic("snpac_rtrequest");
423*50230Ssklower 	rt->rt_rmx.rmx_expire = ht + time.tv_sec;
42443071Ssklower 	lc->lc_flags = SNPA_VALID | type;
42536392Ssklower 	if (type & SNPA_IS)
42643071Ssklower 		snpac_logdefis(rt);
42743334Ssklower 	return (new_entry);
42836392Ssklower }
42936392Ssklower 
430*50230Ssklower static void
431*50230Ssklower snpac_fixdstandmask(nsellength)
43243334Ssklower {
43343334Ssklower 	register char *cp = msk.siso_data, *cplim;
43443334Ssklower 
43543334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
43643334Ssklower 	msk.siso_len = cplim - (char *)&msk;
43743334Ssklower 	msk.siso_nlen = 0;
43843334Ssklower 	while (cp < cplim)
43943334Ssklower 		*cp++ = -1;
44043334Ssklower 	while (cp < (char *)msk.siso_pad)
44143334Ssklower 		*cp++ = 0;
44243334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
44343334Ssklower 		*cp++ = 0;
44443334Ssklower }
44543334Ssklower 
44636392Ssklower /*
44736392Ssklower  * FUNCTION:		snpac_ioctl
44836392Ssklower  *
44936392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
45036392Ssklower  *
45136392Ssklower  * RETURNS:			0 on success, or unix error code
45236392Ssklower  *
45336392Ssklower  * SIDE EFFECTS:
45436392Ssklower  *
45536392Ssklower  * NOTES:
45636392Ssklower  */
457*50230Ssklower snpac_ioctl (so, cmd, data)
458*50230Ssklower struct socket *so;
45936392Ssklower int		cmd;	/* ioctl to process */
46036392Ssklower caddr_t	data;	/* data for the cmd */
46136392Ssklower {
46236392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
46336392Ssklower 
46443334Ssklower 	IFDEBUG(D_IOCTL)
46536392Ssklower 		if (cmd == SIOCSSTYPE)
46643071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
46736392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
46836392Ssklower 		else
46943071Ssklower 			printf("snpac_ioctl: cmd get\n");
47036392Ssklower 	ENDDEBUG
47136392Ssklower 
47236392Ssklower 	if (cmd == SIOCSSTYPE) {
473*50230Ssklower 		if ((so->so_state & SS_PRIV) == 0)
474*50230Ssklower 			return (EPERM);
47536392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
47636392Ssklower 			return(EINVAL);
47736392Ssklower 		if (rq->sr_type & SNPA_ES) {
47836392Ssklower 			iso_systype = SNPA_ES;
47936392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
48036392Ssklower 			iso_systype = SNPA_IS;
48136392Ssklower 		} else {
48236392Ssklower 			return(EINVAL);
48336392Ssklower 		}
48436392Ssklower 		esis_holding_time = rq->sr_holdt;
48536392Ssklower 		esis_config_time = rq->sr_configt;
48643423Ssklower 		if (esis_esconfig_time != rq->sr_esconfigt) {
48743423Ssklower 			untimeout(esis_config, (caddr_t)0);
48843423Ssklower 			esis_esconfig_time = rq->sr_esconfigt;
48943423Ssklower 			esis_config();
49043423Ssklower 		}
49136392Ssklower 	} else if (cmd == SIOCGSTYPE) {
49236392Ssklower 		rq->sr_type = iso_systype;
49336392Ssklower 		rq->sr_holdt = esis_holding_time;
49436392Ssklower 		rq->sr_configt = esis_config_time;
49543423Ssklower 		rq->sr_esconfigt = esis_esconfig_time;
49636392Ssklower 	} else {
49743071Ssklower 		return (EINVAL);
49836392Ssklower 	}
49943071Ssklower 	return (0);
50036392Ssklower }
50136392Ssklower 
50236392Ssklower /*
50336392Ssklower  * FUNCTION:		snpac_logdefis
50436392Ssklower  *
50536392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
50636392Ssklower  *
50736392Ssklower  * RETURNS:			nothing
50836392Ssklower  *
50936392Ssklower  * SIDE EFFECTS:
51036392Ssklower  *
51136392Ssklower  * NOTES:
51236392Ssklower  */
51336392Ssklower snpac_logdefis(sc)
51443071Ssklower register struct rtentry *sc;
51536392Ssklower {
51637469Ssklower 	register struct iso_addr *r;
51743071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
51837469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
51943071Ssklower 
52043071Ssklower 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
52137469Ssklower 	if (known_is == 0)
52237469Ssklower 		known_is = sc;
52337469Ssklower 	if (known_is != sc) {
52443071Ssklower 		rtfree(known_is);
52537469Ssklower 		known_is = sc;
52636392Ssklower 	}
52737469Ssklower 	if (rt == 0) {
52843071Ssklower 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
52943071Ssklower 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
53037469Ssklower 		return;
53137469Ssklower 	}
53243334Ssklower 	rt->rt_refcnt--;
53337469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
53443071Ssklower 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
53537469Ssklower 	}
53636392Ssklower }
53736392Ssklower 
53836392Ssklower /*
53936392Ssklower  * FUNCTION:		snpac_age
54036392Ssklower  *
54136392Ssklower  * PURPOSE:			Time out snpac entries
54236392Ssklower  *
54336392Ssklower  * RETURNS:
54436392Ssklower  *
54536392Ssklower  * SIDE EFFECTS:
54636392Ssklower  *
54736392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
54836392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
54936392Ssklower  *					if the entry is added a moment before snpac_age is
55036392Ssklower  *					called, the entry will immediately have SNPAC_AGE
55136392Ssklower  *					seconds taken off the holding time, even though
55236392Ssklower  *					it has only been held a brief moment.
55336392Ssklower  *
55436392Ssklower  *					The proper way to do this is set an expiry timeval
55536392Ssklower  *					equal to current time + holding time. Then snpac_age
55636392Ssklower  *					would time out entries where expiry date is older
55736392Ssklower  *					than the current time.
55836392Ssklower  */
55936392Ssklower snpac_age()
56036392Ssklower {
561*50230Ssklower 	register struct	llinfo_llc *lc, *nlc;
562*50230Ssklower 	register struct	rtentry *rt;
56336392Ssklower 
56436392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
56536392Ssklower 
566*50230Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) {
567*50230Ssklower 		nlc = lc->lc_next;
56843071Ssklower 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
569*50230Ssklower 			rt = lc->lc_rt;
570*50230Ssklower 			if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec)
571*50230Ssklower 				snpac_free(lc);
572*50230Ssklower 			else
57336392Ssklower 				continue;
57436392Ssklower 		}
57536392Ssklower 	}
57636392Ssklower }
57736392Ssklower 
57836392Ssklower /*
57936392Ssklower  * FUNCTION:		snpac_ownmulti
58036392Ssklower  *
58136392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
58236392Ssklower  *					of the same type as the system.
58336392Ssklower  *
58436392Ssklower  * RETURNS:			true or false
58536392Ssklower  *
58636392Ssklower  * SIDE EFFECTS:
58736392Ssklower  *
58836392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
58936392Ssklower  *					as interm kludge until
59036392Ssklower  *					real multicast addresses can be configured
59136392Ssklower  */
59236392Ssklower snpac_ownmulti(snpa, len)
59343071Ssklower caddr_t	snpa;
59443071Ssklower u_int	len;
59536392Ssklower {
59637469Ssklower 	return (((iso_systype & SNPA_ES) &&
59743071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
59837469Ssklower 			((iso_systype & SNPA_IS) &&
59943071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
60036392Ssklower }
60136392Ssklower 
60236392Ssklower /*
60336392Ssklower  * FUNCTION:		snpac_flushifp
60436392Ssklower  *
60536392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
60636392Ssklower  *
60736392Ssklower  * RETURNS:			nothing
60836392Ssklower  *
60936392Ssklower  * SIDE EFFECTS:
61036392Ssklower  *
61136392Ssklower  * NOTES:
61236392Ssklower  */
61336392Ssklower snpac_flushifp(ifp)
61436392Ssklower struct ifnet	*ifp;
61536392Ssklower {
61643071Ssklower 	register struct llinfo_llc	*lc;
61736392Ssklower 
61843071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
61943071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
62043071Ssklower 			snpac_free(lc);
62136392Ssklower 	}
62236392Ssklower }
62336392Ssklower 
62436392Ssklower /*
62536392Ssklower  * FUNCTION:		snpac_rtrequest
62636392Ssklower  *
62736392Ssklower  * PURPOSE:			Make a routing request
62836392Ssklower  *
62936392Ssklower  * RETURNS:			nothing
63036392Ssklower  *
63136392Ssklower  * SIDE EFFECTS:
63236392Ssklower  *
63336392Ssklower  * NOTES:			In the future, this should make a request of a user
63436392Ssklower  *					level routing daemon.
63536392Ssklower  */
63637469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
63736392Ssklower int				req;
63837469Ssklower struct iso_addr	*host;
63936392Ssklower struct iso_addr	*gateway;
64037469Ssklower struct iso_addr	*netmask;
64136392Ssklower short			flags;
64237469Ssklower struct rtentry	**ret_nrt;
64336392Ssklower {
64437469Ssklower 	register struct iso_addr *r;
64536392Ssklower 
64636392Ssklower 	IFDEBUG(D_SNPA)
64736392Ssklower 		printf("snpac_rtrequest: ");
64837469Ssklower 		if (req == RTM_ADD)
64936392Ssklower 			printf("add");
65037469Ssklower 		else if (req == RTM_DELETE)
65136392Ssklower 			printf("delete");
65236392Ssklower 		else
65336392Ssklower 			printf("unknown command");
65437469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
65536392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
65636392Ssklower 	ENDDEBUG
65736392Ssklower 
65836392Ssklower 
65937469Ssklower 	zap_isoaddr(dst, host);
66037469Ssklower 	zap_isoaddr(gte, gateway);
66143334Ssklower 	if (netmask) {
66243334Ssklower 		zap_isoaddr(msk, netmask);
66343334Ssklower 		msk.siso_nlen = 0;
66443334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
66543334Ssklower 	}
66637469Ssklower 
66737469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
66837469Ssklower 		flags, ret_nrt);
66936392Ssklower }
67036392Ssklower 
67136392Ssklower /*
67236392Ssklower  * FUNCTION:		snpac_addrt
67336392Ssklower  *
67436392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
67536392Ssklower  *
67636392Ssklower  * RETURNS:			nothing
67736392Ssklower  *
67836392Ssklower  * SIDE EFFECTS:
67936392Ssklower  *
68036392Ssklower  * NOTES:			If a cache entry exists for gateway, then
68136392Ssklower  *					make a routing entry (host, gateway) and associate
68236392Ssklower  *					with gateway.
68336392Ssklower  *
68436392Ssklower  *					If a route already exists and is different, first delete
68536392Ssklower  *					it.
68636392Ssklower  *
68736392Ssklower  *					This could be made more efficient by checking
68836392Ssklower  *					the existing route before adding a new one.
68936392Ssklower  */
69039950Ssklower snpac_addrt(ifp, host, gateway, netmask)
69139950Ssklower struct ifnet *ifp;
69239950Ssklower struct iso_addr	*host, *gateway, *netmask;
69336392Ssklower {
69437469Ssklower 	register struct iso_addr *r;
69536392Ssklower 
69643071Ssklower 	zap_isoaddr(dst, host);
69743071Ssklower 	zap_isoaddr(gte, gateway);
69843071Ssklower 	if (netmask) {
69943334Ssklower 		zap_isoaddr(msk, netmask);
70043334Ssklower 		msk.siso_nlen = 0;
70143334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
70243071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
70343071Ssklower 	} else
70443071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
70543071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
70636392Ssklower }
70736392Ssklower #endif	ISO
708