xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 57952)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*57952Ssklower  *	@(#)iso_snpac.c	7.22 (Berkeley) 02/12/93
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 
4156533Sbostic #include <sys/param.h>
4256533Sbostic #include <sys/systm.h>
4356533Sbostic #include <sys/mbuf.h>
4456533Sbostic #include <sys/domain.h>
4556533Sbostic #include <sys/protosw.h>
4656533Sbostic #include <sys/socket.h>
4756533Sbostic #include <sys/socketvar.h>
4856533Sbostic #include <sys/errno.h>
4956533Sbostic #include <sys/ioctl.h>
5056533Sbostic #include <sys/syslog.h>
5136392Ssklower 
5256533Sbostic #include <net/if.h>
5356533Sbostic #include <net/if_dl.h>
5456533Sbostic #include <net/route.h>
5536392Ssklower 
5656533Sbostic #include <netiso/iso.h>
5756533Sbostic #include <netiso/iso_var.h>
5856533Sbostic #include <netiso/iso_snpac.h>
5956533Sbostic #include <netiso/clnp.h>
6056533Sbostic #include <netiso/clnp_stat.h>
6156533Sbostic #include <netiso/esis.h>
6256533Sbostic #include <netiso/argo_debug.h>
6336392Ssklower 
6436392Ssklower int 				iso_systype = SNPA_ES;	/* default to be an ES */
6543423Ssklower extern short	esis_holding_time, esis_config_time, esis_esconfig_time;
6650230Ssklower extern struct	timeval time;
6750230Ssklower extern int esis_config(), hz;
6850230Ssklower static void snpac_fixdstandmask();
6936392Ssklower 
7037469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
7137469Ssklower extern u_long iso_hashchar();
7237469Ssklower static struct sockaddr_iso
7337469Ssklower 	dst	= {sizeof(dst), AF_ISO},
7437469Ssklower 	gte	= {sizeof(dst), AF_ISO},
7537469Ssklower 	src	= {sizeof(dst), AF_ISO},
7637469Ssklower 	msk	= {sizeof(dst), AF_ISO},
7753691Ssklower 	zmk = {0};
7837469Ssklower #define zsi blank_siso
7937469Ssklower #define zero_isoa	zsi.siso_addr
8050230Ssklower #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \
8150230Ssklower 	   Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);}
8237469Ssklower #define S(x) ((struct sockaddr *)&(x))
8337469Ssklower 
8443071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
8543071Ssklower static struct sockaddr_dl gte_dl;
8643071Ssklower #define zap_linkaddr(a, b, c, i) \
8743071Ssklower 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
8836392Ssklower 
8936392Ssklower /*
9036392Ssklower  *	We only keep track of a single IS at a time.
9136392Ssklower  */
9243071Ssklower struct rtentry	*known_is;
9336392Ssklower 
9436392Ssklower /*
9536392Ssklower  *	Addresses taken from NBS agreements, December 1987.
9636392Ssklower  *
9736392Ssklower  *	These addresses assume on-the-wire transmission of least significant
9836392Ssklower  *	bit first. This is the method used by 802.3. When these
9936392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
10036392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
10136392Ssklower  *
10236392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
10336392Ssklower  *	true token ring multicast addresses. More work is necessary
10436392Ssklower  *	to get multicast to work right on token ring.
10536392Ssklower  *
10636392Ssklower  *	Currently, the token ring driver does not handle multicast, so
10736392Ssklower  *	these addresses are converted into the broadcast address in
10836392Ssklower  *	lan_output() That means that if these multicast addresses change
10936392Ssklower  *	the token ring driver must be altered.
11036392Ssklower  */
11143334Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 };
11243334Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 };
11345898Ssklower char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14};
11445898Ssklower char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15};
11536392Ssklower 
11643071Ssklower union sockunion {
11743071Ssklower 	struct sockaddr_iso siso;
11843071Ssklower 	struct sockaddr_dl	sdl;
11943071Ssklower 	struct sockaddr		sa;
12043071Ssklower };
12136392Ssklower 
12236392Ssklower /*
12343071Ssklower  * FUNCTION:		llc_rtrequest
12443071Ssklower  *
12543071Ssklower  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
12643071Ssklower  *
12743071Ssklower  * NOTES:			This does a lot of obscure magic;
12843071Ssklower  */
12943071Ssklower llc_rtrequest(req, rt, sa)
13043071Ssklower int req;
13143071Ssklower register struct rtentry *rt;
13243071Ssklower struct sockaddr *sa;
13343071Ssklower {
13443071Ssklower 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
13543071Ssklower 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
13643071Ssklower 	struct rtentry *rt2;
13743071Ssklower 	struct ifnet *ifp = rt->rt_ifp;
13843071Ssklower 	int addrlen = ifp->if_addrlen;
13948732Ssklower #define LLC_SIZE 3 /* XXXXXX do this right later */
14043071Ssklower 
14143334Ssklower 	IFDEBUG (D_SNPA)
14243334Ssklower 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
14343334Ssklower 	ENDDEBUG
14450231Ssklower 	if (rt->rt_flags & RTF_GATEWAY)
14550231Ssklower 		return;
14650231Ssklower 	else switch (req) {
14743071Ssklower 	case RTM_ADD:
14843334Ssklower 		/*
14943334Ssklower 		 * Case 1: This route may come from a route to iface with mask
15043334Ssklower 		 * or from a default route.
15143334Ssklower 		 */
15243071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
15354717Ssklower 			iso_setmcasts(ifp, req);
15450231Ssklower 			rt_setgate(rt, rt_key(rt), &blank_dl);
15550231Ssklower 			return;
15643071Ssklower 		}
15750231Ssklower 		if (lc != 0)
15850231Ssklower 			return; /* happens on a route change */
15943334Ssklower 		/* FALLTHROUGH */
16043334Ssklower 	case RTM_RESOLVE:
16143334Ssklower 		/*
16243334Ssklower 		 * Case 2:  This route may come from cloning, or a manual route
16343334Ssklower 		 * add with a LL address.
16443334Ssklower 		 */
16543334Ssklower 		if (gate->sdl.sdl_family != AF_LINK) {
16647274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
16748732Ssklower 			break;
16843334Ssklower 		}
16943334Ssklower 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
17043334Ssklower 		rt->rt_llinfo = (caddr_t)lc;
17143334Ssklower 		if (lc == 0) {
17247274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
17348732Ssklower 			break;
17443334Ssklower 		}
17543334Ssklower 		Bzero(lc, sizeof(*lc));
17643334Ssklower 		lc->lc_rt = rt;
17743334Ssklower 		rt->rt_flags |= RTF_LLINFO;
17843334Ssklower 		insque(lc, &llinfo_llc);
17943334Ssklower 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
18043334Ssklower 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
18143334Ssklower 			bcopy(addrlen + LLADDR(&gate->sdl),
18243334Ssklower 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
18343334Ssklower 		} else if (gate->sdl.sdl_alen == addrlen)
18443334Ssklower 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
18543071Ssklower 		break;
18643071Ssklower 	case RTM_DELETE:
18754717Ssklower 		if (rt->rt_flags & RTF_CLONING)
18854717Ssklower 			iso_setmcasts(ifp, req);
18954717Ssklower 		if (lc == 0)
19043334Ssklower 			return;
19143334Ssklower 		remque(lc);
19243334Ssklower 		Free(lc);
19343334Ssklower 		rt->rt_llinfo = 0;
19443334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
19543071Ssklower 		break;
19643071Ssklower 	}
19748732Ssklower 	if (rt->rt_rmx.rmx_mtu == 0) {
19848732Ssklower 			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
19948732Ssklower 	}
20043071Ssklower }
20143071Ssklower /*
20254717Ssklower  * FUNCTION:		iso_setmcasts
20354717Ssklower  *
20454717Ssklower  * PURPOSE:			Enable/Disable ESIS/ISIS multicast reception on interfaces.
20554717Ssklower  *
20654717Ssklower  * NOTES:			This also does a lot of obscure magic;
20754717Ssklower  */
20854717Ssklower iso_setmcasts(ifp, req)
20954717Ssklower 	struct	ifnet *ifp;
21054717Ssklower 	int		req;
21154717Ssklower {
21254717Ssklower 	static char *addrlist[] =
21354717Ssklower 		{ all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0};
21454717Ssklower 	struct ifreq ifr;
21554717Ssklower 	register caddr_t *cpp;
21654717Ssklower 	int		doreset = 0;
21754717Ssklower 
21854717Ssklower 	bzero((caddr_t)&ifr, sizeof(ifr));
21955903Ssklower 	for (cpp = (caddr_t *)addrlist; *cpp; cpp++) {
22054717Ssklower 		bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6);
22154717Ssklower 		if (req == RTM_ADD)
22254717Ssklower 			if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
22354717Ssklower 				doreset++;
22454717Ssklower 		else
225*57952Ssklower 			if (ether_delmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
22654717Ssklower 				doreset++;
22754717Ssklower 	}
228*57952Ssklower 	if (doreset) {
229*57952Ssklower 		if (ifp->if_reset)
230*57952Ssklower 			(*ifp->if_reset)(ifp->if_unit);
231*57952Ssklower 		else
232*57952Ssklower 			printf("iso_setmcasts: %s%d needs reseting to receive iso mcasts\n",
233*57952Ssklower 					ifp->if_name, ifp->if_unit);
234*57952Ssklower 	}
23554717Ssklower }
23654717Ssklower /*
23736392Ssklower  * FUNCTION:		iso_snparesolve
23836392Ssklower  *
23936392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
24036392Ssklower  *
24136392Ssklower  * RETURNS:			0 if addr is resolved
24236392Ssklower  *					errno if addr is unknown
24336392Ssklower  *
24436392Ssklower  * SIDE EFFECTS:
24536392Ssklower  *
24643071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
24743071Ssklower  *					table, we know there is no snpa address known for this
24843071Ssklower  *					destination.  If we know of a default IS, then the address
24943071Ssklower  *					of the IS is returned.  If no IS is known, then return the
25043071Ssklower  *					multi-cast address for "all ES" for this interface.
25136392Ssklower  *
25236392Ssklower  *					NB: the last case described above constitutes the
25336392Ssklower  *					query configuration function 9542, sec 6.5
25436392Ssklower  *					A mechanism is needed to prevent this function from
25536392Ssklower  *					being invoked if the system is an IS.
25636392Ssklower  */
25737469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
25843071Ssklower struct	ifnet *ifp;			/* outgoing interface */
25943071Ssklower struct	sockaddr_iso *dest;	/* destination */
26043071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
26143071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
26236392Ssklower {
26343071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
26443071Ssklower 	caddr_t	found_snpa;
26543071Ssklower 	int 	addrlen;
26636392Ssklower 
26736392Ssklower 	/*
26836392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
26936392Ssklower 	 *	addresss embedded in the destination nsap address
27036392Ssklower 	 */
27143071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
27236392Ssklower 		/*
27336392Ssklower 		 *	This is a subnetwork address. Return it immediately
27436392Ssklower 		 */
27536392Ssklower 		IFDEBUG(D_SNPA)
27636392Ssklower 			printf("iso_snparesolve: return SN address\n");
27736392Ssklower 		ENDDEBUG
27843071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
27943071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
28036392Ssklower 	/*
28143071Ssklower 	 * If we are an IS, we can't do much with the packet;
28243071Ssklower 	 *	Check if we know about an IS.
28336392Ssklower 	 */
28443071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
28543071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
28643071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
28743071Ssklower 		register struct sockaddr_dl *sdl =
28843071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
28943071Ssklower 		found_snpa = LLADDR(sdl);
29043071Ssklower 		addrlen = sdl->sdl_alen;
29143071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
29243071Ssklower 		/*
29343071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
29443071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
29543071Ssklower 		 *
29643071Ssklower 		 *	Note: there is a potential problem here. If the destination
29743071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
29843071Ssklower 		 *	does send back a TP CC, a connection could be established
29943071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
30036392Ssklower 		 */
30143071Ssklower 		addrlen = ifp->if_addrlen;
30243071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
30343071Ssklower 	} else
30443071Ssklower 		return (ENETUNREACH);
30543071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
30636392Ssklower 	return (0);
30736392Ssklower }
30836392Ssklower 
30936392Ssklower 
31036392Ssklower /*
31136392Ssklower  * FUNCTION:		snpac_free
31236392Ssklower  *
31336392Ssklower  * PURPOSE:			free an entry in the iso address map table
31436392Ssklower  *
31536392Ssklower  * RETURNS:			nothing
31636392Ssklower  *
31736392Ssklower  * SIDE EFFECTS:
31836392Ssklower  *
31936392Ssklower  * NOTES:			If there is a route entry associated with cache
32036392Ssklower  *					entry, then delete that as well
32136392Ssklower  */
32243071Ssklower snpac_free(lc)
32343071Ssklower register struct llinfo_llc *lc;		/* entry to free */
32436392Ssklower {
32543071Ssklower 	register struct rtentry *rt = lc->lc_rt;
32637469Ssklower 	register struct iso_addr *r;
32736392Ssklower 
32843071Ssklower 	if (known_is == rt)
32943071Ssklower 		known_is = 0;
33043071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
33143071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
33237469Ssklower 			RTFREE(rt);
33337469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
33437469Ssklower 						rt->rt_flags, (struct rtentry **)0);
33537469Ssklower 		RTFREE(rt);
33636392Ssklower 	}
33736392Ssklower }
33836392Ssklower 
33936392Ssklower /*
34036392Ssklower  * FUNCTION:		snpac_add
34136392Ssklower  *
34236392Ssklower  * PURPOSE:			Add an entry to the snpa cache
34336392Ssklower  *
34436392Ssklower  * RETURNS:
34536392Ssklower  *
34636392Ssklower  * SIDE EFFECTS:
34736392Ssklower  *
34836392Ssklower  * NOTES:			If entry already exists, then update holding time.
34936392Ssklower  */
35043334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
35136392Ssklower struct ifnet		*ifp;		/* interface info is related to */
35236392Ssklower struct iso_addr		*nsap;		/* nsap to add */
35336392Ssklower caddr_t				snpa;		/* translation */
35436392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
35537469Ssklower u_short				ht;			/* holding time (in seconds) */
35643334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
35736392Ssklower {
35843071Ssklower 	register struct	llinfo_llc *lc;
35943334Ssklower 	register struct rtentry *rt;
36043334Ssklower 	struct	rtentry *mrt = 0;
36143071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
36243071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
36352625Ssklower 	int		new_entry = 0, index = ifp->if_index, iftype = ifp->if_type;
36436392Ssklower 
36543334Ssklower 	IFDEBUG(D_SNPA)
36643334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
36743334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
36843334Ssklower 	ENDDEBUG
36943071Ssklower 	zap_isoaddr(dst, nsap);
37043071Ssklower 	rt = rtalloc1(S(dst), 0);
37143334Ssklower 	IFDEBUG(D_SNPA)
37243334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
37343334Ssklower 	ENDDEBUG
37443071Ssklower 	if (rt == 0) {
37543334Ssklower 		struct sockaddr *netmask;
37643334Ssklower 		int flags;
37743334Ssklower 		add:
37843334Ssklower 		if (nsellength) {
37943334Ssklower 			netmask = S(msk); flags = RTF_UP;
38043334Ssklower 			snpac_fixdstandmask(nsellength);
38143334Ssklower 		} else {
38243334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
38343334Ssklower 		}
38443071Ssklower 		new_entry = 1;
38543071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
38652625Ssklower 		gte_dl.sdl_type = iftype;
38743334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
38843334Ssklower 			mrt == 0)
38943071Ssklower 			return (0);
39043334Ssklower 		rt = mrt;
39143334Ssklower 		rt->rt_refcnt--;
39243071Ssklower 	} else {
39343071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
39443334Ssklower 		rt->rt_refcnt--;
39543334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
39643334Ssklower 			goto add;
39743334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
39843334Ssklower 			if (rt->rt_refcnt == 0) {
39943334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
40043334Ssklower 					(struct sockaddr *)0, 0, (struct rtentry *)0);
40143334Ssklower 				rt = 0;
40243334Ssklower 				goto add;
40343334Ssklower 			} else {
40443334Ssklower 				static struct iso_addr nsap2; register char *cp;
40543334Ssklower 				nsap2 = *nsap;
40643334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
40743334Ssklower 				while (cp < (char *)(1 + &nsap2))
40843334Ssklower 					*cp++ = 0;
40943334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
41043334Ssklower 			}
41143334Ssklower 		}
41243071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
41343071Ssklower 			int old_sdl_len = sdl->sdl_len;
41443334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
41547274Ssklower 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
41643071Ssklower 				return (0);
41743334Ssklower 			}
41843071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
41943071Ssklower 			sdl->sdl_len = old_sdl_len;
42052625Ssklower 			sdl->sdl_type = iftype;
42143071Ssklower 			new_entry = 1;
42243071Ssklower 		}
42336392Ssklower 	}
42443334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
42543334Ssklower 		panic("snpac_rtrequest");
42650230Ssklower 	rt->rt_rmx.rmx_expire = ht + time.tv_sec;
42743071Ssklower 	lc->lc_flags = SNPA_VALID | type;
42853691Ssklower 	if ((type & SNPA_IS) && !(iso_systype & SNPA_IS))
42943071Ssklower 		snpac_logdefis(rt);
43043334Ssklower 	return (new_entry);
43136392Ssklower }
43236392Ssklower 
43350230Ssklower static void
43450230Ssklower snpac_fixdstandmask(nsellength)
43543334Ssklower {
43643334Ssklower 	register char *cp = msk.siso_data, *cplim;
43743334Ssklower 
43843334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
43943334Ssklower 	msk.siso_len = cplim - (char *)&msk;
44043334Ssklower 	msk.siso_nlen = 0;
44143334Ssklower 	while (cp < cplim)
44243334Ssklower 		*cp++ = -1;
44343334Ssklower 	while (cp < (char *)msk.siso_pad)
44443334Ssklower 		*cp++ = 0;
44543334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
44643334Ssklower 		*cp++ = 0;
44743334Ssklower }
44843334Ssklower 
44936392Ssklower /*
45036392Ssklower  * FUNCTION:		snpac_ioctl
45136392Ssklower  *
45236392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
45336392Ssklower  *
45436392Ssklower  * RETURNS:			0 on success, or unix error code
45536392Ssklower  *
45636392Ssklower  * SIDE EFFECTS:
45736392Ssklower  *
45836392Ssklower  * NOTES:
45936392Ssklower  */
46050230Ssklower snpac_ioctl (so, cmd, data)
46150230Ssklower struct socket *so;
46236392Ssklower int		cmd;	/* ioctl to process */
46336392Ssklower caddr_t	data;	/* data for the cmd */
46436392Ssklower {
46536392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
46636392Ssklower 
46743334Ssklower 	IFDEBUG(D_IOCTL)
46836392Ssklower 		if (cmd == SIOCSSTYPE)
46943071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
47036392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
47136392Ssklower 		else
47243071Ssklower 			printf("snpac_ioctl: cmd get\n");
47336392Ssklower 	ENDDEBUG
47436392Ssklower 
47536392Ssklower 	if (cmd == SIOCSSTYPE) {
47650230Ssklower 		if ((so->so_state & SS_PRIV) == 0)
47750230Ssklower 			return (EPERM);
47836392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
47936392Ssklower 			return(EINVAL);
48036392Ssklower 		if (rq->sr_type & SNPA_ES) {
48136392Ssklower 			iso_systype = SNPA_ES;
48236392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
48336392Ssklower 			iso_systype = SNPA_IS;
48436392Ssklower 		} else {
48536392Ssklower 			return(EINVAL);
48636392Ssklower 		}
48736392Ssklower 		esis_holding_time = rq->sr_holdt;
48836392Ssklower 		esis_config_time = rq->sr_configt;
48943423Ssklower 		if (esis_esconfig_time != rq->sr_esconfigt) {
49043423Ssklower 			untimeout(esis_config, (caddr_t)0);
49143423Ssklower 			esis_esconfig_time = rq->sr_esconfigt;
49243423Ssklower 			esis_config();
49343423Ssklower 		}
49436392Ssklower 	} else if (cmd == SIOCGSTYPE) {
49536392Ssklower 		rq->sr_type = iso_systype;
49636392Ssklower 		rq->sr_holdt = esis_holding_time;
49736392Ssklower 		rq->sr_configt = esis_config_time;
49843423Ssklower 		rq->sr_esconfigt = esis_esconfig_time;
49936392Ssklower 	} else {
50043071Ssklower 		return (EINVAL);
50136392Ssklower 	}
50243071Ssklower 	return (0);
50336392Ssklower }
50436392Ssklower 
50536392Ssklower /*
50636392Ssklower  * FUNCTION:		snpac_logdefis
50736392Ssklower  *
50836392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
50936392Ssklower  *
51036392Ssklower  * RETURNS:			nothing
51136392Ssklower  *
51236392Ssklower  * SIDE EFFECTS:
51336392Ssklower  *
51436392Ssklower  * NOTES:
51536392Ssklower  */
51636392Ssklower snpac_logdefis(sc)
51743071Ssklower register struct rtentry *sc;
51836392Ssklower {
51937469Ssklower 	register struct iso_addr *r;
52043071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
52153691Ssklower 	register struct rtentry *rt;
52243071Ssklower 
52353691Ssklower 	if (known_is == sc || !(sc->rt_flags & RTF_HOST))
52437469Ssklower 		return;
52553691Ssklower 	if (known_is) {
52653691Ssklower 		RTFREE(known_is);
52737469Ssklower 	}
52853691Ssklower 	known_is = sc;
52953691Ssklower 	sc->rt_refcnt++;
53053691Ssklower 	rt = rtalloc1((struct sockaddr *)&zsi, 0);
53153691Ssklower 	if (rt == 0)
53253691Ssklower 		rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk),
53353691Ssklower 						RTF_DYNAMIC|RTF_GATEWAY, 0);
53453691Ssklower 	else {
53553691Ssklower 		if ((rt->rt_flags & RTF_DYNAMIC) &&
53653691Ssklower 		    (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0)
53753691Ssklower 			rt_setgate(rt, rt_key(rt), rt_key(sc));
53837469Ssklower 	}
53936392Ssklower }
54036392Ssklower 
54136392Ssklower /*
54236392Ssklower  * FUNCTION:		snpac_age
54336392Ssklower  *
54436392Ssklower  * PURPOSE:			Time out snpac entries
54536392Ssklower  *
54636392Ssklower  * RETURNS:
54736392Ssklower  *
54836392Ssklower  * SIDE EFFECTS:
54936392Ssklower  *
55036392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
55136392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
55236392Ssklower  *					if the entry is added a moment before snpac_age is
55336392Ssklower  *					called, the entry will immediately have SNPAC_AGE
55436392Ssklower  *					seconds taken off the holding time, even though
55536392Ssklower  *					it has only been held a brief moment.
55636392Ssklower  *
55736392Ssklower  *					The proper way to do this is set an expiry timeval
55836392Ssklower  *					equal to current time + holding time. Then snpac_age
55936392Ssklower  *					would time out entries where expiry date is older
56036392Ssklower  *					than the current time.
56136392Ssklower  */
56236392Ssklower snpac_age()
56336392Ssklower {
56450230Ssklower 	register struct	llinfo_llc *lc, *nlc;
56550230Ssklower 	register struct	rtentry *rt;
56636392Ssklower 
56736392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
56836392Ssklower 
56950230Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) {
57050230Ssklower 		nlc = lc->lc_next;
57153691Ssklower 		if (lc->lc_flags & SNPA_VALID) {
57250230Ssklower 			rt = lc->lc_rt;
57350230Ssklower 			if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec)
57450230Ssklower 				snpac_free(lc);
57536392Ssklower 		}
57636392Ssklower 	}
57736392Ssklower }
57836392Ssklower 
57936392Ssklower /*
58036392Ssklower  * FUNCTION:		snpac_ownmulti
58136392Ssklower  *
58236392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
58336392Ssklower  *					of the same type as the system.
58436392Ssklower  *
58536392Ssklower  * RETURNS:			true or false
58636392Ssklower  *
58736392Ssklower  * SIDE EFFECTS:
58836392Ssklower  *
58936392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
59036392Ssklower  *					as interm kludge until
59136392Ssklower  *					real multicast addresses can be configured
59236392Ssklower  */
59336392Ssklower snpac_ownmulti(snpa, len)
59443071Ssklower caddr_t	snpa;
59543071Ssklower u_int	len;
59636392Ssklower {
59737469Ssklower 	return (((iso_systype & SNPA_ES) &&
59843071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
59937469Ssklower 			((iso_systype & SNPA_IS) &&
60043071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
60136392Ssklower }
60236392Ssklower 
60336392Ssklower /*
60436392Ssklower  * FUNCTION:		snpac_flushifp
60536392Ssklower  *
60636392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
60736392Ssklower  *
60836392Ssklower  * RETURNS:			nothing
60936392Ssklower  *
61036392Ssklower  * SIDE EFFECTS:
61136392Ssklower  *
61236392Ssklower  * NOTES:
61336392Ssklower  */
61436392Ssklower snpac_flushifp(ifp)
61536392Ssklower struct ifnet	*ifp;
61636392Ssklower {
61743071Ssklower 	register struct llinfo_llc	*lc;
61836392Ssklower 
61943071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
62043071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
62143071Ssklower 			snpac_free(lc);
62236392Ssklower 	}
62336392Ssklower }
62436392Ssklower 
62536392Ssklower /*
62636392Ssklower  * FUNCTION:		snpac_rtrequest
62736392Ssklower  *
62836392Ssklower  * PURPOSE:			Make a routing request
62936392Ssklower  *
63036392Ssklower  * RETURNS:			nothing
63136392Ssklower  *
63236392Ssklower  * SIDE EFFECTS:
63336392Ssklower  *
63436392Ssklower  * NOTES:			In the future, this should make a request of a user
63536392Ssklower  *					level routing daemon.
63636392Ssklower  */
63737469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
63836392Ssklower int				req;
63937469Ssklower struct iso_addr	*host;
64036392Ssklower struct iso_addr	*gateway;
64137469Ssklower struct iso_addr	*netmask;
64236392Ssklower short			flags;
64337469Ssklower struct rtentry	**ret_nrt;
64436392Ssklower {
64537469Ssklower 	register struct iso_addr *r;
64636392Ssklower 
64736392Ssklower 	IFDEBUG(D_SNPA)
64836392Ssklower 		printf("snpac_rtrequest: ");
64937469Ssklower 		if (req == RTM_ADD)
65036392Ssklower 			printf("add");
65137469Ssklower 		else if (req == RTM_DELETE)
65236392Ssklower 			printf("delete");
65336392Ssklower 		else
65436392Ssklower 			printf("unknown command");
65537469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
65636392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
65736392Ssklower 	ENDDEBUG
65836392Ssklower 
65936392Ssklower 
66037469Ssklower 	zap_isoaddr(dst, host);
66137469Ssklower 	zap_isoaddr(gte, gateway);
66243334Ssklower 	if (netmask) {
66343334Ssklower 		zap_isoaddr(msk, netmask);
66443334Ssklower 		msk.siso_nlen = 0;
66543334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
66643334Ssklower 	}
66737469Ssklower 
66837469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
66937469Ssklower 		flags, ret_nrt);
67036392Ssklower }
67136392Ssklower 
67236392Ssklower /*
67336392Ssklower  * FUNCTION:		snpac_addrt
67436392Ssklower  *
67536392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
67636392Ssklower  *
67736392Ssklower  * RETURNS:			nothing
67836392Ssklower  *
67936392Ssklower  * SIDE EFFECTS:
68036392Ssklower  *
68136392Ssklower  * NOTES:			If a cache entry exists for gateway, then
68236392Ssklower  *					make a routing entry (host, gateway) and associate
68336392Ssklower  *					with gateway.
68436392Ssklower  *
68536392Ssklower  *					If a route already exists and is different, first delete
68636392Ssklower  *					it.
68736392Ssklower  *
68836392Ssklower  *					This could be made more efficient by checking
68936392Ssklower  *					the existing route before adding a new one.
69036392Ssklower  */
69139950Ssklower snpac_addrt(ifp, host, gateway, netmask)
69239950Ssklower struct ifnet *ifp;
69339950Ssklower struct iso_addr	*host, *gateway, *netmask;
69436392Ssklower {
69537469Ssklower 	register struct iso_addr *r;
69636392Ssklower 
69743071Ssklower 	zap_isoaddr(dst, host);
69843071Ssklower 	zap_isoaddr(gte, gateway);
69943071Ssklower 	if (netmask) {
70043334Ssklower 		zap_isoaddr(msk, netmask);
70143334Ssklower 		msk.siso_nlen = 0;
70243334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
70343071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
70443071Ssklower 	} else
70543071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
70643071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
70736392Ssklower }
70836392Ssklower #endif	ISO
709