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