xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 48732)
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*48732Ssklower /*	@(#)iso_snpac.c	7.12 (Berkeley) 04/26/91 */
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"
4947274Ssklower #include "syslog.h"
5036392Ssklower 
5136392Ssklower #include "../net/if.h"
5243071Ssklower #include "../net/if_dl.h"
5336392Ssklower #include "../net/route.h"
5436392Ssklower 
5537469Ssklower #include "iso.h"
5637469Ssklower #include "iso_var.h"
5737469Ssklower #include "iso_snpac.h"
5837469Ssklower #include "clnp.h"
5937469Ssklower #include "clnp_stat.h"
6038841Ssklower #include "esis.h"
6137469Ssklower #include "argo_debug.h"
6236392Ssklower 
6336392Ssklower int 				iso_systype = SNPA_ES;	/* default to be an ES */
6443423Ssklower extern short	esis_holding_time, esis_config_time, esis_esconfig_time;
6543423Ssklower extern int esis_config();
6636392Ssklower 
6737469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
6837469Ssklower extern u_long iso_hashchar();
6937469Ssklower static struct sockaddr_iso
7037469Ssklower 	dst	= {sizeof(dst), AF_ISO},
7137469Ssklower 	gte	= {sizeof(dst), AF_ISO},
7237469Ssklower 	src	= {sizeof(dst), AF_ISO},
7337469Ssklower 	msk	= {sizeof(dst), AF_ISO},
7437469Ssklower 	zmk = {1};
7537469Ssklower #define zsi blank_siso
7637469Ssklower #define zero_isoa	zsi.siso_addr
7737469Ssklower #define zap_isoaddr(a, b) (bzero((caddr_t)&a.siso_addr, sizeof(*r)), \
7837469Ssklower 	   ((r = b) && bcopy((caddr_t)r, (caddr_t)&a.siso_addr, 1 + (r)->isoa_len)))
7937469Ssklower #define S(x) ((struct sockaddr *)&(x))
8037469Ssklower 
8143071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
8243071Ssklower static struct sockaddr_dl gte_dl;
8343071Ssklower #define zap_linkaddr(a, b, c, i) \
8443071Ssklower 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
8536392Ssklower 
8636392Ssklower /*
8736392Ssklower  *	We only keep track of a single IS at a time.
8836392Ssklower  */
8943071Ssklower struct rtentry	*known_is;
9036392Ssklower 
9136392Ssklower /*
9236392Ssklower  *	Addresses taken from NBS agreements, December 1987.
9336392Ssklower  *
9436392Ssklower  *	These addresses assume on-the-wire transmission of least significant
9536392Ssklower  *	bit first. This is the method used by 802.3. When these
9636392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
9736392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
9836392Ssklower  *
9936392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
10036392Ssklower  *	true token ring multicast addresses. More work is necessary
10136392Ssklower  *	to get multicast to work right on token ring.
10236392Ssklower  *
10336392Ssklower  *	Currently, the token ring driver does not handle multicast, so
10436392Ssklower  *	these addresses are converted into the broadcast address in
10536392Ssklower  *	lan_output() That means that if these multicast addresses change
10636392Ssklower  *	the token ring driver must be altered.
10736392Ssklower  */
10843334Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 };
10943334Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 };
11045898Ssklower char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14};
11145898Ssklower char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15};
11236392Ssklower 
11343071Ssklower union sockunion {
11443071Ssklower 	struct sockaddr_iso siso;
11543071Ssklower 	struct sockaddr_dl	sdl;
11643071Ssklower 	struct sockaddr		sa;
11743071Ssklower };
11836392Ssklower 
11936392Ssklower /*
12043071Ssklower  * FUNCTION:		llc_rtrequest
12143071Ssklower  *
12243071Ssklower  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
12343071Ssklower  *
12443071Ssklower  * NOTES:			This does a lot of obscure magic;
12543071Ssklower  */
12643071Ssklower llc_rtrequest(req, rt, sa)
12743071Ssklower int req;
12843071Ssklower register struct rtentry *rt;
12943071Ssklower struct sockaddr *sa;
13043071Ssklower {
13143071Ssklower 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
13243071Ssklower 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
13343071Ssklower 	struct rtentry *rt2;
13443071Ssklower 	struct ifnet *ifp = rt->rt_ifp;
13543071Ssklower 	int addrlen = ifp->if_addrlen;
13643334Ssklower 	static struct rtentry *recursing = 0;
137*48732Ssklower #define LLC_SIZE 3 /* XXXXXX do this right later */
13843071Ssklower 
13943334Ssklower 	IFDEBUG (D_SNPA)
14043334Ssklower 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
14143334Ssklower 	ENDDEBUG
14243334Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
14343334Ssklower 		if (recursing) {
14447274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: gateway route points to same type %x %x\n",
14543334Ssklower 				recursing, rt);
14643334Ssklower 		} else switch (req) {
14743334Ssklower 		case RTM_RESOLVE:
14843334Ssklower 		case RTM_ADD:
14943334Ssklower 			recursing = rt;
15043334Ssklower 			rt->rt_llinfo = (caddr_t)rtalloc1(&gate->sa, 1);
15143334Ssklower 			recursing = 0;
152*48732Ssklower 			if (rt->rt_rmx.rmx_mtu == 0) {
153*48732Ssklower 				rt->rt_rmx.rmx_mtu =
154*48732Ssklower 				    ((rt2 = (struct rtentry *)rt->rt_llinfo) &&
155*48732Ssklower 					    (rt2->rt_rmx.rmx_mtu)) ?
156*48732Ssklower 				    rt2->rt_rmx.rmx_mtu :
157*48732Ssklower 				    rt->rt_ifp->if_mtu - LLC_SIZE;
158*48732Ssklower 			}
15943334Ssklower 			return;
16043334Ssklower 
16143334Ssklower 		case RTM_DELETE:
16243334Ssklower 			if (lc)
16343334Ssklower 				RTFREE((struct rtentry *)lc);
16443334Ssklower 			rt->rt_llinfo = 0;
16543071Ssklower 		}
16643334Ssklower 	} else switch (req) {
16743071Ssklower 	case RTM_ADD:
16843334Ssklower 		/*
16943334Ssklower 		 * Case 1: This route may come from a route to iface with mask
17043334Ssklower 		 * or from a default route.
17143334Ssklower 		 */
17243071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
17343334Ssklower 			register struct ifaddr *ifa;
17443334Ssklower 			register struct sockaddr *sa;
17543334Ssklower 			for (ifa = ifp->if_addrlist; ifa; ifa->ifa_next)
17643334Ssklower 				if ((sa = ifa->ifa_addr)->sa_family == AF_LINK) {
17743334Ssklower 					if (sa->sa_len > gate->sa.sa_len)
17847274Ssklower 						log(LOG_DEBUG, "llc_rtrequest: cloning address too small\n");
17943334Ssklower 					else {
18043334Ssklower 						Bcopy(sa, gate, gate->sa.sa_len);
18143334Ssklower 						gate->sdl.sdl_alen = 0;
18243334Ssklower 					}
183*48732Ssklower 					break;
18443071Ssklower 				}
18543334Ssklower 			if (ifa == 0)
18647274Ssklower 				log(LOG_DEBUG, "llc_rtrequest: can't find LL ifaddr for iface\n");
187*48732Ssklower 			break;
18843071Ssklower 		}
18943334Ssklower 		/* FALLTHROUGH */
19043334Ssklower 	case RTM_RESOLVE:
19143334Ssklower 		/*
19243334Ssklower 		 * Case 2:  This route may come from cloning, or a manual route
19343334Ssklower 		 * add with a LL address.
19443334Ssklower 		 */
19543334Ssklower 		if (gate->sdl.sdl_family != AF_LINK) {
19647274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
197*48732Ssklower 			break;
19843334Ssklower 		}
19943334Ssklower 		if (lc != 0)
20047274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: losing old rt_llinfo\n");
20143334Ssklower 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
20243334Ssklower 		rt->rt_llinfo = (caddr_t)lc;
20343334Ssklower 		if (lc == 0) {
20447274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
205*48732Ssklower 			break;
20643334Ssklower 		}
20743334Ssklower 		Bzero(lc, sizeof(*lc));
20843334Ssklower 		lc->lc_rt = rt;
20943334Ssklower 		rt->rt_flags |= RTF_LLINFO;
21043334Ssklower 		insque(lc, &llinfo_llc);
21143334Ssklower 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
21243334Ssklower 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
21343334Ssklower 			bcopy(addrlen + LLADDR(&gate->sdl),
21443334Ssklower 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
21543334Ssklower 		} else if (gate->sdl.sdl_alen == addrlen)
21643334Ssklower 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
21743071Ssklower 		break;
21843071Ssklower 	case RTM_DELETE:
21943334Ssklower 		if (lc == 0 || (rt->rt_flags & RTF_CLONING))
22043334Ssklower 			return;
22143334Ssklower 		remque(lc);
22243334Ssklower 		Free(lc);
22343334Ssklower 		rt->rt_llinfo = 0;
22443334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
22543071Ssklower 		break;
22643071Ssklower 	}
227*48732Ssklower 	if (rt->rt_rmx.rmx_mtu == 0) {
228*48732Ssklower 			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
229*48732Ssklower 	}
23043071Ssklower }
23143071Ssklower /*
23236392Ssklower  * FUNCTION:		iso_snparesolve
23336392Ssklower  *
23436392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
23536392Ssklower  *
23636392Ssklower  * RETURNS:			0 if addr is resolved
23736392Ssklower  *					errno if addr is unknown
23836392Ssklower  *
23936392Ssklower  * SIDE EFFECTS:
24036392Ssklower  *
24143071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
24243071Ssklower  *					table, we know there is no snpa address known for this
24343071Ssklower  *					destination.  If we know of a default IS, then the address
24443071Ssklower  *					of the IS is returned.  If no IS is known, then return the
24543071Ssklower  *					multi-cast address for "all ES" for this interface.
24636392Ssklower  *
24736392Ssklower  *					NB: the last case described above constitutes the
24836392Ssklower  *					query configuration function 9542, sec 6.5
24936392Ssklower  *					A mechanism is needed to prevent this function from
25036392Ssklower  *					being invoked if the system is an IS.
25136392Ssklower  */
25237469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
25343071Ssklower struct	ifnet *ifp;			/* outgoing interface */
25443071Ssklower struct	sockaddr_iso *dest;	/* destination */
25543071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
25643071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
25736392Ssklower {
25843071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
25943071Ssklower 	caddr_t	found_snpa;
26043071Ssklower 	int 	addrlen;
26136392Ssklower 
26236392Ssklower 	/*
26336392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
26436392Ssklower 	 *	addresss embedded in the destination nsap address
26536392Ssklower 	 */
26643071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
26736392Ssklower 		/*
26836392Ssklower 		 *	This is a subnetwork address. Return it immediately
26936392Ssklower 		 */
27036392Ssklower 		IFDEBUG(D_SNPA)
27136392Ssklower 			printf("iso_snparesolve: return SN address\n");
27236392Ssklower 		ENDDEBUG
27343071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
27443071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
27536392Ssklower 	/*
27643071Ssklower 	 * If we are an IS, we can't do much with the packet;
27743071Ssklower 	 *	Check if we know about an IS.
27836392Ssklower 	 */
27943071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
28043071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
28143071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
28243071Ssklower 		register struct sockaddr_dl *sdl =
28343071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
28443071Ssklower 		found_snpa = LLADDR(sdl);
28543071Ssklower 		addrlen = sdl->sdl_alen;
28643071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
28743071Ssklower 		/*
28843071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
28943071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
29043071Ssklower 		 *
29143071Ssklower 		 *	Note: there is a potential problem here. If the destination
29243071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
29343071Ssklower 		 *	does send back a TP CC, a connection could be established
29443071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
29536392Ssklower 		 */
29643071Ssklower 		addrlen = ifp->if_addrlen;
29743071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
29843071Ssklower 	} else
29943071Ssklower 		return (ENETUNREACH);
30043071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
30136392Ssklower 	return (0);
30236392Ssklower }
30336392Ssklower 
30436392Ssklower 
30536392Ssklower /*
30636392Ssklower  * FUNCTION:		snpac_free
30736392Ssklower  *
30836392Ssklower  * PURPOSE:			free an entry in the iso address map table
30936392Ssklower  *
31036392Ssklower  * RETURNS:			nothing
31136392Ssklower  *
31236392Ssklower  * SIDE EFFECTS:
31336392Ssklower  *
31436392Ssklower  * NOTES:			If there is a route entry associated with cache
31536392Ssklower  *					entry, then delete that as well
31636392Ssklower  */
31743071Ssklower snpac_free(lc)
31843071Ssklower register struct llinfo_llc *lc;		/* entry to free */
31936392Ssklower {
32043071Ssklower 	register struct rtentry *rt = lc->lc_rt;
32137469Ssklower 	register struct iso_addr *r;
32236392Ssklower 
32343071Ssklower 	if (known_is == rt)
32443071Ssklower 		known_is = 0;
32543071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
32643071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
32737469Ssklower 			RTFREE(rt);
32837469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
32937469Ssklower 						rt->rt_flags, (struct rtentry **)0);
33037469Ssklower 		RTFREE(rt);
33136392Ssklower 	}
33236392Ssklower }
33336392Ssklower 
33436392Ssklower /*
33536392Ssklower  * FUNCTION:		snpac_add
33636392Ssklower  *
33736392Ssklower  * PURPOSE:			Add an entry to the snpa cache
33836392Ssklower  *
33936392Ssklower  * RETURNS:
34036392Ssklower  *
34136392Ssklower  * SIDE EFFECTS:
34236392Ssklower  *
34336392Ssklower  * NOTES:			If entry already exists, then update holding time.
34436392Ssklower  */
34543334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
34636392Ssklower struct ifnet		*ifp;		/* interface info is related to */
34736392Ssklower struct iso_addr		*nsap;		/* nsap to add */
34836392Ssklower caddr_t				snpa;		/* translation */
34936392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
35037469Ssklower u_short				ht;			/* holding time (in seconds) */
35143334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
35236392Ssklower {
35343071Ssklower 	register struct	llinfo_llc *lc;
35443334Ssklower 	register struct rtentry *rt;
35543334Ssklower 	struct	rtentry *mrt = 0;
35643071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
35743071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
35843071Ssklower 	int		new_entry = 0, index = ifp->if_index;
35936392Ssklower 
36043334Ssklower 	IFDEBUG(D_SNPA)
36143334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
36243334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
36343334Ssklower 	ENDDEBUG
36443071Ssklower 	zap_isoaddr(dst, nsap);
36543071Ssklower 	rt = rtalloc1(S(dst), 0);
36643334Ssklower 	IFDEBUG(D_SNPA)
36743334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
36843334Ssklower 	ENDDEBUG
36943071Ssklower 	if (rt == 0) {
37043334Ssklower 		struct sockaddr *netmask;
37143334Ssklower 		int flags;
37243334Ssklower 		add:
37343334Ssklower 		if (nsellength) {
37443334Ssklower 			netmask = S(msk); flags = RTF_UP;
37543334Ssklower 			snpac_fixdstandmask(nsellength);
37643334Ssklower 		} else {
37743334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
37843334Ssklower 		}
37943071Ssklower 		new_entry = 1;
38043071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
38143334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
38243334Ssklower 			mrt == 0)
38343071Ssklower 			return (0);
38443334Ssklower 		rt = mrt;
38543334Ssklower 		rt->rt_refcnt--;
38643071Ssklower 	} else {
38743071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
38843334Ssklower 		rt->rt_refcnt--;
38943334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
39043334Ssklower 			goto add;
39143334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
39243334Ssklower 			if (rt->rt_refcnt == 0) {
39343334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
39443334Ssklower 					(struct sockaddr *)0, 0, (struct rtentry *)0);
39543334Ssklower 				rt = 0;
39643334Ssklower 				goto add;
39743334Ssklower 			} else {
39843334Ssklower 				static struct iso_addr nsap2; register char *cp;
39943334Ssklower 				nsap2 = *nsap;
40043334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
40143334Ssklower 				while (cp < (char *)(1 + &nsap2))
40243334Ssklower 					*cp++ = 0;
40343334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
40443334Ssklower 			}
40543334Ssklower 		}
40643071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
40743071Ssklower 			int old_sdl_len = sdl->sdl_len;
40843334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
40947274Ssklower 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
41043071Ssklower 				return (0);
41143334Ssklower 			}
41243071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
41343071Ssklower 			sdl->sdl_len = old_sdl_len;
41443071Ssklower 			new_entry = 1;
41543071Ssklower 		}
41636392Ssklower 	}
41743334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
41843334Ssklower 		panic("snpac_rtrequest");
41943334Ssklower 	rt->rt_idle = ht;
42043071Ssklower 	lc->lc_flags = SNPA_VALID | type;
42136392Ssklower 	if (type & SNPA_IS)
42243071Ssklower 		snpac_logdefis(rt);
42343334Ssklower 	return (new_entry);
42436392Ssklower }
42536392Ssklower 
42643334Ssklower static snpac_fixdstandmask(nsellength)
42743334Ssklower {
42843334Ssklower 	register char *cp = msk.siso_data, *cplim;
42943334Ssklower 
43043334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
43143334Ssklower 	msk.siso_len = cplim - (char *)&msk;
43243334Ssklower 	msk.siso_nlen = 0;
43343334Ssklower 	while (cp < cplim)
43443334Ssklower 		*cp++ = -1;
43543334Ssklower 	while (cp < (char *)msk.siso_pad)
43643334Ssklower 		*cp++ = 0;
43743334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
43843334Ssklower 		*cp++ = 0;
43943334Ssklower }
44043334Ssklower 
44136392Ssklower /*
44236392Ssklower  * FUNCTION:		snpac_ioctl
44336392Ssklower  *
44436392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
44536392Ssklower  *
44636392Ssklower  * RETURNS:			0 on success, or unix error code
44736392Ssklower  *
44836392Ssklower  * SIDE EFFECTS:
44936392Ssklower  *
45036392Ssklower  * NOTES:
45136392Ssklower  */
45243071Ssklower snpac_ioctl (cmd, data)
45336392Ssklower int		cmd;	/* ioctl to process */
45436392Ssklower caddr_t	data;	/* data for the cmd */
45536392Ssklower {
45636392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
45736392Ssklower 
45843334Ssklower 	IFDEBUG(D_IOCTL)
45936392Ssklower 		if (cmd == SIOCSSTYPE)
46043071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
46136392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
46236392Ssklower 		else
46343071Ssklower 			printf("snpac_ioctl: cmd get\n");
46436392Ssklower 	ENDDEBUG
46536392Ssklower 
46636392Ssklower 	if (cmd == SIOCSSTYPE) {
46737551Smckusick 		if (suser(u.u_cred, &u.u_acflag))
46836392Ssklower 			return(EACCES);
46936392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
47036392Ssklower 			return(EINVAL);
47136392Ssklower 		if (rq->sr_type & SNPA_ES) {
47236392Ssklower 			iso_systype = SNPA_ES;
47336392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
47436392Ssklower 			iso_systype = SNPA_IS;
47536392Ssklower 		} else {
47636392Ssklower 			return(EINVAL);
47736392Ssklower 		}
47836392Ssklower 		esis_holding_time = rq->sr_holdt;
47936392Ssklower 		esis_config_time = rq->sr_configt;
48043423Ssklower 		if (esis_esconfig_time != rq->sr_esconfigt) {
48143423Ssklower 			untimeout(esis_config, (caddr_t)0);
48243423Ssklower 			esis_esconfig_time = rq->sr_esconfigt;
48343423Ssklower 			esis_config();
48443423Ssklower 		}
48536392Ssklower 	} else if (cmd == SIOCGSTYPE) {
48636392Ssklower 		rq->sr_type = iso_systype;
48736392Ssklower 		rq->sr_holdt = esis_holding_time;
48836392Ssklower 		rq->sr_configt = esis_config_time;
48943423Ssklower 		rq->sr_esconfigt = esis_esconfig_time;
49036392Ssklower 	} else {
49143071Ssklower 		return (EINVAL);
49236392Ssklower 	}
49343071Ssklower 	return (0);
49436392Ssklower }
49536392Ssklower 
49636392Ssklower /*
49736392Ssklower  * FUNCTION:		snpac_logdefis
49836392Ssklower  *
49936392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
50036392Ssklower  *
50136392Ssklower  * RETURNS:			nothing
50236392Ssklower  *
50336392Ssklower  * SIDE EFFECTS:
50436392Ssklower  *
50536392Ssklower  * NOTES:
50636392Ssklower  */
50736392Ssklower snpac_logdefis(sc)
50843071Ssklower register struct rtentry *sc;
50936392Ssklower {
51037469Ssklower 	register struct iso_addr *r;
51143071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
51237469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
51343071Ssklower 
51443071Ssklower 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
51537469Ssklower 	if (known_is == 0)
51637469Ssklower 		known_is = sc;
51737469Ssklower 	if (known_is != sc) {
51843071Ssklower 		rtfree(known_is);
51937469Ssklower 		known_is = sc;
52036392Ssklower 	}
52137469Ssklower 	if (rt == 0) {
52243071Ssklower 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
52343071Ssklower 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
52437469Ssklower 		return;
52537469Ssklower 	}
52643334Ssklower 	rt->rt_refcnt--;
52737469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
52843071Ssklower 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
52937469Ssklower 	}
53036392Ssklower }
53136392Ssklower 
53236392Ssklower /*
53336392Ssklower  * FUNCTION:		snpac_age
53436392Ssklower  *
53536392Ssklower  * PURPOSE:			Time out snpac entries
53636392Ssklower  *
53736392Ssklower  * RETURNS:
53836392Ssklower  *
53936392Ssklower  * SIDE EFFECTS:
54036392Ssklower  *
54136392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
54236392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
54336392Ssklower  *					if the entry is added a moment before snpac_age is
54436392Ssklower  *					called, the entry will immediately have SNPAC_AGE
54536392Ssklower  *					seconds taken off the holding time, even though
54636392Ssklower  *					it has only been held a brief moment.
54736392Ssklower  *
54836392Ssklower  *					The proper way to do this is set an expiry timeval
54936392Ssklower  *					equal to current time + holding time. Then snpac_age
55036392Ssklower  *					would time out entries where expiry date is older
55136392Ssklower  *					than the current time.
55236392Ssklower  */
55336392Ssklower snpac_age()
55436392Ssklower {
55543071Ssklower 	register struct llinfo_llc	*lc;
55636392Ssklower 
55736392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
55836392Ssklower 
55943071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
56043071Ssklower 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
56143334Ssklower 			lc->lc_rt->rt_idle -= SNPAC_AGE;
56243334Ssklower 			if (lc->lc_rt->rt_idle > 0)
56336392Ssklower 				continue;
56436392Ssklower 			else
56543071Ssklower 				snpac_free(lc);
56636392Ssklower 		}
56736392Ssklower 	}
56836392Ssklower }
56936392Ssklower 
57036392Ssklower /*
57136392Ssklower  * FUNCTION:		snpac_ownmulti
57236392Ssklower  *
57336392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
57436392Ssklower  *					of the same type as the system.
57536392Ssklower  *
57636392Ssklower  * RETURNS:			true or false
57736392Ssklower  *
57836392Ssklower  * SIDE EFFECTS:
57936392Ssklower  *
58036392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
58136392Ssklower  *					as interm kludge until
58236392Ssklower  *					real multicast addresses can be configured
58336392Ssklower  */
58436392Ssklower snpac_ownmulti(snpa, len)
58543071Ssklower caddr_t	snpa;
58643071Ssklower u_int	len;
58736392Ssklower {
58837469Ssklower 	return (((iso_systype & SNPA_ES) &&
58943071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
59037469Ssklower 			((iso_systype & SNPA_IS) &&
59143071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
59236392Ssklower }
59336392Ssklower 
59436392Ssklower /*
59536392Ssklower  * FUNCTION:		snpac_flushifp
59636392Ssklower  *
59736392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
59836392Ssklower  *
59936392Ssklower  * RETURNS:			nothing
60036392Ssklower  *
60136392Ssklower  * SIDE EFFECTS:
60236392Ssklower  *
60336392Ssklower  * NOTES:
60436392Ssklower  */
60536392Ssklower snpac_flushifp(ifp)
60636392Ssklower struct ifnet	*ifp;
60736392Ssklower {
60843071Ssklower 	register struct llinfo_llc	*lc;
60936392Ssklower 
61043071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
61143071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
61243071Ssklower 			snpac_free(lc);
61336392Ssklower 	}
61436392Ssklower }
61536392Ssklower 
61636392Ssklower /*
61736392Ssklower  * FUNCTION:		snpac_rtrequest
61836392Ssklower  *
61936392Ssklower  * PURPOSE:			Make a routing request
62036392Ssklower  *
62136392Ssklower  * RETURNS:			nothing
62236392Ssklower  *
62336392Ssklower  * SIDE EFFECTS:
62436392Ssklower  *
62536392Ssklower  * NOTES:			In the future, this should make a request of a user
62636392Ssklower  *					level routing daemon.
62736392Ssklower  */
62837469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
62936392Ssklower int				req;
63037469Ssklower struct iso_addr	*host;
63136392Ssklower struct iso_addr	*gateway;
63237469Ssklower struct iso_addr	*netmask;
63336392Ssklower short			flags;
63437469Ssklower struct rtentry	**ret_nrt;
63536392Ssklower {
63637469Ssklower 	register struct iso_addr *r;
63736392Ssklower 
63836392Ssklower 	IFDEBUG(D_SNPA)
63936392Ssklower 		printf("snpac_rtrequest: ");
64037469Ssklower 		if (req == RTM_ADD)
64136392Ssklower 			printf("add");
64237469Ssklower 		else if (req == RTM_DELETE)
64336392Ssklower 			printf("delete");
64436392Ssklower 		else
64536392Ssklower 			printf("unknown command");
64637469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
64736392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
64836392Ssklower 	ENDDEBUG
64936392Ssklower 
65036392Ssklower 
65137469Ssklower 	zap_isoaddr(dst, host);
65237469Ssklower 	zap_isoaddr(gte, gateway);
65343334Ssklower 	if (netmask) {
65443334Ssklower 		zap_isoaddr(msk, netmask);
65543334Ssklower 		msk.siso_nlen = 0;
65643334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
65743334Ssklower 	}
65837469Ssklower 
65937469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
66037469Ssklower 		flags, ret_nrt);
66136392Ssklower }
66236392Ssklower 
66336392Ssklower /*
66436392Ssklower  * FUNCTION:		snpac_addrt
66536392Ssklower  *
66636392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
66736392Ssklower  *
66836392Ssklower  * RETURNS:			nothing
66936392Ssklower  *
67036392Ssklower  * SIDE EFFECTS:
67136392Ssklower  *
67236392Ssklower  * NOTES:			If a cache entry exists for gateway, then
67336392Ssklower  *					make a routing entry (host, gateway) and associate
67436392Ssklower  *					with gateway.
67536392Ssklower  *
67636392Ssklower  *					If a route already exists and is different, first delete
67736392Ssklower  *					it.
67836392Ssklower  *
67936392Ssklower  *					This could be made more efficient by checking
68036392Ssklower  *					the existing route before adding a new one.
68136392Ssklower  */
68239950Ssklower snpac_addrt(ifp, host, gateway, netmask)
68339950Ssklower struct ifnet *ifp;
68439950Ssklower struct iso_addr	*host, *gateway, *netmask;
68536392Ssklower {
68637469Ssklower 	register struct iso_addr *r;
68736392Ssklower 
68843071Ssklower 	zap_isoaddr(dst, host);
68943071Ssklower 	zap_isoaddr(gte, gateway);
69043071Ssklower 	if (netmask) {
69143334Ssklower 		zap_isoaddr(msk, netmask);
69243334Ssklower 		msk.siso_nlen = 0;
69343334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
69443071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
69543071Ssklower 	} else
69643071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
69743071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
69836392Ssklower }
69936392Ssklower #endif	ISO
700