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