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