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