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