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