xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 43334)
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*43334Ssklower /*	@(#)iso_snpac.c	7.8 (Berkeley) 06/20/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 */
6336392Ssklower 
6437469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
6537469Ssklower extern u_long iso_hashchar();
6637469Ssklower static struct sockaddr_iso
6737469Ssklower 	dst	= {sizeof(dst), AF_ISO},
6837469Ssklower 	gte	= {sizeof(dst), AF_ISO},
6937469Ssklower 	src	= {sizeof(dst), AF_ISO},
7037469Ssklower 	msk	= {sizeof(dst), AF_ISO},
7137469Ssklower 	zmk = {1};
7237469Ssklower #define zsi blank_siso
7337469Ssklower #define zero_isoa	zsi.siso_addr
7437469Ssklower #define zap_isoaddr(a, b) (bzero((caddr_t)&a.siso_addr, sizeof(*r)), \
7537469Ssklower 	   ((r = b) && bcopy((caddr_t)r, (caddr_t)&a.siso_addr, 1 + (r)->isoa_len)))
7637469Ssklower #define S(x) ((struct sockaddr *)&(x))
7737469Ssklower 
7843071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
7943071Ssklower static struct sockaddr_dl gte_dl;
8043071Ssklower #define zap_linkaddr(a, b, c, i) \
8143071Ssklower 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
8236392Ssklower 
8336392Ssklower /*
8436392Ssklower  *	We only keep track of a single IS at a time.
8536392Ssklower  */
8643071Ssklower struct rtentry	*known_is;
8736392Ssklower 
8836392Ssklower /*
8936392Ssklower  *	Addresses taken from NBS agreements, December 1987.
9036392Ssklower  *
9136392Ssklower  *	These addresses assume on-the-wire transmission of least significant
9236392Ssklower  *	bit first. This is the method used by 802.3. When these
9336392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
9436392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
9536392Ssklower  *
9636392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
9736392Ssklower  *	true token ring multicast addresses. More work is necessary
9836392Ssklower  *	to get multicast to work right on token ring.
9936392Ssklower  *
10036392Ssklower  *	Currently, the token ring driver does not handle multicast, so
10136392Ssklower  *	these addresses are converted into the broadcast address in
10236392Ssklower  *	lan_output() That means that if these multicast addresses change
10336392Ssklower  *	the token ring driver must be altered.
10436392Ssklower  */
105*43334Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 };
106*43334Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 };
10736392Ssklower 
10843071Ssklower union sockunion {
10943071Ssklower 	struct sockaddr_iso siso;
11043071Ssklower 	struct sockaddr_dl	sdl;
11143071Ssklower 	struct sockaddr		sa;
11243071Ssklower };
11336392Ssklower 
11436392Ssklower /*
11543071Ssklower  * FUNCTION:		llc_rtrequest
11643071Ssklower  *
11743071Ssklower  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
11843071Ssklower  *
11943071Ssklower  * NOTES:			This does a lot of obscure magic;
12043071Ssklower  */
12143071Ssklower llc_rtrequest(req, rt, sa)
12243071Ssklower int req;
12343071Ssklower register struct rtentry *rt;
12443071Ssklower struct sockaddr *sa;
12543071Ssklower {
12643071Ssklower 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
12743071Ssklower 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
12843071Ssklower 	struct rtentry *rt2;
12943071Ssklower 	struct ifnet *ifp = rt->rt_ifp;
13043071Ssklower 	int addrlen = ifp->if_addrlen;
131*43334Ssklower 	static struct rtentry *recursing = 0;
13243071Ssklower 
133*43334Ssklower 	IFDEBUG (D_SNPA)
134*43334Ssklower 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
135*43334Ssklower 	ENDDEBUG
136*43334Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
137*43334Ssklower 		if (recursing) {
138*43334Ssklower 			log("llc_rtrequest: gateway route points to same type %x %x\n",
139*43334Ssklower 				recursing, rt);
140*43334Ssklower 		} else switch (req) {
141*43334Ssklower 		case RTM_RESOLVE:
142*43334Ssklower 		case RTM_ADD:
143*43334Ssklower 			recursing = rt;
144*43334Ssklower 			rt->rt_llinfo = (caddr_t)rtalloc1(&gate->sa, 1);
145*43334Ssklower 			recursing = 0;
146*43334Ssklower 			return;
147*43334Ssklower 
148*43334Ssklower 		case RTM_DELETE:
149*43334Ssklower 			if (lc)
150*43334Ssklower 				RTFREE((struct rtentry *)lc);
151*43334Ssklower 			rt->rt_llinfo = 0;
15243071Ssklower 		}
153*43334Ssklower 	} else switch (req) {
15443071Ssklower 	case RTM_ADD:
155*43334Ssklower 		/*
156*43334Ssklower 		 * Case 1: This route may come from a route to iface with mask
157*43334Ssklower 		 * or from a default route.
158*43334Ssklower 		 */
15943071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
160*43334Ssklower 			register struct ifaddr *ifa;
161*43334Ssklower 			register struct sockaddr *sa;
162*43334Ssklower 			for (ifa = ifp->if_addrlist; ifa; ifa->ifa_next)
163*43334Ssklower 				if ((sa = ifa->ifa_addr)->sa_family == AF_LINK) {
164*43334Ssklower 					if (sa->sa_len > gate->sa.sa_len)
165*43334Ssklower 						log("llc_rtrequest: cloning address too small\n");
166*43334Ssklower 					else {
167*43334Ssklower 						Bcopy(sa, gate, gate->sa.sa_len);
168*43334Ssklower 						gate->sdl.sdl_alen = 0;
169*43334Ssklower 					}
170*43334Ssklower 					return;
17143071Ssklower 				}
172*43334Ssklower 			if (ifa == 0)
173*43334Ssklower 				log("llc_rtrequest: can't find LL ifaddr for iface\n");
174*43334Ssklower 			return;
17543071Ssklower 		}
176*43334Ssklower 		/* FALLTHROUGH */
177*43334Ssklower 	case RTM_RESOLVE:
178*43334Ssklower 		/*
179*43334Ssklower 		 * Case 2:  This route may come from cloning, or a manual route
180*43334Ssklower 		 * add with a LL address.
181*43334Ssklower 		 */
182*43334Ssklower 		if (gate->sdl.sdl_family != AF_LINK) {
183*43334Ssklower 			log("llc_rtrequest: got non-link non-gateway route\n");
184*43334Ssklower 			return;
185*43334Ssklower 		}
186*43334Ssklower 		if (lc != 0)
187*43334Ssklower 			log("llc_rtrequest: losing old rt_llinfo\n");
188*43334Ssklower 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
189*43334Ssklower 		rt->rt_llinfo = (caddr_t)lc;
190*43334Ssklower 		if (lc == 0) {
191*43334Ssklower 			log("llc_rtrequest: malloc failed\n");
192*43334Ssklower 			return;
193*43334Ssklower 		}
194*43334Ssklower 		Bzero(lc, sizeof(*lc));
195*43334Ssklower 		lc->lc_rt = rt;
196*43334Ssklower 		rt->rt_flags |= RTF_LLINFO;
197*43334Ssklower 		insque(lc, &llinfo_llc);
198*43334Ssklower 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
199*43334Ssklower 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
200*43334Ssklower 			bcopy(addrlen + LLADDR(&gate->sdl),
201*43334Ssklower 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
202*43334Ssklower 		} else if (gate->sdl.sdl_alen == addrlen)
203*43334Ssklower 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
20443071Ssklower 		break;
20543071Ssklower 	case RTM_DELETE:
206*43334Ssklower 		if (lc == 0 || (rt->rt_flags & RTF_CLONING))
207*43334Ssklower 			return;
208*43334Ssklower 		remque(lc);
209*43334Ssklower 		Free(lc);
210*43334Ssklower 		rt->rt_llinfo = 0;
211*43334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
21243071Ssklower 		break;
21343071Ssklower 	}
21443071Ssklower }
21543071Ssklower /*
21636392Ssklower  * FUNCTION:		iso_snparesolve
21736392Ssklower  *
21836392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
21936392Ssklower  *
22036392Ssklower  * RETURNS:			0 if addr is resolved
22136392Ssklower  *					errno if addr is unknown
22236392Ssklower  *
22336392Ssklower  * SIDE EFFECTS:
22436392Ssklower  *
22543071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
22643071Ssklower  *					table, we know there is no snpa address known for this
22743071Ssklower  *					destination.  If we know of a default IS, then the address
22843071Ssklower  *					of the IS is returned.  If no IS is known, then return the
22943071Ssklower  *					multi-cast address for "all ES" for this interface.
23036392Ssklower  *
23136392Ssklower  *					NB: the last case described above constitutes the
23236392Ssklower  *					query configuration function 9542, sec 6.5
23336392Ssklower  *					A mechanism is needed to prevent this function from
23436392Ssklower  *					being invoked if the system is an IS.
23536392Ssklower  */
23637469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
23743071Ssklower struct	ifnet *ifp;			/* outgoing interface */
23843071Ssklower struct	sockaddr_iso *dest;	/* destination */
23943071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
24043071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
24136392Ssklower {
24243071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
24343071Ssklower 	caddr_t	found_snpa;
24443071Ssklower 	int 	addrlen;
24536392Ssklower 
24636392Ssklower 	/*
24736392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
24836392Ssklower 	 *	addresss embedded in the destination nsap address
24936392Ssklower 	 */
25043071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
25136392Ssklower 		/*
25236392Ssklower 		 *	This is a subnetwork address. Return it immediately
25336392Ssklower 		 */
25436392Ssklower 		IFDEBUG(D_SNPA)
25536392Ssklower 			printf("iso_snparesolve: return SN address\n");
25636392Ssklower 		ENDDEBUG
25743071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
25843071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
25936392Ssklower 	/*
26043071Ssklower 	 * If we are an IS, we can't do much with the packet;
26143071Ssklower 	 *	Check if we know about an IS.
26236392Ssklower 	 */
26343071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
26443071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
26543071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
26643071Ssklower 		register struct sockaddr_dl *sdl =
26743071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
26843071Ssklower 		found_snpa = LLADDR(sdl);
26943071Ssklower 		addrlen = sdl->sdl_alen;
27043071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
27143071Ssklower 		/*
27243071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
27343071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
27443071Ssklower 		 *
27543071Ssklower 		 *	Note: there is a potential problem here. If the destination
27643071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
27743071Ssklower 		 *	does send back a TP CC, a connection could be established
27843071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
27936392Ssklower 		 */
28043071Ssklower 		addrlen = ifp->if_addrlen;
28143071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
28243071Ssklower 	} else
28343071Ssklower 		return (ENETUNREACH);
28443071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
28536392Ssklower 	return (0);
28636392Ssklower }
28736392Ssklower 
28836392Ssklower 
28936392Ssklower /*
29036392Ssklower  * FUNCTION:		snpac_free
29136392Ssklower  *
29236392Ssklower  * PURPOSE:			free an entry in the iso address map table
29336392Ssklower  *
29436392Ssklower  * RETURNS:			nothing
29536392Ssklower  *
29636392Ssklower  * SIDE EFFECTS:
29736392Ssklower  *
29836392Ssklower  * NOTES:			If there is a route entry associated with cache
29936392Ssklower  *					entry, then delete that as well
30036392Ssklower  */
30143071Ssklower snpac_free(lc)
30243071Ssklower register struct llinfo_llc *lc;		/* entry to free */
30336392Ssklower {
30443071Ssklower 	register struct rtentry *rt = lc->lc_rt;
30537469Ssklower 	register struct iso_addr *r;
30636392Ssklower 
30743071Ssklower 	if (known_is == rt)
30843071Ssklower 		known_is = 0;
30943071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
31043071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
31137469Ssklower 			RTFREE(rt);
31237469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
31337469Ssklower 						rt->rt_flags, (struct rtentry **)0);
31437469Ssklower 		RTFREE(rt);
31536392Ssklower 	}
31636392Ssklower }
31736392Ssklower 
31836392Ssklower /*
31936392Ssklower  * FUNCTION:		snpac_add
32036392Ssklower  *
32136392Ssklower  * PURPOSE:			Add an entry to the snpa cache
32236392Ssklower  *
32336392Ssklower  * RETURNS:
32436392Ssklower  *
32536392Ssklower  * SIDE EFFECTS:
32636392Ssklower  *
32736392Ssklower  * NOTES:			If entry already exists, then update holding time.
32836392Ssklower  */
329*43334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
33036392Ssklower struct ifnet		*ifp;		/* interface info is related to */
33136392Ssklower struct iso_addr		*nsap;		/* nsap to add */
33236392Ssklower caddr_t				snpa;		/* translation */
33336392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
33437469Ssklower u_short				ht;			/* holding time (in seconds) */
335*43334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
33636392Ssklower {
33743071Ssklower 	register struct	llinfo_llc *lc;
338*43334Ssklower 	register struct rtentry *rt;
339*43334Ssklower 	struct	rtentry *mrt = 0;
34043071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
34143071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
34243071Ssklower 	int		new_entry = 0, index = ifp->if_index;
34336392Ssklower 
344*43334Ssklower 	IFDEBUG(D_SNPA)
345*43334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
346*43334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
347*43334Ssklower 	ENDDEBUG
34843071Ssklower 	zap_isoaddr(dst, nsap);
34943071Ssklower 	rt = rtalloc1(S(dst), 0);
350*43334Ssklower 	IFDEBUG(D_SNPA)
351*43334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
352*43334Ssklower 	ENDDEBUG
35343071Ssklower 	if (rt == 0) {
354*43334Ssklower 		struct sockaddr *netmask;
355*43334Ssklower 		int flags;
356*43334Ssklower 		add:
357*43334Ssklower 		if (nsellength) {
358*43334Ssklower 			netmask = S(msk); flags = RTF_UP;
359*43334Ssklower 			snpac_fixdstandmask(nsellength);
360*43334Ssklower 		} else {
361*43334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
362*43334Ssklower 		}
36343071Ssklower 		new_entry = 1;
36443071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
365*43334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
366*43334Ssklower 			mrt == 0)
36743071Ssklower 			return (0);
368*43334Ssklower 		rt = mrt;
369*43334Ssklower 		rt->rt_refcnt--;
37043071Ssklower 	} else {
37143071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
372*43334Ssklower 		rt->rt_refcnt--;
373*43334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
374*43334Ssklower 			goto add;
375*43334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
376*43334Ssklower 			if (rt->rt_refcnt == 0) {
377*43334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
378*43334Ssklower 					(struct sockaddr *)0, 0, (struct rtentry *)0);
379*43334Ssklower 				rt = 0;
380*43334Ssklower 				goto add;
381*43334Ssklower 			} else {
382*43334Ssklower 				static struct iso_addr nsap2; register char *cp;
383*43334Ssklower 				nsap2 = *nsap;
384*43334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
385*43334Ssklower 				while (cp < (char *)(1 + &nsap2))
386*43334Ssklower 					*cp++ = 0;
387*43334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
388*43334Ssklower 			}
389*43334Ssklower 		}
39043071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
39143071Ssklower 			int old_sdl_len = sdl->sdl_len;
392*43334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
393*43334Ssklower 				log("snpac_add: cant make room for lladdr\n");
39443071Ssklower 				return (0);
395*43334Ssklower 			}
39643071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
39743071Ssklower 			sdl->sdl_len = old_sdl_len;
39843071Ssklower 			new_entry = 1;
39943071Ssklower 		}
40036392Ssklower 	}
401*43334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
402*43334Ssklower 		panic("snpac_rtrequest");
403*43334Ssklower 	rt->rt_idle = ht;
40443071Ssklower 	lc->lc_flags = SNPA_VALID | type;
40536392Ssklower 	if (type & SNPA_IS)
40643071Ssklower 		snpac_logdefis(rt);
407*43334Ssklower 	return (new_entry);
40836392Ssklower }
40936392Ssklower 
410*43334Ssklower static snpac_fixdstandmask(nsellength)
411*43334Ssklower {
412*43334Ssklower 	register char *cp = msk.siso_data, *cplim;
413*43334Ssklower 
414*43334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
415*43334Ssklower 	msk.siso_len = cplim - (char *)&msk;
416*43334Ssklower 	msk.siso_nlen = 0;
417*43334Ssklower 	while (cp < cplim)
418*43334Ssklower 		*cp++ = -1;
419*43334Ssklower 	while (cp < (char *)msk.siso_pad)
420*43334Ssklower 		*cp++ = 0;
421*43334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
422*43334Ssklower 		*cp++ = 0;
423*43334Ssklower }
424*43334Ssklower 
42536392Ssklower /*
42636392Ssklower  * FUNCTION:		snpac_ioctl
42736392Ssklower  *
42836392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
42936392Ssklower  *
43036392Ssklower  * RETURNS:			0 on success, or unix error code
43136392Ssklower  *
43236392Ssklower  * SIDE EFFECTS:
43336392Ssklower  *
43436392Ssklower  * NOTES:
43536392Ssklower  */
43643071Ssklower snpac_ioctl (cmd, data)
43736392Ssklower int		cmd;	/* ioctl to process */
43836392Ssklower caddr_t	data;	/* data for the cmd */
43936392Ssklower {
44036392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
44136392Ssklower 	extern short	esis_holding_time, esis_config_time;
44236392Ssklower 
443*43334Ssklower 	IFDEBUG(D_IOCTL)
44436392Ssklower 		if (cmd == SIOCSSTYPE)
44543071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
44636392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
44736392Ssklower 		else
44843071Ssklower 			printf("snpac_ioctl: cmd get\n");
44936392Ssklower 	ENDDEBUG
45036392Ssklower 
45136392Ssklower 	if (cmd == SIOCSSTYPE) {
45237551Smckusick 		if (suser(u.u_cred, &u.u_acflag))
45336392Ssklower 			return(EACCES);
45436392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
45536392Ssklower 			return(EINVAL);
45636392Ssklower 		if (rq->sr_type & SNPA_ES) {
45736392Ssklower 			iso_systype = SNPA_ES;
45836392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
45936392Ssklower 			iso_systype = SNPA_IS;
46036392Ssklower 		} else {
46136392Ssklower 			return(EINVAL);
46236392Ssklower 		}
46336392Ssklower 		esis_holding_time = rq->sr_holdt;
46436392Ssklower 		esis_config_time = rq->sr_configt;
46536392Ssklower 	} else if (cmd == SIOCGSTYPE) {
46636392Ssklower 		rq->sr_type = iso_systype;
46736392Ssklower 		rq->sr_holdt = esis_holding_time;
46836392Ssklower 		rq->sr_configt = esis_config_time;
46936392Ssklower 	} else {
47043071Ssklower 		return (EINVAL);
47136392Ssklower 	}
47243071Ssklower 	return (0);
47336392Ssklower }
47436392Ssklower 
47536392Ssklower /*
47636392Ssklower  * FUNCTION:		snpac_logdefis
47736392Ssklower  *
47836392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
47936392Ssklower  *
48036392Ssklower  * RETURNS:			nothing
48136392Ssklower  *
48236392Ssklower  * SIDE EFFECTS:
48336392Ssklower  *
48436392Ssklower  * NOTES:
48536392Ssklower  */
48636392Ssklower snpac_logdefis(sc)
48743071Ssklower register struct rtentry *sc;
48836392Ssklower {
48937469Ssklower 	register struct iso_addr *r;
49043071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
49137469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
49243071Ssklower 
49343071Ssklower 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
49437469Ssklower 	if (known_is == 0)
49537469Ssklower 		known_is = sc;
49637469Ssklower 	if (known_is != sc) {
49743071Ssklower 		rtfree(known_is);
49837469Ssklower 		known_is = sc;
49936392Ssklower 	}
50037469Ssklower 	if (rt == 0) {
50143071Ssklower 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
50243071Ssklower 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
50337469Ssklower 		return;
50437469Ssklower 	}
505*43334Ssklower 	rt->rt_refcnt--;
50637469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
50743071Ssklower 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
50837469Ssklower 	}
50936392Ssklower }
51036392Ssklower 
51136392Ssklower /*
51236392Ssklower  * FUNCTION:		snpac_age
51336392Ssklower  *
51436392Ssklower  * PURPOSE:			Time out snpac entries
51536392Ssklower  *
51636392Ssklower  * RETURNS:
51736392Ssklower  *
51836392Ssklower  * SIDE EFFECTS:
51936392Ssklower  *
52036392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
52136392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
52236392Ssklower  *					if the entry is added a moment before snpac_age is
52336392Ssklower  *					called, the entry will immediately have SNPAC_AGE
52436392Ssklower  *					seconds taken off the holding time, even though
52536392Ssklower  *					it has only been held a brief moment.
52636392Ssklower  *
52736392Ssklower  *					The proper way to do this is set an expiry timeval
52836392Ssklower  *					equal to current time + holding time. Then snpac_age
52936392Ssklower  *					would time out entries where expiry date is older
53036392Ssklower  *					than the current time.
53136392Ssklower  */
53236392Ssklower snpac_age()
53336392Ssklower {
53443071Ssklower 	register struct llinfo_llc	*lc;
53536392Ssklower 
53636392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
53736392Ssklower 
53843071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
53943071Ssklower 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
540*43334Ssklower 			lc->lc_rt->rt_idle -= SNPAC_AGE;
541*43334Ssklower 			if (lc->lc_rt->rt_idle > 0)
54236392Ssklower 				continue;
54336392Ssklower 			else
54443071Ssklower 				snpac_free(lc);
54536392Ssklower 		}
54636392Ssklower 	}
54736392Ssklower }
54836392Ssklower 
54936392Ssklower /*
55036392Ssklower  * FUNCTION:		snpac_ownmulti
55136392Ssklower  *
55236392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
55336392Ssklower  *					of the same type as the system.
55436392Ssklower  *
55536392Ssklower  * RETURNS:			true or false
55636392Ssklower  *
55736392Ssklower  * SIDE EFFECTS:
55836392Ssklower  *
55936392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
56036392Ssklower  *					as interm kludge until
56136392Ssklower  *					real multicast addresses can be configured
56236392Ssklower  */
56336392Ssklower snpac_ownmulti(snpa, len)
56443071Ssklower caddr_t	snpa;
56543071Ssklower u_int	len;
56636392Ssklower {
56737469Ssklower 	return (((iso_systype & SNPA_ES) &&
56843071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
56937469Ssklower 			((iso_systype & SNPA_IS) &&
57043071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
57136392Ssklower }
57236392Ssklower 
57336392Ssklower /*
57436392Ssklower  * FUNCTION:		snpac_flushifp
57536392Ssklower  *
57636392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
57736392Ssklower  *
57836392Ssklower  * RETURNS:			nothing
57936392Ssklower  *
58036392Ssklower  * SIDE EFFECTS:
58136392Ssklower  *
58236392Ssklower  * NOTES:
58336392Ssklower  */
58436392Ssklower snpac_flushifp(ifp)
58536392Ssklower struct ifnet	*ifp;
58636392Ssklower {
58743071Ssklower 	register struct llinfo_llc	*lc;
58836392Ssklower 
58943071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
59043071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
59143071Ssklower 			snpac_free(lc);
59236392Ssklower 	}
59336392Ssklower }
59436392Ssklower 
59536392Ssklower /*
59636392Ssklower  * FUNCTION:		snpac_rtrequest
59736392Ssklower  *
59836392Ssklower  * PURPOSE:			Make a routing request
59936392Ssklower  *
60036392Ssklower  * RETURNS:			nothing
60136392Ssklower  *
60236392Ssklower  * SIDE EFFECTS:
60336392Ssklower  *
60436392Ssklower  * NOTES:			In the future, this should make a request of a user
60536392Ssklower  *					level routing daemon.
60636392Ssklower  */
60737469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
60836392Ssklower int				req;
60937469Ssklower struct iso_addr	*host;
61036392Ssklower struct iso_addr	*gateway;
61137469Ssklower struct iso_addr	*netmask;
61236392Ssklower short			flags;
61337469Ssklower struct rtentry	**ret_nrt;
61436392Ssklower {
61537469Ssklower 	register struct iso_addr *r;
61636392Ssklower 
61736392Ssklower 	IFDEBUG(D_SNPA)
61836392Ssklower 		printf("snpac_rtrequest: ");
61937469Ssklower 		if (req == RTM_ADD)
62036392Ssklower 			printf("add");
62137469Ssklower 		else if (req == RTM_DELETE)
62236392Ssklower 			printf("delete");
62336392Ssklower 		else
62436392Ssklower 			printf("unknown command");
62537469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
62636392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
62736392Ssklower 	ENDDEBUG
62836392Ssklower 
62936392Ssklower 
63037469Ssklower 	zap_isoaddr(dst, host);
63137469Ssklower 	zap_isoaddr(gte, gateway);
632*43334Ssklower 	if (netmask) {
633*43334Ssklower 		zap_isoaddr(msk, netmask);
634*43334Ssklower 		msk.siso_nlen = 0;
635*43334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
636*43334Ssklower 	}
63737469Ssklower 
63837469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
63937469Ssklower 		flags, ret_nrt);
64036392Ssklower }
64136392Ssklower 
64236392Ssklower /*
64336392Ssklower  * FUNCTION:		snpac_addrt
64436392Ssklower  *
64536392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
64636392Ssklower  *
64736392Ssklower  * RETURNS:			nothing
64836392Ssklower  *
64936392Ssklower  * SIDE EFFECTS:
65036392Ssklower  *
65136392Ssklower  * NOTES:			If a cache entry exists for gateway, then
65236392Ssklower  *					make a routing entry (host, gateway) and associate
65336392Ssklower  *					with gateway.
65436392Ssklower  *
65536392Ssklower  *					If a route already exists and is different, first delete
65636392Ssklower  *					it.
65736392Ssklower  *
65836392Ssklower  *					This could be made more efficient by checking
65936392Ssklower  *					the existing route before adding a new one.
66036392Ssklower  */
66139950Ssklower snpac_addrt(ifp, host, gateway, netmask)
66239950Ssklower struct ifnet *ifp;
66339950Ssklower struct iso_addr	*host, *gateway, *netmask;
66436392Ssklower {
66537469Ssklower 	register struct iso_addr *r;
66636392Ssklower 
66743071Ssklower 	zap_isoaddr(dst, host);
66843071Ssklower 	zap_isoaddr(gte, gateway);
66943071Ssklower 	if (netmask) {
670*43334Ssklower 		zap_isoaddr(msk, netmask);
671*43334Ssklower 		msk.siso_nlen = 0;
672*43334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
67343071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
67443071Ssklower 	} else
67543071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
67643071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
67736392Ssklower }
67836392Ssklower #endif	ISO
679