xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 43071)
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*43071Ssklower /*	@(#)iso_snpac.c	7.7 (Berkeley) 06/09/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"
39*43071Ssklower #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"
51*43071Ssklower #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 #define	SNPAC_BSIZ	20		/* bucket size */
6336392Ssklower #define	SNPAC_NB	13		/* number of buckets */
6436392Ssklower #define	SNPAC_SIZE	(SNPAC_BSIZ * SNPAC_NB)
6536392Ssklower struct	snpa_cache	iso_snpac[SNPAC_SIZE];
6637469Ssklower u_int				iso_snpac_size = SNPAC_SIZE;/* for iso_map command */
6736392Ssklower int 				iso_systype = SNPA_ES;	/* default to be an ES */
6836392Ssklower 
6937469Ssklower struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
7037469Ssklower extern u_long iso_hashchar();
7137469Ssklower static struct sockaddr_iso
7237469Ssklower 	dst	= {sizeof(dst), AF_ISO},
7337469Ssklower 	gte	= {sizeof(dst), AF_ISO},
7437469Ssklower 	src	= {sizeof(dst), AF_ISO},
7537469Ssklower 	msk	= {sizeof(dst), AF_ISO},
7637469Ssklower 	zmk = {1};
7737469Ssklower #define zsi blank_siso
7837469Ssklower #define zero_isoa	zsi.siso_addr
7937469Ssklower #define zap_isoaddr(a, b) (bzero((caddr_t)&a.siso_addr, sizeof(*r)), \
8037469Ssklower 	   ((r = b) && bcopy((caddr_t)r, (caddr_t)&a.siso_addr, 1 + (r)->isoa_len)))
8137469Ssklower #define S(x) ((struct sockaddr *)&(x))
8237469Ssklower 
83*43071Ssklower static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
84*43071Ssklower static struct sockaddr_dl gte_dl;
85*43071Ssklower #define zap_linkaddr(a, b, c, i) \
86*43071Ssklower 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
8736392Ssklower 
8836392Ssklower /*
8936392Ssklower  *	We only keep track of a single IS at a time.
9036392Ssklower  */
91*43071Ssklower struct rtentry	*known_is;
9236392Ssklower 
9336392Ssklower /*
9436392Ssklower  *	Addresses taken from NBS agreements, December 1987.
9536392Ssklower  *
9636392Ssklower  *	These addresses assume on-the-wire transmission of least significant
9736392Ssklower  *	bit first. This is the method used by 802.3. When these
9836392Ssklower  *	addresses are passed to the token ring driver, (802.5), they
9936392Ssklower  *	must be bit-swaped because 802.5 transmission order is MSb first.
10036392Ssklower  *
10136392Ssklower  *	Furthermore, according to IBM Austin, these addresses are not
10236392Ssklower  *	true token ring multicast addresses. More work is necessary
10336392Ssklower  *	to get multicast to work right on token ring.
10436392Ssklower  *
10536392Ssklower  *	Currently, the token ring driver does not handle multicast, so
10636392Ssklower  *	these addresses are converted into the broadcast address in
10736392Ssklower  *	lan_output() That means that if these multicast addresses change
10836392Ssklower  *	the token ring driver must be altered.
10936392Ssklower  */
11036392Ssklower struct snpa_cache	all_es = {
11136392Ssklower 	{ { 0x0 },							/* sc_nsap */
11236392Ssklower 	6,									/* sc_len */
11336392Ssklower 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }, /* sc_snpa */
11436392Ssklower 	SNPA_VALID,							/* sc_flags */
11536392Ssklower 	0	}								/* sc_ht */
11636392Ssklower };
11736392Ssklower struct snpa_cache	all_is = {
11836392Ssklower 	{ { 0x0 },							/* sc_nsap */
11936392Ssklower 	6,									/* sc_len */
12036392Ssklower 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }, /* sc_snpa */
12136392Ssklower 	SNPA_VALID,							/* sc_flags */
12236392Ssklower 	0	}								/* sc_ht */
12336392Ssklower };
124*43071Ssklower char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }; /* sc_snpa */
125*43071Ssklower char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }; /* sc_snpa */
12636392Ssklower 
127*43071Ssklower union sockunion {
128*43071Ssklower 	struct sockaddr_iso siso;
129*43071Ssklower 	struct sockaddr_dl	sdl;
130*43071Ssklower 	struct sockaddr		sa;
131*43071Ssklower };
13236392Ssklower 
13336392Ssklower /*
134*43071Ssklower  * FUNCTION:		llc_rtrequest
135*43071Ssklower  *
136*43071Ssklower  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
137*43071Ssklower  *
138*43071Ssklower  * NOTES:			This does a lot of obscure magic;
139*43071Ssklower  */
140*43071Ssklower llc_rtrequest(req, rt, sa)
141*43071Ssklower int req;
142*43071Ssklower register struct rtentry *rt;
143*43071Ssklower struct sockaddr *sa;
144*43071Ssklower {
145*43071Ssklower 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
146*43071Ssklower 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
147*43071Ssklower 	struct rtentry *rt2;
148*43071Ssklower 	struct ifnet *ifp = rt->rt_ifp;
149*43071Ssklower 	int addrlen = ifp->if_addrlen;
150*43071Ssklower 
151*43071Ssklower 	if (lc == 0)
152*43071Ssklower 		panic("llc_rtrequest 1");
153*43071Ssklower 	switch (req) {
154*43071Ssklower 	case RTM_RESOLVE:
155*43071Ssklower 		if (gate->sdl.sdl_family == AF_LINK) {
156*43071Ssklower 			/* We have just cloned a route to a host presumed to be on
157*43071Ssklower 			   our local net */
158*43071Ssklower 			gate->sdl.sdl_alen = 0;
159*43071Ssklower 		}
160*43071Ssklower 		/* Fall Through */
161*43071Ssklower 	case RTM_ADD:
162*43071Ssklower 		lc->lc_rt = rt;
163*43071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
164*43071Ssklower 			/*
165*43071Ssklower 			 * Case 1: This route may come from a route to iface with mask
166*43071Ssklower 			 * or from a default IS.
167*43071Ssklower 			 */
168*43071Ssklower 			rt->rt_gateway = ifp->if_addrlist->ifa_addr;
169*43071Ssklower 		} else if ((rt->rt_flags & RTF_GATEWAY == 0) &&
170*43071Ssklower 				   gate->sdl.sdl_family == AF_LINK) {
171*43071Ssklower 			/*
172*43071Ssklower 			 * Case 2:  This route may come from ESIS or a manual route
173*43071Ssklower 			 * add with a LL address.
174*43071Ssklower 			 */
175*43071Ssklower 			insque(lc, &llinfo_llc);
176*43071Ssklower 			if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
177*43071Ssklower 				gate->sdl.sdl_alen -= sizeof(struct esis_req);
178*43071Ssklower 				bcopy(addrlen + LLADDR(&gate->sdl),
179*43071Ssklower 					  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
180*43071Ssklower 			} else if (gate->sdl.sdl_alen == addrlen)
181*43071Ssklower 				lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
182*43071Ssklower 		} else {
183*43071Ssklower 			/*
184*43071Ssklower 			 * Case 3:  Told to add route via a gateway;
185*43071Ssklower 			 * try to provoke LL route to exist for gateway by cloning.
186*43071Ssklower 			 */
187*43071Ssklower 			if (gate->siso.siso_family == AF_ISO &&
188*43071Ssklower 				(rt->rt_flags & RTF_GATEWAY) &&
189*43071Ssklower 				(rt2 = rtalloc1(&gate->sa, 1)) &&
190*43071Ssklower 					(lc2 = (struct llinfo_llc *)rt2->rt_llinfo)) {
191*43071Ssklower 				lc->lc_rtgate = rt2;
192*43071Ssklower 				rt2->rt_use++;
193*43071Ssklower 				if (lc2->lc_rtgate == 0) {
194*43071Ssklower 					lc->lc_prev = lc->lc_next = lc;
195*43071Ssklower 					lc2->lc_rtgate = rt;
196*43071Ssklower 					rt->rt_use++;
197*43071Ssklower 				} else {
198*43071Ssklower 					if (lc2->lc_rtgate->rt_llinfo == 0)
199*43071Ssklower 						panic("llc_rtrequest 2");
200*43071Ssklower 					insque(lc, lc2->lc_rtgate->rt_llinfo);
201*43071Ssklower 				}
202*43071Ssklower 			}
203*43071Ssklower 		}
204*43071Ssklower 		break;
205*43071Ssklower 	case RTM_DELETE:
206*43071Ssklower 		if (rt->rt_flags & RTF_GATEWAY) {
207*43071Ssklower 			if (rt2 = lc->lc_rtgate) {
208*43071Ssklower 				if ((lc2 = (struct llinfo_llc *)rt2->rt_llinfo) &&
209*43071Ssklower 				    (lc2->lc_rtgate == rt)) {
210*43071Ssklower 						rt->rt_use--;
211*43071Ssklower 						lc2->lc_rtgate = (lc->lc_next != lc->lc_prev) ?
212*43071Ssklower 						   lc->lc_next->lc_rt : 0;
213*43071Ssklower 					}
214*43071Ssklower 					RTFREE(rt2);
215*43071Ssklower 			}
216*43071Ssklower 		} else {
217*43071Ssklower 			if ((rt2 = lc->lc_rtgate) &&
218*43071Ssklower 			    (lc2 == (struct llinfo_llc *)rt2->rt_llinfo)) {
219*43071Ssklower 					struct llinfo_llc *head = lc2;
220*43071Ssklower 					do {
221*43071Ssklower 						rt->rt_use--;
222*43071Ssklower 						lc2->lc_rtgate = 0;
223*43071Ssklower 						lc2 = lc2->lc_next;
224*43071Ssklower 					} while (lc2 != head);
225*43071Ssklower 			}
226*43071Ssklower 		}
227*43071Ssklower 		if (lc->lc_next)
228*43071Ssklower 			remque(lc);
229*43071Ssklower 		break;
230*43071Ssklower 	}
231*43071Ssklower }
232*43071Ssklower /*
23336392Ssklower  * FUNCTION:		iso_snparesolve
23436392Ssklower  *
23536392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
23636392Ssklower  *
23736392Ssklower  * RETURNS:			0 if addr is resolved
23836392Ssklower  *					errno if addr is unknown
23936392Ssklower  *
24036392Ssklower  * SIDE EFFECTS:
24136392Ssklower  *
242*43071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
243*43071Ssklower  *					table, we know there is no snpa address known for this
244*43071Ssklower  *					destination.  If we know of a default IS, then the address
245*43071Ssklower  *					of the IS is returned.  If no IS is known, then return the
246*43071Ssklower  *					multi-cast address for "all ES" for this interface.
24736392Ssklower  *
24836392Ssklower  *					NB: the last case described above constitutes the
24936392Ssklower  *					query configuration function 9542, sec 6.5
25036392Ssklower  *					A mechanism is needed to prevent this function from
25136392Ssklower  *					being invoked if the system is an IS.
25236392Ssklower  */
25337469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
254*43071Ssklower struct	ifnet *ifp;			/* outgoing interface */
255*43071Ssklower struct	sockaddr_iso *dest;	/* destination */
256*43071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
257*43071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
25836392Ssklower {
259*43071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
260*43071Ssklower 	caddr_t	found_snpa;
261*43071Ssklower 	int 	addrlen;
26236392Ssklower 
26336392Ssklower 	/*
26436392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
26536392Ssklower 	 *	addresss embedded in the destination nsap address
26636392Ssklower 	 */
267*43071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
26836392Ssklower 		/*
26936392Ssklower 		 *	This is a subnetwork address. Return it immediately
27036392Ssklower 		 */
27136392Ssklower 		IFDEBUG(D_SNPA)
27236392Ssklower 			printf("iso_snparesolve: return SN address\n");
27336392Ssklower 		ENDDEBUG
274*43071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
275*43071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
27636392Ssklower 	/*
277*43071Ssklower 	 * If we are an IS, we can't do much with the packet;
278*43071Ssklower 	 *	Check if we know about an IS.
27936392Ssklower 	 */
280*43071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
281*43071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
282*43071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
283*43071Ssklower 		register struct sockaddr_dl *sdl =
284*43071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
285*43071Ssklower 		found_snpa = LLADDR(sdl);
286*43071Ssklower 		addrlen = sdl->sdl_alen;
287*43071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
288*43071Ssklower 		/*
289*43071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
290*43071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
291*43071Ssklower 		 *
292*43071Ssklower 		 *	Note: there is a potential problem here. If the destination
293*43071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
294*43071Ssklower 		 *	does send back a TP CC, a connection could be established
295*43071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
29636392Ssklower 		 */
297*43071Ssklower 		addrlen = ifp->if_addrlen;
298*43071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
299*43071Ssklower 	} else
300*43071Ssklower 		return (ENETUNREACH);
301*43071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
30236392Ssklower 	return (0);
30336392Ssklower }
30436392Ssklower 
30536392Ssklower 
30636392Ssklower /*
30736392Ssklower  * FUNCTION:		snpac_free
30836392Ssklower  *
30936392Ssklower  * PURPOSE:			free an entry in the iso address map table
31036392Ssklower  *
31136392Ssklower  * RETURNS:			nothing
31236392Ssklower  *
31336392Ssklower  * SIDE EFFECTS:
31436392Ssklower  *
31536392Ssklower  * NOTES:			If there is a route entry associated with cache
31636392Ssklower  *					entry, then delete that as well
31736392Ssklower  */
318*43071Ssklower snpac_free(lc)
319*43071Ssklower register struct llinfo_llc *lc;		/* entry to free */
32036392Ssklower {
321*43071Ssklower 	register struct rtentry *rt = lc->lc_rt;
32237469Ssklower 	register struct iso_addr *r;
32336392Ssklower 
324*43071Ssklower 	if (known_is == rt)
325*43071Ssklower 		known_is = 0;
326*43071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
327*43071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
32837469Ssklower 			RTFREE(rt);
32937469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
33037469Ssklower 						rt->rt_flags, (struct rtentry **)0);
33137469Ssklower 		RTFREE(rt);
33236392Ssklower 	}
33336392Ssklower }
33436392Ssklower 
33536392Ssklower /*
33636392Ssklower  * FUNCTION:		snpac_add
33736392Ssklower  *
33836392Ssklower  * PURPOSE:			Add an entry to the snpa cache
33936392Ssklower  *
34036392Ssklower  * RETURNS:
34136392Ssklower  *
34236392Ssklower  * SIDE EFFECTS:
34336392Ssklower  *
34436392Ssklower  * NOTES:			If entry already exists, then update holding time.
34536392Ssklower  */
346*43071Ssklower snpac_add(ifp, nsap, snpa, type, ht)
34736392Ssklower struct ifnet		*ifp;		/* interface info is related to */
34836392Ssklower struct iso_addr		*nsap;		/* nsap to add */
34936392Ssklower caddr_t				snpa;		/* translation */
35036392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
35137469Ssklower u_short				ht;			/* holding time (in seconds) */
35236392Ssklower {
353*43071Ssklower 	register struct	llinfo_llc *lc;
354*43071Ssklower 	struct	rtentry *rt;
355*43071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
356*43071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
357*43071Ssklower 	int		new_entry = 0, index = ifp->if_index;
35836392Ssklower 
359*43071Ssklower 	zap_isoaddr(dst, nsap);
360*43071Ssklower 	rt = rtalloc1(S(dst), 0);
361*43071Ssklower 	if (rt == 0) {
362*43071Ssklower 		new_entry = 1;
363*43071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
364*43071Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), (struct sockaddr *)0,
365*43071Ssklower 						RTF_UP | RTF_HOST, &rt) || rt == 0)
366*43071Ssklower 			return (0);
367*43071Ssklower 	} else {
368*43071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
369*43071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
370*43071Ssklower 			int old_sdl_len = sdl->sdl_len;
371*43071Ssklower 			if (old_sdl_len < sizeof(*sdl))
372*43071Ssklower 				return (0);
373*43071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
374*43071Ssklower 			sdl->sdl_len = old_sdl_len;
375*43071Ssklower 			new_entry = 1;
376*43071Ssklower 		}
37736392Ssklower 	}
378*43071Ssklower 	lc = (struct llinfo_llc *)rt->rt_llinfo;
379*43071Ssklower 	lc->lc_ht = ht;
380*43071Ssklower 	lc->lc_flags = SNPA_VALID | type;
38136392Ssklower 	if (type & SNPA_IS)
382*43071Ssklower 		snpac_logdefis(rt);
38336392Ssklower }
38436392Ssklower 
38536392Ssklower /*
38636392Ssklower  * FUNCTION:		snpac_ioctl
38736392Ssklower  *
38836392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
38936392Ssklower  *
39036392Ssklower  * RETURNS:			0 on success, or unix error code
39136392Ssklower  *
39236392Ssklower  * SIDE EFFECTS:
39336392Ssklower  *
39436392Ssklower  * NOTES:
39536392Ssklower  */
396*43071Ssklower snpac_ioctl (cmd, data)
39736392Ssklower int		cmd;	/* ioctl to process */
39836392Ssklower caddr_t	data;	/* data for the cmd */
39936392Ssklower {
40036392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
40136392Ssklower 	extern short	esis_holding_time, esis_config_time;
40236392Ssklower 
40336392Ssklower 	IFDEBUG (D_IOCTL)
40436392Ssklower 		if (cmd == SIOCSSTYPE)
405*43071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
40636392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
40736392Ssklower 		else
408*43071Ssklower 			printf("snpac_ioctl: cmd get\n");
40936392Ssklower 	ENDDEBUG
41036392Ssklower 
41136392Ssklower 	if (cmd == SIOCSSTYPE) {
41237551Smckusick 		if (suser(u.u_cred, &u.u_acflag))
41336392Ssklower 			return(EACCES);
41436392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
41536392Ssklower 			return(EINVAL);
41636392Ssklower 		if (rq->sr_type & SNPA_ES) {
41736392Ssklower 			iso_systype = SNPA_ES;
41836392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
41936392Ssklower 			iso_systype = SNPA_IS;
42036392Ssklower 		} else {
42136392Ssklower 			return(EINVAL);
42236392Ssklower 		}
42336392Ssklower 		esis_holding_time = rq->sr_holdt;
42436392Ssklower 		esis_config_time = rq->sr_configt;
42536392Ssklower 	} else if (cmd == SIOCGSTYPE) {
42636392Ssklower 		rq->sr_type = iso_systype;
42736392Ssklower 		rq->sr_holdt = esis_holding_time;
42836392Ssklower 		rq->sr_configt = esis_config_time;
42936392Ssklower 	} else {
430*43071Ssklower 		return (EINVAL);
43136392Ssklower 	}
432*43071Ssklower 	return (0);
43336392Ssklower }
43436392Ssklower 
43536392Ssklower /*
43636392Ssklower  * FUNCTION:		snpac_logdefis
43736392Ssklower  *
43836392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
43936392Ssklower  *
44036392Ssklower  * RETURNS:			nothing
44136392Ssklower  *
44236392Ssklower  * SIDE EFFECTS:
44336392Ssklower  *
44436392Ssklower  * NOTES:
44536392Ssklower  */
44636392Ssklower snpac_logdefis(sc)
447*43071Ssklower register struct rtentry *sc;
44836392Ssklower {
44937469Ssklower 	register struct iso_addr *r;
450*43071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
45137469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
452*43071Ssklower 
453*43071Ssklower 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
45437469Ssklower 	if (known_is == 0)
45537469Ssklower 		known_is = sc;
45637469Ssklower 	if (known_is != sc) {
457*43071Ssklower 		rtfree(known_is);
45837469Ssklower 		known_is = sc;
45936392Ssklower 	}
46037469Ssklower 	if (rt == 0) {
461*43071Ssklower 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
462*43071Ssklower 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
46337469Ssklower 		return;
46437469Ssklower 	}
46537469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
466*43071Ssklower 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
46737469Ssklower 	}
46836392Ssklower }
46936392Ssklower 
47036392Ssklower /*
47136392Ssklower  * FUNCTION:		snpac_age
47236392Ssklower  *
47336392Ssklower  * PURPOSE:			Time out snpac entries
47436392Ssklower  *
47536392Ssklower  * RETURNS:
47636392Ssklower  *
47736392Ssklower  * SIDE EFFECTS:
47836392Ssklower  *
47936392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
48036392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
48136392Ssklower  *					if the entry is added a moment before snpac_age is
48236392Ssklower  *					called, the entry will immediately have SNPAC_AGE
48336392Ssklower  *					seconds taken off the holding time, even though
48436392Ssklower  *					it has only been held a brief moment.
48536392Ssklower  *
48636392Ssklower  *					The proper way to do this is set an expiry timeval
48736392Ssklower  *					equal to current time + holding time. Then snpac_age
48836392Ssklower  *					would time out entries where expiry date is older
48936392Ssklower  *					than the current time.
49036392Ssklower  */
49136392Ssklower snpac_age()
49236392Ssklower {
493*43071Ssklower 	register struct llinfo_llc	*lc;
49436392Ssklower 
49536392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
49636392Ssklower 
497*43071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
498*43071Ssklower 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
499*43071Ssklower 			lc->lc_ht -= SNPAC_AGE;
500*43071Ssklower 			if (lc->lc_ht > 0)
50136392Ssklower 				continue;
50236392Ssklower 			else
503*43071Ssklower 				snpac_free(lc);
50436392Ssklower 		}
50536392Ssklower 	}
50636392Ssklower }
50736392Ssklower 
50836392Ssklower /*
50936392Ssklower  * FUNCTION:		snpac_ownmulti
51036392Ssklower  *
51136392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
51236392Ssklower  *					of the same type as the system.
51336392Ssklower  *
51436392Ssklower  * RETURNS:			true or false
51536392Ssklower  *
51636392Ssklower  * SIDE EFFECTS:
51736392Ssklower  *
51836392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
51936392Ssklower  *					as interm kludge until
52036392Ssklower  *					real multicast addresses can be configured
52136392Ssklower  */
52236392Ssklower snpac_ownmulti(snpa, len)
523*43071Ssklower caddr_t	snpa;
524*43071Ssklower u_int	len;
52536392Ssklower {
52637469Ssklower 	return (((iso_systype & SNPA_ES) &&
527*43071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
52837469Ssklower 			((iso_systype & SNPA_IS) &&
529*43071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
53036392Ssklower }
53136392Ssklower 
53236392Ssklower /*
53336392Ssklower  * FUNCTION:		snpac_flushifp
53436392Ssklower  *
53536392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
53636392Ssklower  *
53736392Ssklower  * RETURNS:			nothing
53836392Ssklower  *
53936392Ssklower  * SIDE EFFECTS:
54036392Ssklower  *
54136392Ssklower  * NOTES:
54236392Ssklower  */
54336392Ssklower snpac_flushifp(ifp)
54436392Ssklower struct ifnet	*ifp;
54536392Ssklower {
546*43071Ssklower 	register struct llinfo_llc	*lc;
54736392Ssklower 
548*43071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
549*43071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
550*43071Ssklower 			snpac_free(lc);
55136392Ssklower 	}
55236392Ssklower }
55336392Ssklower 
55436392Ssklower /*
55536392Ssklower  * FUNCTION:		snpac_rtrequest
55636392Ssklower  *
55736392Ssklower  * PURPOSE:			Make a routing request
55836392Ssklower  *
55936392Ssklower  * RETURNS:			nothing
56036392Ssklower  *
56136392Ssklower  * SIDE EFFECTS:
56236392Ssklower  *
56336392Ssklower  * NOTES:			In the future, this should make a request of a user
56436392Ssklower  *					level routing daemon.
56536392Ssklower  */
56637469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
56736392Ssklower int				req;
56837469Ssklower struct iso_addr	*host;
56936392Ssklower struct iso_addr	*gateway;
57037469Ssklower struct iso_addr	*netmask;
57136392Ssklower short			flags;
57237469Ssklower struct rtentry	**ret_nrt;
57336392Ssklower {
57437469Ssklower 	register struct iso_addr *r;
57536392Ssklower 
57636392Ssklower 	IFDEBUG(D_SNPA)
57736392Ssklower 		printf("snpac_rtrequest: ");
57837469Ssklower 		if (req == RTM_ADD)
57936392Ssklower 			printf("add");
58037469Ssklower 		else if (req == RTM_DELETE)
58136392Ssklower 			printf("delete");
58236392Ssklower 		else
58336392Ssklower 			printf("unknown command");
58437469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
58536392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
58636392Ssklower 	ENDDEBUG
58736392Ssklower 
58836392Ssklower 
58937469Ssklower 	zap_isoaddr(dst, host);
59037469Ssklower 	zap_isoaddr(gte, gateway);
59137469Ssklower 	zap_isoaddr(msk, netmask);
59237469Ssklower 
59337469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
59437469Ssklower 		flags, ret_nrt);
59536392Ssklower }
59636392Ssklower 
59736392Ssklower /*
59836392Ssklower  * FUNCTION:		snpac_addrt
59936392Ssklower  *
60036392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
60136392Ssklower  *
60236392Ssklower  * RETURNS:			nothing
60336392Ssklower  *
60436392Ssklower  * SIDE EFFECTS:
60536392Ssklower  *
60636392Ssklower  * NOTES:			If a cache entry exists for gateway, then
60736392Ssklower  *					make a routing entry (host, gateway) and associate
60836392Ssklower  *					with gateway.
60936392Ssklower  *
61036392Ssklower  *					If a route already exists and is different, first delete
61136392Ssklower  *					it.
61236392Ssklower  *
61336392Ssklower  *					This could be made more efficient by checking
61436392Ssklower  *					the existing route before adding a new one.
61536392Ssklower  */
61639950Ssklower snpac_addrt(ifp, host, gateway, netmask)
61739950Ssklower struct ifnet *ifp;
61839950Ssklower struct iso_addr	*host, *gateway, *netmask;
61936392Ssklower {
62037469Ssklower 	register struct iso_addr *r;
62136392Ssklower 
622*43071Ssklower 	zap_isoaddr(dst, host);
623*43071Ssklower 	zap_isoaddr(gte, gateway);
624*43071Ssklower 	zap_isoaddr(msk, netmask);
625*43071Ssklower 	if (netmask) {
626*43071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
627*43071Ssklower 	} else
628*43071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
629*43071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
63036392Ssklower }
63136392Ssklower #endif	ISO
632