xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 50231)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*50231Ssklower  *	@(#)iso_snpac.c	7.15 (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;
6750230Ssklower extern struct	timeval time;
6850230Ssklower extern int esis_config(), 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},
7837469Ssklower 	zmk = {1};
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
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;
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
145*50231Ssklower 	if (rt->rt_flags & RTF_GATEWAY)
146*50231Ssklower 		return;
147*50231Ssklower 	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) {
154*50231Ssklower 			rt_setgate(rt, rt_key(rt), &blank_dl);
155*50231Ssklower 			return;
15643071Ssklower 		}
157*50231Ssklower 		if (lc != 0)
158*50231Ssklower 			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:
18743334Ssklower 		if (lc == 0 || (rt->rt_flags & RTF_CLONING))
18843334Ssklower 			return;
18943334Ssklower 		remque(lc);
19043334Ssklower 		Free(lc);
19143334Ssklower 		rt->rt_llinfo = 0;
19243334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
19343071Ssklower 		break;
19443071Ssklower 	}
19548732Ssklower 	if (rt->rt_rmx.rmx_mtu == 0) {
19648732Ssklower 			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
19748732Ssklower 	}
19843071Ssklower }
19943071Ssklower /*
20036392Ssklower  * FUNCTION:		iso_snparesolve
20136392Ssklower  *
20236392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
20336392Ssklower  *
20436392Ssklower  * RETURNS:			0 if addr is resolved
20536392Ssklower  *					errno if addr is unknown
20636392Ssklower  *
20736392Ssklower  * SIDE EFFECTS:
20836392Ssklower  *
20943071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
21043071Ssklower  *					table, we know there is no snpa address known for this
21143071Ssklower  *					destination.  If we know of a default IS, then the address
21243071Ssklower  *					of the IS is returned.  If no IS is known, then return the
21343071Ssklower  *					multi-cast address for "all ES" for this interface.
21436392Ssklower  *
21536392Ssklower  *					NB: the last case described above constitutes the
21636392Ssklower  *					query configuration function 9542, sec 6.5
21736392Ssklower  *					A mechanism is needed to prevent this function from
21836392Ssklower  *					being invoked if the system is an IS.
21936392Ssklower  */
22037469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
22143071Ssklower struct	ifnet *ifp;			/* outgoing interface */
22243071Ssklower struct	sockaddr_iso *dest;	/* destination */
22343071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
22443071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
22536392Ssklower {
22643071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
22743071Ssklower 	caddr_t	found_snpa;
22843071Ssklower 	int 	addrlen;
22936392Ssklower 
23036392Ssklower 	/*
23136392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
23236392Ssklower 	 *	addresss embedded in the destination nsap address
23336392Ssklower 	 */
23443071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
23536392Ssklower 		/*
23636392Ssklower 		 *	This is a subnetwork address. Return it immediately
23736392Ssklower 		 */
23836392Ssklower 		IFDEBUG(D_SNPA)
23936392Ssklower 			printf("iso_snparesolve: return SN address\n");
24036392Ssklower 		ENDDEBUG
24143071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
24243071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
24336392Ssklower 	/*
24443071Ssklower 	 * If we are an IS, we can't do much with the packet;
24543071Ssklower 	 *	Check if we know about an IS.
24636392Ssklower 	 */
24743071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
24843071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
24943071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
25043071Ssklower 		register struct sockaddr_dl *sdl =
25143071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
25243071Ssklower 		found_snpa = LLADDR(sdl);
25343071Ssklower 		addrlen = sdl->sdl_alen;
25443071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
25543071Ssklower 		/*
25643071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
25743071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
25843071Ssklower 		 *
25943071Ssklower 		 *	Note: there is a potential problem here. If the destination
26043071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
26143071Ssklower 		 *	does send back a TP CC, a connection could be established
26243071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
26336392Ssklower 		 */
26443071Ssklower 		addrlen = ifp->if_addrlen;
26543071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
26643071Ssklower 	} else
26743071Ssklower 		return (ENETUNREACH);
26843071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
26936392Ssklower 	return (0);
27036392Ssklower }
27136392Ssklower 
27236392Ssklower 
27336392Ssklower /*
27436392Ssklower  * FUNCTION:		snpac_free
27536392Ssklower  *
27636392Ssklower  * PURPOSE:			free an entry in the iso address map table
27736392Ssklower  *
27836392Ssklower  * RETURNS:			nothing
27936392Ssklower  *
28036392Ssklower  * SIDE EFFECTS:
28136392Ssklower  *
28236392Ssklower  * NOTES:			If there is a route entry associated with cache
28336392Ssklower  *					entry, then delete that as well
28436392Ssklower  */
28543071Ssklower snpac_free(lc)
28643071Ssklower register struct llinfo_llc *lc;		/* entry to free */
28736392Ssklower {
28843071Ssklower 	register struct rtentry *rt = lc->lc_rt;
28937469Ssklower 	register struct iso_addr *r;
29036392Ssklower 
29143071Ssklower 	if (known_is == rt)
29243071Ssklower 		known_is = 0;
29343071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
29443071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
29537469Ssklower 			RTFREE(rt);
29637469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
29737469Ssklower 						rt->rt_flags, (struct rtentry **)0);
29837469Ssklower 		RTFREE(rt);
29936392Ssklower 	}
30036392Ssklower }
30136392Ssklower 
30236392Ssklower /*
30336392Ssklower  * FUNCTION:		snpac_add
30436392Ssklower  *
30536392Ssklower  * PURPOSE:			Add an entry to the snpa cache
30636392Ssklower  *
30736392Ssklower  * RETURNS:
30836392Ssklower  *
30936392Ssklower  * SIDE EFFECTS:
31036392Ssklower  *
31136392Ssklower  * NOTES:			If entry already exists, then update holding time.
31236392Ssklower  */
31343334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
31436392Ssklower struct ifnet		*ifp;		/* interface info is related to */
31536392Ssklower struct iso_addr		*nsap;		/* nsap to add */
31636392Ssklower caddr_t				snpa;		/* translation */
31736392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
31837469Ssklower u_short				ht;			/* holding time (in seconds) */
31943334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
32036392Ssklower {
32143071Ssklower 	register struct	llinfo_llc *lc;
32243334Ssklower 	register struct rtentry *rt;
32343334Ssklower 	struct	rtentry *mrt = 0;
32443071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
32543071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
32643071Ssklower 	int		new_entry = 0, index = ifp->if_index;
32736392Ssklower 
32843334Ssklower 	IFDEBUG(D_SNPA)
32943334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
33043334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
33143334Ssklower 	ENDDEBUG
33243071Ssklower 	zap_isoaddr(dst, nsap);
33343071Ssklower 	rt = rtalloc1(S(dst), 0);
33443334Ssklower 	IFDEBUG(D_SNPA)
33543334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
33643334Ssklower 	ENDDEBUG
33743071Ssklower 	if (rt == 0) {
33843334Ssklower 		struct sockaddr *netmask;
33943334Ssklower 		int flags;
34043334Ssklower 		add:
34143334Ssklower 		if (nsellength) {
34243334Ssklower 			netmask = S(msk); flags = RTF_UP;
34343334Ssklower 			snpac_fixdstandmask(nsellength);
34443334Ssklower 		} else {
34543334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
34643334Ssklower 		}
34743071Ssklower 		new_entry = 1;
34843071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
34943334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
35043334Ssklower 			mrt == 0)
35143071Ssklower 			return (0);
35243334Ssklower 		rt = mrt;
35343334Ssklower 		rt->rt_refcnt--;
35443071Ssklower 	} else {
35543071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
35643334Ssklower 		rt->rt_refcnt--;
35743334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
35843334Ssklower 			goto add;
35943334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
36043334Ssklower 			if (rt->rt_refcnt == 0) {
36143334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
36243334Ssklower 					(struct sockaddr *)0, 0, (struct rtentry *)0);
36343334Ssklower 				rt = 0;
36443334Ssklower 				goto add;
36543334Ssklower 			} else {
36643334Ssklower 				static struct iso_addr nsap2; register char *cp;
36743334Ssklower 				nsap2 = *nsap;
36843334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
36943334Ssklower 				while (cp < (char *)(1 + &nsap2))
37043334Ssklower 					*cp++ = 0;
37143334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
37243334Ssklower 			}
37343334Ssklower 		}
37443071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
37543071Ssklower 			int old_sdl_len = sdl->sdl_len;
37643334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
37747274Ssklower 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
37843071Ssklower 				return (0);
37943334Ssklower 			}
38043071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
38143071Ssklower 			sdl->sdl_len = old_sdl_len;
38243071Ssklower 			new_entry = 1;
38343071Ssklower 		}
38436392Ssklower 	}
38543334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
38643334Ssklower 		panic("snpac_rtrequest");
38750230Ssklower 	rt->rt_rmx.rmx_expire = ht + time.tv_sec;
38843071Ssklower 	lc->lc_flags = SNPA_VALID | type;
38936392Ssklower 	if (type & SNPA_IS)
39043071Ssklower 		snpac_logdefis(rt);
39143334Ssklower 	return (new_entry);
39236392Ssklower }
39336392Ssklower 
39450230Ssklower static void
39550230Ssklower snpac_fixdstandmask(nsellength)
39643334Ssklower {
39743334Ssklower 	register char *cp = msk.siso_data, *cplim;
39843334Ssklower 
39943334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
40043334Ssklower 	msk.siso_len = cplim - (char *)&msk;
40143334Ssklower 	msk.siso_nlen = 0;
40243334Ssklower 	while (cp < cplim)
40343334Ssklower 		*cp++ = -1;
40443334Ssklower 	while (cp < (char *)msk.siso_pad)
40543334Ssklower 		*cp++ = 0;
40643334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
40743334Ssklower 		*cp++ = 0;
40843334Ssklower }
40943334Ssklower 
41036392Ssklower /*
41136392Ssklower  * FUNCTION:		snpac_ioctl
41236392Ssklower  *
41336392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
41436392Ssklower  *
41536392Ssklower  * RETURNS:			0 on success, or unix error code
41636392Ssklower  *
41736392Ssklower  * SIDE EFFECTS:
41836392Ssklower  *
41936392Ssklower  * NOTES:
42036392Ssklower  */
42150230Ssklower snpac_ioctl (so, cmd, data)
42250230Ssklower struct socket *so;
42336392Ssklower int		cmd;	/* ioctl to process */
42436392Ssklower caddr_t	data;	/* data for the cmd */
42536392Ssklower {
42636392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
42736392Ssklower 
42843334Ssklower 	IFDEBUG(D_IOCTL)
42936392Ssklower 		if (cmd == SIOCSSTYPE)
43043071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
43136392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
43236392Ssklower 		else
43343071Ssklower 			printf("snpac_ioctl: cmd get\n");
43436392Ssklower 	ENDDEBUG
43536392Ssklower 
43636392Ssklower 	if (cmd == SIOCSSTYPE) {
43750230Ssklower 		if ((so->so_state & SS_PRIV) == 0)
43850230Ssklower 			return (EPERM);
43936392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
44036392Ssklower 			return(EINVAL);
44136392Ssklower 		if (rq->sr_type & SNPA_ES) {
44236392Ssklower 			iso_systype = SNPA_ES;
44336392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
44436392Ssklower 			iso_systype = SNPA_IS;
44536392Ssklower 		} else {
44636392Ssklower 			return(EINVAL);
44736392Ssklower 		}
44836392Ssklower 		esis_holding_time = rq->sr_holdt;
44936392Ssklower 		esis_config_time = rq->sr_configt;
45043423Ssklower 		if (esis_esconfig_time != rq->sr_esconfigt) {
45143423Ssklower 			untimeout(esis_config, (caddr_t)0);
45243423Ssklower 			esis_esconfig_time = rq->sr_esconfigt;
45343423Ssklower 			esis_config();
45443423Ssklower 		}
45536392Ssklower 	} else if (cmd == SIOCGSTYPE) {
45636392Ssklower 		rq->sr_type = iso_systype;
45736392Ssklower 		rq->sr_holdt = esis_holding_time;
45836392Ssklower 		rq->sr_configt = esis_config_time;
45943423Ssklower 		rq->sr_esconfigt = esis_esconfig_time;
46036392Ssklower 	} else {
46143071Ssklower 		return (EINVAL);
46236392Ssklower 	}
46343071Ssklower 	return (0);
46436392Ssklower }
46536392Ssklower 
46636392Ssklower /*
46736392Ssklower  * FUNCTION:		snpac_logdefis
46836392Ssklower  *
46936392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
47036392Ssklower  *
47136392Ssklower  * RETURNS:			nothing
47236392Ssklower  *
47336392Ssklower  * SIDE EFFECTS:
47436392Ssklower  *
47536392Ssklower  * NOTES:
47636392Ssklower  */
47736392Ssklower snpac_logdefis(sc)
47843071Ssklower register struct rtentry *sc;
47936392Ssklower {
48037469Ssklower 	register struct iso_addr *r;
48143071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
48237469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
48343071Ssklower 
48443071Ssklower 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
48537469Ssklower 	if (known_is == 0)
48637469Ssklower 		known_is = sc;
48737469Ssklower 	if (known_is != sc) {
48843071Ssklower 		rtfree(known_is);
48937469Ssklower 		known_is = sc;
49036392Ssklower 	}
49137469Ssklower 	if (rt == 0) {
49243071Ssklower 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
49343071Ssklower 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
49437469Ssklower 		return;
49537469Ssklower 	}
49643334Ssklower 	rt->rt_refcnt--;
49737469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
49843071Ssklower 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
49937469Ssklower 	}
50036392Ssklower }
50136392Ssklower 
50236392Ssklower /*
50336392Ssklower  * FUNCTION:		snpac_age
50436392Ssklower  *
50536392Ssklower  * PURPOSE:			Time out snpac entries
50636392Ssklower  *
50736392Ssklower  * RETURNS:
50836392Ssklower  *
50936392Ssklower  * SIDE EFFECTS:
51036392Ssklower  *
51136392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
51236392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
51336392Ssklower  *					if the entry is added a moment before snpac_age is
51436392Ssklower  *					called, the entry will immediately have SNPAC_AGE
51536392Ssklower  *					seconds taken off the holding time, even though
51636392Ssklower  *					it has only been held a brief moment.
51736392Ssklower  *
51836392Ssklower  *					The proper way to do this is set an expiry timeval
51936392Ssklower  *					equal to current time + holding time. Then snpac_age
52036392Ssklower  *					would time out entries where expiry date is older
52136392Ssklower  *					than the current time.
52236392Ssklower  */
52336392Ssklower snpac_age()
52436392Ssklower {
52550230Ssklower 	register struct	llinfo_llc *lc, *nlc;
52650230Ssklower 	register struct	rtentry *rt;
52736392Ssklower 
52836392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
52936392Ssklower 
53050230Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) {
53150230Ssklower 		nlc = lc->lc_next;
53243071Ssklower 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
53350230Ssklower 			rt = lc->lc_rt;
53450230Ssklower 			if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec)
53550230Ssklower 				snpac_free(lc);
53650230Ssklower 			else
53736392Ssklower 				continue;
53836392Ssklower 		}
53936392Ssklower 	}
54036392Ssklower }
54136392Ssklower 
54236392Ssklower /*
54336392Ssklower  * FUNCTION:		snpac_ownmulti
54436392Ssklower  *
54536392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
54636392Ssklower  *					of the same type as the system.
54736392Ssklower  *
54836392Ssklower  * RETURNS:			true or false
54936392Ssklower  *
55036392Ssklower  * SIDE EFFECTS:
55136392Ssklower  *
55236392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
55336392Ssklower  *					as interm kludge until
55436392Ssklower  *					real multicast addresses can be configured
55536392Ssklower  */
55636392Ssklower snpac_ownmulti(snpa, len)
55743071Ssklower caddr_t	snpa;
55843071Ssklower u_int	len;
55936392Ssklower {
56037469Ssklower 	return (((iso_systype & SNPA_ES) &&
56143071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
56237469Ssklower 			((iso_systype & SNPA_IS) &&
56343071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
56436392Ssklower }
56536392Ssklower 
56636392Ssklower /*
56736392Ssklower  * FUNCTION:		snpac_flushifp
56836392Ssklower  *
56936392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
57036392Ssklower  *
57136392Ssklower  * RETURNS:			nothing
57236392Ssklower  *
57336392Ssklower  * SIDE EFFECTS:
57436392Ssklower  *
57536392Ssklower  * NOTES:
57636392Ssklower  */
57736392Ssklower snpac_flushifp(ifp)
57836392Ssklower struct ifnet	*ifp;
57936392Ssklower {
58043071Ssklower 	register struct llinfo_llc	*lc;
58136392Ssklower 
58243071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
58343071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
58443071Ssklower 			snpac_free(lc);
58536392Ssklower 	}
58636392Ssklower }
58736392Ssklower 
58836392Ssklower /*
58936392Ssklower  * FUNCTION:		snpac_rtrequest
59036392Ssklower  *
59136392Ssklower  * PURPOSE:			Make a routing request
59236392Ssklower  *
59336392Ssklower  * RETURNS:			nothing
59436392Ssklower  *
59536392Ssklower  * SIDE EFFECTS:
59636392Ssklower  *
59736392Ssklower  * NOTES:			In the future, this should make a request of a user
59836392Ssklower  *					level routing daemon.
59936392Ssklower  */
60037469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
60136392Ssklower int				req;
60237469Ssklower struct iso_addr	*host;
60336392Ssklower struct iso_addr	*gateway;
60437469Ssklower struct iso_addr	*netmask;
60536392Ssklower short			flags;
60637469Ssklower struct rtentry	**ret_nrt;
60736392Ssklower {
60837469Ssklower 	register struct iso_addr *r;
60936392Ssklower 
61036392Ssklower 	IFDEBUG(D_SNPA)
61136392Ssklower 		printf("snpac_rtrequest: ");
61237469Ssklower 		if (req == RTM_ADD)
61336392Ssklower 			printf("add");
61437469Ssklower 		else if (req == RTM_DELETE)
61536392Ssklower 			printf("delete");
61636392Ssklower 		else
61736392Ssklower 			printf("unknown command");
61837469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
61936392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
62036392Ssklower 	ENDDEBUG
62136392Ssklower 
62236392Ssklower 
62337469Ssklower 	zap_isoaddr(dst, host);
62437469Ssklower 	zap_isoaddr(gte, gateway);
62543334Ssklower 	if (netmask) {
62643334Ssklower 		zap_isoaddr(msk, netmask);
62743334Ssklower 		msk.siso_nlen = 0;
62843334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
62943334Ssklower 	}
63037469Ssklower 
63137469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
63237469Ssklower 		flags, ret_nrt);
63336392Ssklower }
63436392Ssklower 
63536392Ssklower /*
63636392Ssklower  * FUNCTION:		snpac_addrt
63736392Ssklower  *
63836392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
63936392Ssklower  *
64036392Ssklower  * RETURNS:			nothing
64136392Ssklower  *
64236392Ssklower  * SIDE EFFECTS:
64336392Ssklower  *
64436392Ssklower  * NOTES:			If a cache entry exists for gateway, then
64536392Ssklower  *					make a routing entry (host, gateway) and associate
64636392Ssklower  *					with gateway.
64736392Ssklower  *
64836392Ssklower  *					If a route already exists and is different, first delete
64936392Ssklower  *					it.
65036392Ssklower  *
65136392Ssklower  *					This could be made more efficient by checking
65236392Ssklower  *					the existing route before adding a new one.
65336392Ssklower  */
65439950Ssklower snpac_addrt(ifp, host, gateway, netmask)
65539950Ssklower struct ifnet *ifp;
65639950Ssklower struct iso_addr	*host, *gateway, *netmask;
65736392Ssklower {
65837469Ssklower 	register struct iso_addr *r;
65936392Ssklower 
66043071Ssklower 	zap_isoaddr(dst, host);
66143071Ssklower 	zap_isoaddr(gte, gateway);
66243071Ssklower 	if (netmask) {
66343334Ssklower 		zap_isoaddr(msk, netmask);
66443334Ssklower 		msk.siso_nlen = 0;
66543334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
66643071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
66743071Ssklower 	} else
66843071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
66943071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
67036392Ssklower }
67136392Ssklower #endif	ISO
672