xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 69163)
149268Sbostic /*-
263222Sbostic  * Copyright (c) 1991, 1993
363222Sbostic  *	The Regents of the University of California.  All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*69163Smckusick  *	@(#)iso_snpac.c	8.4 (Berkeley) 05/02/95
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;
6758990Ssklower extern void esis_config();
6858990Ssklower extern int hz;
6950230Ssklower 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},
7853691Ssklower 	zmk = {0};
7937469Ssklower #define zsi blank_siso
8037469Ssklower #define zero_isoa	zsi.siso_addr
8150230Ssklower #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \
8250230Ssklower 	   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
101*69163Smckusick  *	must be bit-swapped 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  */
llc_rtrequest(req,rt,sa)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;
14048732Ssklower #define LLC_SIZE 3 /* XXXXXX do this right later */
14143071Ssklower 
14243334Ssklower 	IFDEBUG (D_SNPA)
14343334Ssklower 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
14443334Ssklower 	ENDDEBUG
14550231Ssklower 	if (rt->rt_flags & RTF_GATEWAY)
14650231Ssklower 		return;
14750231Ssklower 	else switch (req) {
14843071Ssklower 	case RTM_ADD:
14943334Ssklower 		/*
15043334Ssklower 		 * Case 1: This route may come from a route to iface with mask
15143334Ssklower 		 * or from a default route.
15243334Ssklower 		 */
15343071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
15454717Ssklower 			iso_setmcasts(ifp, req);
15568261Scgd 			rt_setgate(rt, rt_key(rt),
15668261Scgd 			    (struct sockaddr *)&blank_dl);
15750231Ssklower 			return;
15843071Ssklower 		}
15950231Ssklower 		if (lc != 0)
16050231Ssklower 			return; /* happens on a route change */
16143334Ssklower 		/* FALLTHROUGH */
16243334Ssklower 	case RTM_RESOLVE:
16343334Ssklower 		/*
16443334Ssklower 		 * Case 2:  This route may come from cloning, or a manual route
16543334Ssklower 		 * add with a LL address.
16643334Ssklower 		 */
16743334Ssklower 		if (gate->sdl.sdl_family != AF_LINK) {
16847274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
16948732Ssklower 			break;
17043334Ssklower 		}
17143334Ssklower 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
17243334Ssklower 		rt->rt_llinfo = (caddr_t)lc;
17343334Ssklower 		if (lc == 0) {
17447274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
17548732Ssklower 			break;
17643334Ssklower 		}
17743334Ssklower 		Bzero(lc, sizeof(*lc));
17843334Ssklower 		lc->lc_rt = rt;
17943334Ssklower 		rt->rt_flags |= RTF_LLINFO;
18043334Ssklower 		insque(lc, &llinfo_llc);
18143334Ssklower 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
18243334Ssklower 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
18343334Ssklower 			bcopy(addrlen + LLADDR(&gate->sdl),
18443334Ssklower 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
18543334Ssklower 		} else if (gate->sdl.sdl_alen == addrlen)
18643334Ssklower 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
18743071Ssklower 		break;
18843071Ssklower 	case RTM_DELETE:
18954717Ssklower 		if (rt->rt_flags & RTF_CLONING)
19054717Ssklower 			iso_setmcasts(ifp, req);
19154717Ssklower 		if (lc == 0)
19243334Ssklower 			return;
19343334Ssklower 		remque(lc);
19443334Ssklower 		Free(lc);
19543334Ssklower 		rt->rt_llinfo = 0;
19643334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
19743071Ssklower 		break;
19843071Ssklower 	}
19948732Ssklower 	if (rt->rt_rmx.rmx_mtu == 0) {
20048732Ssklower 			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
20148732Ssklower 	}
20243071Ssklower }
20343071Ssklower /*
20454717Ssklower  * FUNCTION:		iso_setmcasts
20554717Ssklower  *
20654717Ssklower  * PURPOSE:			Enable/Disable ESIS/ISIS multicast reception on interfaces.
20754717Ssklower  *
20854717Ssklower  * NOTES:			This also does a lot of obscure magic;
20954717Ssklower  */
21054717Ssklower iso_setmcasts(ifp, req)
21154717Ssklower 	struct	ifnet *ifp;
21254717Ssklower 	int		req;
21354717Ssklower {
21454717Ssklower 	static char *addrlist[] =
21554717Ssklower 		{ all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0};
21654717Ssklower 	struct ifreq ifr;
21754717Ssklower 	register caddr_t *cpp;
21854717Ssklower 	int		doreset = 0;
21954717Ssklower 
22054717Ssklower 	bzero((caddr_t)&ifr, sizeof(ifr));
22155903Ssklower 	for (cpp = (caddr_t *)addrlist; *cpp; cpp++) {
22254717Ssklower 		bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6);
22354717Ssklower 		if (req == RTM_ADD)
22454717Ssklower 			if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
22554717Ssklower 				doreset++;
22654717Ssklower 		else
22757952Ssklower 			if (ether_delmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
22854717Ssklower 				doreset++;
22954717Ssklower 	}
23057952Ssklower 	if (doreset) {
23157952Ssklower 		if (ifp->if_reset)
23257952Ssklower 			(*ifp->if_reset)(ifp->if_unit);
23357952Ssklower 		else
23457952Ssklower 			printf("iso_setmcasts: %s%d needs reseting to receive iso mcasts\n",
23557952Ssklower 					ifp->if_name, ifp->if_unit);
23657952Ssklower 	}
23754717Ssklower }
23854717Ssklower /*
23936392Ssklower  * FUNCTION:		iso_snparesolve
24036392Ssklower  *
24136392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
24236392Ssklower  *
24336392Ssklower  * RETURNS:			0 if addr is resolved
24436392Ssklower  *					errno if addr is unknown
24536392Ssklower  *
24636392Ssklower  * SIDE EFFECTS:
24736392Ssklower  *
24843071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
24943071Ssklower  *					table, we know there is no snpa address known for this
25043071Ssklower  *					destination.  If we know of a default IS, then the address
25143071Ssklower  *					of the IS is returned.  If no IS is known, then return the
25243071Ssklower  *					multi-cast address for "all ES" for this interface.
25336392Ssklower  *
25436392Ssklower  *					NB: the last case described above constitutes the
25536392Ssklower  *					query configuration function 9542, sec 6.5
25636392Ssklower  *					A mechanism is needed to prevent this function from
25736392Ssklower  *					being invoked if the system is an IS.
25836392Ssklower  */
25937469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
26043071Ssklower struct	ifnet *ifp;			/* outgoing interface */
26143071Ssklower struct	sockaddr_iso *dest;	/* destination */
26243071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
26343071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
26436392Ssklower {
26543071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
26643071Ssklower 	caddr_t	found_snpa;
26743071Ssklower 	int 	addrlen;
26836392Ssklower 
26936392Ssklower 	/*
27036392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
27136392Ssklower 	 *	addresss embedded in the destination nsap address
27236392Ssklower 	 */
27343071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
27436392Ssklower 		/*
27536392Ssklower 		 *	This is a subnetwork address. Return it immediately
27636392Ssklower 		 */
27736392Ssklower 		IFDEBUG(D_SNPA)
27836392Ssklower 			printf("iso_snparesolve: return SN address\n");
27936392Ssklower 		ENDDEBUG
28043071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
28143071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
28236392Ssklower 	/*
28343071Ssklower 	 * If we are an IS, we can't do much with the packet;
28443071Ssklower 	 *	Check if we know about an IS.
28536392Ssklower 	 */
28643071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
28743071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
28843071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
28943071Ssklower 		register struct sockaddr_dl *sdl =
29043071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
29143071Ssklower 		found_snpa = LLADDR(sdl);
29243071Ssklower 		addrlen = sdl->sdl_alen;
29343071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
29443071Ssklower 		/*
29543071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
29643071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
29743071Ssklower 		 *
29843071Ssklower 		 *	Note: there is a potential problem here. If the destination
29943071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
30043071Ssklower 		 *	does send back a TP CC, a connection could be established
30143071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
30236392Ssklower 		 */
30343071Ssklower 		addrlen = ifp->if_addrlen;
30443071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
30543071Ssklower 	} else
30643071Ssklower 		return (ENETUNREACH);
30743071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
30836392Ssklower 	return (0);
30936392Ssklower }
31036392Ssklower 
31136392Ssklower 
31236392Ssklower /*
31336392Ssklower  * FUNCTION:		snpac_free
31436392Ssklower  *
31536392Ssklower  * PURPOSE:			free an entry in the iso address map table
31636392Ssklower  *
31736392Ssklower  * RETURNS:			nothing
31836392Ssklower  *
31936392Ssklower  * SIDE EFFECTS:
32036392Ssklower  *
32136392Ssklower  * NOTES:			If there is a route entry associated with cache
32236392Ssklower  *					entry, then delete that as well
32336392Ssklower  */
snpac_free(lc)32443071Ssklower snpac_free(lc)
32543071Ssklower register struct llinfo_llc *lc;		/* entry to free */
32636392Ssklower {
32743071Ssklower 	register struct rtentry *rt = lc->lc_rt;
32837469Ssklower 	register struct iso_addr *r;
32936392Ssklower 
33043071Ssklower 	if (known_is == rt)
33143071Ssklower 		known_is = 0;
33243071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
33343071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
33437469Ssklower 			RTFREE(rt);
33537469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
33637469Ssklower 						rt->rt_flags, (struct rtentry **)0);
33737469Ssklower 		RTFREE(rt);
33836392Ssklower 	}
33936392Ssklower }
34036392Ssklower 
34136392Ssklower /*
34236392Ssklower  * FUNCTION:		snpac_add
34336392Ssklower  *
34436392Ssklower  * PURPOSE:			Add an entry to the snpa cache
34536392Ssklower  *
34636392Ssklower  * RETURNS:
34736392Ssklower  *
34836392Ssklower  * SIDE EFFECTS:
34936392Ssklower  *
35036392Ssklower  * NOTES:			If entry already exists, then update holding time.
35136392Ssklower  */
35243334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
35336392Ssklower struct ifnet		*ifp;		/* interface info is related to */
35436392Ssklower struct iso_addr		*nsap;		/* nsap to add */
35536392Ssklower caddr_t				snpa;		/* translation */
35636392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
35737469Ssklower u_short				ht;			/* holding time (in seconds) */
35843334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
35936392Ssklower {
36043071Ssklower 	register struct	llinfo_llc *lc;
36143334Ssklower 	register struct rtentry *rt;
36243334Ssklower 	struct	rtentry *mrt = 0;
36343071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
36443071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
36552625Ssklower 	int		new_entry = 0, index = ifp->if_index, iftype = ifp->if_type;
36636392Ssklower 
36743334Ssklower 	IFDEBUG(D_SNPA)
36843334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
36943334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
37043334Ssklower 	ENDDEBUG
37143071Ssklower 	zap_isoaddr(dst, nsap);
37243071Ssklower 	rt = rtalloc1(S(dst), 0);
37343334Ssklower 	IFDEBUG(D_SNPA)
37443334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
37543334Ssklower 	ENDDEBUG
37643071Ssklower 	if (rt == 0) {
37743334Ssklower 		struct sockaddr *netmask;
37843334Ssklower 		int flags;
37943334Ssklower 		add:
38043334Ssklower 		if (nsellength) {
38143334Ssklower 			netmask = S(msk); flags = RTF_UP;
38243334Ssklower 			snpac_fixdstandmask(nsellength);
38343334Ssklower 		} else {
38443334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
38543334Ssklower 		}
38643071Ssklower 		new_entry = 1;
38743071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
38852625Ssklower 		gte_dl.sdl_type = iftype;
38943334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
39043334Ssklower 			mrt == 0)
39143071Ssklower 			return (0);
39243334Ssklower 		rt = mrt;
39343334Ssklower 		rt->rt_refcnt--;
39443071Ssklower 	} else {
39543071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
39643334Ssklower 		rt->rt_refcnt--;
39743334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
39843334Ssklower 			goto add;
39943334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
40043334Ssklower 			if (rt->rt_refcnt == 0) {
40143334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
40268261Scgd 					(struct sockaddr *)0, 0, (struct rtentry **)0);
40343334Ssklower 				rt = 0;
40443334Ssklower 				goto add;
40543334Ssklower 			} else {
40643334Ssklower 				static struct iso_addr nsap2; register char *cp;
40743334Ssklower 				nsap2 = *nsap;
40843334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
40943334Ssklower 				while (cp < (char *)(1 + &nsap2))
41043334Ssklower 					*cp++ = 0;
41143334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
41243334Ssklower 			}
41343334Ssklower 		}
41443071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
41543071Ssklower 			int old_sdl_len = sdl->sdl_len;
41643334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
41747274Ssklower 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
41843071Ssklower 				return (0);
41943334Ssklower 			}
42043071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
42143071Ssklower 			sdl->sdl_len = old_sdl_len;
42252625Ssklower 			sdl->sdl_type = iftype;
42343071Ssklower 			new_entry = 1;
42443071Ssklower 		}
42536392Ssklower 	}
42643334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
42743334Ssklower 		panic("snpac_rtrequest");
42850230Ssklower 	rt->rt_rmx.rmx_expire = ht + time.tv_sec;
42943071Ssklower 	lc->lc_flags = SNPA_VALID | type;
43053691Ssklower 	if ((type & SNPA_IS) && !(iso_systype & SNPA_IS))
43143071Ssklower 		snpac_logdefis(rt);
43243334Ssklower 	return (new_entry);
43336392Ssklower }
43436392Ssklower 
43550230Ssklower static void
snpac_fixdstandmask(nsellength)43650230Ssklower snpac_fixdstandmask(nsellength)
43743334Ssklower {
43843334Ssklower 	register char *cp = msk.siso_data, *cplim;
43943334Ssklower 
44043334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
44143334Ssklower 	msk.siso_len = cplim - (char *)&msk;
44243334Ssklower 	msk.siso_nlen = 0;
44343334Ssklower 	while (cp < cplim)
44443334Ssklower 		*cp++ = -1;
44543334Ssklower 	while (cp < (char *)msk.siso_pad)
44643334Ssklower 		*cp++ = 0;
44743334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
44843334Ssklower 		*cp++ = 0;
44943334Ssklower }
45043334Ssklower 
45136392Ssklower /*
45236392Ssklower  * FUNCTION:		snpac_ioctl
45336392Ssklower  *
45436392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
45536392Ssklower  *
45636392Ssklower  * RETURNS:			0 on success, or unix error code
45736392Ssklower  *
45836392Ssklower  * SIDE EFFECTS:
45936392Ssklower  *
46036392Ssklower  * NOTES:
46136392Ssklower  */
46250230Ssklower snpac_ioctl (so, cmd, data)
46350230Ssklower struct socket *so;
46468165Scgd u_long	cmd;	/* ioctl to process */
46536392Ssklower caddr_t	data;	/* data for the cmd */
46636392Ssklower {
46736392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
46836392Ssklower 
46943334Ssklower 	IFDEBUG(D_IOCTL)
47036392Ssklower 		if (cmd == SIOCSSTYPE)
47143071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
47236392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
47336392Ssklower 		else
47443071Ssklower 			printf("snpac_ioctl: cmd get\n");
47536392Ssklower 	ENDDEBUG
47636392Ssklower 
47736392Ssklower 	if (cmd == SIOCSSTYPE) {
47850230Ssklower 		if ((so->so_state & SS_PRIV) == 0)
47950230Ssklower 			return (EPERM);
48036392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
48136392Ssklower 			return(EINVAL);
48236392Ssklower 		if (rq->sr_type & SNPA_ES) {
48336392Ssklower 			iso_systype = SNPA_ES;
48436392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
48536392Ssklower 			iso_systype = SNPA_IS;
48636392Ssklower 		} else {
48736392Ssklower 			return(EINVAL);
48836392Ssklower 		}
48936392Ssklower 		esis_holding_time = rq->sr_holdt;
49036392Ssklower 		esis_config_time = rq->sr_configt;
49143423Ssklower 		if (esis_esconfig_time != rq->sr_esconfigt) {
49243423Ssklower 			untimeout(esis_config, (caddr_t)0);
49343423Ssklower 			esis_esconfig_time = rq->sr_esconfigt;
49443423Ssklower 			esis_config();
49543423Ssklower 		}
49636392Ssklower 	} else if (cmd == SIOCGSTYPE) {
49736392Ssklower 		rq->sr_type = iso_systype;
49836392Ssklower 		rq->sr_holdt = esis_holding_time;
49936392Ssklower 		rq->sr_configt = esis_config_time;
50043423Ssklower 		rq->sr_esconfigt = esis_esconfig_time;
50136392Ssklower 	} else {
50243071Ssklower 		return (EINVAL);
50336392Ssklower 	}
50443071Ssklower 	return (0);
50536392Ssklower }
50636392Ssklower 
50736392Ssklower /*
50836392Ssklower  * FUNCTION:		snpac_logdefis
50936392Ssklower  *
51036392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
51136392Ssklower  *
51236392Ssklower  * RETURNS:			nothing
51336392Ssklower  *
51436392Ssklower  * SIDE EFFECTS:
51536392Ssklower  *
51636392Ssklower  * NOTES:
51736392Ssklower  */
snpac_logdefis(sc)51836392Ssklower snpac_logdefis(sc)
51943071Ssklower register struct rtentry *sc;
52036392Ssklower {
52137469Ssklower 	register struct iso_addr *r;
52243071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
52353691Ssklower 	register struct rtentry *rt;
52443071Ssklower 
52553691Ssklower 	if (known_is == sc || !(sc->rt_flags & RTF_HOST))
52637469Ssklower 		return;
52753691Ssklower 	if (known_is) {
52853691Ssklower 		RTFREE(known_is);
52937469Ssklower 	}
53053691Ssklower 	known_is = sc;
53153691Ssklower 	sc->rt_refcnt++;
53253691Ssklower 	rt = rtalloc1((struct sockaddr *)&zsi, 0);
53353691Ssklower 	if (rt == 0)
53453691Ssklower 		rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk),
53553691Ssklower 						RTF_DYNAMIC|RTF_GATEWAY, 0);
53653691Ssklower 	else {
53753691Ssklower 		if ((rt->rt_flags & RTF_DYNAMIC) &&
53853691Ssklower 		    (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0)
53953691Ssklower 			rt_setgate(rt, rt_key(rt), rt_key(sc));
54037469Ssklower 	}
54136392Ssklower }
54236392Ssklower 
54336392Ssklower /*
54436392Ssklower  * FUNCTION:		snpac_age
54536392Ssklower  *
54636392Ssklower  * PURPOSE:			Time out snpac entries
54736392Ssklower  *
54836392Ssklower  * RETURNS:
54936392Ssklower  *
55036392Ssklower  * SIDE EFFECTS:
55136392Ssklower  *
55236392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
55336392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
55436392Ssklower  *					if the entry is added a moment before snpac_age is
55536392Ssklower  *					called, the entry will immediately have SNPAC_AGE
55636392Ssklower  *					seconds taken off the holding time, even though
55736392Ssklower  *					it has only been held a brief moment.
55836392Ssklower  *
55936392Ssklower  *					The proper way to do this is set an expiry timeval
56036392Ssklower  *					equal to current time + holding time. Then snpac_age
56136392Ssklower  *					would time out entries where expiry date is older
56236392Ssklower  *					than the current time.
56336392Ssklower  */
56458990Ssklower void
snpac_age()56536392Ssklower snpac_age()
56636392Ssklower {
56750230Ssklower 	register struct	llinfo_llc *lc, *nlc;
56850230Ssklower 	register struct	rtentry *rt;
56936392Ssklower 
57036392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
57136392Ssklower 
57250230Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) {
57350230Ssklower 		nlc = lc->lc_next;
57453691Ssklower 		if (lc->lc_flags & SNPA_VALID) {
57550230Ssklower 			rt = lc->lc_rt;
57650230Ssklower 			if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec)
57750230Ssklower 				snpac_free(lc);
57836392Ssklower 		}
57936392Ssklower 	}
58036392Ssklower }
58136392Ssklower 
58236392Ssklower /*
58336392Ssklower  * FUNCTION:		snpac_ownmulti
58436392Ssklower  *
58536392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
58636392Ssklower  *					of the same type as the system.
58736392Ssklower  *
58836392Ssklower  * RETURNS:			true or false
58936392Ssklower  *
59036392Ssklower  * SIDE EFFECTS:
59136392Ssklower  *
59236392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
59336392Ssklower  *					as interm kludge until
59436392Ssklower  *					real multicast addresses can be configured
59536392Ssklower  */
snpac_ownmulti(snpa,len)59636392Ssklower snpac_ownmulti(snpa, len)
59743071Ssklower caddr_t	snpa;
59843071Ssklower u_int	len;
59936392Ssklower {
60037469Ssklower 	return (((iso_systype & SNPA_ES) &&
60143071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
60237469Ssklower 			((iso_systype & SNPA_IS) &&
60343071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
60436392Ssklower }
60536392Ssklower 
60636392Ssklower /*
60736392Ssklower  * FUNCTION:		snpac_flushifp
60836392Ssklower  *
60936392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
61036392Ssklower  *
61136392Ssklower  * RETURNS:			nothing
61236392Ssklower  *
61336392Ssklower  * SIDE EFFECTS:
61436392Ssklower  *
61536392Ssklower  * NOTES:
61636392Ssklower  */
61736392Ssklower snpac_flushifp(ifp)
61836392Ssklower struct ifnet	*ifp;
61936392Ssklower {
62043071Ssklower 	register struct llinfo_llc	*lc;
62136392Ssklower 
62243071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
62343071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
62443071Ssklower 			snpac_free(lc);
62536392Ssklower 	}
62636392Ssklower }
62736392Ssklower 
62836392Ssklower /*
62936392Ssklower  * FUNCTION:		snpac_rtrequest
63036392Ssklower  *
63136392Ssklower  * PURPOSE:			Make a routing request
63236392Ssklower  *
63336392Ssklower  * RETURNS:			nothing
63436392Ssklower  *
63536392Ssklower  * SIDE EFFECTS:
63636392Ssklower  *
63736392Ssklower  * NOTES:			In the future, this should make a request of a user
63836392Ssklower  *					level routing daemon.
63936392Ssklower  */
snpac_rtrequest(req,host,gateway,netmask,flags,ret_nrt)64037469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
64136392Ssklower int				req;
64237469Ssklower struct iso_addr	*host;
64336392Ssklower struct iso_addr	*gateway;
64437469Ssklower struct iso_addr	*netmask;
64536392Ssklower short			flags;
64637469Ssklower struct rtentry	**ret_nrt;
64736392Ssklower {
64837469Ssklower 	register struct iso_addr *r;
64936392Ssklower 
65036392Ssklower 	IFDEBUG(D_SNPA)
65136392Ssklower 		printf("snpac_rtrequest: ");
65237469Ssklower 		if (req == RTM_ADD)
65336392Ssklower 			printf("add");
65437469Ssklower 		else if (req == RTM_DELETE)
65536392Ssklower 			printf("delete");
65636392Ssklower 		else
65736392Ssklower 			printf("unknown command");
65837469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
65936392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
66036392Ssklower 	ENDDEBUG
66136392Ssklower 
66236392Ssklower 
66337469Ssklower 	zap_isoaddr(dst, host);
66437469Ssklower 	zap_isoaddr(gte, gateway);
66543334Ssklower 	if (netmask) {
66643334Ssklower 		zap_isoaddr(msk, netmask);
66743334Ssklower 		msk.siso_nlen = 0;
66843334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
66943334Ssklower 	}
67037469Ssklower 
67137469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
67237469Ssklower 		flags, ret_nrt);
67336392Ssklower }
67436392Ssklower 
67536392Ssklower /*
67636392Ssklower  * FUNCTION:		snpac_addrt
67736392Ssklower  *
67836392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
67936392Ssklower  *
68036392Ssklower  * RETURNS:			nothing
68136392Ssklower  *
68236392Ssklower  * SIDE EFFECTS:
68336392Ssklower  *
68436392Ssklower  * NOTES:			If a cache entry exists for gateway, then
68536392Ssklower  *					make a routing entry (host, gateway) and associate
68636392Ssklower  *					with gateway.
68736392Ssklower  *
68836392Ssklower  *					If a route already exists and is different, first delete
68936392Ssklower  *					it.
69036392Ssklower  *
69136392Ssklower  *					This could be made more efficient by checking
69236392Ssklower  *					the existing route before adding a new one.
69336392Ssklower  */
69439950Ssklower snpac_addrt(ifp, host, gateway, netmask)
69539950Ssklower struct ifnet *ifp;
69639950Ssklower struct iso_addr	*host, *gateway, *netmask;
69736392Ssklower {
69837469Ssklower 	register struct iso_addr *r;
69936392Ssklower 
70043071Ssklower 	zap_isoaddr(dst, host);
70143071Ssklower 	zap_isoaddr(gte, gateway);
70243071Ssklower 	if (netmask) {
70343334Ssklower 		zap_isoaddr(msk, netmask);
70443334Ssklower 		msk.siso_nlen = 0;
70543334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
70643071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
70743071Ssklower 	} else
70843071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
70943071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
71036392Ssklower }
71161288Ssklower #endif	/* ISO */
712