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