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