xref: /original-bsd/sys/netiso/iso_snpac.c (revision de3f5c4e)
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.13 (Berkeley) 05/06/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 "user.h"
45 #include "mbuf.h"
46 #include "domain.h"
47 #include "protosw.h"
48 #include "socket.h"
49 #include "socketvar.h"
50 #include "errno.h"
51 #include "ioctl.h"
52 #include "kernel.h"
53 #include "syslog.h"
54 
55 #include "../net/if.h"
56 #include "../net/if_dl.h"
57 #include "../net/route.h"
58 
59 #include "iso.h"
60 #include "iso_var.h"
61 #include "iso_snpac.h"
62 #include "clnp.h"
63 #include "clnp_stat.h"
64 #include "esis.h"
65 #include "argo_debug.h"
66 
67 int 				iso_systype = SNPA_ES;	/* default to be an ES */
68 extern short	esis_holding_time, esis_config_time, esis_esconfig_time;
69 extern int esis_config();
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((caddr_t)&a.siso_addr, sizeof(*r)), \
82 	   ((r = b) && bcopy((caddr_t)r, (caddr_t)&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 			log(LOG_DEBUG, "llc_rtrequest: losing old rt_llinfo\n");
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_idle = ht;
424 	lc->lc_flags = SNPA_VALID | type;
425 	if (type & SNPA_IS)
426 		snpac_logdefis(rt);
427 	return (new_entry);
428 }
429 
430 static snpac_fixdstandmask(nsellength)
431 {
432 	register char *cp = msk.siso_data, *cplim;
433 
434 	cplim = cp + (dst.siso_nlen -= nsellength);
435 	msk.siso_len = cplim - (char *)&msk;
436 	msk.siso_nlen = 0;
437 	while (cp < cplim)
438 		*cp++ = -1;
439 	while (cp < (char *)msk.siso_pad)
440 		*cp++ = 0;
441 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
442 		*cp++ = 0;
443 }
444 
445 /*
446  * FUNCTION:		snpac_ioctl
447  *
448  * PURPOSE:			Set/Get the system type and esis parameters
449  *
450  * RETURNS:			0 on success, or unix error code
451  *
452  * SIDE EFFECTS:
453  *
454  * NOTES:
455  */
456 snpac_ioctl (cmd, data)
457 int		cmd;	/* ioctl to process */
458 caddr_t	data;	/* data for the cmd */
459 {
460 	register struct systype_req *rq = (struct systype_req *)data;
461 
462 	IFDEBUG(D_IOCTL)
463 		if (cmd == SIOCSSTYPE)
464 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
465 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
466 		else
467 			printf("snpac_ioctl: cmd get\n");
468 	ENDDEBUG
469 
470 	if (cmd == SIOCSSTYPE) {
471 		if (suser(u.u_cred, &u.u_acflag))
472 			return(EACCES);
473 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
474 			return(EINVAL);
475 		if (rq->sr_type & SNPA_ES) {
476 			iso_systype = SNPA_ES;
477 		} else if (rq->sr_type & SNPA_IS) {
478 			iso_systype = SNPA_IS;
479 		} else {
480 			return(EINVAL);
481 		}
482 		esis_holding_time = rq->sr_holdt;
483 		esis_config_time = rq->sr_configt;
484 		if (esis_esconfig_time != rq->sr_esconfigt) {
485 			untimeout(esis_config, (caddr_t)0);
486 			esis_esconfig_time = rq->sr_esconfigt;
487 			esis_config();
488 		}
489 	} else if (cmd == SIOCGSTYPE) {
490 		rq->sr_type = iso_systype;
491 		rq->sr_holdt = esis_holding_time;
492 		rq->sr_configt = esis_config_time;
493 		rq->sr_esconfigt = esis_esconfig_time;
494 	} else {
495 		return (EINVAL);
496 	}
497 	return (0);
498 }
499 
500 /*
501  * FUNCTION:		snpac_logdefis
502  *
503  * PURPOSE:			Mark the IS passed as the default IS
504  *
505  * RETURNS:			nothing
506  *
507  * SIDE EFFECTS:
508  *
509  * NOTES:
510  */
511 snpac_logdefis(sc)
512 register struct rtentry *sc;
513 {
514 	register struct iso_addr *r;
515 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
516 	register struct rtentry *rt = rtalloc1((struct sockaddr *)&zsi, 0);
517 
518 	zap_linkaddr((&gte_dl), LLADDR(sdl), sdl->sdl_alen, sdl->sdl_index);
519 	if (known_is == 0)
520 		known_is = sc;
521 	if (known_is != sc) {
522 		rtfree(known_is);
523 		known_is = sc;
524 	}
525 	if (rt == 0) {
526 		rtrequest(RTM_ADD, S(zsi), S(gte_dl), S(zmk),
527 						RTF_DYNAMIC|RTF_GATEWAY|RTF_CLONING, 0);
528 		return;
529 	}
530 	rt->rt_refcnt--;
531 	if (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) {
532 		*((struct sockaddr_dl *)rt->rt_gateway) = gte_dl;
533 	}
534 }
535 
536 /*
537  * FUNCTION:		snpac_age
538  *
539  * PURPOSE:			Time out snpac entries
540  *
541  * RETURNS:
542  *
543  * SIDE EFFECTS:
544  *
545  * NOTES:			When encountering an entry for the first time, snpac_age
546  *					may delete up to SNPAC_AGE too many seconds. Ie.
547  *					if the entry is added a moment before snpac_age is
548  *					called, the entry will immediately have SNPAC_AGE
549  *					seconds taken off the holding time, even though
550  *					it has only been held a brief moment.
551  *
552  *					The proper way to do this is set an expiry timeval
553  *					equal to current time + holding time. Then snpac_age
554  *					would time out entries where expiry date is older
555  *					than the current time.
556  */
557 snpac_age()
558 {
559 	register struct llinfo_llc	*lc;
560 
561 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
562 
563 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
564 		if (((lc->lc_flags & SNPA_PERM) == 0) && (lc->lc_flags & SNPA_VALID)) {
565 			lc->lc_rt->rt_idle -= SNPAC_AGE;
566 			if (lc->lc_rt->rt_idle > 0)
567 				continue;
568 			else
569 				snpac_free(lc);
570 		}
571 	}
572 }
573 
574 /*
575  * FUNCTION:		snpac_ownmulti
576  *
577  * PURPOSE:			Determine if the snpa address is a multicast address
578  *					of the same type as the system.
579  *
580  * RETURNS:			true or false
581  *
582  * SIDE EFFECTS:
583  *
584  * NOTES:			Used by interface drivers when not in eavesdrop mode
585  *					as interm kludge until
586  *					real multicast addresses can be configured
587  */
588 snpac_ownmulti(snpa, len)
589 caddr_t	snpa;
590 u_int	len;
591 {
592 	return (((iso_systype & SNPA_ES) &&
593 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
594 			((iso_systype & SNPA_IS) &&
595 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
596 }
597 
598 /*
599  * FUNCTION:		snpac_flushifp
600  *
601  * PURPOSE:			Flush entries associated with specific ifp
602  *
603  * RETURNS:			nothing
604  *
605  * SIDE EFFECTS:
606  *
607  * NOTES:
608  */
609 snpac_flushifp(ifp)
610 struct ifnet	*ifp;
611 {
612 	register struct llinfo_llc	*lc;
613 
614 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
615 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
616 			snpac_free(lc);
617 	}
618 }
619 
620 /*
621  * FUNCTION:		snpac_rtrequest
622  *
623  * PURPOSE:			Make a routing request
624  *
625  * RETURNS:			nothing
626  *
627  * SIDE EFFECTS:
628  *
629  * NOTES:			In the future, this should make a request of a user
630  *					level routing daemon.
631  */
632 snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
633 int				req;
634 struct iso_addr	*host;
635 struct iso_addr	*gateway;
636 struct iso_addr	*netmask;
637 short			flags;
638 struct rtentry	**ret_nrt;
639 {
640 	register struct iso_addr *r;
641 
642 	IFDEBUG(D_SNPA)
643 		printf("snpac_rtrequest: ");
644 		if (req == RTM_ADD)
645 			printf("add");
646 		else if (req == RTM_DELETE)
647 			printf("delete");
648 		else
649 			printf("unknown command");
650 		printf(" dst: %s\n", clnp_iso_addrp(host));
651 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
652 	ENDDEBUG
653 
654 
655 	zap_isoaddr(dst, host);
656 	zap_isoaddr(gte, gateway);
657 	if (netmask) {
658 		zap_isoaddr(msk, netmask);
659 		msk.siso_nlen = 0;
660 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
661 	}
662 
663 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
664 		flags, ret_nrt);
665 }
666 
667 /*
668  * FUNCTION:		snpac_addrt
669  *
670  * PURPOSE:			Associate a routing entry with an snpac entry
671  *
672  * RETURNS:			nothing
673  *
674  * SIDE EFFECTS:
675  *
676  * NOTES:			If a cache entry exists for gateway, then
677  *					make a routing entry (host, gateway) and associate
678  *					with gateway.
679  *
680  *					If a route already exists and is different, first delete
681  *					it.
682  *
683  *					This could be made more efficient by checking
684  *					the existing route before adding a new one.
685  */
686 snpac_addrt(ifp, host, gateway, netmask)
687 struct ifnet *ifp;
688 struct iso_addr	*host, *gateway, *netmask;
689 {
690 	register struct iso_addr *r;
691 
692 	zap_isoaddr(dst, host);
693 	zap_isoaddr(gte, gateway);
694 	if (netmask) {
695 		zap_isoaddr(msk, netmask);
696 		msk.siso_nlen = 0;
697 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
698 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
699 	} else
700 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
701 							RTF_DONE | RTF_HOST, S(gte), 0);
702 }
703 #endif	ISO
704