1 /* $NetBSD: iso_snpac.c,v 1.40 2006/11/16 01:33:51 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)iso_snpac.c 8.4 (Berkeley) 5/2/95
32 */
33
34 /***********************************************************
35 Copyright IBM Corporation 1987
36
37 All Rights Reserved
38
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
46
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
54
55 ******************************************************************/
56
57 /*
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
59 */
60
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: iso_snpac.c,v 1.40 2006/11/16 01:33:51 christos Exp $");
63
64 #include "opt_iso.h"
65 #ifdef ISO
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/mbuf.h>
71 #include <sys/domain.h>
72 #include <sys/protosw.h>
73 #include <sys/socket.h>
74 #include <sys/socketvar.h>
75 #include <sys/errno.h>
76 #include <sys/ioctl.h>
77 #include <sys/syslog.h>
78 #include <sys/proc.h>
79 #include <sys/kauth.h>
80
81 #include <net/if.h>
82 #include <net/if_dl.h>
83 #include <net/route.h>
84
85 #include <net/if_ether.h>
86
87 #include <netinet/in.h>
88
89 #include <netiso/iso.h>
90 #include <netiso/iso_var.h>
91 #include <netiso/iso_snpac.h>
92 #include <netiso/clnp.h>
93 #include <netiso/clnp_stat.h>
94 #include <netiso/esis.h>
95 #include <netiso/argo_debug.h>
96
97 int iso_systype = SNPA_ES; /* default to be an ES */
98
99 LIST_HEAD(, llinfo_llc) llinfo_llc;
100
101 struct callout snpac_age_ch;
102
103 struct sockaddr_iso blank_siso = {
104 .siso_len = sizeof(blank_siso),
105 .siso_family = AF_ISO,
106 };
107 static struct sockaddr_iso
108 dst = {
109 .siso_len = sizeof(dst),
110 .siso_family = AF_ISO,
111 },
112 gte = {
113 .siso_len = sizeof(gte),
114 .siso_family = AF_ISO,
115 },
116 #if 0
117 src = {
118 .siso_len = sizeof(src),
119 .siso_family = AF_ISO,
120 },
121 #endif
122 msk = {
123 .siso_len = sizeof(msk),
124 .siso_family = AF_ISO,
125 },
126 zmk = {
127 .siso_len = 0,
128 };
129
130 #define zsi blank_siso
131 #define zero_isoa zsi.siso_addr
132 #define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \
133 Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);}
134 #define S(x) ((struct sockaddr *)&(x))
135
136 static struct sockaddr_dl blank_dl = {
137 .sdl_len = sizeof(blank_dl),
138 .sdl_family = AF_LINK,
139 };
140 static struct sockaddr_dl gte_dl;
141 #define zap_linkaddr(a, b, c, i) \
142 (*a = blank_dl, memcpy(a->sdl_data, b, a->sdl_alen = c), a->sdl_index = i)
143
144 static void snpac_fixdstandmask (int);
145
146 /*
147 * We only keep track of a single IS at a time.
148 */
149 struct rtentry *known_is;
150
151 /*
152 * Addresses taken from NBS agreements, December 1987.
153 *
154 * These addresses assume on-the-wire transmission of least significant
155 * bit first. This is the method used by 802.3. When these
156 * addresses are passed to the token ring driver, (802.5), they
157 * must be bit-swapped because 802.5 transmission order is MSb first.
158 *
159 * Furthermore, according to IBM Austin, these addresses are not
160 * true token ring multicast addresses. More work is necessary
161 * to get multicast to work right on token ring.
162 *
163 * Currently, the token ring driver does not handle multicast, so
164 * these addresses are converted into the broadcast address in
165 * lan_output() That means that if these multicast addresses change
166 * the token ring driver must be altered.
167 */
168 const char all_es_snpa[] = {0x09, 0x00, 0x2b, 0x00, 0x00, 0x04};
169 const char all_is_snpa[] = {0x09, 0x00, 0x2b, 0x00, 0x00, 0x05};
170 const char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14};
171 const char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15};
172
173 union sockunion {
174 struct sockaddr_iso siso;
175 struct sockaddr_dl sdl;
176 struct sockaddr sa;
177 };
178
179 /*
180 * FUNCTION: llc_rtrequest
181 *
182 * PURPOSE: Manage routing table entries specific to LLC for ISO.
183 *
184 * NOTES: This does a lot of obscure magic;
185 */
186 void
187 llc_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
188 {
189 union sockunion *gate = (union sockunion *) rt->rt_gateway;
190 struct llinfo_llc *lc = (struct llinfo_llc *) rt->rt_llinfo;
191 struct ifnet *ifp = rt->rt_ifp;
192 int addrlen = ifp->if_addrlen;
193 #define LLC_SIZE 3 /* XXXXXX do this right later */
194
195 #ifdef ARGO_DEBUG
196 if (argo_debug[D_SNPA]) {
197 printf("llc_rtrequest(%d, %p, %p)\n", req, rt, info);
198 }
199 #endif
200 if (rt->rt_flags & RTF_GATEWAY)
201 return;
202 else
203 switch (req) {
204 case RTM_ADD:
205 /*
206 * Case 1: This route may come from a route to iface with mask
207 * or from a default route.
208 */
209 if (rt->rt_flags & RTF_CLONING) {
210 iso_setmcasts(ifp, req);
211 rt_setgate(rt, rt_key(rt),
212 (struct sockaddr *) & blank_dl);
213 return;
214 }
215 if (lc != 0)
216 return; /* happens on a route change */
217 /* FALLTHROUGH */
218 case RTM_RESOLVE:
219 /*
220 * Case 2: This route may come from cloning, or a manual route
221 * add with a LL address.
222 */
223 if (gate->sdl.sdl_family != AF_LINK) {
224 log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
225 break;
226 }
227 R_Malloc(lc, struct llinfo_llc *, sizeof(*lc));
228 rt->rt_llinfo = (caddr_t) lc;
229 if (lc == 0) {
230 log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
231 break;
232 }
233 Bzero(lc, sizeof(*lc));
234 lc->lc_rt = rt;
235 rt->rt_flags |= RTF_LLINFO;
236 LIST_INSERT_HEAD(&llinfo_llc, lc, lc_list);
237 if (gate->sdl.sdl_alen == sizeof(struct esis_req)
238 + addrlen) {
239 gate->sdl.sdl_alen -= sizeof(struct esis_req);
240 (void)memcpy(&lc->lc_er,
241 (const char *)CLLADDR(&gate->sdl) +
242 addrlen, sizeof(lc->lc_er));
243 } else if (gate->sdl.sdl_alen == addrlen)
244 lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
245 break;
246 case RTM_DELETE:
247 if (rt->rt_flags & RTF_CLONING)
248 iso_setmcasts(ifp, req);
249 if (lc == 0)
250 return;
251 LIST_REMOVE(lc, lc_list);
252 Free(lc);
253 rt->rt_llinfo = 0;
254 rt->rt_flags &= ~RTF_LLINFO;
255 break;
256 }
257 if (rt->rt_rmx.rmx_mtu == 0) {
258 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
259 }
260 }
261
262 /*
263 * FUNCTION: iso_setmcasts
264 *
265 * PURPOSE: Enable/Disable ESIS/ISIS multicast reception on
266 * interfaces.
267 *
268 * NOTES: This also does a lot of obscure magic;
269 */
270 void
271 iso_setmcasts(struct ifnet *ifp, int req)
272 {
273 static const char * const addrlist[] =
274 {all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0};
275 struct ifreq ifr;
276 const char *const *cpp;
277
278 (void)memset(&ifr, 0, sizeof(ifr));
279 for (cpp = addrlist; *cpp; cpp++) {
280 (void)memcpy(ifr.ifr_addr.sa_data, *cpp, 6);
281 if (req == RTM_ADD && (ifp->if_ioctl == 0 ||
282 (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr) != 0))
283 printf("iso_setmcasts: %s unable to add mcast\n",
284 ifp->if_xname);
285 else if (req == RTM_DELETE && (ifp->if_ioctl == 0 ||
286 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr) != 0))
287 printf("iso_setmcasts: %s unable to delete mcast\n",
288 ifp->if_xname);
289 }
290 }
291
292 /*
293 * FUNCTION: iso_snparesolve
294 *
295 * PURPOSE: Resolve an iso address into snpa address
296 *
297 * RETURNS: 0 if addr is resolved
298 * errno if addr is unknown
299 *
300 * SIDE EFFECTS:
301 *
302 * NOTES: Now that we have folded the snpa cache into the routing
303 * table, we know there is no snpa address known for this
304 * destination. If we know of a default IS, then the
305 * address of the IS is returned. If no IS is known,
306 * then return the multi-cast address for "all ES" for
307 * this interface.
308 *
309 * NB: the last case described above constitutes the
310 * query configuration function 9542, sec 6.5
311 * A mechanism is needed to prevent this function from
312 * being invoked if the system is an IS.
313 */
314 int
315 iso_snparesolve(
316 struct ifnet *ifp, /* outgoing interface */
317 struct sockaddr_iso *dest, /* destination */
318 caddr_t snpa, /* RESULT: snpa to be used */
319 int *snpa_len) /* RESULT: length of snpa */
320 {
321 struct llinfo_llc *sc; /* ptr to snpa table entry */
322 const char *found_snpa;
323 int addrlen;
324
325 /*
326 * This hack allows us to send esis packets that have the destination
327 * snpa addresss embedded in the destination nsap address
328 */
329 if (dest->siso_data[0] == AFI_SNA) {
330 /*
331 * This is a subnetwork address. Return it immediately
332 */
333 #ifdef ARGO_DEBUG
334 if (argo_debug[D_SNPA]) {
335 printf("iso_snparesolve: return SN address\n");
336 }
337 #endif
338 addrlen = dest->siso_nlen - 1; /* subtract size of AFI */
339 found_snpa = (const char *)dest->siso_data + 1;
340 /*
341 * If we are an IS, we can't do much with the packet; Check
342 * if we know about an IS.
343 */
344 } else if (iso_systype != SNPA_IS && known_is != 0 &&
345 (sc = (struct llinfo_llc *) known_is->rt_llinfo) &&
346 (sc->lc_flags & SNPA_VALID)) {
347 struct sockaddr_dl *sdl =
348 (struct sockaddr_dl *) (known_is->rt_gateway);
349 found_snpa = LLADDR(sdl);
350 addrlen = sdl->sdl_alen;
351 } else if (ifp->if_flags & IFF_BROADCAST) {
352 /*
353 * no IS, no match. Return "all es" multicast address for
354 * this interface, as per Query Configuration Function (9542
355 * sec 6.5)
356 *
357 * Note: there is a potential problem here. If the destination
358 * is on the subnet and it does not respond with a ESH, but
359 * does send back a TP CC, a connection could be established
360 * where we always transmit the CLNP packet to "all es"
361 */
362 addrlen = ifp->if_addrlen;
363 found_snpa = (const char *) all_es_snpa;
364 } else
365 return (ENETUNREACH);
366 memcpy(snpa, found_snpa, *snpa_len = addrlen);
367 return (0);
368 }
369
370
371 /*
372 * FUNCTION: snpac_free
373 *
374 * PURPOSE: free an entry in the iso address map table
375 *
376 * RETURNS: nothing
377 *
378 * SIDE EFFECTS:
379 *
380 * NOTES: If there is a route entry associated with cache
381 * entry, then delete that as well
382 */
383 void
384 snpac_free(
385 struct llinfo_llc *lc) /* entry to free */
386 {
387 struct rtentry *rt = lc->lc_rt;
388
389 if (known_is == rt)
390 known_is = 0;
391 if (rt && (rt->rt_flags & RTF_UP) &&
392 (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
393 RTFREE(rt);
394 rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt),
395 rt->rt_flags, (struct rtentry **) 0);
396 RTFREE(rt);
397 }
398 }
399
400 /*
401 * FUNCTION: snpac_add
402 *
403 * PURPOSE: Add an entry to the snpa cache
404 *
405 * RETURNS:
406 *
407 * SIDE EFFECTS:
408 *
409 * NOTES: If entry already exists, then update holding time.
410 */
411 int
412 snpac_add(
413 struct ifnet *ifp, /* interface info is related to */
414 struct iso_addr *nsap, /* nsap to add */
415 caddr_t snpa, /* translation */
416 int type, /* SNPA_IS or SNPA_ES */
417 u_short ht, /* holding time (in seconds) */
418 int nsellength) /* nsaps may differ only in trailing
419 * bytes */
420 {
421 struct llinfo_llc *lc;
422 struct rtentry *rt;
423 struct rtentry *mrt = 0;
424 struct iso_addr *r; /* for zap_isoaddr macro */
425 int snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
426 int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type;
427
428 #ifdef ARGO_DEBUG
429 if (argo_debug[D_SNPA]) {
430 printf("snpac_add(%p, %p, %p, %x, %x, %x)\n",
431 ifp, nsap, snpa, type, ht, nsellength);
432 }
433 #endif
434 zap_isoaddr(dst, nsap);
435 rt = rtalloc1(sisotosa(&dst), 0);
436 #ifdef ARGO_DEBUG
437 if (argo_debug[D_SNPA]) {
438 printf("snpac_add: rtalloc1 returns %p\n", rt);
439 }
440 #endif
441 if (rt == 0) {
442 struct sockaddr *netmask;
443 int flags;
444 add:
445 if (nsellength) {
446 netmask = sisotosa(&msk);
447 flags = RTF_UP;
448 snpac_fixdstandmask(nsellength);
449 } else {
450 netmask = 0;
451 flags = RTF_UP | RTF_HOST;
452 }
453 new_entry = 1;
454 zap_linkaddr((>e_dl), snpa, snpalen, index);
455 gte_dl.sdl_type = iftype;
456 if (rtrequest(RTM_ADD, sisotosa(&dst), S(gte_dl), netmask,
457 flags, &mrt) || mrt == 0)
458 return (0);
459 rt = mrt;
460 rt->rt_refcnt--;
461 } else {
462 struct sockaddr_dl *sdl = (struct sockaddr_dl *) rt->rt_gateway;
463 rt->rt_refcnt--;
464 if ((rt->rt_flags & RTF_LLINFO) == 0)
465 goto add;
466 if (nsellength && (rt->rt_flags & RTF_HOST)) {
467 if (rt->rt_refcnt == 0) {
468 rtrequest(RTM_DELETE, sisotosa(&dst),
469 (struct sockaddr *) 0, (struct sockaddr *) 0,
470 0, (struct rtentry **) 0);
471 rt = 0;
472 goto add;
473 } else {
474 static struct iso_addr nsap2;
475 char *cp;
476 nsap2 = *nsap;
477 cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
478 while (cp < (char *) (1 + &nsap2))
479 *cp++ = 0;
480 (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
481 }
482 }
483 if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
484 int old_sdl_len = sdl->sdl_len;
485 if (old_sdl_len < sizeof(*sdl)) {
486 log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
487 return (0);
488 }
489 zap_linkaddr(sdl, snpa, snpalen, index);
490 sdl->sdl_len = old_sdl_len;
491 sdl->sdl_type = iftype;
492 new_entry = 1;
493 }
494 }
495 if ((lc = (struct llinfo_llc *) rt->rt_llinfo) == 0)
496 panic("snpac_rtrequest");
497 rt->rt_rmx.rmx_expire = ht + time_second;
498 lc->lc_flags = SNPA_VALID | type;
499 if ((type & SNPA_IS) && !(iso_systype & SNPA_IS))
500 snpac_logdefis(rt);
501 return (new_entry);
502 }
503
504 static void
505 snpac_fixdstandmask(int nsellength)
506 {
507 char *cp = msk.siso_data, *cplim;
508
509 cplim = cp + (dst.siso_nlen -= nsellength);
510 msk.siso_len = cplim - (char *) &msk;
511 msk.siso_nlen = 0;
512 while (cp < cplim)
513 *cp++ = -1;
514 while (cp < (char *) msk.siso_pad)
515 *cp++ = 0;
516 for (cp = dst.siso_data + dst.siso_nlen; cp < (char *) dst.siso_pad;)
517 *cp++ = 0;
518 }
519
520 /*
521 * FUNCTION: snpac_ioctl
522 *
523 * PURPOSE: Set/Get the system type and esis parameters
524 *
525 * RETURNS: 0 on success, or unix error code
526 *
527 * SIDE EFFECTS:
528 *
529 * NOTES:
530 */
531 int
532 snpac_ioctl(
533 struct socket *so,
534 u_long cmd, /* ioctl to process */
535 caddr_t data, /* data for the cmd */
536 struct lwp *l)
537 {
538 struct systype_req *rq = (struct systype_req *) data;
539
540 #ifdef ARGO_DEBUG
541 if (argo_debug[D_IOCTL]) {
542 if (cmd == SIOCSSTYPE)
543 printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
544 rq->sr_type, rq->sr_holdt, rq->sr_configt);
545 else
546 printf("snpac_ioctl: cmd get\n");
547 }
548 #endif
549
550 if (cmd == SIOCSSTYPE) {
551 if (l == NULL || kauth_authorize_generic(l->l_cred,
552 KAUTH_GENERIC_ISSUSER, &l->l_acflag))
553 return (EPERM);
554 if ((rq->sr_type & (SNPA_ES | SNPA_IS)) == (SNPA_ES | SNPA_IS))
555 return (EINVAL);
556 if (rq->sr_type & SNPA_ES) {
557 iso_systype = SNPA_ES;
558 } else if (rq->sr_type & SNPA_IS) {
559 iso_systype = SNPA_IS;
560 } else {
561 return (EINVAL);
562 }
563 esis_holding_time = rq->sr_holdt;
564 esis_config_time = rq->sr_configt;
565 if (esis_esconfig_time != rq->sr_esconfigt) {
566 callout_stop(&esis_config_ch);
567 esis_esconfig_time = rq->sr_esconfigt;
568 esis_config(NULL);
569 }
570 } else if (cmd == SIOCGSTYPE) {
571 rq->sr_type = iso_systype;
572 rq->sr_holdt = esis_holding_time;
573 rq->sr_configt = esis_config_time;
574 rq->sr_esconfigt = esis_esconfig_time;
575 } else {
576 return (EINVAL);
577 }
578 return (0);
579 }
580
581 /*
582 * FUNCTION: snpac_logdefis
583 *
584 * PURPOSE: Mark the IS passed as the default IS
585 *
586 * RETURNS: nothing
587 *
588 * SIDE EFFECTS:
589 *
590 * NOTES:
591 */
592 void
593 snpac_logdefis(struct rtentry *sc)
594 {
595 struct rtentry *rt;
596
597 if (known_is == sc || !(sc->rt_flags & RTF_HOST))
598 return;
599 if (known_is) {
600 RTFREE(known_is);
601 }
602 known_is = sc;
603 sc->rt_refcnt++;
604 rt = rtalloc1((struct sockaddr *) & zsi, 0);
605 if (rt == 0)
606 rtrequest(RTM_ADD, sisotosa(&zsi), rt_key(sc), sisotosa(&zmk),
607 RTF_DYNAMIC | RTF_GATEWAY, 0);
608 else {
609 if ((rt->rt_flags & RTF_DYNAMIC) &&
610 (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0)
611 rt_setgate(rt, rt_key(rt), rt_key(sc));
612 }
613 }
614
615 /*
616 * FUNCTION: snpac_age
617 *
618 * PURPOSE: Time out snpac entries
619 *
620 * RETURNS:
621 *
622 * SIDE EFFECTS:
623 *
624 * NOTES: When encountering an entry for the first time, snpac_age
625 * may delete up to SNPAC_AGE too many seconds. Ie.
626 * if the entry is added a moment before snpac_age is
627 * called, the entry will immediately have SNPAC_AGE
628 * seconds taken off the holding time, even though
629 * it has only been held a brief moment.
630 *
631 * The proper way to do this is set an expiry timeval
632 * equal to current time + holding time. Then snpac_age
633 * would time out entries where expiry date is older
634 * than the current time.
635 */
636 /*ARGSUSED*/
637 void
638 snpac_age(void *v)
639 {
640 struct llinfo_llc *lc, *nlc;
641 struct rtentry *rt;
642
643 callout_reset(&snpac_age_ch, SNPAC_AGE * hz, snpac_age, NULL);
644
645 for (lc = llinfo_llc.lh_first; lc != 0; lc = nlc) {
646 nlc = lc->lc_list.le_next;
647 if (lc->lc_flags & SNPA_VALID) {
648 rt = lc->lc_rt;
649 if (rt->rt_rmx.rmx_expire &&
650 rt->rt_rmx.rmx_expire < time_second)
651 snpac_free(lc);
652 }
653 }
654 }
655
656 /*
657 * FUNCTION: snpac_ownmulti
658 *
659 * PURPOSE: Determine if the snpa address is a multicast address
660 * of the same type as the system.
661 *
662 * RETURNS: true or false
663 *
664 * SIDE EFFECTS:
665 *
666 * NOTES: Used by interface drivers when not in eavesdrop mode
667 * as interm kludge until
668 * real multicast addresses can be configured
669 */
670 int
671 snpac_ownmulti(caddr_t snpa, u_int len)
672 {
673 return (((iso_systype & SNPA_ES) &&
674 (!memcmp(snpa, all_es_snpa, len))) ||
675 ((iso_systype & SNPA_IS) &&
676 (!memcmp(snpa, all_is_snpa, len))));
677 }
678
679 /*
680 * FUNCTION: snpac_flushifp
681 *
682 * PURPOSE: Flush entries associated with specific ifp
683 *
684 * RETURNS: nothing
685 *
686 * SIDE EFFECTS:
687 *
688 * NOTES:
689 */
690 void
691 snpac_flushifp(struct ifnet *ifp)
692 {
693 struct llinfo_llc *lc;
694
695 for (lc = llinfo_llc.lh_first; lc != 0; lc = lc->lc_list.le_next) {
696 if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
697 snpac_free(lc);
698 }
699 }
700
701 /*
702 * FUNCTION: snpac_rtrequest
703 *
704 * PURPOSE: Make a routing request
705 *
706 * RETURNS: nothing
707 *
708 * SIDE EFFECTS:
709 *
710 * NOTES: In the future, this should make a request of a user
711 * level routing daemon.
712 */
713 void
714 snpac_rtrequest(int req, struct iso_addr *host, struct iso_addr *gateway,
715 struct iso_addr *netmask, int flags, struct rtentry **ret_nrt)
716 {
717 struct iso_addr *r;
718
719 #ifdef ARGO_DEBUG
720 if (argo_debug[D_SNPA]) {
721 printf("snpac_rtrequest: ");
722 if (req == RTM_ADD)
723 printf("add");
724 else if (req == RTM_DELETE)
725 printf("delete");
726 else
727 printf("unknown command");
728 printf(" dst: %s\n", clnp_iso_addrp(host));
729 printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
730 }
731 #endif
732
733
734 zap_isoaddr(dst, host);
735 zap_isoaddr(gte, gateway);
736 if (netmask) {
737 zap_isoaddr(msk, netmask);
738 msk.siso_nlen = 0;
739 msk.siso_len = msk.siso_pad - (u_char *) & msk;
740 }
741 rtrequest(req, sisotosa(&dst), sisotosa(>e),
742 (netmask ? sisotosa(&msk) : (struct sockaddr *) 0), flags, ret_nrt);
743 }
744
745 /*
746 * FUNCTION: snpac_addrt
747 *
748 * PURPOSE: Associate a routing entry with an snpac entry
749 *
750 * RETURNS: nothing
751 *
752 * SIDE EFFECTS:
753 *
754 * NOTES: If a cache entry exists for gateway, then
755 * make a routing entry (host, gateway) and associate
756 * with gateway.
757 *
758 * If a route already exists and is different, first delete
759 * it.
760 *
761 * This could be made more efficient by checking
762 * the existing route before adding a new one.
763 */
764 void
765 snpac_addrt(struct ifnet *ifp, struct iso_addr *host,
766 struct iso_addr *gateway, struct iso_addr *netmask)
767 {
768 struct iso_addr *r;
769
770 zap_isoaddr(dst, host);
771 zap_isoaddr(gte, gateway);
772 if (netmask) {
773 zap_isoaddr(msk, netmask);
774 msk.siso_nlen = 0;
775 msk.siso_len = msk.siso_pad - (u_char *) & msk;
776 rtredirect(sisotosa(&dst), sisotosa(>e), sisotosa(&msk),
777 RTF_DONE, sisotosa(>e), 0);
778 } else
779 rtredirect(sisotosa(&dst), sisotosa(>e), (struct sockaddr *) 0,
780 RTF_DONE | RTF_HOST, sisotosa(>e), 0);
781 }
782 #endif /* ISO */
Cache object: 53fdf239e668aef1193be68709b2cf05
|