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