xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 43423)
136392Ssklower /***********************************************************
236392Ssklower 		Copyright IBM Corporation 1987
336392Ssklower 
436392Ssklower                       All Rights Reserved
536392Ssklower 
636392Ssklower Permission to use, copy, modify, and distribute this software and its
736392Ssklower documentation for any purpose and without fee is hereby granted,
836392Ssklower provided that the above copyright notice appear in all copies and that
936392Ssklower both that copyright notice and this permission notice appear in
1036392Ssklower supporting documentation, and that the name of IBM not be
1136392Ssklower used in advertising or publicity pertaining to distribution of the
1236392Ssklower software without specific, written prior permission.
1336392Ssklower 
1436392Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536392Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636392Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736392Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836392Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936392Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036392Ssklower SOFTWARE.
2136392Ssklower 
2236392Ssklower ******************************************************************/
2336392Ssklower 
2436392Ssklower /*
2536392Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636392Ssklower  */
2736392Ssklower /* $Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $ */
2836392Ssklower /* $Source: /usr/argo/sys/netiso/RCS/iso_snpac.c,v $ */
29*43423Ssklower /*	@(#)iso_snpac.c	7.9 (Berkeley) 06/22/90 */
3036392Ssklower 
3136392Ssklower #ifndef lint
3236392Ssklower static char *rcsid = "$Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $";
3336392Ssklower #endif lint
3436392Ssklower 
3536392Ssklower #ifdef ISO
3636392Ssklower 
3737469Ssklower #include "types.h"
3837469Ssklower #include "param.h"
3943071Ssklower #include "systm.h"
4037551Smckusick #include "user.h"
4137469Ssklower #include "mbuf.h"
4237469Ssklower #include "domain.h"
4337469Ssklower #include "protosw.h"
4437469Ssklower #include "socket.h"
4537469Ssklower #include "socketvar.h"
4637469Ssklower #include "errno.h"
4737469Ssklower #include "ioctl.h"
4837469Ssklower #include "kernel.h"
4936392Ssklower 
5036392Ssklower #include "../net/if.h"
5143071Ssklower #include "../net/if_dl.h"
5236392Ssklower #include "../net/route.h"
5336392Ssklower 
5437469Ssklower #include "iso.h"
5537469Ssklower #include "iso_var.h"
5637469Ssklower #include "iso_snpac.h"
5737469Ssklower #include "clnp.h"
5837469Ssklower #include "clnp_stat.h"
5938841Ssklower #include "esis.h"
6037469Ssklower #include "argo_debug.h"
6136392Ssklower 
6236392Ssklower int 				iso_systype = SNPA_ES;	/* default to be an ES */
63*43423Ssklower extern short	esis_holding_time, esis_config_time, esis_esconfig_time;
64*43423Ssklower extern int esis_config();
6536392Ssklower 
6637469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
6737469Ssklower extern u_long iso_hashchar();
6837469Ssklower static struct sockaddr_iso
6937469Ssklower 	dst	= {sizeof(dst), AF_ISO},
7037469Ssklower 	gte	= {sizeof(dst), AF_ISO},
7137469Ssklower 	src	= {sizeof(dst), AF_ISO},
7237469Ssklower 	msk	= {sizeof(dst), AF_ISO},
7337469Ssklower 	zmk = {1};
7437469Ssklower #define zsi blank_siso
7537469Ssklower #define zero_isoa	zsi.siso_addr
7637469Ssklower #define zap_isoaddr(a, b) (bzero((caddr_t)&a.siso_addr, sizeof(*r)), \
7737469Ssklower 	   ((r = b) && bcopy((caddr_t)r, (caddr_t)&a.siso_addr, 1 + (r)->isoa_len)))
7837469Ssklower #define S(x) ((struct sockaddr *)&(x))
7937469Ssklower 
8043071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
8143071Ssklower static struct sockaddr_dl gte_dl;
8243071Ssklower #define zap_linkaddr(a, b, c, i) \
8343071Ssklower 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
8436392Ssklower 
8536392Ssklower /*
8636392Ssklower  *	We only keep track of a single IS at a time.
8736392Ssklower  */
8843071Ssklower struct rtentry	*known_is;
8936392Ssklower 
9036392Ssklower /*
9136392Ssklower  *	Addresses taken from NBS agreements, December 1987.
9236392Ssklower  *
9336392Ssklower  *	These addresses assume on-the-wire transmission of least significant
9436392Ssklower  *	bit first. This is the method used by 802.3. When these
9536392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
9636392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
9736392Ssklower  *
9836392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
9936392Ssklower  *	true token ring multicast addresses. More work is necessary
10036392Ssklower  *	to get multicast to work right on token ring.
10136392Ssklower  *
10236392Ssklower  *	Currently, the token ring driver does not handle multicast, so
10336392Ssklower  *	these addresses are converted into the broadcast address in
10436392Ssklower  *	lan_output() That means that if these multicast addresses change
10536392Ssklower  *	the token ring driver must be altered.
10636392Ssklower  */
10743334Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 };
10843334Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 };
10936392Ssklower 
11043071Ssklower union sockunion {
11143071Ssklower 	struct sockaddr_iso siso;
11243071Ssklower 	struct sockaddr_dl	sdl;
11343071Ssklower 	struct sockaddr		sa;
11443071Ssklower };
11536392Ssklower 
11636392Ssklower /*
11743071Ssklower  * FUNCTION:		llc_rtrequest
11843071Ssklower  *
11943071Ssklower  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
12043071Ssklower  *
12143071Ssklower  * NOTES:			This does a lot of obscure magic;
12243071Ssklower  */
12343071Ssklower llc_rtrequest(req, rt, sa)
12443071Ssklower int req;
12543071Ssklower register struct rtentry *rt;
12643071Ssklower struct sockaddr *sa;
12743071Ssklower {
12843071Ssklower 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
12943071Ssklower 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
13043071Ssklower 	struct rtentry *rt2;
13143071Ssklower 	struct ifnet *ifp = rt->rt_ifp;
13243071Ssklower 	int addrlen = ifp->if_addrlen;
13343334Ssklower 	static struct rtentry *recursing = 0;
13443071Ssklower 
13543334Ssklower 	IFDEBUG (D_SNPA)
13643334Ssklower 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
13743334Ssklower 	ENDDEBUG
13843334Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
13943334Ssklower 		if (recursing) {
14043334Ssklower 			log("llc_rtrequest: gateway route points to same type %x %x\n",
14143334Ssklower 				recursing, rt);
14243334Ssklower 		} else switch (req) {
14343334Ssklower 		case RTM_RESOLVE:
14443334Ssklower 		case RTM_ADD:
14543334Ssklower 			recursing = rt;
14643334Ssklower 			rt->rt_llinfo = (caddr_t)rtalloc1(&gate->sa, 1);
14743334Ssklower 			recursing = 0;
14843334Ssklower 			return;
14943334Ssklower 
15043334Ssklower 		case RTM_DELETE:
15143334Ssklower 			if (lc)
15243334Ssklower 				RTFREE((struct rtentry *)lc);
15343334Ssklower 			rt->rt_llinfo = 0;
15443071Ssklower 		}
15543334Ssklower 	} else switch (req) {
15643071Ssklower 	case RTM_ADD:
15743334Ssklower 		/*
15843334Ssklower 		 * Case 1: This route may come from a route to iface with mask
15943334Ssklower 		 * or from a default route.
16043334Ssklower 		 */
16143071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
16243334Ssklower 			register struct ifaddr *ifa;
16343334Ssklower 			register struct sockaddr *sa;
16443334Ssklower 			for (ifa = ifp->if_addrlist; ifa; ifa->ifa_next)
16543334Ssklower 				if ((sa = ifa->ifa_addr)->sa_family == AF_LINK) {
16643334Ssklower 					if (sa->sa_len > gate->sa.sa_len)
16743334Ssklower 						log("llc_rtrequest: cloning address too small\n");
16843334Ssklower 					else {
16943334Ssklower 						Bcopy(sa, gate, gate->sa.sa_len);
17043334Ssklower 						gate->sdl.sdl_alen = 0;
17143334Ssklower 					}
17243334Ssklower 					return;
17343071Ssklower 				}
17443334Ssklower 			if (ifa == 0)
17543334Ssklower 				log("llc_rtrequest: can't find LL ifaddr for iface\n");
17643334Ssklower 			return;
17743071Ssklower 		}
17843334Ssklower 		/* FALLTHROUGH */
17943334Ssklower 	case RTM_RESOLVE:
18043334Ssklower 		/*
18143334Ssklower 		 * Case 2:  This route may come from cloning, or a manual route
18243334Ssklower 		 * add with a LL address.
18343334Ssklower 		 */
18443334Ssklower 		if (gate->sdl.sdl_family != AF_LINK) {
18543334Ssklower 			log("llc_rtrequest: got non-link non-gateway route\n");
18643334Ssklower 			return;
18743334Ssklower 		}
18843334Ssklower 		if (lc != 0)
18943334Ssklower 			log("llc_rtrequest: losing old rt_llinfo\n");
19043334Ssklower 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
19143334Ssklower 		rt->rt_llinfo = (caddr_t)lc;
19243334Ssklower 		if (lc == 0) {
19343334Ssklower 			log("llc_rtrequest: malloc failed\n");
19443334Ssklower 			return;
19543334Ssklower 		}
19643334Ssklower 		Bzero(lc, sizeof(*lc));
19743334Ssklower 		lc->lc_rt = rt;
19843334Ssklower 		rt->rt_flags |= RTF_LLINFO;
19943334Ssklower 		insque(lc, &llinfo_llc);
20043334Ssklower 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
20143334Ssklower 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
20243334Ssklower 			bcopy(addrlen + LLADDR(&gate->sdl),
20343334Ssklower 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
20443334Ssklower 		} else if (gate->sdl.sdl_alen == addrlen)
20543334Ssklower 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
20643071Ssklower 		break;
20743071Ssklower 	case RTM_DELETE:
20843334Ssklower 		if (lc == 0 || (rt->rt_flags & RTF_CLONING))
20943334Ssklower 			return;
21043334Ssklower 		remque(lc);
21143334Ssklower 		Free(lc);
21243334Ssklower 		rt->rt_llinfo = 0;
21343334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
21443071Ssklower 		break;
21543071Ssklower 	}
21643071Ssklower }
21743071Ssklower /*
21836392Ssklower  * FUNCTION:		iso_snparesolve
21936392Ssklower  *
22036392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
22136392Ssklower  *
22236392Ssklower  * RETURNS:			0 if addr is resolved
22336392Ssklower  *					errno if addr is unknown
22436392Ssklower  *
22536392Ssklower  * SIDE EFFECTS:
22636392Ssklower  *
22743071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
22843071Ssklower  *					table, we know there is no snpa address known for this
22943071Ssklower  *					destination.  If we know of a default IS, then the address
23043071Ssklower  *					of the IS is returned.  If no IS is known, then return the
23143071Ssklower  *					multi-cast address for "all ES" for this interface.
23236392Ssklower  *
23336392Ssklower  *					NB: the last case described above constitutes the
23436392Ssklower  *					query configuration function 9542, sec 6.5
23536392Ssklower  *					A mechanism is needed to prevent this function from
23636392Ssklower  *					being invoked if the system is an IS.
23736392Ssklower  */
23837469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
23943071Ssklower struct	ifnet *ifp;			/* outgoing interface */
24043071Ssklower struct	sockaddr_iso *dest;	/* destination */
24143071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
24243071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
24336392Ssklower {
24443071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
24543071Ssklower 	caddr_t	found_snpa;
24643071Ssklower 	int 	addrlen;
24736392Ssklower 
24836392Ssklower 	/*
24936392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
25036392Ssklower 	 *	addresss embedded in the destination nsap address
25136392Ssklower 	 */
25243071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
25336392Ssklower 		/*
25436392Ssklower 		 *	This is a subnetwork address. Return it immediately
25536392Ssklower 		 */
25636392Ssklower 		IFDEBUG(D_SNPA)
25736392Ssklower 			printf("iso_snparesolve: return SN address\n");
25836392Ssklower 		ENDDEBUG
25943071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
26043071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
26136392Ssklower 	/*
26243071Ssklower 	 * If we are an IS, we can't do much with the packet;
26343071Ssklower 	 *	Check if we know about an IS.
26436392Ssklower 	 */
26543071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
26643071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
26743071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
26843071Ssklower 		register struct sockaddr_dl *sdl =
26943071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
27043071Ssklower 		found_snpa = LLADDR(sdl);
27143071Ssklower 		addrlen = sdl->sdl_alen;
27243071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
27343071Ssklower 		/*
27443071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
27543071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
27643071Ssklower 		 *
27743071Ssklower 		 *	Note: there is a potential problem here. If the destination
27843071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
27943071Ssklower 		 *	does send back a TP CC, a connection could be established
28043071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
28136392Ssklower 		 */
28243071Ssklower 		addrlen = ifp->if_addrlen;
28343071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
28443071Ssklower 	} else
28543071Ssklower 		return (ENETUNREACH);
28643071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
28736392Ssklower 	return (0);
28836392Ssklower }
28936392Ssklower 
29036392Ssklower 
29136392Ssklower /*
29236392Ssklower  * FUNCTION:		snpac_free
29336392Ssklower  *
29436392Ssklower  * PURPOSE:			free an entry in the iso address map table
29536392Ssklower  *
29636392Ssklower  * RETURNS:			nothing
29736392Ssklower  *
29836392Ssklower  * SIDE EFFECTS:
29936392Ssklower  *
30036392Ssklower  * NOTES:			If there is a route entry associated with cache
30136392Ssklower  *					entry, then delete that as well
30236392Ssklower  */
30343071Ssklower snpac_free(lc)
30443071Ssklower register struct llinfo_llc *lc;		/* entry to free */
30536392Ssklower {
30643071Ssklower 	register struct rtentry *rt = lc->lc_rt;
30737469Ssklower 	register struct iso_addr *r;
30836392Ssklower 
30943071Ssklower 	if (known_is == rt)
31043071Ssklower 		known_is = 0;
31143071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
31243071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
31337469Ssklower 			RTFREE(rt);
31437469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
31537469Ssklower 						rt->rt_flags, (struct rtentry **)0);
31637469Ssklower 		RTFREE(rt);
31736392Ssklower 	}
31836392Ssklower }
31936392Ssklower 
32036392Ssklower /*
32136392Ssklower  * FUNCTION:		snpac_add
32236392Ssklower  *
32336392Ssklower  * PURPOSE:			Add an entry to the snpa cache
32436392Ssklower  *
32536392Ssklower  * RETURNS:
32636392Ssklower  *
32736392Ssklower  * SIDE EFFECTS:
32836392Ssklower  *
32936392Ssklower  * NOTES:			If entry already exists, then update holding time.
33036392Ssklower  */
33143334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
33236392Ssklower struct ifnet		*ifp;		/* interface info is related to */
33336392Ssklower struct iso_addr		*nsap;		/* nsap to add */
33436392Ssklower caddr_t				snpa;		/* translation */
33536392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
33637469Ssklower u_short				ht;			/* holding time (in seconds) */
33743334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
33836392Ssklower {
33943071Ssklower 	register struct	llinfo_llc *lc;
34043334Ssklower 	register struct rtentry *rt;
34143334Ssklower 	struct	rtentry *mrt = 0;
34243071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
34343071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
34443071Ssklower 	int		new_entry = 0, index = ifp->if_index;
34536392Ssklower 
34643334Ssklower 	IFDEBUG(D_SNPA)
34743334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
34843334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
34943334Ssklower 	ENDDEBUG
35043071Ssklower 	zap_isoaddr(dst, nsap);
35143071Ssklower 	rt = rtalloc1(S(dst), 0);
35243334Ssklower 	IFDEBUG(D_SNPA)
35343334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
35443334Ssklower 	ENDDEBUG
35543071Ssklower 	if (rt == 0) {
35643334Ssklower 		struct sockaddr *netmask;
35743334Ssklower 		int flags;
35843334Ssklower 		add:
35943334Ssklower 		if (nsellength) {
36043334Ssklower 			netmask = S(msk); flags = RTF_UP;
36143334Ssklower 			snpac_fixdstandmask(nsellength);
36243334Ssklower 		} else {
36343334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
36443334Ssklower 		}
36543071Ssklower 		new_entry = 1;
36643071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
36743334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
36843334Ssklower 			mrt == 0)
36943071Ssklower 			return (0);
37043334Ssklower 		rt = mrt;
37143334Ssklower 		rt->rt_refcnt--;
37243071Ssklower 	} else {
37343071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
37443334Ssklower 		rt->rt_refcnt--;
37543334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
37643334Ssklower 			goto add;
37743334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
37843334Ssklower 			if (rt->rt_refcnt == 0) {
37943334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
38043334Ssklower 					(struct sockaddr *)0, 0, (struct rtentry *)0);
38143334Ssklower 				rt = 0;
38243334Ssklower 				goto add;
38343334Ssklower 			} else {
38443334Ssklower 				static struct iso_addr nsap2; register char *cp;
38543334Ssklower 				nsap2 = *nsap;
38643334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
38743334Ssklower 				while (cp < (char *)(1 + &nsap2))
38843334Ssklower 					*cp++ = 0;
38943334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
39043334Ssklower 			}
39143334Ssklower 		}
39243071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
39343071Ssklower 			int old_sdl_len = sdl->sdl_len;
39443334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
39543334Ssklower 				log("snpac_add: cant make room for lladdr\n");
39643071Ssklower 				return (0);
39743334Ssklower 			}
39843071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
39943071Ssklower 			sdl->sdl_len = old_sdl_len;
40043071Ssklower 			new_entry = 1;
40143071Ssklower 		}
40236392Ssklower 	}
40343334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
40443334Ssklower 		panic("snpac_rtrequest");
40543334Ssklower 	rt->rt_idle = ht;
40643071Ssklower 	lc->lc_flags = SNPA_VALID | type;
40736392Ssklower 	if (type & SNPA_IS)
40843071Ssklower 		snpac_logdefis(rt);
40943334Ssklower 	return (new_entry);
41036392Ssklower }
41136392Ssklower 
41243334Ssklower static snpac_fixdstandmask(nsellength)
41343334Ssklower {
41443334Ssklower 	register char *cp = msk.siso_data, *cplim;
41543334Ssklower 
41643334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
41743334Ssklower 	msk.siso_len = cplim - (char *)&msk;
41843334Ssklower 	msk.siso_nlen = 0;
41943334Ssklower 	while (cp < cplim)
42043334Ssklower 		*cp++ = -1;
42143334Ssklower 	while (cp < (char *)msk.siso_pad)
42243334Ssklower 		*cp++ = 0;
42343334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
42443334Ssklower 		*cp++ = 0;
42543334Ssklower }
42643334Ssklower 
42736392Ssklower /*
42836392Ssklower  * FUNCTION:		snpac_ioctl
42936392Ssklower  *
43036392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
43136392Ssklower  *
43236392Ssklower  * RETURNS:			0 on success, or unix error code
43336392Ssklower  *
43436392Ssklower  * SIDE EFFECTS:
43536392Ssklower  *
43636392Ssklower  * NOTES:
43736392Ssklower  */
43843071Ssklower snpac_ioctl (cmd, data)
43936392Ssklower int		cmd;	/* ioctl to process */
44036392Ssklower caddr_t	data;	/* data for the cmd */
44136392Ssklower {
44236392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
44336392Ssklower 
44443334Ssklower 	IFDEBUG(D_IOCTL)
44536392Ssklower 		if (cmd == SIOCSSTYPE)
44643071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
44736392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
44836392Ssklower 		else
44943071Ssklower 			printf("snpac_ioctl: cmd get\n");
45036392Ssklower 	ENDDEBUG
45136392Ssklower 
45236392Ssklower 	if (cmd == SIOCSSTYPE) {
45337551Smckusick 		if (suser(u.u_cred, &u.u_acflag))
45436392Ssklower 			return(EACCES);
45536392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
45636392Ssklower 			return(EINVAL);
45736392Ssklower 		if (rq->sr_type & SNPA_ES) {
45836392Ssklower 			iso_systype = SNPA_ES;
45936392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
46036392Ssklower 			iso_systype = SNPA_IS;
46136392Ssklower 		} else {
46236392Ssklower 			return(EINVAL);
46336392Ssklower 		}
46436392Ssklower 		esis_holding_time = rq->sr_holdt;
46536392Ssklower 		esis_config_time = rq->sr_configt;
466*43423Ssklower 		if (esis_esconfig_time != rq->sr_esconfigt) {
467*43423Ssklower 			untimeout(esis_config, (caddr_t)0);
468*43423Ssklower 			esis_esconfig_time = rq->sr_esconfigt;
469*43423Ssklower 			esis_config();
470*43423Ssklower 		}
47136392Ssklower 	} else if (cmd == SIOCGSTYPE) {
47236392Ssklower 		rq->sr_type = iso_systype;
47336392Ssklower 		rq->sr_holdt = esis_holding_time;
47436392Ssklower 		rq->sr_configt = esis_config_time;
475*43423Ssklower 		rq->sr_esconfigt = esis_esconfig_time;
47636392Ssklower 	} else {
47743071Ssklower 		return (EINVAL);
47836392Ssklower 	}
47943071Ssklower 	return (0);
48036392Ssklower }
48136392Ssklower 
48236392Ssklower /*
48336392Ssklower  * FUNCTION:		snpac_logdefis
48436392Ssklower  *
48536392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
48636392Ssklower  *
48736392Ssklower  * RETURNS:			nothing
48836392Ssklower  *
48936392Ssklower  * SIDE EFFECTS:
49036392Ssklower  *
49136392Ssklower  * NOTES:
49236392Ssklower  */
49336392Ssklower snpac_logdefis(sc)
49443071Ssklower register struct rtentry *sc;
49536392Ssklower {
49637469Ssklower 	register struct iso_addr *r;
49743071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
49837469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
49943071Ssklower 
50043071Ssklower 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
50137469Ssklower 	if (known_is == 0)
50237469Ssklower 		known_is = sc;
50337469Ssklower 	if (known_is != sc) {
50443071Ssklower 		rtfree(known_is);
50537469Ssklower 		known_is = sc;
50636392Ssklower 	}
50737469Ssklower 	if (rt == 0) {
50843071Ssklower 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
50943071Ssklower 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
51037469Ssklower 		return;
51137469Ssklower 	}
51243334Ssklower 	rt->rt_refcnt--;
51337469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
51443071Ssklower 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
51537469Ssklower 	}
51636392Ssklower }
51736392Ssklower 
51836392Ssklower /*
51936392Ssklower  * FUNCTION:		snpac_age
52036392Ssklower  *
52136392Ssklower  * PURPOSE:			Time out snpac entries
52236392Ssklower  *
52336392Ssklower  * RETURNS:
52436392Ssklower  *
52536392Ssklower  * SIDE EFFECTS:
52636392Ssklower  *
52736392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
52836392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
52936392Ssklower  *					if the entry is added a moment before snpac_age is
53036392Ssklower  *					called, the entry will immediately have SNPAC_AGE
53136392Ssklower  *					seconds taken off the holding time, even though
53236392Ssklower  *					it has only been held a brief moment.
53336392Ssklower  *
53436392Ssklower  *					The proper way to do this is set an expiry timeval
53536392Ssklower  *					equal to current time + holding time. Then snpac_age
53636392Ssklower  *					would time out entries where expiry date is older
53736392Ssklower  *					than the current time.
53836392Ssklower  */
53936392Ssklower snpac_age()
54036392Ssklower {
54143071Ssklower 	register struct llinfo_llc	*lc;
54236392Ssklower 
54336392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
54436392Ssklower 
54543071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
54643071Ssklower 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
54743334Ssklower 			lc->lc_rt->rt_idle -= SNPAC_AGE;
54843334Ssklower 			if (lc->lc_rt->rt_idle > 0)
54936392Ssklower 				continue;
55036392Ssklower 			else
55143071Ssklower 				snpac_free(lc);
55236392Ssklower 		}
55336392Ssklower 	}
55436392Ssklower }
55536392Ssklower 
55636392Ssklower /*
55736392Ssklower  * FUNCTION:		snpac_ownmulti
55836392Ssklower  *
55936392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
56036392Ssklower  *					of the same type as the system.
56136392Ssklower  *
56236392Ssklower  * RETURNS:			true or false
56336392Ssklower  *
56436392Ssklower  * SIDE EFFECTS:
56536392Ssklower  *
56636392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
56736392Ssklower  *					as interm kludge until
56836392Ssklower  *					real multicast addresses can be configured
56936392Ssklower  */
57036392Ssklower snpac_ownmulti(snpa, len)
57143071Ssklower caddr_t	snpa;
57243071Ssklower u_int	len;
57336392Ssklower {
57437469Ssklower 	return (((iso_systype & SNPA_ES) &&
57543071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
57637469Ssklower 			((iso_systype & SNPA_IS) &&
57743071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
57836392Ssklower }
57936392Ssklower 
58036392Ssklower /*
58136392Ssklower  * FUNCTION:		snpac_flushifp
58236392Ssklower  *
58336392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
58436392Ssklower  *
58536392Ssklower  * RETURNS:			nothing
58636392Ssklower  *
58736392Ssklower  * SIDE EFFECTS:
58836392Ssklower  *
58936392Ssklower  * NOTES:
59036392Ssklower  */
59136392Ssklower snpac_flushifp(ifp)
59236392Ssklower struct ifnet	*ifp;
59336392Ssklower {
59443071Ssklower 	register struct llinfo_llc	*lc;
59536392Ssklower 
59643071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
59743071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
59843071Ssklower 			snpac_free(lc);
59936392Ssklower 	}
60036392Ssklower }
60136392Ssklower 
60236392Ssklower /*
60336392Ssklower  * FUNCTION:		snpac_rtrequest
60436392Ssklower  *
60536392Ssklower  * PURPOSE:			Make a routing request
60636392Ssklower  *
60736392Ssklower  * RETURNS:			nothing
60836392Ssklower  *
60936392Ssklower  * SIDE EFFECTS:
61036392Ssklower  *
61136392Ssklower  * NOTES:			In the future, this should make a request of a user
61236392Ssklower  *					level routing daemon.
61336392Ssklower  */
61437469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
61536392Ssklower int				req;
61637469Ssklower struct iso_addr	*host;
61736392Ssklower struct iso_addr	*gateway;
61837469Ssklower struct iso_addr	*netmask;
61936392Ssklower short			flags;
62037469Ssklower struct rtentry	**ret_nrt;
62136392Ssklower {
62237469Ssklower 	register struct iso_addr *r;
62336392Ssklower 
62436392Ssklower 	IFDEBUG(D_SNPA)
62536392Ssklower 		printf("snpac_rtrequest: ");
62637469Ssklower 		if (req == RTM_ADD)
62736392Ssklower 			printf("add");
62837469Ssklower 		else if (req == RTM_DELETE)
62936392Ssklower 			printf("delete");
63036392Ssklower 		else
63136392Ssklower 			printf("unknown command");
63237469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
63336392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
63436392Ssklower 	ENDDEBUG
63536392Ssklower 
63636392Ssklower 
63737469Ssklower 	zap_isoaddr(dst, host);
63837469Ssklower 	zap_isoaddr(gte, gateway);
63943334Ssklower 	if (netmask) {
64043334Ssklower 		zap_isoaddr(msk, netmask);
64143334Ssklower 		msk.siso_nlen = 0;
64243334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
64343334Ssklower 	}
64437469Ssklower 
64537469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
64637469Ssklower 		flags, ret_nrt);
64736392Ssklower }
64836392Ssklower 
64936392Ssklower /*
65036392Ssklower  * FUNCTION:		snpac_addrt
65136392Ssklower  *
65236392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
65336392Ssklower  *
65436392Ssklower  * RETURNS:			nothing
65536392Ssklower  *
65636392Ssklower  * SIDE EFFECTS:
65736392Ssklower  *
65836392Ssklower  * NOTES:			If a cache entry exists for gateway, then
65936392Ssklower  *					make a routing entry (host, gateway) and associate
66036392Ssklower  *					with gateway.
66136392Ssklower  *
66236392Ssklower  *					If a route already exists and is different, first delete
66336392Ssklower  *					it.
66436392Ssklower  *
66536392Ssklower  *					This could be made more efficient by checking
66636392Ssklower  *					the existing route before adding a new one.
66736392Ssklower  */
66839950Ssklower snpac_addrt(ifp, host, gateway, netmask)
66939950Ssklower struct ifnet *ifp;
67039950Ssklower struct iso_addr	*host, *gateway, *netmask;
67136392Ssklower {
67237469Ssklower 	register struct iso_addr *r;
67336392Ssklower 
67443071Ssklower 	zap_isoaddr(dst, host);
67543071Ssklower 	zap_isoaddr(gte, gateway);
67643071Ssklower 	if (netmask) {
67743334Ssklower 		zap_isoaddr(msk, netmask);
67843334Ssklower 		msk.siso_nlen = 0;
67943334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
68043071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
68143071Ssklower 	} else
68243071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
68343071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
68436392Ssklower }
68536392Ssklower #endif	ISO
686