xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 47274)
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*47274Ssklower /*	@(#)iso_snpac.c	7.11 (Berkeley) 03/12/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"
49*47274Ssklower #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;
13743071Ssklower 
13843334Ssklower 	IFDEBUG (D_SNPA)
13943334Ssklower 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
14043334Ssklower 	ENDDEBUG
14143334Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
14243334Ssklower 		if (recursing) {
143*47274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: gateway route points to same type %x %x\n",
14443334Ssklower 				recursing, rt);
14543334Ssklower 		} else switch (req) {
14643334Ssklower 		case RTM_RESOLVE:
14743334Ssklower 		case RTM_ADD:
14843334Ssklower 			recursing = rt;
14943334Ssklower 			rt->rt_llinfo = (caddr_t)rtalloc1(&gate->sa, 1);
15043334Ssklower 			recursing = 0;
15143334Ssklower 			return;
15243334Ssklower 
15343334Ssklower 		case RTM_DELETE:
15443334Ssklower 			if (lc)
15543334Ssklower 				RTFREE((struct rtentry *)lc);
15643334Ssklower 			rt->rt_llinfo = 0;
15743071Ssklower 		}
15843334Ssklower 	} else switch (req) {
15943071Ssklower 	case RTM_ADD:
16043334Ssklower 		/*
16143334Ssklower 		 * Case 1: This route may come from a route to iface with mask
16243334Ssklower 		 * or from a default route.
16343334Ssklower 		 */
16443071Ssklower 		if (rt->rt_flags & RTF_CLONING) {
16543334Ssklower 			register struct ifaddr *ifa;
16643334Ssklower 			register struct sockaddr *sa;
16743334Ssklower 			for (ifa = ifp->if_addrlist; ifa; ifa->ifa_next)
16843334Ssklower 				if ((sa = ifa->ifa_addr)->sa_family == AF_LINK) {
16943334Ssklower 					if (sa->sa_len > gate->sa.sa_len)
170*47274Ssklower 						log(LOG_DEBUG, "llc_rtrequest: cloning address too small\n");
17143334Ssklower 					else {
17243334Ssklower 						Bcopy(sa, gate, gate->sa.sa_len);
17343334Ssklower 						gate->sdl.sdl_alen = 0;
17443334Ssklower 					}
17543334Ssklower 					return;
17643071Ssklower 				}
17743334Ssklower 			if (ifa == 0)
178*47274Ssklower 				log(LOG_DEBUG, "llc_rtrequest: can't find LL ifaddr for iface\n");
17943334Ssklower 			return;
18043071Ssklower 		}
18143334Ssklower 		/* FALLTHROUGH */
18243334Ssklower 	case RTM_RESOLVE:
18343334Ssklower 		/*
18443334Ssklower 		 * Case 2:  This route may come from cloning, or a manual route
18543334Ssklower 		 * add with a LL address.
18643334Ssklower 		 */
18743334Ssklower 		if (gate->sdl.sdl_family != AF_LINK) {
188*47274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
18943334Ssklower 			return;
19043334Ssklower 		}
19143334Ssklower 		if (lc != 0)
192*47274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: losing old rt_llinfo\n");
19343334Ssklower 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
19443334Ssklower 		rt->rt_llinfo = (caddr_t)lc;
19543334Ssklower 		if (lc == 0) {
196*47274Ssklower 			log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
19743334Ssklower 			return;
19843334Ssklower 		}
19943334Ssklower 		Bzero(lc, sizeof(*lc));
20043334Ssklower 		lc->lc_rt = rt;
20143334Ssklower 		rt->rt_flags |= RTF_LLINFO;
20243334Ssklower 		insque(lc, &llinfo_llc);
20343334Ssklower 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
20443334Ssklower 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
20543334Ssklower 			bcopy(addrlen + LLADDR(&gate->sdl),
20643334Ssklower 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
20743334Ssklower 		} else if (gate->sdl.sdl_alen == addrlen)
20843334Ssklower 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
20943071Ssklower 		break;
21043071Ssklower 	case RTM_DELETE:
21143334Ssklower 		if (lc == 0 || (rt->rt_flags & RTF_CLONING))
21243334Ssklower 			return;
21343334Ssklower 		remque(lc);
21443334Ssklower 		Free(lc);
21543334Ssklower 		rt->rt_llinfo = 0;
21643334Ssklower 		rt->rt_flags &= ~RTF_LLINFO;
21743071Ssklower 		break;
21843071Ssklower 	}
21943071Ssklower }
22043071Ssklower /*
22136392Ssklower  * FUNCTION:		iso_snparesolve
22236392Ssklower  *
22336392Ssklower  * PURPOSE:			Resolve an iso address into snpa address
22436392Ssklower  *
22536392Ssklower  * RETURNS:			0 if addr is resolved
22636392Ssklower  *					errno if addr is unknown
22736392Ssklower  *
22836392Ssklower  * SIDE EFFECTS:
22936392Ssklower  *
23043071Ssklower  * NOTES:			Now that we have folded the snpa cache into the routing
23143071Ssklower  *					table, we know there is no snpa address known for this
23243071Ssklower  *					destination.  If we know of a default IS, then the address
23343071Ssklower  *					of the IS is returned.  If no IS is known, then return the
23443071Ssklower  *					multi-cast address for "all ES" for this interface.
23536392Ssklower  *
23636392Ssklower  *					NB: the last case described above constitutes the
23736392Ssklower  *					query configuration function 9542, sec 6.5
23836392Ssklower  *					A mechanism is needed to prevent this function from
23936392Ssklower  *					being invoked if the system is an IS.
24036392Ssklower  */
24137469Ssklower iso_snparesolve(ifp, dest, snpa, snpa_len)
24243071Ssklower struct	ifnet *ifp;			/* outgoing interface */
24343071Ssklower struct	sockaddr_iso *dest;	/* destination */
24443071Ssklower caddr_t	snpa;				/* RESULT: snpa to be used */
24543071Ssklower int		*snpa_len;			/* RESULT: length of snpa */
24636392Ssklower {
24743071Ssklower 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
24843071Ssklower 	caddr_t	found_snpa;
24943071Ssklower 	int 	addrlen;
25036392Ssklower 
25136392Ssklower 	/*
25236392Ssklower 	 *	This hack allows us to send esis packets that have the destination snpa
25336392Ssklower 	 *	addresss embedded in the destination nsap address
25436392Ssklower 	 */
25543071Ssklower 	if (dest->siso_data[0] == AFI_SNA) {
25636392Ssklower 		/*
25736392Ssklower 		 *	This is a subnetwork address. Return it immediately
25836392Ssklower 		 */
25936392Ssklower 		IFDEBUG(D_SNPA)
26036392Ssklower 			printf("iso_snparesolve: return SN address\n");
26136392Ssklower 		ENDDEBUG
26243071Ssklower 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
26343071Ssklower 		found_snpa = (caddr_t) dest->siso_data + 1;
26436392Ssklower 	/*
26543071Ssklower 	 * If we are an IS, we can't do much with the packet;
26643071Ssklower 	 *	Check if we know about an IS.
26736392Ssklower 	 */
26843071Ssklower 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
26943071Ssklower 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
27043071Ssklower 				 (sc->lc_flags & SNPA_VALID)) {
27143071Ssklower 		register struct sockaddr_dl *sdl =
27243071Ssklower 			(struct sockaddr_dl *)(known_is->rt_gateway);
27343071Ssklower 		found_snpa = LLADDR(sdl);
27443071Ssklower 		addrlen = sdl->sdl_alen;
27543071Ssklower 	} else if (ifp->if_flags & IFF_BROADCAST) {
27643071Ssklower 		/*
27743071Ssklower 		 *	no IS, no match. Return "all es" multicast address for this
27843071Ssklower 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
27943071Ssklower 		 *
28043071Ssklower 		 *	Note: there is a potential problem here. If the destination
28143071Ssklower 		 *	is on the subnet and it does not respond with a ESH, but
28243071Ssklower 		 *	does send back a TP CC, a connection could be established
28343071Ssklower 		 *	where we always transmit the CLNP packet to "all es"
28436392Ssklower 		 */
28543071Ssklower 		addrlen = ifp->if_addrlen;
28643071Ssklower 		found_snpa = (caddr_t)all_es_snpa;
28743071Ssklower 	} else
28843071Ssklower 		return (ENETUNREACH);
28943071Ssklower 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
29036392Ssklower 	return (0);
29136392Ssklower }
29236392Ssklower 
29336392Ssklower 
29436392Ssklower /*
29536392Ssklower  * FUNCTION:		snpac_free
29636392Ssklower  *
29736392Ssklower  * PURPOSE:			free an entry in the iso address map table
29836392Ssklower  *
29936392Ssklower  * RETURNS:			nothing
30036392Ssklower  *
30136392Ssklower  * SIDE EFFECTS:
30236392Ssklower  *
30336392Ssklower  * NOTES:			If there is a route entry associated with cache
30436392Ssklower  *					entry, then delete that as well
30536392Ssklower  */
30643071Ssklower snpac_free(lc)
30743071Ssklower register struct llinfo_llc *lc;		/* entry to free */
30836392Ssklower {
30943071Ssklower 	register struct rtentry *rt = lc->lc_rt;
31037469Ssklower 	register struct iso_addr *r;
31136392Ssklower 
31243071Ssklower 	if (known_is == rt)
31343071Ssklower 		known_is = 0;
31443071Ssklower 	if (rt && (rt->rt_flags & RTF_UP) &&
31543071Ssklower 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
31637469Ssklower 			RTFREE(rt);
31737469Ssklower 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
31837469Ssklower 						rt->rt_flags, (struct rtentry **)0);
31937469Ssklower 		RTFREE(rt);
32036392Ssklower 	}
32136392Ssklower }
32236392Ssklower 
32336392Ssklower /*
32436392Ssklower  * FUNCTION:		snpac_add
32536392Ssklower  *
32636392Ssklower  * PURPOSE:			Add an entry to the snpa cache
32736392Ssklower  *
32836392Ssklower  * RETURNS:
32936392Ssklower  *
33036392Ssklower  * SIDE EFFECTS:
33136392Ssklower  *
33236392Ssklower  * NOTES:			If entry already exists, then update holding time.
33336392Ssklower  */
33443334Ssklower snpac_add(ifp, nsap, snpa, type, ht, nsellength)
33536392Ssklower struct ifnet		*ifp;		/* interface info is related to */
33636392Ssklower struct iso_addr		*nsap;		/* nsap to add */
33736392Ssklower caddr_t				snpa;		/* translation */
33836392Ssklower char				type;		/* SNPA_IS or SNPA_ES */
33937469Ssklower u_short				ht;			/* holding time (in seconds) */
34043334Ssklower int					nsellength;	/* nsaps may differ only in trailing bytes */
34136392Ssklower {
34243071Ssklower 	register struct	llinfo_llc *lc;
34343334Ssklower 	register struct rtentry *rt;
34443334Ssklower 	struct	rtentry *mrt = 0;
34543071Ssklower 	register struct	iso_addr *r; /* for zap_isoaddr macro */
34643071Ssklower 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
34743071Ssklower 	int		new_entry = 0, index = ifp->if_index;
34836392Ssklower 
34943334Ssklower 	IFDEBUG(D_SNPA)
35043334Ssklower 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
35143334Ssklower 			ifp, nsap, snpa, type, ht, nsellength);
35243334Ssklower 	ENDDEBUG
35343071Ssklower 	zap_isoaddr(dst, nsap);
35443071Ssklower 	rt = rtalloc1(S(dst), 0);
35543334Ssklower 	IFDEBUG(D_SNPA)
35643334Ssklower 		printf("snpac_add: rtalloc1 returns %x\n", rt);
35743334Ssklower 	ENDDEBUG
35843071Ssklower 	if (rt == 0) {
35943334Ssklower 		struct sockaddr *netmask;
36043334Ssklower 		int flags;
36143334Ssklower 		add:
36243334Ssklower 		if (nsellength) {
36343334Ssklower 			netmask = S(msk); flags = RTF_UP;
36443334Ssklower 			snpac_fixdstandmask(nsellength);
36543334Ssklower 		} else {
36643334Ssklower 			netmask = 0; flags = RTF_UP | RTF_HOST;
36743334Ssklower 		}
36843071Ssklower 		new_entry = 1;
36943071Ssklower 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
37043334Ssklower 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
37143334Ssklower 			mrt == 0)
37243071Ssklower 			return (0);
37343334Ssklower 		rt = mrt;
37443334Ssklower 		rt->rt_refcnt--;
37543071Ssklower 	} else {
37643071Ssklower 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
37743334Ssklower 		rt->rt_refcnt--;
37843334Ssklower 		if ((rt->rt_flags & RTF_LLINFO) == 0)
37943334Ssklower 			goto add;
38043334Ssklower 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
38143334Ssklower 			if (rt->rt_refcnt == 0) {
38243334Ssklower 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
38343334Ssklower 					(struct sockaddr *)0, 0, (struct rtentry *)0);
38443334Ssklower 				rt = 0;
38543334Ssklower 				goto add;
38643334Ssklower 			} else {
38743334Ssklower 				static struct iso_addr nsap2; register char *cp;
38843334Ssklower 				nsap2 = *nsap;
38943334Ssklower 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
39043334Ssklower 				while (cp < (char *)(1 + &nsap2))
39143334Ssklower 					*cp++ = 0;
39243334Ssklower 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
39343334Ssklower 			}
39443334Ssklower 		}
39543071Ssklower 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
39643071Ssklower 			int old_sdl_len = sdl->sdl_len;
39743334Ssklower 			if (old_sdl_len < sizeof(*sdl)) {
398*47274Ssklower 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
39943071Ssklower 				return (0);
40043334Ssklower 			}
40143071Ssklower 			zap_linkaddr(sdl, snpa, snpalen, index);
40243071Ssklower 			sdl->sdl_len = old_sdl_len;
40343071Ssklower 			new_entry = 1;
40443071Ssklower 		}
40536392Ssklower 	}
40643334Ssklower 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
40743334Ssklower 		panic("snpac_rtrequest");
40843334Ssklower 	rt->rt_idle = ht;
40943071Ssklower 	lc->lc_flags = SNPA_VALID | type;
41036392Ssklower 	if (type & SNPA_IS)
41143071Ssklower 		snpac_logdefis(rt);
41243334Ssklower 	return (new_entry);
41336392Ssklower }
41436392Ssklower 
41543334Ssklower static snpac_fixdstandmask(nsellength)
41643334Ssklower {
41743334Ssklower 	register char *cp = msk.siso_data, *cplim;
41843334Ssklower 
41943334Ssklower 	cplim = cp + (dst.siso_nlen -= nsellength);
42043334Ssklower 	msk.siso_len = cplim - (char *)&msk;
42143334Ssklower 	msk.siso_nlen = 0;
42243334Ssklower 	while (cp < cplim)
42343334Ssklower 		*cp++ = -1;
42443334Ssklower 	while (cp < (char *)msk.siso_pad)
42543334Ssklower 		*cp++ = 0;
42643334Ssklower 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
42743334Ssklower 		*cp++ = 0;
42843334Ssklower }
42943334Ssklower 
43036392Ssklower /*
43136392Ssklower  * FUNCTION:		snpac_ioctl
43236392Ssklower  *
43336392Ssklower  * PURPOSE:			Set/Get the system type and esis parameters
43436392Ssklower  *
43536392Ssklower  * RETURNS:			0 on success, or unix error code
43636392Ssklower  *
43736392Ssklower  * SIDE EFFECTS:
43836392Ssklower  *
43936392Ssklower  * NOTES:
44036392Ssklower  */
44143071Ssklower snpac_ioctl (cmd, data)
44236392Ssklower int		cmd;	/* ioctl to process */
44336392Ssklower caddr_t	data;	/* data for the cmd */
44436392Ssklower {
44536392Ssklower 	register struct systype_req *rq = (struct systype_req *)data;
44636392Ssklower 
44743334Ssklower 	IFDEBUG(D_IOCTL)
44836392Ssklower 		if (cmd == SIOCSSTYPE)
44943071Ssklower 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
45036392Ssklower 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
45136392Ssklower 		else
45243071Ssklower 			printf("snpac_ioctl: cmd get\n");
45336392Ssklower 	ENDDEBUG
45436392Ssklower 
45536392Ssklower 	if (cmd == SIOCSSTYPE) {
45637551Smckusick 		if (suser(u.u_cred, &u.u_acflag))
45736392Ssklower 			return(EACCES);
45836392Ssklower 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
45936392Ssklower 			return(EINVAL);
46036392Ssklower 		if (rq->sr_type & SNPA_ES) {
46136392Ssklower 			iso_systype = SNPA_ES;
46236392Ssklower 		} else if (rq->sr_type & SNPA_IS) {
46336392Ssklower 			iso_systype = SNPA_IS;
46436392Ssklower 		} else {
46536392Ssklower 			return(EINVAL);
46636392Ssklower 		}
46736392Ssklower 		esis_holding_time = rq->sr_holdt;
46836392Ssklower 		esis_config_time = rq->sr_configt;
46943423Ssklower 		if (esis_esconfig_time != rq->sr_esconfigt) {
47043423Ssklower 			untimeout(esis_config, (caddr_t)0);
47143423Ssklower 			esis_esconfig_time = rq->sr_esconfigt;
47243423Ssklower 			esis_config();
47343423Ssklower 		}
47436392Ssklower 	} else if (cmd == SIOCGSTYPE) {
47536392Ssklower 		rq->sr_type = iso_systype;
47636392Ssklower 		rq->sr_holdt = esis_holding_time;
47736392Ssklower 		rq->sr_configt = esis_config_time;
47843423Ssklower 		rq->sr_esconfigt = esis_esconfig_time;
47936392Ssklower 	} else {
48043071Ssklower 		return (EINVAL);
48136392Ssklower 	}
48243071Ssklower 	return (0);
48336392Ssklower }
48436392Ssklower 
48536392Ssklower /*
48636392Ssklower  * FUNCTION:		snpac_logdefis
48736392Ssklower  *
48836392Ssklower  * PURPOSE:			Mark the IS passed as the default IS
48936392Ssklower  *
49036392Ssklower  * RETURNS:			nothing
49136392Ssklower  *
49236392Ssklower  * SIDE EFFECTS:
49336392Ssklower  *
49436392Ssklower  * NOTES:
49536392Ssklower  */
49636392Ssklower snpac_logdefis(sc)
49743071Ssklower register struct rtentry *sc;
49836392Ssklower {
49937469Ssklower 	register struct iso_addr *r;
50043071Ssklower 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
50137469Ssklower 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
50243071Ssklower 
50343071Ssklower 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
50437469Ssklower 	if (known_is == 0)
50537469Ssklower 		known_is = sc;
50637469Ssklower 	if (known_is != sc) {
50743071Ssklower 		rtfree(known_is);
50837469Ssklower 		known_is = sc;
50936392Ssklower 	}
51037469Ssklower 	if (rt == 0) {
51143071Ssklower 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
51243071Ssklower 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
51337469Ssklower 		return;
51437469Ssklower 	}
51543334Ssklower 	rt->rt_refcnt--;
51637469Ssklower 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
51743071Ssklower 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
51837469Ssklower 	}
51936392Ssklower }
52036392Ssklower 
52136392Ssklower /*
52236392Ssklower  * FUNCTION:		snpac_age
52336392Ssklower  *
52436392Ssklower  * PURPOSE:			Time out snpac entries
52536392Ssklower  *
52636392Ssklower  * RETURNS:
52736392Ssklower  *
52836392Ssklower  * SIDE EFFECTS:
52936392Ssklower  *
53036392Ssklower  * NOTES:			When encountering an entry for the first time, snpac_age
53136392Ssklower  *					may delete up to SNPAC_AGE too many seconds. Ie.
53236392Ssklower  *					if the entry is added a moment before snpac_age is
53336392Ssklower  *					called, the entry will immediately have SNPAC_AGE
53436392Ssklower  *					seconds taken off the holding time, even though
53536392Ssklower  *					it has only been held a brief moment.
53636392Ssklower  *
53736392Ssklower  *					The proper way to do this is set an expiry timeval
53836392Ssklower  *					equal to current time + holding time. Then snpac_age
53936392Ssklower  *					would time out entries where expiry date is older
54036392Ssklower  *					than the current time.
54136392Ssklower  */
54236392Ssklower snpac_age()
54336392Ssklower {
54443071Ssklower 	register struct llinfo_llc	*lc;
54536392Ssklower 
54636392Ssklower 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
54736392Ssklower 
54843071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
54943071Ssklower 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
55043334Ssklower 			lc->lc_rt->rt_idle -= SNPAC_AGE;
55143334Ssklower 			if (lc->lc_rt->rt_idle > 0)
55236392Ssklower 				continue;
55336392Ssklower 			else
55443071Ssklower 				snpac_free(lc);
55536392Ssklower 		}
55636392Ssklower 	}
55736392Ssklower }
55836392Ssklower 
55936392Ssklower /*
56036392Ssklower  * FUNCTION:		snpac_ownmulti
56136392Ssklower  *
56236392Ssklower  * PURPOSE:			Determine if the snpa address is a multicast address
56336392Ssklower  *					of the same type as the system.
56436392Ssklower  *
56536392Ssklower  * RETURNS:			true or false
56636392Ssklower  *
56736392Ssklower  * SIDE EFFECTS:
56836392Ssklower  *
56936392Ssklower  * NOTES:			Used by interface drivers when not in eavesdrop mode
57036392Ssklower  *					as interm kludge until
57136392Ssklower  *					real multicast addresses can be configured
57236392Ssklower  */
57336392Ssklower snpac_ownmulti(snpa, len)
57443071Ssklower caddr_t	snpa;
57543071Ssklower u_int	len;
57636392Ssklower {
57737469Ssklower 	return (((iso_systype & SNPA_ES) &&
57843071Ssklower 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
57937469Ssklower 			((iso_systype & SNPA_IS) &&
58043071Ssklower 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
58136392Ssklower }
58236392Ssklower 
58336392Ssklower /*
58436392Ssklower  * FUNCTION:		snpac_flushifp
58536392Ssklower  *
58636392Ssklower  * PURPOSE:			Flush entries associated with specific ifp
58736392Ssklower  *
58836392Ssklower  * RETURNS:			nothing
58936392Ssklower  *
59036392Ssklower  * SIDE EFFECTS:
59136392Ssklower  *
59236392Ssklower  * NOTES:
59336392Ssklower  */
59436392Ssklower snpac_flushifp(ifp)
59536392Ssklower struct ifnet	*ifp;
59636392Ssklower {
59743071Ssklower 	register struct llinfo_llc	*lc;
59836392Ssklower 
59943071Ssklower 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
60043071Ssklower 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
60143071Ssklower 			snpac_free(lc);
60236392Ssklower 	}
60336392Ssklower }
60436392Ssklower 
60536392Ssklower /*
60636392Ssklower  * FUNCTION:		snpac_rtrequest
60736392Ssklower  *
60836392Ssklower  * PURPOSE:			Make a routing request
60936392Ssklower  *
61036392Ssklower  * RETURNS:			nothing
61136392Ssklower  *
61236392Ssklower  * SIDE EFFECTS:
61336392Ssklower  *
61436392Ssklower  * NOTES:			In the future, this should make a request of a user
61536392Ssklower  *					level routing daemon.
61636392Ssklower  */
61737469Ssklower snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
61836392Ssklower int				req;
61937469Ssklower struct iso_addr	*host;
62036392Ssklower struct iso_addr	*gateway;
62137469Ssklower struct iso_addr	*netmask;
62236392Ssklower short			flags;
62337469Ssklower struct rtentry	**ret_nrt;
62436392Ssklower {
62537469Ssklower 	register struct iso_addr *r;
62636392Ssklower 
62736392Ssklower 	IFDEBUG(D_SNPA)
62836392Ssklower 		printf("snpac_rtrequest: ");
62937469Ssklower 		if (req == RTM_ADD)
63036392Ssklower 			printf("add");
63137469Ssklower 		else if (req == RTM_DELETE)
63236392Ssklower 			printf("delete");
63336392Ssklower 		else
63436392Ssklower 			printf("unknown command");
63537469Ssklower 		printf(" dst: %s\n", clnp_iso_addrp(host));
63636392Ssklower 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
63736392Ssklower 	ENDDEBUG
63836392Ssklower 
63936392Ssklower 
64037469Ssklower 	zap_isoaddr(dst, host);
64137469Ssklower 	zap_isoaddr(gte, gateway);
64243334Ssklower 	if (netmask) {
64343334Ssklower 		zap_isoaddr(msk, netmask);
64443334Ssklower 		msk.siso_nlen = 0;
64543334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
64643334Ssklower 	}
64737469Ssklower 
64837469Ssklower 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
64937469Ssklower 		flags, ret_nrt);
65036392Ssklower }
65136392Ssklower 
65236392Ssklower /*
65336392Ssklower  * FUNCTION:		snpac_addrt
65436392Ssklower  *
65536392Ssklower  * PURPOSE:			Associate a routing entry with an snpac entry
65636392Ssklower  *
65736392Ssklower  * RETURNS:			nothing
65836392Ssklower  *
65936392Ssklower  * SIDE EFFECTS:
66036392Ssklower  *
66136392Ssklower  * NOTES:			If a cache entry exists for gateway, then
66236392Ssklower  *					make a routing entry (host, gateway) and associate
66336392Ssklower  *					with gateway.
66436392Ssklower  *
66536392Ssklower  *					If a route already exists and is different, first delete
66636392Ssklower  *					it.
66736392Ssklower  *
66836392Ssklower  *					This could be made more efficient by checking
66936392Ssklower  *					the existing route before adding a new one.
67036392Ssklower  */
67139950Ssklower snpac_addrt(ifp, host, gateway, netmask)
67239950Ssklower struct ifnet *ifp;
67339950Ssklower struct iso_addr	*host, *gateway, *netmask;
67436392Ssklower {
67537469Ssklower 	register struct iso_addr *r;
67636392Ssklower 
67743071Ssklower 	zap_isoaddr(dst, host);
67843071Ssklower 	zap_isoaddr(gte, gateway);
67943071Ssklower 	if (netmask) {
68043334Ssklower 		zap_isoaddr(msk, netmask);
68143334Ssklower 		msk.siso_nlen = 0;
68243334Ssklower 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
68343071Ssklower 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
68443071Ssklower 	} else
68543071Ssklower 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
68643071Ssklower 							RTF_DONE | RTF_HOST, S(gte), 0);
68736392Ssklower }
68836392Ssklower #endif	ISO
689