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