xref: /csrg-svn/sys/netiso/iso_snpac.c (revision 36392)
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 
30 #ifndef lint
31 static char *rcsid = "$Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $";
32 #endif lint
33 
34 #ifdef ISO
35 
36 #include "../h/types.h"
37 #include "../h/param.h"
38 #include "../h/mbuf.h"
39 #include "../h/domain.h"
40 #include "../h/protosw.h"
41 #include "../h/socket.h"
42 #include "../h/socketvar.h"
43 #include "../h/errno.h"
44 #include "../h/ioctl.h"
45 #include "../h/time.h"
46 #include "../h/kernel.h"
47 
48 #include "../net/if.h"
49 #include "../net/route.h"
50 
51 #include "../netiso/iso.h"
52 #include "../netiso/iso_var.h"
53 #include "../netiso/iso_snpac.h"
54 #include "../netiso/clnp.h"
55 #include "../netiso/clnp_stat.h"
56 #include "../netiso/argo_debug.h"
57 #include "../netiso/esis.h"
58 
59 #define	SNPAC_BSIZ	20		/* bucket size */
60 #define	SNPAC_NB	13		/* number of buckets */
61 #define	SNPAC_SIZE	(SNPAC_BSIZ * SNPAC_NB)
62 struct	snpa_cache	iso_snpac[SNPAC_SIZE];
63 int					iso_snpac_size = SNPAC_SIZE;/* for iso_map command */
64 int 				iso_systype = SNPA_ES;	/* default to be an ES */
65 static struct iso_addr	zero_isoa;
66 
67 #define	SNPAC_HASH(addr) \
68 	(((u_long) iso_hashchar(addr, addr->isoa_len)) % SNPAC_NB)
69 
70 #define	SNPAC_LOOK(sc,addr) { \
71 	register n; \
72 	sc = &iso_snpac[SNPAC_HASH(addr) * SNPAC_BSIZ]; \
73 	for (n = 0 ; n < SNPAC_BSIZ ; n++,sc++) \
74 		if ((sc->sc_flags & SNPA_VALID) && \
75 			(iso_addrmatch1(&sc->sc_nsap, addr))) \
76 			break; \
77 	if (n >= SNPAC_BSIZ) \
78 		sc = 0; \
79 }
80 
81 struct snpa_cache	*snpac_new();
82 
83 /*
84  *	We only keep track of a single IS at a time.
85  */
86 struct snpa_cache	*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 struct snpa_cache	all_es = {
106 	{ { 0x0 },							/* sc_nsap */
107 	6,									/* sc_len */
108 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }, /* sc_snpa */
109 	SNPA_VALID,							/* sc_flags */
110 	0	}								/* sc_ht */
111 };
112 struct snpa_cache	all_is = {
113 	{ { 0x0 },							/* sc_nsap */
114 	6,									/* sc_len */
115 	{ 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }, /* sc_snpa */
116 	SNPA_VALID,							/* sc_flags */
117 	0	}								/* sc_ht */
118 };
119 
120 
121 /*
122  * FUNCTION:		iso_snparesolve
123  *
124  * PURPOSE:			Resolve an iso address into snpa address
125  *
126  * RETURNS:			0 if addr is resolved
127  *					errno if addr is unknown
128  *
129  * SIDE EFFECTS:
130  *
131  * NOTES:			If an entry is found that matches the address, that
132  *					snpa is returned. If no entry is found, but an IS is
133  *					known, then the address of the IS is returned. If
134  *					neither an address is found that matches or an IS is
135  *					known, then the multi-cast address for "all ES" for
136  *					this interface is returned.
137  *
138  *					NB: the last case described above constitutes the
139  *					query configuration function 9542, sec 6.5
140  *					A mechanism is needed to prevent this function from
141  *					being invoked if the system is an IS.
142  */
143 iso_snparesolve(ifp, dst, snpa, snpa_len)
144 struct ifnet 		*ifp;	/* outgoing interface */
145 struct sockaddr_iso *dst;	/* destination */
146 char				*snpa;	/* RESULT: snpa to be used */
147 int					*snpa_len;	/* RESULT: length of snpa */
148 {
149 	extern struct ifnet 	loif;		/* loopback interface */
150 	struct snpa_cache		*sc;		/* ptr to snpa table entry */
151 	struct iso_addr			*destiso;	/* destination iso addr */
152 	int						s;
153 
154  	destiso = &dst->siso_addr;
155 
156 	/*
157 	 *	This hack allows us to send esis packets that have the destination snpa
158 	 *	addresss embedded in the destination nsap address
159 	 */
160 	if (destiso->isoa_afi == AFI_SNA) {
161 		/*
162 		 *	This is a subnetwork address. Return it immediately
163 		 */
164 		IFDEBUG(D_SNPA)
165 			printf("iso_snparesolve: return SN address\n");
166 		ENDDEBUG
167 
168 		*snpa_len = destiso->isoa_len - 1;	/* subtract size of AFI */
169 		bcopy((caddr_t) destiso->sna_idi, (caddr_t)snpa, *snpa_len);
170 		return (0);
171 	}
172 
173 	IFDEBUG(D_SNPA)
174 		printf("iso_snparesolve: resolving %s\n", clnp_iso_addrp(destiso));
175 	ENDDEBUG
176 
177 	/*
178 	 *	packet is not for us, check cache for an entry
179 	 */
180 	s = splimp();
181 	SNPAC_LOOK(sc, destiso);
182 	if (sc == 0) {			/* not found */
183 		/* If we are an IS, we can't do much with the packet */
184 		if (iso_systype == SNPA_IS)
185 			goto bad;
186 
187 		/*
188 		 *	Check if we know about an IS
189 		 */
190 		if ((known_is) && (known_is->sc_flags & SNPA_VALID)) {
191 			sc = known_is;
192 		} else if (ifp->if_flags & IFF_BROADCAST) {
193 			/*
194 			 *	no IS, no match. Return "all es" multicast address for this
195 			 *	interface, as per Query Configuration Function (9542 sec 6.5)
196 			 *
197 			 *	Note: there is a potential problem here. If the destination
198 			 *	is on the subnet and it does not respond with a ESH, but
199 			 *	does send back a TP CC, a connection could be established
200 			 *	where we always transmit the CLNP packet to "all es"
201 			 */
202 			sc = &all_es;
203 		} else {
204 			goto bad;
205 		}
206 	}
207 
208 	bcopy((caddr_t)sc->sc_snpa, (caddr_t)snpa, sc->sc_len);
209 	*snpa_len = sc->sc_len;
210 	splx(s);
211 	return (0);
212 
213 bad:
214 	splx(s);
215 	return(ENETUNREACH);
216 }
217 
218 
219 /*
220  * FUNCTION:		snpac_look
221  *
222  * PURPOSE:			Look up an entry in the snpa cache
223  *
224  * RETURNS:			Pointer to snpa_cache structure, or null
225  *
226  * SIDE EFFECTS:
227  *
228  * NOTES:			This is simply SNPAC_LOOK as a procedure.
229  */
230 struct snpa_cache *
231 snpac_look(isoa)
232 struct iso_addr *isoa;	/* destination nsap */
233 {
234 	struct snpa_cache	*sc;
235 	int 				s = splimp();
236 
237 	SNPAC_LOOK(sc, isoa);
238 
239 	splx(s);
240 	return(sc);
241 }
242 
243 /*
244  * FUNCTION:		iso_8208snparesolve
245  *
246  * PURPOSE:			Find the X.121 address that corresponds to an NSAP addr
247  *
248  * RETURNS:			0 or unix errno
249  *
250  * SIDE EFFECTS:
251  *
252  * NOTES:			This ought to invoke the 8208 ES-IS function
253  */
254 iso_8208snparesolve(dst, snpa, snpa_len)
255 struct sockaddr_iso *dst;	/* destination */
256 char				*snpa;	/* RESULT: snpa to be used */
257 int					*snpa_len;	/* RESULT: length of snpa */
258 {
259 	struct snpa_cache		*sc;		/* ptr to snpa table entry */
260 	struct iso_addr			*destiso;	/* destination iso addr */
261 	int						s;
262 	int						err = 0;
263 
264  	destiso = &dst->siso_addr;
265 
266 	s = splimp();
267 	SNPAC_LOOK(sc, destiso);
268 	if (sc) {
269 		bcopy((caddr_t)sc->sc_snpa, (caddr_t)snpa, sc->sc_len);
270 		*snpa_len = sc->sc_len;
271 	} else {
272 		err = ENETUNREACH;
273 	}
274 	splx(s);
275 	return (err);
276 }
277 
278 /*
279  * FUNCTION:		iso_8208snpaadd
280  *
281  * PURPOSE:			Add an entry to the snpa cache
282  *
283  * RETURNS:
284  *
285  * SIDE EFFECTS:
286  *
287  * NOTES:			used by cons
288  */
289 iso_8208snpaadd(ifp, nsap, snpa, snpalen, ht)
290 struct ifnet		*ifp;		/* interface info is related to */
291 struct iso_addr		*nsap;		/* nsap to add */
292 caddr_t				snpa;		/* translation */
293 int					snpalen;	/* length in bytes */
294 short				ht;			/* holding time (in seconds) */
295 {
296 	snpac_add(ifp, nsap, snpa, snpalen, SNPA_ES, ht);
297 }
298 
299 /*
300  * FUNCTION:		iso_8208snpadelete
301  *
302  * PURPOSE:			Delete an entry from the snpa cache
303  *
304  * RETURNS:			nothing
305  *
306  * SIDE EFFECTS:
307  *
308  * NOTES:			used by CONS
309  */
310 iso_8208snpadelete(nsap)
311 struct iso_addr	*nsap;
312 {
313 	struct snpa_cache	*sc = snpac_look(nsap);
314 
315 	if (sc != NULL)
316 		snpac_free(sc);
317 }
318 
319 /*
320  * FUNCTION:		snpac_new
321  *
322  * PURPOSE:			create a new entry in the iso address to ethernet
323  *					address table
324  *
325  * RETURNS:			pointer to newest entry
326  *
327  * SIDE EFFECTS:	times out old entries if no new entries are found
328  *
329  * NOTES:			If the bucket is full, then timeout the oldest entry
330  *					(ie. the one with the youngest holding time)
331  */
332 struct snpa_cache *
333 snpac_new(isoa)
334 struct iso_addr *isoa;		/* iso address to enter into table */
335 {
336 	register struct snpa_cache	*sc;
337 	register int 				n;
338 	int							smallest_ht = 1000000;
339 	struct snpa_cache			*maybe;
340 
341 	sc = &iso_snpac[SNPAC_HASH(isoa) * SNPAC_BSIZ];
342 	for (n = 0 ; n < SNPAC_BSIZ ; n++,sc++) {
343 
344 		IFDEBUG (D_IOCTL)
345 			printf("snpac_new: sc x%x ", sc);
346 
347 			if (sc->sc_flags & SNPA_VALID) {
348 				int i;
349 
350 				printf("(valid) %s ", clnp_iso_addrp(&sc->sc_nsap));
351 				for (i=0; i<sc->sc_len; i++)
352 					printf("%x%c", sc->sc_snpa[i], i < (sc->sc_len-1) ? ':'
353 						: '\n');
354 			} else {
355 				printf("invalid\n");
356 			}
357 		ENDDEBUG
358 
359 		if (sc->sc_flags & SNPA_VALID) {
360 			if (sc->sc_ht < smallest_ht) {
361 				smallest_ht = sc->sc_ht;
362 				maybe = sc;
363 			}
364 		} else {
365 			return sc; /* found unused slot */
366 		}
367 	}
368 	snpac_free(maybe);
369 	return maybe;
370 }
371 
372 /*
373  * FUNCTION:		snpac_free
374  *
375  * PURPOSE:			free an entry in the iso address map table
376  *
377  * RETURNS:			nothing
378  *
379  * SIDE EFFECTS:
380  *
381  * NOTES:			If there is a route entry associated with cache
382  *					entry, then delete that as well
383  */
384 snpac_free(sc)
385 register struct snpa_cache *sc;		/* entry to free */
386 {
387 	int s = splimp();
388 
389 	if (known_is == sc) {
390 		snpac_rtrequest(SIOCDELRT, &zero_isoa, &known_is->sc_nsap,
391 			RTF_DYNAMIC|RTF_GATEWAY);
392 		known_is = NULL;
393 	}
394 	if (sc->sc_da.isoa_len > 0) {
395 		snpac_rtrequest(SIOCDELRT, &sc->sc_da, &known_is->sc_nsap,
396 			RTF_DYNAMIC|RTF_GATEWAY);
397 	}
398 	bzero((caddr_t)sc, sizeof(struct snpa_cache));
399 
400 	splx(s);
401 }
402 
403 /*
404  * FUNCTION:		snpac_add
405  *
406  * PURPOSE:			Add an entry to the snpa cache
407  *
408  * RETURNS:
409  *
410  * SIDE EFFECTS:
411  *
412  * NOTES:			If entry already exists, then update holding time.
413  */
414 snpac_add(ifp, nsap, snpa, snpalen, type, ht)
415 struct ifnet		*ifp;		/* interface info is related to */
416 struct iso_addr		*nsap;		/* nsap to add */
417 caddr_t				snpa;		/* translation */
418 int					snpalen;	/* length in bytes */
419 char				type;		/* SNPA_IS or SNPA_ES */
420 short				ht;			/* holding time (in seconds) */
421 {
422 	struct snpa_cache	*sc;
423 	int					s = splimp();
424 
425 	SNPAC_LOOK(sc, nsap);
426 	if (sc == NULL) {
427 		sc = snpac_new(nsap);
428 		sc->sc_nsap = *nsap;
429 	}
430 
431 	sc->sc_ht = ht;
432 
433 	sc->sc_len = min(snpalen, MAX_SNPALEN);
434 	bcopy(snpa, sc->sc_snpa, sc->sc_len);
435 	sc->sc_flags = SNPA_VALID | type;
436 	sc->sc_ifp = ifp;
437 
438 	if (type & SNPA_IS)
439 		snpac_logdefis(sc);
440 
441 	splx(s);
442 }
443 
444 /*
445  * FUNCTION:		snpac_ioctl
446  *
447  * PURPOSE:			handle ioctls to change the iso address map
448  *
449  * RETURNS:			unix error code
450  *
451  * SIDE EFFECTS:	changes the snpa_cache table declared above.
452  *
453  * NOTES:
454  */
455 snpac_ioctl(cmd, data)
456 int		cmd;		/* ioctl to process */
457 caddr_t	data;	/* data for the cmd */
458 {
459 	register struct snpa_req	*rq = (struct snpa_req *)data;
460 	register struct snpa_cache	*sc;
461 	register struct iso_addr	*isoa;
462 	int							s;
463 
464 	/* look up this address in table */
465 	isoa = &rq->sr_isoa;
466 
467 	/* sanity check */
468 	if (rq->sr_len > MAX_SNPALEN)
469 		return(EINVAL);
470 
471 	IFDEBUG (D_IOCTL)
472 		int i;
473 
474 		printf("snpac_ioctl: ");
475 		switch(cmd) {
476 			case SIOCSISOMAP: printf("set"); break;
477 			case SIOCDISOMAP: printf("delete"); break;
478 			case SIOCGISOMAP: printf("get"); break;
479 		}
480 		printf(" %s to ", clnp_iso_addrp(isoa));
481 		for (i=0; i<rq->sr_len; i++)
482 			printf("%x%c", rq->sr_snpa[i], i < (rq->sr_len-1) ? ':' : '\n');
483 	ENDDEBUG
484 
485 	s = splimp();
486 	SNPAC_LOOK(sc, isoa);
487 	if (sc == NULL) {	 /* not found */
488 		if (cmd != SIOCSISOMAP)
489 			return(ENXIO);
490 	}
491 
492 	switch(cmd) {
493 		case SIOCSISOMAP:	/* set entry */
494 			snpac_add(NULL, isoa, rq->sr_snpa, rq->sr_len,
495 				rq->sr_flags & (SNPA_ES|SNPA_IS|SNPA_PERM), rq->sr_ht);
496 			break;
497 
498 		case SIOCDISOMAP:	/* delete entry */
499 			snpac_free(sc);
500 			break;
501 
502 		case SIOCGISOMAP:	/* get entry */
503 			bcopy((caddr_t)&sc->sc_sr, rq, sizeof(struct snpa_req));
504 			break;
505 	}
506 	splx(s);
507 	return(0);
508 }
509 
510 /*
511  * FUNCTION:		iso_tryloopback
512  *
513  * PURPOSE:			Attempt to use the software loopback interface for pkt
514  *
515  * RETURNS:			0		if packet was sent successfully
516  *					errno	if there was a problem sending the packet
517  *							Ie. the return value of looutput
518  *					-1 		if software loopback is not appropriate
519  *
520  * SIDE EFFECTS:
521  *
522  * NOTES:
523  */
524 iso_tryloopback(m, dst)
525 struct mbuf			*m;		/* pkt */
526 struct sockaddr_iso *dst;	/* destination */
527 {
528 	struct iso_addr			*destiso;	/* destination iso addr */
529 
530  	destiso = &dst->siso_addr;
531 
532 	if (clnp_ours(destiso)) {
533 		IFDEBUG(D_SNPA)
534 			printf("iso_tryloopback: local destination\n");
535 		ENDDEBUG
536 		if (loif.if_flags & IFF_UP) {
537 			IFDEBUG(D_SNPA)
538 				printf("iso_tryloopback: calling looutput\n");
539 			ENDDEBUG
540 			return (looutput(&loif, m, (struct sockaddr *)dst));
541 		}
542 	}
543 	return (-1);
544 }
545 
546 /*
547  * FUNCTION:		snpac_systype
548  *
549  * PURPOSE:			Set/Get the system type and esis parameters
550  *
551  * RETURNS:			0 on success, or unix error code
552  *
553  * SIDE EFFECTS:
554  *
555  * NOTES:
556  */
557 snpac_systype (cmd, data)
558 int		cmd;	/* ioctl to process */
559 caddr_t	data;	/* data for the cmd */
560 {
561 	register struct systype_req *rq = (struct systype_req *)data;
562 	extern short	esis_holding_time, esis_config_time;
563 
564 	IFDEBUG (D_IOCTL)
565 		if (cmd == SIOCSSTYPE)
566 			printf("snpac_systype: cmd set, type x%x, ht %d, ct %d\n",
567 				rq->sr_type, rq->sr_holdt, rq->sr_configt);
568 		else
569 			printf("snpac_systype: cmd get\n");
570 	ENDDEBUG
571 
572 	if (cmd == SIOCSSTYPE) {
573 		if (!suser())
574 			return(EACCES);
575 		if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS))
576 			return(EINVAL);
577 		if (rq->sr_type & SNPA_ES) {
578 			iso_systype = SNPA_ES;
579 		} else if (rq->sr_type & SNPA_IS) {
580 			iso_systype = SNPA_IS;
581 		} else {
582 			return(EINVAL);
583 		}
584 		esis_holding_time = rq->sr_holdt;
585 		esis_config_time = rq->sr_configt;
586 	} else if (cmd == SIOCGSTYPE) {
587 		rq->sr_type = iso_systype;
588 		rq->sr_holdt = esis_holding_time;
589 		rq->sr_configt = esis_config_time;
590 	} else {
591 		return(EINVAL);
592 	}
593 	return(0);
594 }
595 
596 /*
597  * FUNCTION:		snpac_logdefis
598  *
599  * PURPOSE:			Mark the IS passed as the default IS
600  *
601  * RETURNS:			nothing
602  *
603  * SIDE EFFECTS:
604  *
605  * NOTES:
606  */
607 snpac_logdefis(sc)
608 struct snpa_cache	*sc;
609 {
610 	if (known_is) {
611 		snpac_rtrequest(SIOCDELRT, &zero_isoa, &known_is->sc_nsap,
612 			RTF_DYNAMIC|RTF_GATEWAY);
613 	}
614 	known_is = sc;
615 	snpac_rtrequest(SIOCADDRT, &zero_isoa, &sc->sc_nsap,
616 		RTF_DYNAMIC|RTF_GATEWAY);
617 }
618 
619 /*
620  * FUNCTION:		snpac_age
621  *
622  * PURPOSE:			Time out snpac entries
623  *
624  * RETURNS:
625  *
626  * SIDE EFFECTS:
627  *
628  * NOTES:			When encountering an entry for the first time, snpac_age
629  *					may delete up to SNPAC_AGE too many seconds. Ie.
630  *					if the entry is added a moment before snpac_age is
631  *					called, the entry will immediately have SNPAC_AGE
632  *					seconds taken off the holding time, even though
633  *					it has only been held a brief moment.
634  *
635  *					The proper way to do this is set an expiry timeval
636  *					equal to current time + holding time. Then snpac_age
637  *					would time out entries where expiry date is older
638  *					than the current time.
639  */
640 snpac_age()
641 {
642 	register struct snpa_cache	*sc;
643 	register int 				i;
644 
645 	timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz);
646 
647 	sc = &iso_snpac[0];
648 	for (i=0; i<SNPAC_SIZE; i++, sc++) {
649 		if (((sc->sc_flags & SNPA_PERM) == 0) && (sc->sc_flags & SNPA_VALID)) {
650 			sc->sc_ht -= SNPAC_AGE;
651 			if (sc->sc_ht > 0)
652 				continue;
653 			else
654 				snpac_free(sc);
655 		}
656 	}
657 }
658 
659 /*
660  * FUNCTION:		snpac_ownmulti
661  *
662  * PURPOSE:			Determine if the snpa address is a multicast address
663  *					of the same type as the system.
664  *
665  * RETURNS:			true or false
666  *
667  * SIDE EFFECTS:
668  *
669  * NOTES:			Used by interface drivers when not in eavesdrop mode
670  *					as interm kludge until
671  *					real multicast addresses can be configured
672  */
673 snpac_ownmulti(snpa, len)
674 char	*snpa;
675 int		len;
676 {
677 	return (((iso_systype & SNPA_ES) && (!bcmp(snpa, all_es.sc_snpa, len)))
678 		|| ((iso_systype & SNPA_IS) && (!bcmp(snpa, all_is.sc_snpa, len))));
679 }
680 
681 /*
682  * FUNCTION:		snpac_flushifp
683  *
684  * PURPOSE:			Flush entries associated with specific ifp
685  *
686  * RETURNS:			nothing
687  *
688  * SIDE EFFECTS:
689  *
690  * NOTES:
691  */
692 snpac_flushifp(ifp)
693 struct ifnet	*ifp;
694 {
695 	register struct snpa_cache	*sc;
696 	register int 				i;
697 
698 	sc = &iso_snpac[0];
699 	for (i=0; i<SNPAC_SIZE; i++, sc++) {
700 		if ((sc->sc_ifp == ifp) && (sc->sc_flags & SNPA_VALID)) {
701 			snpac_free(sc);
702 		}
703 	}
704 }
705 
706 /*
707  * FUNCTION:		snpac_rtrequest
708  *
709  * PURPOSE:			Make a routing request
710  *
711  * RETURNS:			nothing
712  *
713  * SIDE EFFECTS:
714  *
715  * NOTES:			In the future, this should make a request of a user
716  *					level routing daemon.
717  */
718 snpac_rtrequest(req, dst, gateway, flags)
719 int				req;
720 struct iso_addr	*dst;
721 struct iso_addr	*gateway;
722 short			flags;
723 {
724 	struct rtentry	rte;
725 	struct iso_addr	*isoa;
726 
727 	IFDEBUG(D_SNPA)
728 		printf("snpac_rtrequest: ");
729 		if (req == SIOCADDRT)
730 			printf("add");
731 		else if (req == SIOCDELRT)
732 			printf("delete");
733 		else
734 			printf("unknown command");
735 		printf(" dst: %s\n", clnp_iso_addrp(dst));
736 		printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
737 	ENDDEBUG
738 
739 	bzero((caddr_t)&rte, sizeof(struct rtentry));
740 	rte.rt_dst.sa_family = rte.rt_gateway.sa_family = AF_ISO;
741 	isoa = &((struct sockaddr_iso *)&rte.rt_dst)->siso_addr;
742 	*isoa = *dst;
743 	isoa = &((struct sockaddr_iso *)&rte.rt_gateway)->siso_addr;
744 	*isoa = *gateway;
745 	rte.rt_flags = RTF_UP|flags;
746 
747 	rtrequest(req, &rte);
748 }
749 
750 
751 /*
752  * FUNCTION:		snpac_addrt
753  *
754  * PURPOSE:			Associate a routing entry with an snpac entry
755  *
756  * RETURNS:			nothing
757  *
758  * SIDE EFFECTS:
759  *
760  * NOTES:			If a cache entry exists for gateway, then
761  *					make a routing entry (host, gateway) and associate
762  *					with gateway.
763  *
764  *					If a route already exists and is different, first delete
765  *					it.
766  *
767  *					This could be made more efficient by checking
768  *					the existing route before adding a new one.
769  */
770 snpac_addrt(host, gateway)
771 struct iso_addr	*host;
772 struct iso_addr	*gateway;
773 {
774 	struct snpa_cache	*sc;
775 	int					s;
776 
777 	s = splimp();
778 	SNPAC_LOOK(sc, gateway);
779 	if (sc != NULL) {
780 		snpac_rtrequest(SIOCDELRT, &sc->sc_da, gateway,
781 			RTF_DYNAMIC|RTF_GATEWAY);
782 		snpac_rtrequest(SIOCADDRT, host, gateway, RTF_DYNAMIC|RTF_GATEWAY);
783 		bcopy(host, &sc->sc_da, sizeof(struct iso_addr));
784 	}
785 	s = splx(s);
786 }
787 #endif	ISO
788