xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 57952)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)iso_snpac.c	7.22 (Berkeley) 02/12/93
8  */
9 
10 /***********************************************************
11 		Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /* $Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $ */
37 /* $Source: /usr/argo/sys/netiso/RCS/iso_snpac.c,v $ */
38 
39 #ifdef ISO
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/errno.h>
49 #include <sys/ioctl.h>
50 #include <sys/syslog.h>
51 
52 #include <net/if.h>
53 #include <net/if_dl.h>
54 #include <net/route.h>
55 
56 #include <netiso/iso.h>
57 #include <netiso/iso_var.h>
58 #include <netiso/iso_snpac.h>
59 #include <netiso/clnp.h>
60 #include <netiso/clnp_stat.h>
61 #include <netiso/esis.h>
62 #include <netiso/argo_debug.h>
63 
64 int 				iso_systype = SNPA_ES;	/* default to be an ES */
65 extern short	esis_holding_time, esis_config_time, esis_esconfig_time;
66 extern struct	timeval time;
67 extern int esis_config(), hz;
68 static void snpac_fixdstandmask();
69 
70 struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
71 extern u_long iso_hashchar();
72 static struct sockaddr_iso
73 	dst	= {sizeof(dst), AF_ISO},
74 	gte	= {sizeof(dst), AF_ISO},
75 	src	= {sizeof(dst), AF_ISO},
76 	msk	= {sizeof(dst), AF_ISO},
77 	zmk = {0};
78 #define zsi blank_siso
79 #define zero_isoa	zsi.siso_addr
80 #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \
81 	   Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);}
82 #define S(x) ((struct sockaddr *)&(x))
83 
84 static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
85 static struct sockaddr_dl gte_dl;
86 #define zap_linkaddr(a, b, c, i) \
87 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
88 
89 /*
90  *	We only keep track of a single IS at a time.
91  */
92 struct rtentry	*known_is;
93 
94 /*
95  *	Addresses taken from NBS agreements, December 1987.
96  *
97  *	These addresses assume on-the-wire transmission of least significant
98  *	bit first. This is the method used by 802.3. When these
99  *	addresses are passed to the token ring driver, (802.5), they
100  *	must be bit-swaped because 802.5 transmission order is MSb first.
101  *
102  *	Furthermore, according to IBM Austin, these addresses are not
103  *	true token ring multicast addresses. More work is necessary
104  *	to get multicast to work right on token ring.
105  *
106  *	Currently, the token ring driver does not handle multicast, so
107  *	these addresses are converted into the broadcast address in
108  *	lan_output() That means that if these multicast addresses change
109  *	the token ring driver must be altered.
110  */
111 char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 };
112 char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 };
113 char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14};
114 char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15};
115 
116 union sockunion {
117 	struct sockaddr_iso siso;
118 	struct sockaddr_dl	sdl;
119 	struct sockaddr		sa;
120 };
121 
122 /*
123  * FUNCTION:		llc_rtrequest
124  *
125  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
126  *
127  * NOTES:			This does a lot of obscure magic;
128  */
129 llc_rtrequest(req, rt, sa)
130 int req;
131 register struct rtentry *rt;
132 struct sockaddr *sa;
133 {
134 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
135 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
136 	struct rtentry *rt2;
137 	struct ifnet *ifp = rt->rt_ifp;
138 	int addrlen = ifp->if_addrlen;
139 #define LLC_SIZE 3 /* XXXXXX do this right later */
140 
141 	IFDEBUG (D_SNPA)
142 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
143 	ENDDEBUG
144 	if (rt->rt_flags & RTF_GATEWAY)
145 		return;
146 	else switch (req) {
147 	case RTM_ADD:
148 		/*
149 		 * Case 1: This route may come from a route to iface with mask
150 		 * or from a default route.
151 		 */
152 		if (rt->rt_flags & RTF_CLONING) {
153 			iso_setmcasts(ifp, req);
154 			rt_setgate(rt, rt_key(rt), &blank_dl);
155 			return;
156 		}
157 		if (lc != 0)
158 			return; /* happens on a route change */
159 		/* FALLTHROUGH */
160 	case RTM_RESOLVE:
161 		/*
162 		 * Case 2:  This route may come from cloning, or a manual route
163 		 * add with a LL address.
164 		 */
165 		if (gate->sdl.sdl_family != AF_LINK) {
166 			log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
167 			break;
168 		}
169 		R_Malloc(lc, struct llinfo_llc *, sizeof (*lc));
170 		rt->rt_llinfo = (caddr_t)lc;
171 		if (lc == 0) {
172 			log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
173 			break;
174 		}
175 		Bzero(lc, sizeof(*lc));
176 		lc->lc_rt = rt;
177 		rt->rt_flags |= RTF_LLINFO;
178 		insque(lc, &llinfo_llc);
179 		if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) {
180 			gate->sdl.sdl_alen -= sizeof(struct esis_req);
181 			bcopy(addrlen + LLADDR(&gate->sdl),
182 				  (caddr_t)&lc->lc_er, sizeof(lc->lc_er));
183 		} else if (gate->sdl.sdl_alen == addrlen)
184 			lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
185 		break;
186 	case RTM_DELETE:
187 		if (rt->rt_flags & RTF_CLONING)
188 			iso_setmcasts(ifp, req);
189 		if (lc == 0)
190 			return;
191 		remque(lc);
192 		Free(lc);
193 		rt->rt_llinfo = 0;
194 		rt->rt_flags &= ~RTF_LLINFO;
195 		break;
196 	}
197 	if (rt->rt_rmx.rmx_mtu == 0) {
198 			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
199 	}
200 }
201 /*
202  * FUNCTION:		iso_setmcasts
203  *
204  * PURPOSE:			Enable/Disable ESIS/ISIS multicast reception on interfaces.
205  *
206  * NOTES:			This also does a lot of obscure magic;
207  */
208 iso_setmcasts(ifp, req)
209 	struct	ifnet *ifp;
210 	int		req;
211 {
212 	static char *addrlist[] =
213 		{ all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0};
214 	struct ifreq ifr;
215 	register caddr_t *cpp;
216 	int		doreset = 0;
217 
218 	bzero((caddr_t)&ifr, sizeof(ifr));
219 	for (cpp = (caddr_t *)addrlist; *cpp; cpp++) {
220 		bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6);
221 		if (req == RTM_ADD)
222 			if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
223 				doreset++;
224 		else
225 			if (ether_delmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
226 				doreset++;
227 	}
228 	if (doreset) {
229 		if (ifp->if_reset)
230 			(*ifp->if_reset)(ifp->if_unit);
231 		else
232 			printf("iso_setmcasts: %s%d needs reseting to receive iso mcasts\n",
233 					ifp->if_name, ifp->if_unit);
234 	}
235 }
236 /*
237  * FUNCTION:		iso_snparesolve
238  *
239  * PURPOSE:			Resolve an iso address into snpa address
240  *
241  * RETURNS:			0 if addr is resolved
242  *					errno if addr is unknown
243  *
244  * SIDE EFFECTS:
245  *
246  * NOTES:			Now that we have folded the snpa cache into the routing
247  *					table, we know there is no snpa address known for this
248  *					destination.  If we know of a default IS, then the address
249  *					of the IS is returned.  If no IS is known, then return the
250  *					multi-cast address for "all ES" for this interface.
251  *
252  *					NB: the last case described above constitutes the
253  *					query configuration function 9542, sec 6.5
254  *					A mechanism is needed to prevent this function from
255  *					being invoked if the system is an IS.
256  */
257 iso_snparesolve(ifp, dest, snpa, snpa_len)
258 struct	ifnet *ifp;			/* outgoing interface */
259 struct	sockaddr_iso *dest;	/* destination */
260 caddr_t	snpa;				/* RESULT: snpa to be used */
261 int		*snpa_len;			/* RESULT: length of snpa */
262 {
263 	struct	llinfo_llc *sc;	/* ptr to snpa table entry */
264 	caddr_t	found_snpa;
265 	int 	addrlen;
266 
267 	/*
268 	 *	This hack allows us to send esis packets that have the destination snpa
269 	 *	addresss embedded in the destination nsap address
270 	 */
271 	if (dest->siso_data[0] == AFI_SNA) {
272 		/*
273 		 *	This is a subnetwork address. Return it immediately
274 		 */
275 		IFDEBUG(D_SNPA)
276 			printf("iso_snparesolve: return SN address\n");
277 		ENDDEBUG
278 		addrlen = dest->siso_nlen - 1;	/* subtract size of AFI */
279 		found_snpa = (caddr_t) dest->siso_data + 1;
280 	/*
281 	 * If we are an IS, we can't do much with the packet;
282 	 *	Check if we know about an IS.
283 	 */
284 	} else if (iso_systype != SNPA_IS && known_is != 0 &&
285 				(sc = (struct llinfo_llc *)known_is->rt_llinfo) &&
286 				 (sc->lc_flags & SNPA_VALID)) {
287 		register struct sockaddr_dl *sdl =
288 			(struct sockaddr_dl *)(known_is->rt_gateway);
289 		found_snpa = LLADDR(sdl);
290 		addrlen = sdl->sdl_alen;
291 	} else if (ifp->if_flags & IFF_BROADCAST) {
292 		/*
293 		 *	no IS, no match. Return "all es" multicast address for this
294 		 *	interface, as per Query Configuration Function (9542 sec 6.5)
295 		 *
296 		 *	Note: there is a potential problem here. If the destination
297 		 *	is on the subnet and it does not respond with a ESH, but
298 		 *	does send back a TP CC, a connection could be established
299 		 *	where we always transmit the CLNP packet to "all es"
300 		 */
301 		addrlen = ifp->if_addrlen;
302 		found_snpa = (caddr_t)all_es_snpa;
303 	} else
304 		return (ENETUNREACH);
305 	bcopy(found_snpa, snpa, *snpa_len = addrlen);
306 	return (0);
307 }
308 
309 
310 /*
311  * FUNCTION:		snpac_free
312  *
313  * PURPOSE:			free an entry in the iso address map table
314  *
315  * RETURNS:			nothing
316  *
317  * SIDE EFFECTS:
318  *
319  * NOTES:			If there is a route entry associated with cache
320  *					entry, then delete that as well
321  */
322 snpac_free(lc)
323 register struct llinfo_llc *lc;		/* entry to free */
324 {
325 	register struct rtentry *rt = lc->lc_rt;
326 	register struct iso_addr *r;
327 
328 	if (known_is == rt)
329 		known_is = 0;
330 	if (rt && (rt->rt_flags & RTF_UP) &&
331 		(rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
332 			RTFREE(rt);
333 			rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
334 						rt->rt_flags, (struct rtentry **)0);
335 		RTFREE(rt);
336 	}
337 }
338 
339 /*
340  * FUNCTION:		snpac_add
341  *
342  * PURPOSE:			Add an entry to the snpa cache
343  *
344  * RETURNS:
345  *
346  * SIDE EFFECTS:
347  *
348  * NOTES:			If entry already exists, then update holding time.
349  */
350 snpac_add(ifp, nsap, snpa, type, ht, nsellength)
351 struct ifnet		*ifp;		/* interface info is related to */
352 struct iso_addr		*nsap;		/* nsap to add */
353 caddr_t				snpa;		/* translation */
354 char				type;		/* SNPA_IS or SNPA_ES */
355 u_short				ht;			/* holding time (in seconds) */
356 int					nsellength;	/* nsaps may differ only in trailing bytes */
357 {
358 	register struct	llinfo_llc *lc;
359 	register struct rtentry *rt;
360 	struct	rtentry *mrt = 0;
361 	register struct	iso_addr *r; /* for zap_isoaddr macro */
362 	int		snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
363 	int		new_entry = 0, index = ifp->if_index, iftype = ifp->if_type;
364 
365 	IFDEBUG(D_SNPA)
366 		printf("snpac_add(%x, %x, %x, %x, %x, %x)\n",
367 			ifp, nsap, snpa, type, ht, nsellength);
368 	ENDDEBUG
369 	zap_isoaddr(dst, nsap);
370 	rt = rtalloc1(S(dst), 0);
371 	IFDEBUG(D_SNPA)
372 		printf("snpac_add: rtalloc1 returns %x\n", rt);
373 	ENDDEBUG
374 	if (rt == 0) {
375 		struct sockaddr *netmask;
376 		int flags;
377 		add:
378 		if (nsellength) {
379 			netmask = S(msk); flags = RTF_UP;
380 			snpac_fixdstandmask(nsellength);
381 		} else {
382 			netmask = 0; flags = RTF_UP | RTF_HOST;
383 		}
384 		new_entry = 1;
385 		zap_linkaddr((&gte_dl), snpa, snpalen, index);
386 		gte_dl.sdl_type = iftype;
387 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
388 			mrt == 0)
389 			return (0);
390 		rt = mrt;
391 		rt->rt_refcnt--;
392 	} else {
393 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
394 		rt->rt_refcnt--;
395 		if ((rt->rt_flags & RTF_LLINFO) == 0)
396 			goto add;
397 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
398 			if (rt->rt_refcnt == 0) {
399 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
400 					(struct sockaddr *)0, 0, (struct rtentry *)0);
401 				rt = 0;
402 				goto add;
403 			} else {
404 				static struct iso_addr nsap2; register char *cp;
405 				nsap2 = *nsap;
406 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
407 				while (cp < (char *)(1 + &nsap2))
408 					*cp++ = 0;
409 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
410 			}
411 		}
412 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
413 			int old_sdl_len = sdl->sdl_len;
414 			if (old_sdl_len < sizeof(*sdl)) {
415 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
416 				return (0);
417 			}
418 			zap_linkaddr(sdl, snpa, snpalen, index);
419 			sdl->sdl_len = old_sdl_len;
420 			sdl->sdl_type = iftype;
421 			new_entry = 1;
422 		}
423 	}
424 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
425 		panic("snpac_rtrequest");
426 	rt->rt_rmx.rmx_expire = ht + time.tv_sec;
427 	lc->lc_flags = SNPA_VALID | type;
428 	if ((type & SNPA_IS) && !(iso_systype & SNPA_IS))
429 		snpac_logdefis(rt);
430 	return (new_entry);
431 }
432 
433 static void
434 snpac_fixdstandmask(nsellength)
435 {
436 	register char *cp = msk.siso_data, *cplim;
437 
438 	cplim = cp + (dst.siso_nlen -= nsellength);
439 	msk.siso_len = cplim - (char *)&msk;
440 	msk.siso_nlen = 0;
441 	while (cp < cplim)
442 		*cp++ = -1;
443 	while (cp < (char *)msk.siso_pad)
444 		*cp++ = 0;
445 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
446 		*cp++ = 0;
447 }
448 
449 /*
450  * FUNCTION:		snpac_ioctl
451  *
452  * PURPOSE:			Set/Get the system type and esis parameters
453  *
454  * RETURNS:			0 on success, or unix error code
455  *
456  * SIDE EFFECTS:
457  *
458  * NOTES:
459  */
460 snpac_ioctl (so, cmd, data)
461 struct socket *so;
462 int		cmd;	/* ioctl to process */
463 caddr_t	data;	/* data for the cmd */
464 {
465 	register struct systype_req *rq = (struct systype_req *)data;
466 
467 	IFDEBUG(D_IOCTL)
468 		if (cmd == SIOCSSTYPE)
469 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
470 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
471 		else
472 			printf("snpac_ioctl: cmd get\n");
473 	ENDDEBUG
474 
475 	if (cmd == SIOCSSTYPE) {
476 		if ((so->so_state & SS_PRIV) == 0)
477 			return (EPERM);
478 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
479 			return(EINVAL);
480 		if (rq->sr_type & SNPA_ES) {
481 			iso_systype = SNPA_ES;
482 		} else if (rq->sr_type & SNPA_IS) {
483 			iso_systype = SNPA_IS;
484 		} else {
485 			return(EINVAL);
486 		}
487 		esis_holding_time = rq->sr_holdt;
488 		esis_config_time = rq->sr_configt;
489 		if (esis_esconfig_time != rq->sr_esconfigt) {
490 			untimeout(esis_config, (caddr_t)0);
491 			esis_esconfig_time = rq->sr_esconfigt;
492 			esis_config();
493 		}
494 	} else if (cmd == SIOCGSTYPE) {
495 		rq->sr_type = iso_systype;
496 		rq->sr_holdt = esis_holding_time;
497 		rq->sr_configt = esis_config_time;
498 		rq->sr_esconfigt = esis_esconfig_time;
499 	} else {
500 		return (EINVAL);
501 	}
502 	return (0);
503 }
504 
505 /*
506  * FUNCTION:		snpac_logdefis
507  *
508  * PURPOSE:			Mark the IS passed as the default IS
509  *
510  * RETURNS:			nothing
511  *
512  * SIDE EFFECTS:
513  *
514  * NOTES:
515  */
516 snpac_logdefis(sc)
517 register struct rtentry *sc;
518 {
519 	register struct iso_addr *r;
520 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
521 	register struct rtentry *rt;
522 
523 	if (known_is == sc || !(sc->rt_flags & RTF_HOST))
524 		return;
525 	if (known_is) {
526 		RTFREE(known_is);
527 	}
528 	known_is = sc;
529 	sc->rt_refcnt++;
530 	rt = rtalloc1((struct sockaddr *)&zsi, 0);
531 	if (rt == 0)
532 		rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk),
533 						RTF_DYNAMIC|RTF_GATEWAY, 0);
534 	else {
535 		if ((rt->rt_flags & RTF_DYNAMIC) &&
536 		    (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0)
537 			rt_setgate(rt, rt_key(rt), rt_key(sc));
538 	}
539 }
540 
541 /*
542  * FUNCTION:		snpac_age
543  *
544  * PURPOSE:			Time out snpac entries
545  *
546  * RETURNS:
547  *
548  * SIDE EFFECTS:
549  *
550  * NOTES:			When encountering an entry for the first time, snpac_age
551  *					may delete up to SNPAC_AGE too many seconds. Ie.
552  *					if the entry is added a moment before snpac_age is
553  *					called, the entry will immediately have SNPAC_AGE
554  *					seconds taken off the holding time, even though
555  *					it has only been held a brief moment.
556  *
557  *					The proper way to do this is set an expiry timeval
558  *					equal to current time + holding time. Then snpac_age
559  *					would time out entries where expiry date is older
560  *					than the current time.
561  */
562 snpac_age()
563 {
564 	register struct	llinfo_llc *lc, *nlc;
565 	register struct	rtentry *rt;
566 
567 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
568 
569 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) {
570 		nlc = lc->lc_next;
571 		if (lc->lc_flags & SNPA_VALID) {
572 			rt = lc->lc_rt;
573 			if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec)
574 				snpac_free(lc);
575 		}
576 	}
577 }
578 
579 /*
580  * FUNCTION:		snpac_ownmulti
581  *
582  * PURPOSE:			Determine if the snpa address is a multicast address
583  *					of the same type as the system.
584  *
585  * RETURNS:			true or false
586  *
587  * SIDE EFFECTS:
588  *
589  * NOTES:			Used by interface drivers when not in eavesdrop mode
590  *					as interm kludge until
591  *					real multicast addresses can be configured
592  */
593 snpac_ownmulti(snpa, len)
594 caddr_t	snpa;
595 u_int	len;
596 {
597 	return (((iso_systype & SNPA_ES) &&
598 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
599 			((iso_systype & SNPA_IS) &&
600 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
601 }
602 
603 /*
604  * FUNCTION:		snpac_flushifp
605  *
606  * PURPOSE:			Flush entries associated with specific ifp
607  *
608  * RETURNS:			nothing
609  *
610  * SIDE EFFECTS:
611  *
612  * NOTES:
613  */
614 snpac_flushifp(ifp)
615 struct ifnet	*ifp;
616 {
617 	register struct llinfo_llc	*lc;
618 
619 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
620 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
621 			snpac_free(lc);
622 	}
623 }
624 
625 /*
626  * FUNCTION:		snpac_rtrequest
627  *
628  * PURPOSE:			Make a routing request
629  *
630  * RETURNS:			nothing
631  *
632  * SIDE EFFECTS:
633  *
634  * NOTES:			In the future, this should make a request of a user
635  *					level routing daemon.
636  */
637 snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
638 int				req;
639 struct iso_addr	*host;
640 struct iso_addr	*gateway;
641 struct iso_addr	*netmask;
642 short			flags;
643 struct rtentry	**ret_nrt;
644 {
645 	register struct iso_addr *r;
646 
647 	IFDEBUG(D_SNPA)
648 		printf("snpac_rtrequest: ");
649 		if (req == RTM_ADD)
650 			printf("add");
651 		else if (req == RTM_DELETE)
652 			printf("delete");
653 		else
654 			printf("unknown command");
655 		printf(" dst: %s\n", clnp_iso_addrp(host));
656 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
657 	ENDDEBUG
658 
659 
660 	zap_isoaddr(dst, host);
661 	zap_isoaddr(gte, gateway);
662 	if (netmask) {
663 		zap_isoaddr(msk, netmask);
664 		msk.siso_nlen = 0;
665 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
666 	}
667 
668 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
669 		flags, ret_nrt);
670 }
671 
672 /*
673  * FUNCTION:		snpac_addrt
674  *
675  * PURPOSE:			Associate a routing entry with an snpac entry
676  *
677  * RETURNS:			nothing
678  *
679  * SIDE EFFECTS:
680  *
681  * NOTES:			If a cache entry exists for gateway, then
682  *					make a routing entry (host, gateway) and associate
683  *					with gateway.
684  *
685  *					If a route already exists and is different, first delete
686  *					it.
687  *
688  *					This could be made more efficient by checking
689  *					the existing route before adding a new one.
690  */
691 snpac_addrt(ifp, host, gateway, netmask)
692 struct ifnet *ifp;
693 struct iso_addr	*host, *gateway, *netmask;
694 {
695 	register struct iso_addr *r;
696 
697 	zap_isoaddr(dst, host);
698 	zap_isoaddr(gte, gateway);
699 	if (netmask) {
700 		zap_isoaddr(msk, netmask);
701 		msk.siso_nlen = 0;
702 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
703 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
704 	} else
705 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
706 							RTF_DONE | RTF_HOST, S(gte), 0);
707 }
708 #endif	ISO
709