xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 56533)
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.21 (Berkeley) 10/11/92
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 <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/errno.h>
49 #include <sys/ioctl.h>
50 #include <sys/syslog.h>
51 
52 #include <net/if.h>
53 #include <net/if_dl.h>
54 #include <net/route.h>
55 
56 #include <netiso/iso.h>
57 #include <netiso/iso_var.h>
58 #include <netiso/iso_snpac.h>
59 #include <netiso/clnp.h>
60 #include <netiso/clnp_stat.h>
61 #include <netiso/esis.h>
62 #include <netiso/argo_debug.h>
63 
64 int 				iso_systype = SNPA_ES;	/* default to be an ES */
65 extern short	esis_holding_time, esis_config_time, esis_esconfig_time;
66 extern struct	timeval time;
67 extern int esis_config(), hz;
68 static void snpac_fixdstandmask();
69 
70 struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO};
71 extern u_long iso_hashchar();
72 static struct sockaddr_iso
73 	dst	= {sizeof(dst), AF_ISO},
74 	gte	= {sizeof(dst), AF_ISO},
75 	src	= {sizeof(dst), AF_ISO},
76 	msk	= {sizeof(dst), AF_ISO},
77 	zmk = {0};
78 #define zsi blank_siso
79 #define zero_isoa	zsi.siso_addr
80 #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \
81 	   Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);}
82 #define S(x) ((struct sockaddr *)&(x))
83 
84 static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK};
85 static struct sockaddr_dl gte_dl;
86 #define zap_linkaddr(a, b, c, i) \
87 	(*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i)
88 
89 /*
90  *	We only keep track of a single IS at a time.
91  */
92 struct rtentry	*known_is;
93 
94 /*
95  *	Addresses taken from NBS agreements, December 1987.
96  *
97  *	These addresses assume on-the-wire transmission of least significant
98  *	bit first. This is the method used by 802.3. When these
99  *	addresses are passed to the token ring driver, (802.5), they
100  *	must be bit-swaped because 802.5 transmission order is MSb first.
101  *
102  *	Furthermore, according to IBM Austin, these addresses are not
103  *	true token ring multicast addresses. More work is necessary
104  *	to get multicast to work right on token ring.
105  *
106  *	Currently, the token ring driver does not handle multicast, so
107  *	these addresses are converted into the broadcast address in
108  *	lan_output() That means that if these multicast addresses change
109  *	the token ring driver must be altered.
110  */
111 char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 };
112 char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 };
113 char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14};
114 char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15};
115 
116 union sockunion {
117 	struct sockaddr_iso siso;
118 	struct sockaddr_dl	sdl;
119 	struct sockaddr		sa;
120 };
121 
122 /*
123  * FUNCTION:		llc_rtrequest
124  *
125  * PURPOSE:			Manage routing table entries specific to LLC for ISO.
126  *
127  * NOTES:			This does a lot of obscure magic;
128  */
129 llc_rtrequest(req, rt, sa)
130 int req;
131 register struct rtentry *rt;
132 struct sockaddr *sa;
133 {
134 	register union sockunion *gate = (union sockunion *)rt->rt_gateway;
135 	register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2;
136 	struct rtentry *rt2;
137 	struct ifnet *ifp = rt->rt_ifp;
138 	int addrlen = ifp->if_addrlen;
139 #define LLC_SIZE 3 /* XXXXXX do this right later */
140 
141 	IFDEBUG (D_SNPA)
142 		printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa);
143 	ENDDEBUG
144 	if (rt->rt_flags & RTF_GATEWAY)
145 		return;
146 	else switch (req) {
147 	case RTM_ADD:
148 		/*
149 		 * Case 1: This route may come from a route to iface with mask
150 		 * or from a default route.
151 		 */
152 		if (rt->rt_flags & RTF_CLONING) {
153 			iso_setmcasts(ifp, req);
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 (rt->rt_flags & RTF_CLONING)
188 			iso_setmcasts(ifp, req);
189 		if (lc == 0)
190 			return;
191 		remque(lc);
192 		Free(lc);
193 		rt->rt_llinfo = 0;
194 		rt->rt_flags &= ~RTF_LLINFO;
195 		break;
196 	}
197 	if (rt->rt_rmx.rmx_mtu == 0) {
198 			rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
199 	}
200 }
201 /*
202  * FUNCTION:		iso_setmcasts
203  *
204  * PURPOSE:			Enable/Disable ESIS/ISIS multicast reception on interfaces.
205  *
206  * NOTES:			This also does a lot of obscure magic;
207  */
208 iso_setmcasts(ifp, req)
209 	struct	ifnet *ifp;
210 	int		req;
211 {
212 	static char *addrlist[] =
213 		{ all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0};
214 	struct ifreq ifr;
215 	register caddr_t *cpp;
216 	int		doreset = 0;
217 
218 	bzero((caddr_t)&ifr, sizeof(ifr));
219 	for (cpp = (caddr_t *)addrlist; *cpp; cpp++) {
220 		bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6);
221 		if (req == RTM_ADD)
222 			if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
223 				doreset++;
224 		else
225 			if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET)
226 				doreset++;
227 	}
228 	if (doreset)
229 		(*ifp->if_reset)(ifp->if_unit);
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, iftype = ifp->if_type;
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 		gte_dl.sdl_type = iftype;
382 		if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) ||
383 			mrt == 0)
384 			return (0);
385 		rt = mrt;
386 		rt->rt_refcnt--;
387 	} else {
388 		register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway;
389 		rt->rt_refcnt--;
390 		if ((rt->rt_flags & RTF_LLINFO) == 0)
391 			goto add;
392 		if (nsellength && (rt->rt_flags & RTF_HOST)) {
393 			if (rt->rt_refcnt == 0) {
394 				rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0,
395 					(struct sockaddr *)0, 0, (struct rtentry *)0);
396 				rt = 0;
397 				goto add;
398 			} else {
399 				static struct iso_addr nsap2; register char *cp;
400 				nsap2 = *nsap;
401 				cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
402 				while (cp < (char *)(1 + &nsap2))
403 					*cp++ = 0;
404 				(void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
405 			}
406 		}
407 		if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
408 			int old_sdl_len = sdl->sdl_len;
409 			if (old_sdl_len < sizeof(*sdl)) {
410 				log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
411 				return (0);
412 			}
413 			zap_linkaddr(sdl, snpa, snpalen, index);
414 			sdl->sdl_len = old_sdl_len;
415 			sdl->sdl_type = iftype;
416 			new_entry = 1;
417 		}
418 	}
419 	if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0)
420 		panic("snpac_rtrequest");
421 	rt->rt_rmx.rmx_expire = ht + time.tv_sec;
422 	lc->lc_flags = SNPA_VALID | type;
423 	if ((type & SNPA_IS) && !(iso_systype & SNPA_IS))
424 		snpac_logdefis(rt);
425 	return (new_entry);
426 }
427 
428 static void
429 snpac_fixdstandmask(nsellength)
430 {
431 	register char *cp = msk.siso_data, *cplim;
432 
433 	cplim = cp + (dst.siso_nlen -= nsellength);
434 	msk.siso_len = cplim - (char *)&msk;
435 	msk.siso_nlen = 0;
436 	while (cp < cplim)
437 		*cp++ = -1;
438 	while (cp < (char *)msk.siso_pad)
439 		*cp++ = 0;
440 	for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; )
441 		*cp++ = 0;
442 }
443 
444 /*
445  * FUNCTION:		snpac_ioctl
446  *
447  * PURPOSE:			Set/Get the system type and esis parameters
448  *
449  * RETURNS:			0 on success, or unix error code
450  *
451  * SIDE EFFECTS:
452  *
453  * NOTES:
454  */
455 snpac_ioctl (so, cmd, data)
456 struct socket *so;
457 int		cmd;	/* ioctl to process */
458 caddr_t	data;	/* data for the cmd */
459 {
460 	register struct systype_req *rq = (struct systype_req *)data;
461 
462 	IFDEBUG(D_IOCTL)
463 		if (cmd == SIOCSSTYPE)
464 			printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
465 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
466 		else
467 			printf("snpac_ioctl: cmd get\n");
468 	ENDDEBUG
469 
470 	if (cmd == SIOCSSTYPE) {
471 		if ((so->so_state & SS_PRIV) == 0)
472 			return (EPERM);
473 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
474 			return(EINVAL);
475 		if (rq->sr_type & SNPA_ES) {
476 			iso_systype = SNPA_ES;
477 		} else if (rq->sr_type & SNPA_IS) {
478 			iso_systype = SNPA_IS;
479 		} else {
480 			return(EINVAL);
481 		}
482 		esis_holding_time = rq->sr_holdt;
483 		esis_config_time = rq->sr_configt;
484 		if (esis_esconfig_time != rq->sr_esconfigt) {
485 			untimeout(esis_config, (caddr_t)0);
486 			esis_esconfig_time = rq->sr_esconfigt;
487 			esis_config();
488 		}
489 	} else if (cmd == SIOCGSTYPE) {
490 		rq->sr_type = iso_systype;
491 		rq->sr_holdt = esis_holding_time;
492 		rq->sr_configt = esis_config_time;
493 		rq->sr_esconfigt = esis_esconfig_time;
494 	} else {
495 		return (EINVAL);
496 	}
497 	return (0);
498 }
499 
500 /*
501  * FUNCTION:		snpac_logdefis
502  *
503  * PURPOSE:			Mark the IS passed as the default IS
504  *
505  * RETURNS:			nothing
506  *
507  * SIDE EFFECTS:
508  *
509  * NOTES:
510  */
511 snpac_logdefis(sc)
512 register struct rtentry *sc;
513 {
514 	register struct iso_addr *r;
515 	register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway;
516 	register struct rtentry *rt;
517 
518 	if (known_is == sc || !(sc->rt_flags & RTF_HOST))
519 		return;
520 	if (known_is) {
521 		RTFREE(known_is);
522 	}
523 	known_is = sc;
524 	sc->rt_refcnt++;
525 	rt = rtalloc1((struct sockaddr *)&zsi, 0);
526 	if (rt == 0)
527 		rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk),
528 						RTF_DYNAMIC|RTF_GATEWAY, 0);
529 	else {
530 		if ((rt->rt_flags & RTF_DYNAMIC) &&
531 		    (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0)
532 			rt_setgate(rt, rt_key(rt), rt_key(sc));
533 	}
534 }
535 
536 /*
537  * FUNCTION:		snpac_age
538  *
539  * PURPOSE:			Time out snpac entries
540  *
541  * RETURNS:
542  *
543  * SIDE EFFECTS:
544  *
545  * NOTES:			When encountering an entry for the first time, snpac_age
546  *					may delete up to SNPAC_AGE too many seconds. Ie.
547  *					if the entry is added a moment before snpac_age is
548  *					called, the entry will immediately have SNPAC_AGE
549  *					seconds taken off the holding time, even though
550  *					it has only been held a brief moment.
551  *
552  *					The proper way to do this is set an expiry timeval
553  *					equal to current time + holding time. Then snpac_age
554  *					would time out entries where expiry date is older
555  *					than the current time.
556  */
557 snpac_age()
558 {
559 	register struct	llinfo_llc *lc, *nlc;
560 	register struct	rtentry *rt;
561 
562 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
563 
564 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) {
565 		nlc = lc->lc_next;
566 		if (lc->lc_flags & SNPA_VALID) {
567 			rt = lc->lc_rt;
568 			if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec)
569 				snpac_free(lc);
570 		}
571 	}
572 }
573 
574 /*
575  * FUNCTION:		snpac_ownmulti
576  *
577  * PURPOSE:			Determine if the snpa address is a multicast address
578  *					of the same type as the system.
579  *
580  * RETURNS:			true or false
581  *
582  * SIDE EFFECTS:
583  *
584  * NOTES:			Used by interface drivers when not in eavesdrop mode
585  *					as interm kludge until
586  *					real multicast addresses can be configured
587  */
588 snpac_ownmulti(snpa, len)
589 caddr_t	snpa;
590 u_int	len;
591 {
592 	return (((iso_systype & SNPA_ES) &&
593 			 (!bcmp(snpa, (caddr_t)all_es_snpa, len))) ||
594 			((iso_systype & SNPA_IS) &&
595 			 (!bcmp(snpa, (caddr_t)all_is_snpa, len))));
596 }
597 
598 /*
599  * FUNCTION:		snpac_flushifp
600  *
601  * PURPOSE:			Flush entries associated with specific ifp
602  *
603  * RETURNS:			nothing
604  *
605  * SIDE EFFECTS:
606  *
607  * NOTES:
608  */
609 snpac_flushifp(ifp)
610 struct ifnet	*ifp;
611 {
612 	register struct llinfo_llc	*lc;
613 
614 	for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) {
615 		if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
616 			snpac_free(lc);
617 	}
618 }
619 
620 /*
621  * FUNCTION:		snpac_rtrequest
622  *
623  * PURPOSE:			Make a routing request
624  *
625  * RETURNS:			nothing
626  *
627  * SIDE EFFECTS:
628  *
629  * NOTES:			In the future, this should make a request of a user
630  *					level routing daemon.
631  */
632 snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt)
633 int				req;
634 struct iso_addr	*host;
635 struct iso_addr	*gateway;
636 struct iso_addr	*netmask;
637 short			flags;
638 struct rtentry	**ret_nrt;
639 {
640 	register struct iso_addr *r;
641 
642 	IFDEBUG(D_SNPA)
643 		printf("snpac_rtrequest: ");
644 		if (req == RTM_ADD)
645 			printf("add");
646 		else if (req == RTM_DELETE)
647 			printf("delete");
648 		else
649 			printf("unknown command");
650 		printf(" dst: %s\n", clnp_iso_addrp(host));
651 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
652 	ENDDEBUG
653 
654 
655 	zap_isoaddr(dst, host);
656 	zap_isoaddr(gte, gateway);
657 	if (netmask) {
658 		zap_isoaddr(msk, netmask);
659 		msk.siso_nlen = 0;
660 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
661 	}
662 
663 	rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0),
664 		flags, ret_nrt);
665 }
666 
667 /*
668  * FUNCTION:		snpac_addrt
669  *
670  * PURPOSE:			Associate a routing entry with an snpac entry
671  *
672  * RETURNS:			nothing
673  *
674  * SIDE EFFECTS:
675  *
676  * NOTES:			If a cache entry exists for gateway, then
677  *					make a routing entry (host, gateway) and associate
678  *					with gateway.
679  *
680  *					If a route already exists and is different, first delete
681  *					it.
682  *
683  *					This could be made more efficient by checking
684  *					the existing route before adding a new one.
685  */
686 snpac_addrt(ifp, host, gateway, netmask)
687 struct ifnet *ifp;
688 struct iso_addr	*host, *gateway, *netmask;
689 {
690 	register struct iso_addr *r;
691 
692 	zap_isoaddr(dst, host);
693 	zap_isoaddr(gte, gateway);
694 	if (netmask) {
695 		zap_isoaddr(msk, netmask);
696 		msk.siso_nlen = 0;
697 		msk.siso_len = msk.siso_pad - (u_char *)&msk;
698 		rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0);
699 	} else
700 		rtredirect(S(dst), S(gte), (struct sockaddr *)0,
701 							RTF_DONE | RTF_HOST, S(gte), 0);
702 }
703 #endif	ISO
704