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