1 /* $NetBSD: iso_snpac.c,v 1.51 2008/10/24 21:50:08 dyoung 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.51 2008/10/24 21:50:08 dyoung 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) {memset(&a.siso_addr, 0, sizeof(*r)); r = b; \
133 memmove(&a.siso_addr, r, 1 + (r)->isoa_len);}
134 #define S(x) ((struct sockaddr *)&(x))
135
136 static struct sockaddr_dl gte_dl;
137
138 static void snpac_fixdstandmask (int);
139
140 /*
141 * We only keep track of a single IS at a time.
142 */
143 struct rtentry *known_is;
144
145 /*
146 * Addresses taken from NBS agreements, December 1987.
147 *
148 * These addresses assume on-the-wire transmission of least significant
149 * bit first. This is the method used by 802.3. When these
150 * addresses are passed to the token ring driver, (802.5), they
151 * must be bit-swapped because 802.5 transmission order is MSb first.
152 *
153 * Furthermore, according to IBM Austin, these addresses are not
154 * true token ring multicast addresses. More work is necessary
155 * to get multicast to work right on token ring.
156 *
157 * Currently, the token ring driver does not handle multicast, so
158 * these addresses are converted into the broadcast address in
159 * lan_output() That means that if these multicast addresses change
160 * the token ring driver must be altered.
161 */
162 const char all_es_snpa[] = {0x09, 0x00, 0x2b, 0x00, 0x00, 0x04};
163 const char all_is_snpa[] = {0x09, 0x00, 0x2b, 0x00, 0x00, 0x05};
164 const char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14};
165 const char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15};
166
167 union sockunion {
168 struct sockaddr_iso siso;
169 struct sockaddr_dl sdl;
170 struct sockaddr sa;
171 };
172
173 /*
174 * FUNCTION: llc_rtrequest
175 *
176 * PURPOSE: Manage routing table entries specific to LLC for ISO.
177 *
178 * NOTES: This does a lot of obscure magic;
179 */
180 void
181 llc_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
182 {
183 union sockunion *gate = (union sockunion *) rt->rt_gateway;
184 struct llinfo_llc *lc = (struct llinfo_llc *) rt->rt_llinfo;
185 struct ifnet *ifp = rt->rt_ifp;
186 int addrlen = ifp->if_addrlen;
187 #define LLC_SIZE 3 /* XXXXXX do this right later */
188
189 #ifdef ARGO_DEBUG
190 if (argo_debug[D_SNPA]) {
191 printf("llc_rtrequest(%d, %p, %p)\n", req, rt, info);
192 }
193 #endif
194 if (rt->rt_flags & RTF_GATEWAY)
195 return;
196 else
197 switch (req) {
198 case RTM_ADD:
199 /*
200 * Case 1: This route may come from a route to iface with mask
201 * or from a default route.
202 */
203 if (rt->rt_flags & RTF_CLONING) {
204 union {
205 struct sockaddr sa;
206 struct sockaddr_dl sdl;
207 struct sockaddr_storage ss;
208 } u;
209
210 iso_setmcasts(ifp, req);
211 sockaddr_dl_init(&u.sdl, sizeof(u.ss),
212 ifp->if_index, ifp->if_type,
213 NULL, strlen(ifp->if_xname),
214 NULL, ifp->if_addrlen);
215 rt_setgate(rt, &u.sa);
216 return;
217 }
218 if (lc != 0)
219 return; /* happens on a route change */
220 /* FALLTHROUGH */
221 case RTM_RESOLVE:
222 /*
223 * Case 2: This route may come from cloning, or a manual route
224 * add with a LL address.
225 */
226 if (gate->sdl.sdl_family != AF_LINK) {
227 log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n");
228 break;
229 }
230 R_Malloc(lc, struct llinfo_llc *, sizeof(*lc));
231 rt->rt_llinfo = (void *) lc;
232 if (lc == 0) {
233 log(LOG_DEBUG, "llc_rtrequest: malloc failed\n");
234 break;
235 }
236 memset(lc, 0, sizeof(*lc));
237 lc->lc_rt = rt;
238 rt->rt_flags |= RTF_LLINFO;
239 LIST_INSERT_HEAD(&llinfo_llc, lc, lc_list);
240 if (gate->sdl.sdl_alen == sizeof(struct esis_req)
241 + addrlen) {
242 gate->sdl.sdl_alen -= sizeof(struct esis_req);
243 (void)memcpy(&lc->lc_er,
244 (const char *)CLLADDR(&gate->sdl) +
245 addrlen, sizeof(lc->lc_er));
246 } else if (gate->sdl.sdl_alen == addrlen)
247 lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM);
248 break;
249 case RTM_DELETE:
250 if (rt->rt_flags & RTF_CLONING)
251 iso_setmcasts(ifp, req);
252 if (lc == 0)
253 return;
254 LIST_REMOVE(lc, lc_list);
255 Free(lc);
256 rt->rt_llinfo = 0;
257 rt->rt_flags &= ~RTF_LLINFO;
258 break;
259 }
260 if (rt->rt_rmx.rmx_mtu == 0) {
261 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE;
262 }
263 }
264
265 /*
266 * FUNCTION: iso_setmcasts
267 *
268 * PURPOSE: Enable/Disable ESIS/ISIS multicast reception on
269 * interfaces.
270 *
271 * NOTES: This also does a lot of obscure magic;
272 */
273 void
274 iso_setmcasts(struct ifnet *ifp, int req)
275 {
276 static const char * const addrlist[] =
277 {all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0};
278 struct ifreq ifr;
279 const char *const *cpp;
280
281 (void)memset(&ifr, 0, sizeof(ifr));
282 for (cpp = addrlist; *cpp; cpp++) {
283 (void)memcpy(ifr.ifr_addr.sa_data, *cpp, 6);
284 if (req == RTM_ADD && (ifp->if_ioctl == NULL ||
285 (*ifp->if_ioctl)(ifp, SIOCADDMULTI, &ifr) != 0))
286 printf("iso_setmcasts: %s unable to add mcast\n",
287 ifp->if_xname);
288 else if (req == RTM_DELETE && (ifp->if_ioctl == NULL ||
289 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, &ifr) != 0))
290 printf("iso_setmcasts: %s unable to delete mcast\n",
291 ifp->if_xname);
292 }
293 }
294
295 /*
296 * FUNCTION: iso_snparesolve
297 *
298 * PURPOSE: Resolve an iso address into snpa address
299 *
300 * RETURNS: 0 if addr is resolved
301 * errno if addr is unknown
302 *
303 * SIDE EFFECTS:
304 *
305 * NOTES: Now that we have folded the snpa cache into the routing
306 * table, we know there is no snpa address known for this
307 * destination. If we know of a default IS, then the
308 * address of the IS is returned. If no IS is known,
309 * then return the multi-cast address for "all ES" for
310 * this interface.
311 *
312 * NB: the last case described above constitutes the
313 * query configuration function 9542, sec 6.5
314 * A mechanism is needed to prevent this function from
315 * being invoked if the system is an IS.
316 */
317 int
318 iso_snparesolve(
319 struct ifnet *ifp, /* outgoing interface */
320 const struct sockaddr_iso *dest, /* destination */
321 void * snpa, /* RESULT: snpa to be used */
322 int *snpa_len) /* RESULT: length of snpa */
323 {
324 struct llinfo_llc *sc; /* ptr to snpa table entry */
325 const char *found_snpa;
326 int addrlen;
327
328 /*
329 * This hack allows us to send esis packets that have the destination
330 * snpa addresss embedded in the destination nsap address
331 */
332 if (dest->siso_data[0] == AFI_SNA) {
333 /*
334 * This is a subnetwork address. Return it immediately
335 */
336 #ifdef ARGO_DEBUG
337 if (argo_debug[D_SNPA]) {
338 printf("iso_snparesolve: return SN address\n");
339 }
340 #endif
341 addrlen = dest->siso_nlen - 1; /* subtract size of AFI */
342 found_snpa = (const char *)dest->siso_data + 1;
343 /*
344 * If we are an IS, we can't do much with the packet; Check
345 * if we know about an IS.
346 */
347 } else if (iso_systype != SNPA_IS && known_is != 0 &&
348 (sc = (struct llinfo_llc *) known_is->rt_llinfo) &&
349 (sc->lc_flags & SNPA_VALID)) {
350 const struct sockaddr_dl *sdl = satocsdl(known_is->rt_gateway);
351 found_snpa = CLLADDR(sdl);
352 addrlen = sdl->sdl_alen;
353 } else if (ifp->if_flags & IFF_BROADCAST) {
354 /*
355 * no IS, no match. Return "all es" multicast address for
356 * this interface, as per Query Configuration Function (9542
357 * sec 6.5)
358 *
359 * Note: there is a potential problem here. If the destination
360 * is on the subnet and it does not respond with a ESH, but
361 * does send back a TP CC, a connection could be established
362 * where we always transmit the CLNP packet to "all es"
363 */
364 addrlen = ifp->if_addrlen;
365 found_snpa = (const char *) all_es_snpa;
366 } else
367 return (ENETUNREACH);
368 memcpy(snpa, found_snpa, *snpa_len = addrlen);
369 return (0);
370 }
371
372
373 /*
374 * FUNCTION: snpac_free
375 *
376 * PURPOSE: free an entry in the iso address map table
377 *
378 * RETURNS: nothing
379 *
380 * SIDE EFFECTS:
381 *
382 * NOTES: If there is a route entry associated with cache
383 * entry, then delete that as well
384 */
385 void
386 snpac_free(
387 struct llinfo_llc *lc) /* entry to free */
388 {
389 struct rtentry *rt = lc->lc_rt;
390
391 if (known_is == rt)
392 known_is = 0;
393 if (rt && (rt->rt_flags & RTF_UP) &&
394 (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) {
395 RTFREE(rt);
396 rtrequest(RTM_DELETE, rt_getkey(rt), rt->rt_gateway,
397 rt_mask(rt), rt->rt_flags, NULL);
398 RTFREE(rt);
399 }
400 }
401
402 /*
403 * FUNCTION: snpac_add
404 *
405 * PURPOSE: Add an entry to the snpa cache
406 *
407 * RETURNS:
408 *
409 * SIDE EFFECTS:
410 *
411 * NOTES: If entry already exists, then update holding time.
412 */
413 int
414 snpac_add(
415 struct ifnet *ifp, /* interface info is related to */
416 struct iso_addr *nsap, /* nsap to add */
417 void * snpa, /* translation */
418 int type, /* SNPA_IS or SNPA_ES */
419 u_short ht, /* holding time (in seconds) */
420 int nsellength) /* nsaps may differ only in trailing
421 * bytes */
422 {
423 struct llinfo_llc *lc;
424 struct rtentry *rt;
425 struct rtentry *mrt = 0;
426 struct iso_addr *r; /* for zap_isoaddr macro */
427 int snpalen = min(ifp->if_addrlen, MAX_SNPALEN);
428 int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type;
429
430 #ifdef ARGO_DEBUG
431 if (argo_debug[D_SNPA]) {
432 printf("snpac_add(%p, %p, %p, %x, %x, %x)\n",
433 ifp, nsap, snpa, type, ht, nsellength);
434 }
435 #endif
436 zap_isoaddr(dst, nsap);
437 rt = rtalloc1(sisotosa(&dst), 0);
438 #ifdef ARGO_DEBUG
439 if (argo_debug[D_SNPA]) {
440 printf("snpac_add: rtalloc1 returns %p\n", rt);
441 }
442 #endif
443 if (rt == 0) {
444 struct sockaddr *netmask;
445 int flags;
446 add:
447 if (nsellength) {
448 netmask = sisotosa(&msk);
449 flags = RTF_UP;
450 snpac_fixdstandmask(nsellength);
451 } else {
452 netmask = 0;
453 flags = RTF_UP | RTF_HOST;
454 }
455 new_entry = 1;
456 sockaddr_dl_init(>e_dl, sizeof(gte_dl), index, iftype,
457 NULL, 0, snpa, snpalen);
458
459 if (rtrequest(RTM_ADD, sisotosa(&dst), S(gte_dl), netmask,
460 flags, &mrt) || mrt == 0)
461 return (0);
462 rt = mrt;
463 rt->rt_refcnt--;
464 } else {
465 struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
466 rt->rt_refcnt--;
467 if ((rt->rt_flags & RTF_LLINFO) == 0)
468 goto add;
469 if (nsellength && (rt->rt_flags & RTF_HOST)) {
470 if (rt->rt_refcnt == 0) {
471 rtrequest(RTM_DELETE, sisotosa(&dst),
472 NULL, NULL, 0, NULL);
473 rt = 0;
474 goto add;
475 } else {
476 static struct iso_addr nsap2;
477 char *cp;
478 nsap2 = *nsap;
479 cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength;
480 while (cp < (char *) (1 + &nsap2))
481 *cp++ = 0;
482 (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength);
483 }
484 }
485 if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) {
486 int old_sdl_len = sdl->sdl_len;
487 if (old_sdl_len < sizeof(*sdl)) {
488 log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n");
489 return (0);
490 }
491 sockaddr_dl_init(sdl, sdl->sdl_len, index, iftype,
492 NULL, 0, snpa, snpalen);
493 new_entry = 1;
494 }
495 }
496 if ((lc = (struct llinfo_llc *) rt->rt_llinfo) == 0)
497 panic("snpac_rtrequest");
498 rt->rt_rmx.rmx_expire = ht + time_second;
499 lc->lc_flags = SNPA_VALID | type;
500 if ((type & SNPA_IS) && !(iso_systype & SNPA_IS))
501 snpac_logdefis(rt);
502 return (new_entry);
503 }
504
505 static void
506 snpac_fixdstandmask(int nsellength)
507 {
508 char *cp = msk.siso_data, *cplim;
509
510 cplim = cp + (dst.siso_nlen -= nsellength);
511 msk.siso_len = cplim - (char *) &msk;
512 msk.siso_nlen = 0;
513 while (cp < cplim)
514 *cp++ = -1;
515 while (cp < (char *) msk.siso_pad)
516 *cp++ = 0;
517 for (cp = dst.siso_data + dst.siso_nlen; cp < (char *) dst.siso_pad;)
518 *cp++ = 0;
519 }
520
521 /*
522 * FUNCTION: snpac_ioctl
523 *
524 * PURPOSE: Set/Get the system type and esis parameters
525 *
526 * RETURNS: 0 on success, or unix error code
527 *
528 * SIDE EFFECTS:
529 *
530 * NOTES:
531 */
532 int
533 snpac_ioctl(
534 struct socket *so,
535 u_long cmd, /* ioctl to process */
536 void *data, /* data for the cmd */
537 struct lwp *l)
538 {
539 struct systype_req *rq = (struct systype_req *) data;
540
541 #ifdef ARGO_DEBUG
542 if (argo_debug[D_IOCTL]) {
543 if (cmd == SIOCSSTYPE)
544 printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n",
545 rq->sr_type, rq->sr_holdt, rq->sr_configt);
546 else
547 printf("snpac_ioctl: cmd get\n");
548 }
549 #endif
550
551 if (cmd == SIOCSSTYPE) {
552 if (l == NULL || kauth_authorize_generic(l->l_cred,
553 KAUTH_GENERIC_ISSUSER, NULL))
554 return (EPERM);
555 if ((rq->sr_type & (SNPA_ES | SNPA_IS)) == (SNPA_ES | SNPA_IS))
556 return (EINVAL);
557 if (rq->sr_type & SNPA_ES) {
558 iso_systype = SNPA_ES;
559 } else if (rq->sr_type & SNPA_IS) {
560 iso_systype = SNPA_IS;
561 } else {
562 return (EINVAL);
563 }
564 esis_holding_time = rq->sr_holdt;
565 esis_config_time = rq->sr_configt;
566 if (esis_esconfig_time != rq->sr_esconfigt) {
567 callout_stop(&esis_config_ch);
568 esis_esconfig_time = rq->sr_esconfigt;
569 esis_config(NULL);
570 }
571 } else if (cmd == SIOCGSTYPE) {
572 rq->sr_type = iso_systype;
573 rq->sr_holdt = esis_holding_time;
574 rq->sr_configt = esis_config_time;
575 rq->sr_esconfigt = esis_esconfig_time;
576 } else {
577 return (EINVAL);
578 }
579 return (0);
580 }
581
582 /*
583 * FUNCTION: snpac_logdefis
584 *
585 * PURPOSE: Mark the IS passed as the default IS
586 *
587 * RETURNS: nothing
588 *
589 * SIDE EFFECTS:
590 *
591 * NOTES:
592 */
593 void
594 snpac_logdefis(struct rtentry *sc)
595 {
596 struct rtentry *rt;
597
598 if (known_is == sc || !(sc->rt_flags & RTF_HOST))
599 return;
600 if (known_is) {
601 RTFREE(known_is);
602 }
603 known_is = sc;
604 sc->rt_refcnt++;
605 rt = rtalloc1((struct sockaddr *) & zsi, 0);
606 if (rt == 0) {
607 rtrequest(RTM_ADD, sisotosa(&zsi), rt_getkey(sc),
608 sisotosa(&zmk), RTF_DYNAMIC | RTF_GATEWAY, NULL);
609 } else {
610 if ((rt->rt_flags & RTF_DYNAMIC) &&
611 (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0)
612 rt_setgate(rt, rt_getkey(sc));
613 }
614 }
615
616 /*
617 * FUNCTION: snpac_age
618 *
619 * PURPOSE: Time out snpac entries
620 *
621 * RETURNS:
622 *
623 * SIDE EFFECTS:
624 *
625 * NOTES: When encountering an entry for the first time, snpac_age
626 * may delete up to SNPAC_AGE too many seconds. Ie.
627 * if the entry is added a moment before snpac_age is
628 * called, the entry will immediately have SNPAC_AGE
629 * seconds taken off the holding time, even though
630 * it has only been held a brief moment.
631 *
632 * The proper way to do this is set an expiry timeval
633 * equal to current time + holding time. Then snpac_age
634 * would time out entries where expiry date is older
635 * than the current time.
636 */
637 /*ARGSUSED*/
638 void
639 snpac_age(void *v)
640 {
641 struct llinfo_llc *lc, *nlc;
642 struct rtentry *rt;
643
644 callout_reset(&snpac_age_ch, SNPAC_AGE * hz, snpac_age, NULL);
645
646 for (lc = llinfo_llc.lh_first; lc != 0; lc = nlc) {
647 nlc = lc->lc_list.le_next;
648 if (lc->lc_flags & SNPA_VALID) {
649 rt = lc->lc_rt;
650 if (rt->rt_rmx.rmx_expire &&
651 rt->rt_rmx.rmx_expire < time_second)
652 snpac_free(lc);
653 }
654 }
655 }
656
657 /*
658 * FUNCTION: snpac_ownmulti
659 *
660 * PURPOSE: Determine if the snpa address is a multicast address
661 * of the same type as the system.
662 *
663 * RETURNS: true or false
664 *
665 * SIDE EFFECTS:
666 *
667 * NOTES: Used by interface drivers when not in eavesdrop mode
668 * as interm kludge until
669 * real multicast addresses can be configured
670 */
671 int
672 snpac_ownmulti(void *snpa, u_int len)
673 {
674 return (((iso_systype & SNPA_ES) &&
675 (!memcmp(snpa, all_es_snpa, len))) ||
676 ((iso_systype & SNPA_IS) &&
677 (!memcmp(snpa, all_is_snpa, len))));
678 }
679
680 /*
681 * FUNCTION: snpac_flushifp
682 *
683 * PURPOSE: Flush entries associated with specific ifp
684 *
685 * RETURNS: nothing
686 *
687 * SIDE EFFECTS:
688 *
689 * NOTES:
690 */
691 void
692 snpac_flushifp(struct ifnet *ifp)
693 {
694 struct llinfo_llc *lc;
695
696 for (lc = llinfo_llc.lh_first; lc != 0; lc = lc->lc_list.le_next) {
697 if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID))
698 snpac_free(lc);
699 }
700 }
701
702 /*
703 * FUNCTION: snpac_rtrequest
704 *
705 * PURPOSE: Make a routing request
706 *
707 * RETURNS: nothing
708 *
709 * SIDE EFFECTS:
710 *
711 * NOTES: In the future, this should make a request of a user
712 * level routing daemon.
713 */
714 void
715 snpac_rtrequest(int req, struct iso_addr *host, struct iso_addr *gateway,
716 struct iso_addr *netmask, int flags, struct rtentry **ret_nrt)
717 {
718 struct iso_addr *r;
719
720 #ifdef ARGO_DEBUG
721 if (argo_debug[D_SNPA]) {
722 printf("snpac_rtrequest: ");
723 if (req == RTM_ADD)
724 printf("add");
725 else if (req == RTM_DELETE)
726 printf("delete");
727 else
728 printf("unknown command");
729 printf(" dst: %s\n", clnp_iso_addrp(host));
730 printf("\tgateway: %s\n", clnp_iso_addrp(gateway));
731 }
732 #endif
733
734
735 zap_isoaddr(dst, host);
736 zap_isoaddr(gte, gateway);
737 if (netmask) {
738 zap_isoaddr(msk, netmask);
739 msk.siso_nlen = 0;
740 msk.siso_len = msk.siso_pad - (u_char *) & msk;
741 }
742 rtrequest(req, sisotosa(&dst), sisotosa(>e),
743 (netmask ? sisotosa(&msk) : (struct sockaddr *) 0), flags, ret_nrt);
744 }
745
746 /*
747 * FUNCTION: snpac_addrt
748 *
749 * PURPOSE: Associate a routing entry with an snpac entry
750 *
751 * RETURNS: nothing
752 *
753 * SIDE EFFECTS:
754 *
755 * NOTES: If a cache entry exists for gateway, then
756 * make a routing entry (host, gateway) and associate
757 * with gateway.
758 *
759 * If a route already exists and is different, first delete
760 * it.
761 *
762 * This could be made more efficient by checking
763 * the existing route before adding a new one.
764 */
765 void
766 snpac_addrt(struct ifnet *ifp, struct iso_addr *host,
767 struct iso_addr *gateway, struct iso_addr *netmask)
768 {
769 struct iso_addr *r;
770
771 zap_isoaddr(dst, host);
772 zap_isoaddr(gte, gateway);
773 if (netmask) {
774 zap_isoaddr(msk, netmask);
775 msk.siso_nlen = 0;
776 msk.siso_len = msk.siso_pad - (u_char *) & msk;
777 rtredirect(sisotosa(&dst), sisotosa(>e), sisotosa(&msk),
778 RTF_DONE, sisotosa(>e), 0);
779 } else
780 rtredirect(sisotosa(&dst), sisotosa(>e), (struct sockaddr *) 0,
781 RTF_DONE | RTF_HOST, sisotosa(>e), 0);
782 }
783 #endif /* ISO */
Cache object: 1211620ae9005a448579fe1a41034a3f
|